Import of rc and librdef 1.0

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2721 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
mahlzeit
2003-02-16 15:18:36 +00:00
parent 5c905a2f6a
commit 285c7c7335
25 changed files with 6125 additions and 0 deletions
+188
View File
@@ -0,0 +1,188 @@
# Doxyfile 1.2.17
#---------------------------------------------------------------------------
# General configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = "librdef API version 1"
PROJECT_NUMBER =
OUTPUT_DIRECTORY =
OUTPUT_LANGUAGE = English
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
HIDE_UNDOC_MEMBERS = YES
HIDE_UNDOC_CLASSES = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = NO
STRIP_FROM_PATH =
INTERNAL_DOCS = NO
STRIP_CODE_COMMENTS = YES
CASE_SENSE_NAMES = YES
SHORT_NAMES = NO
HIDE_SCOPE_NAMES = NO
VERBATIM_HEADERS = YES
SHOW_INCLUDE_FILES = YES
JAVADOC_AUTOBRIEF = YES
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
DISTRIBUTE_GROUP_DOC = NO
TAB_SIZE = 4
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
ALIASES =
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
SHOW_USED_FILES = YES
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = .
FILE_PATTERNS = rdef.h
RECURSIVE = NO
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS =
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_SOURCE_FILES = NO
#---------------------------------------------------------------------------
# configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX =
#---------------------------------------------------------------------------
# configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 1
GENERATE_TREEVIEW = NO
TREEVIEW_WIDTH = 250
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4wide
EXTRA_PACKAGES =
LATEX_HEADER =
PDF_HYPERLINKS = NO
USE_PDFLATEX = NO
LATEX_BATCHMODE = NO
#---------------------------------------------------------------------------
# configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
# configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_LINKS = NO
#---------------------------------------------------------------------------
# configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
#---------------------------------------------------------------------------
# configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration::addtions related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
TEMPLATE_RELATIONS = YES
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
GRAPHICAL_HIERARCHY = YES
DOT_IMAGE_FORMAT = png
DOT_PATH =
DOTFILE_DIRS =
MAX_DOT_GRAPH_WIDTH = 1024
MAX_DOT_GRAPH_HEIGHT = 1024
GENERATE_LEGEND = YES
DOT_CLEANUP = YES
#---------------------------------------------------------------------------
# Configuration::addtions related to the search engine
#---------------------------------------------------------------------------
SEARCHENGINE = NO
CGI_NAME = search.cgi
CGI_URL =
DOC_URL =
DOC_ABSPATH =
BIN_ABSPATH = /usr/local/bin/
EXT_DOC_PATHS =
+29
View File
@@ -0,0 +1,29 @@
# settings for debug builds:
#CXXFLAGS = -g -O0 -DDEBUG -Wall -Wno-multichar
# settings for release builds:
CXXFLAGS = -O2 -Wall -Wno-multichar -Wno-sign-compare -Wno-unused
all: rc librdef.so
parser.cpp: parser.y
bison -d -o$@ $^
lexer.cpp: lexer.l parser.cpp
flex -o$@ lexer.l
librdef.so: compile.cpp decompile.cpp lexer.cpp parser.cpp rdef.cpp
$(CXX) $(CXXFLAGS) -D_BUILDING_RDEF -lbe -lstdc++.r4 -o $@ $^ -nostart -Xlinker -soname=$@
mimeset -f $@
rc: rc.cpp librdef.so
$(CXX) $(CXXFLAGS) -L./ -lrdef -o $@ rc.cpp
mimeset -f $@
clean:
rm -f *.o rc librdef.so lexer.cpp parser.cpp parser.cpp.h
install:
cp rc ~/config/bin
cp librdef.so ~/config/lib
+264
View File
@@ -0,0 +1,264 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <Entry.h>
#include <File.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rdef.h"
#include "compile.h"
#include "private.h"
#include "parser.cpp.h"
char lexfile[B_PATH_NAME_LENGTH];
static BEntry entry;
static BFile file;
BResources rsrc;
const char* rsrc_file;
static jmp_buf abort_jmp; // for aborting compilation
// When it encounters an error, the parser immediately aborts (we don't try
// error recovery). But its parse stack may still contain malloc'ed objects.
// We keep track of these memory blocks in the mem_list, so we can properly
// free them in case of an error (which is the polite thing to do since we
// are a shared library). If the compilation was successful, then mem_list
// should be empty. In DEBUG mode we dump some statistics to verify that the
// parser properly frees up objects when it is done with them.
#ifdef DEBUG
struct mem_t
{
void* ptr;
char* file;
int32 line;
};
typedef std::list<mem_t> mem_list_t;
typedef mem_list_t::iterator mem_iter_t;
static mem_list_t mem_list;
#else
static ptr_list_t mem_list;
#endif
//------------------------------------------------------------------------------
void* alloc_mem(size_t size)
{
void* ptr = malloc(size); // can be 0
if (ptr == NULL)
{
abort_compile(B_NO_MEMORY, "out of memory");
}
#ifdef DEBUG
mem_t mem;
mem.ptr = ptr;
mem.file = strdup(lexfile);
mem.line = yylineno;
mem_list.push_front(mem);
#else
mem_list.push_front(ptr);
#endif
return ptr;
}
//------------------------------------------------------------------------------
void free_mem(void* ptr)
{
if (ptr != NULL)
{
#ifdef DEBUG
for (mem_iter_t i = mem_list.begin(); i != mem_list.end(); ++i)
{
if (i->ptr == ptr)
{
free(i->ptr);
free(i->file);
mem_list.erase(i);
return;
}
}
#else
mem_list.remove(ptr);
free(ptr);
#endif
}
}
//------------------------------------------------------------------------------
static void clean_up_mem()
{
#ifdef DEBUG
printf("mem_list leaks %ld objects\n", mem_list.size());
for (mem_iter_t i = mem_list.begin(); i != mem_list.end(); )
{
printf("%p allocated at %s:%ld\n", i->ptr, i->file, i->line);
free(i->ptr);
free(i->file);
i = mem_list.erase(i);
}
#else
free_ptr_list(mem_list);
#endif
}
//------------------------------------------------------------------------------
void abort_compile(status_t err, const char* format, ...)
{
va_list ap;
rdef_err = err;
rdef_err_line = yylineno;
strcpy(rdef_err_file, lexfile);
va_start(ap, format);
vsprintf(rdef_err_msg, format, ap);
va_end(ap);
abort_compile();
}
//------------------------------------------------------------------------------
void abort_compile()
{
longjmp(abort_jmp, 1);
}
//------------------------------------------------------------------------------
static void compile_file(char* file)
{
strcpy(lexfile, file);
yyin = fopen(lexfile, "r");
if (yyin == NULL)
{
strcpy(rdef_err_file, lexfile);
rdef_err = RDEF_FILE_NOT_FOUND;
return;
}
init_lexer();
init_parser();
if (setjmp(abort_jmp) == 0)
{
yyparse();
}
// About error handling: If the bison-generated parser encounters
// a syntax error, it calls yyerror(), aborts parsing, and returns
// from yyparse(). For other kinds of errors (semantics, problem
// writing to BResources, etc), we bail out with a longjmp(). From
// then on, we can tell success or failure by looking at rdef_err.
clean_up_lexer();
clean_up_parser();
clean_up_mem();
}
//------------------------------------------------------------------------------
static status_t open_output_file()
{
status_t err = entry.SetTo(rsrc_file, true);
if (err == B_OK)
{
uint32 openMode = B_READ_WRITE | B_CREATE_FILE;
bool clobber = false;
if (!(flags & RDEF_MERGE_RESOURCES))
{
openMode |= B_ERASE_FILE;
clobber = true;
}
err = file.SetTo(&entry, openMode);
if (err == B_OK)
{
err = rsrc.SetTo(&file, clobber);
}
}
return err;
}
//------------------------------------------------------------------------------
static void close_output_file()
{
if ((rdef_err == B_OK) || (flags & RDEF_MERGE_RESOURCES))
{
rsrc.Sync();
}
else
{
entry.Remove(); // throw away output file
}
file.Unset();
entry.Unset();
}
//------------------------------------------------------------------------------
status_t rdef_compile(const char* output_file)
{
clear_error();
if ((output_file == NULL) || (output_file[0] == '\0'))
{
rdef_err = B_BAD_VALUE;
return rdef_err;
}
rsrc_file = output_file;
rdef_err = open_output_file();
if (rdef_err != B_OK)
{
return rdef_err;
}
for (ptr_iter_t i = input_files.begin();
(i != input_files.end()) && (rdef_err == B_OK); ++i)
{
compile_file((char*) *i);
}
close_output_file();
return rdef_err;
}
//------------------------------------------------------------------------------
+109
View File
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef COMPILE_H
#define COMPILE_H
#include <Resources.h>
#include <TypeConstants.h>
// Handle of file we're currently parsing.
extern FILE* yyin;
// Name of the file we're currently parsing.
extern char lexfile[];
// The line we're currently parsing.
extern int yylineno;
struct field_t;
// Describes a data type.
struct type_t
{
type_code code; // type code
char* name; // name of this type
int32 count; // how many fields
field_t* fields; // field definitions
int32 def_id; // default resource ID
char* def_name; // default resource name
};
// Used by the lexer and parser to pass around resource data. The rdef
// format allows string literals to contain embedded '\0' chars, so we
// can't use strlen() to find their length; instead we look at the size
// field for that (size includes the final '\0' too).
struct data_t
{
type_t type; // data type
char* name; // name (only if this is a field)
size_t size; // byte size of data
void* ptr; // the actual data
};
// Describes a data field in a user-defined type.
struct field_t
{
type_t type; // data type
char* name; // name of this field
data_t data; // default value
};
// Describes an array of data_t or field_t objects.
struct list_t
{
int32 count;
void* items; // cast to data_t* or field_t*
};
// Used by the parser to pass around resource IDs.
struct id_t
{
bool has_id;
bool has_name;
int32 id;
char* name;
};
// The output file we add resources to.
extern BResources rsrc;
extern const char* rsrc_file;
int yylex();
int yyparse();
void init_lexer();
void clean_up_lexer();
void init_parser();
void clean_up_parser();
void* alloc_mem(size_t size);
void free_mem(void* ptr);
// Returns the data type with the specified name.
type_t get_type(char* name);
void abort_compile(status_t err, const char* format, ...);
void abort_compile();
#endif // COMPILE_H
+947
View File
@@ -0,0 +1,947 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <Mime.h>
#include <Resources.h>
#include <TypeConstants.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "rdef.h"
#include "private.h"
// What we add to the front of enum symbols.
#define PREFIX "R_"
static const char* rdef_name;
static char header_name[B_PATH_NAME_LENGTH + 1];
static FILE* rdef_file;
static FILE* header_file;
// Level of indentation (how many tabs).
static int32 tabs;
static void examine_data(const char*, type_code, const void*, size_t);
//------------------------------------------------------------------------------
static void indent()
{
for (int32 t = 0; t < tabs; ++t)
{
fprintf(rdef_file, "\t");
}
}
//------------------------------------------------------------------------------
void open_brace()
{
#ifdef PUSSY_CODER_STYLE
fprintf(rdef_file, " {\n");
#else
fprintf(rdef_file, "\n");
indent();
fprintf(rdef_file, "{\n");
#endif
++tabs;
}
//------------------------------------------------------------------------------
void close_brace()
{
--tabs;
fprintf(rdef_file, "\n");
indent();
fprintf(rdef_file, "}");
}
//------------------------------------------------------------------------------
static bool make_code(uint32 value, char* code)
{
code[0] = (value >> 24) & 0xFF;
if (isprint(code[0]))
{
code[1] = (value >> 16) & 0xFF;
if (isprint(code[1]))
{
code[2] = (value >> 8) & 0xFF;
if (isprint(code[2]))
{
code[3] = value & 0xFF;
if (isprint(code[3]))
{
code[4] = '\0';
return true;
}
}
}
}
return false;
}
//------------------------------------------------------------------------------
static void write_code(uint32 value)
{
char code[5];
if (make_code(value, code))
{
fprintf(rdef_file, "'%s'", code);
}
else
{
fprintf(rdef_file, "%lu", value);
}
}
//------------------------------------------------------------------------------
static void write_field_name(const char* name)
{
// We call this from the write_xxx() functions to properly align a
// field's type code (which goes to the left of the field name) and
// the field's data (to right of the name). If we are not currently
// writing a field (but the entire resource), name is NULL.
if (name != NULL)
{
fprintf(rdef_file, "\"%s\" = ", name);
}
}
//------------------------------------------------------------------------------
static bool is_ident(const char* name)
{
if ((name[0] != '_') && !isalpha(name[0])) { return false; }
for (size_t t = 1; t < strlen(name); ++t)
{
if ((name[t] != '_') && !isalnum(name[t])) { return false; }
}
return true;
}
//------------------------------------------------------------------------------
static bool has_prefix(const char* name)
{
size_t name_len = strlen(name);
size_t prefix_len = strlen(PREFIX);
if (name_len > prefix_len)
{
if (strncmp(name, PREFIX, prefix_len) == 0)
{
return true;
}
}
return false;
}
//------------------------------------------------------------------------------
static void write_rsrc(type_code type, int32 id, const char* name)
{
if (name[0] == '\0')
{
fprintf(rdef_file, "resource(%ld) ", id);
}
else if ((flags & RDEF_AUTO_NAMES) && is_ident(name))
{
char code[5];
if (has_prefix(name))
{
fprintf(rdef_file, "resource(%s) ", name);
fprintf(header_file, "\t%s = %ld,\n", name, id);
}
else if (make_code(type, code))
{
fprintf(rdef_file, "resource(%s%s_%s) ", PREFIX, code, name);
fprintf(header_file, "\t%s%s_%s = %ld,\n", PREFIX, code, name, id);
}
else
{
fprintf(rdef_file, "resource(%s%ld_%s) ", PREFIX, type, name);
fprintf(header_file, "\t%s%ld_%s = %ld,\n", PREFIX, type, name, id);
}
}
else
{
fprintf(rdef_file, "resource(%ld, \"%s\") ", id, name);
}
}
//------------------------------------------------------------------------------
static uint8* write_raw_line(uint8* ptr, uint8* end, size_t bytes_per_line)
{
uint32 count = 0;
fprintf(rdef_file, "$\"");
while ((ptr < end) && (count < bytes_per_line))
{
fprintf(rdef_file, "%02X", *ptr++);
++count;
}
fprintf(rdef_file, "\"");
return ptr;
}
//------------------------------------------------------------------------------
static void write_raw(
const char* name, type_code type, const void* data, size_t length,
size_t bytes_per_line = 32)
{
uint8* ptr = (uint8*) data;
uint8* end = ptr + length;
if (length > bytes_per_line)
{
if (type != B_RAW_TYPE)
{
fprintf(rdef_file, "#");
write_code(type);
fprintf(rdef_file, " ");
}
write_field_name(name);
fprintf(rdef_file, "array");
open_brace();
int32 item = 0;
while (ptr < end)
{
if (item++ > 0) { fprintf(rdef_file, "\n"); }
indent();
ptr = write_raw_line(ptr, end, bytes_per_line);
}
close_brace();
}
else
{
if (type != B_RAW_TYPE)
{
fprintf(rdef_file, "#");
write_code(type);
fprintf(rdef_file, " ");
}
write_field_name(name);
write_raw_line(ptr, end, bytes_per_line);
}
}
//------------------------------------------------------------------------------
static void write_bool(const char* name, const void* data, size_t length)
{
if (length != sizeof(bool))
{
write_raw(name, B_BOOL_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "%s", *((bool*) data) ? "true" : "false");
}
}
//------------------------------------------------------------------------------
static void write_int8(const char* name, const void* data, size_t length)
{
if (length != sizeof(int8))
{
write_raw(name, B_INT8_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(int8)%d", *((int8*) data));
}
}
//------------------------------------------------------------------------------
static void write_int16(const char* name, const void* data, size_t length)
{
if (length != sizeof(int16))
{
write_raw(name, B_INT16_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(int16)%d", *((int16*) data));
}
}
//------------------------------------------------------------------------------
static void write_int32(const char* name, const void* data, size_t length)
{
if (length != sizeof(int32))
{
write_raw(name, B_INT32_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "%ld", *((int32*) data));
}
}
//------------------------------------------------------------------------------
static void write_int64(const char* name, const void* data, size_t length)
{
if (length != sizeof(int64))
{
write_raw(name, B_INT64_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(int64)%lld", *((int64*) data));
}
}
//------------------------------------------------------------------------------
static void write_uint8(const char* name, const void* data, size_t length)
{
if (length != sizeof(uint8))
{
write_raw(name, B_UINT8_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(uint8)%u", *((uint8*) data));
}
}
//------------------------------------------------------------------------------
static void write_uint16(const char* name, const void* data, size_t length)
{
if (length != sizeof(uint16))
{
write_raw(name, B_UINT16_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(uint16)%u", *((uint16*) data));
}
}
//------------------------------------------------------------------------------
static void write_uint32(const char* name, const void* data, size_t length)
{
if (length != sizeof(uint32))
{
write_raw(name, B_UINT32_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(uint32)%lu", *((uint32*) data));
}
}
//------------------------------------------------------------------------------
static void write_uint64(const char* name, const void* data, size_t length)
{
if (length != sizeof(uint64))
{
write_raw(name, B_UINT64_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(uint64)%llu", *((uint64*) data));
}
}
//------------------------------------------------------------------------------
static void write_float(const char* name, const void* data, size_t length)
{
if (length != sizeof(float))
{
write_raw(name, B_FLOAT_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "%#g", *((float*) data));
}
}
//------------------------------------------------------------------------------
static void write_double(const char* name, const void* data, size_t length)
{
if (length != sizeof(double))
{
write_raw(name, B_DOUBLE_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(double)%#g", *((double*) data));
}
}
//------------------------------------------------------------------------------
static void write_size(const char* name, const void* data, size_t length)
{
if (length != sizeof(size_t))
{
write_raw(name, B_SIZE_T_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(size_t)%lu", *((size_t*) data));
}
}
//------------------------------------------------------------------------------
static void write_ssize(const char* name, const void* data, size_t length)
{
if (length != sizeof(ssize_t))
{
write_raw(name, B_SSIZE_T_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(ssize_t)%ld", *((ssize_t*) data));
}
}
//------------------------------------------------------------------------------
static void write_off(const char* name, const void* data, size_t length)
{
if (length != sizeof(off_t))
{
write_raw(name, B_OFF_T_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(off_t)%lld", *((off_t*) data));
}
}
//------------------------------------------------------------------------------
static void write_time(const char* name, const void* data, size_t length)
{
if (length != sizeof(time_t))
{
write_raw(name, B_TIME_TYPE, data, length);
}
else
{
write_field_name(name);
fprintf(rdef_file, "(time_t)%ld", *((time_t*) data));
}
}
//------------------------------------------------------------------------------
static void write_point(const char* name, const void* data)
{
///TODO: using built-in type table
write_field_name(name);
float* f = (float*) data;
fprintf(rdef_file, "point { %#g, %#g }", f[0], f[1]);
}
//------------------------------------------------------------------------------
static void write_rect(const char* name, const void* data)
{
///TODO: using built-in type table
write_field_name(name);
float* f = (float*) data;
fprintf(rdef_file, "rect { %#g, %#g, %#g, %#g }", f[0], f[1], f[2], f[3]);
}
//------------------------------------------------------------------------------
static void write_rgb(const char* name, const void* data)
{
///TODO: using built-in type table
write_field_name(name);
uint8* b = (uint8*) data;
fprintf(
rdef_file, "rgb_color { 0x%02X, 0x%02X, 0x%02X, 0x%02X }",
b[0], b[1], b[2], b[3]);
}
//------------------------------------------------------------------------------
static char* write_string_line(char* ptr, char* end, size_t chars_per_line)
{
uint32 count = 0;
bool end_of_item = false;
fprintf(rdef_file, "\"");
while ((ptr < end) && (count < chars_per_line) && !end_of_item)
{
char c = *ptr++;
switch (c)
{
case '\b': fprintf(rdef_file, "\\b"); count += 2; break;
case '\f': fprintf(rdef_file, "\\f"); count += 2; break;
case '\n': fprintf(rdef_file, "\\n"); count += 2; break;
case '\r': fprintf(rdef_file, "\\r"); count += 2; break;
case '\t': fprintf(rdef_file, "\\t"); count += 2; break;
case '\v': fprintf(rdef_file, "\\v"); count += 2; break;
case '\"': fprintf(rdef_file, "\\\""); count += 2; break;
case '\\': fprintf(rdef_file, "\\\\"); count += 2; break;
case '\0': end_of_item = true; break;
default:
{
if ((((uint8) c) < 128) && !isprint(c))
{
fprintf(rdef_file, "\\0x%02X", (uint8) c); count += 5;
}
else
{
fprintf(rdef_file, "%c", c); ++count;
}
}
}
}
fprintf(rdef_file, "\"");
if (end_of_item && (ptr < end))
{
fprintf(rdef_file, ",");
}
return ptr;
}
//------------------------------------------------------------------------------
static void write_string(
const char* name, type_code type, const void* data, size_t length)
{
char* ptr = (char*) data;
char* end = ptr + length;
size_t chars_per_line = 64;
// We write an "array" resource if the string has more than 64
// characters. A string resource may also be comprised of multiple
// substrings, each terminated by a '\0' char. In that case, we
// must write an "array" resource as well. Sneaky as we are, we use
// strlen() to check for that, because it also looks for a '\0'.
if ((length > chars_per_line) || (strlen(ptr) < length - 1))
{
fprintf(rdef_file, "#");
write_code(type);
fprintf(rdef_file, " array");
if (name != NULL)
{
fprintf(rdef_file, " ");
write_field_name(name);
fprintf(rdef_file, " array");
}
open_brace();
int32 item = 0;
while (ptr < end)
{
if (item++ > 0) { fprintf(rdef_file, "\n"); }
indent();
ptr = write_string_line(ptr, end, chars_per_line);
}
close_brace();
}
else
{
if (type != B_STRING_TYPE)
{
fprintf(rdef_file, "#");
write_code(type);
fprintf(rdef_file, " ");
}
write_field_name(name);
write_string_line(ptr, end, chars_per_line);
}
}
//------------------------------------------------------------------------------
static void write_fields(BMessage& msg)
{
int32 t = 0;
int32 item = 0;
char* name;
type_code type;
int32 count;
const void* data;
size_t length;
open_brace();
while (msg.GetInfo(B_ANY_TYPE, t, &name, &type, &count) == B_OK)
{
for (int32 k = 0; k < count; ++k)
{
if (msg.FindData(name, type, k, &data, (ssize_t*) &length) == B_OK)
{
if (item++ > 0) { fprintf(rdef_file, ",\n"); }
indent();
examine_data(name, type, data, length);
}
}
++t;
}
close_brace();
}
//------------------------------------------------------------------------------
static void write_message(const char* name, BMessage& msg, type_code type)
{
if (type != B_MESSAGE_TYPE)
{
fprintf(rdef_file, "#");
write_code(type);
fprintf(rdef_file, " ");
}
write_field_name(name);
const char* class_;
if (msg.FindString("class", &class_) == B_OK)
{
fprintf(rdef_file, "archive");
const char* add_on;
if (msg.FindString("add_on", &add_on) == B_OK)
{
fprintf(rdef_file, "(\"%s\"", add_on);
if (msg.what != 0)
{
fprintf(rdef_file, ", ");
write_code(msg.what);
}
fprintf(rdef_file, ")");
msg.RemoveName("add_on");
}
else if (msg.what != 0)
{
fprintf(rdef_file, "(, ");
write_code(msg.what);
fprintf(rdef_file, ")");
}
fprintf(rdef_file, " %s", class_);
msg.RemoveName("class");
}
else if (msg.what == 0)
{
fprintf(rdef_file, "message");
}
else
{
fprintf(rdef_file, "message(");
write_code(msg.what);
fprintf(rdef_file, ")");
}
if (msg.CountNames(B_ANY_TYPE) > 0)
{
write_fields(msg);
}
}
//------------------------------------------------------------------------------
static bool is_string(const void* data, size_t length)
{
// We consider the buffer a string if it contains only human readable
// characters. The buffer should also end with a '\0'. Although the
// compiler allows string literals to contain embedded '\0' chars as
// well, we don't allow them here (because they may cause false hits).
if (length == 0) { return false; }
char* ptr = (char*) data;
for (size_t t = 0; t < length - 1; ++t)
{
if (!isprint(*ptr++))
{
return false;
}
}
return (*ptr == '\0');
}
//------------------------------------------------------------------------------
static void write_other(
const char* name, type_code type, const void* data, size_t length)
{
BMessage msg;
if (msg.Unflatten((const char*) data) == B_OK)
{
write_message(name, msg, type);
}
else if (is_string(data, length))
{
write_string(name, type, data, length);
}
else
{
write_raw(name, type, data, length);
}
}
//------------------------------------------------------------------------------
static void examine_data(
const char* name, type_code type, const void* data, size_t length)
{
switch (type)
{
case B_BOOL_TYPE: write_bool(name, data, length); break;
case B_INT8_TYPE: write_int8(name, data, length); break;
case B_INT16_TYPE: write_int16(name, data, length); break;
case B_INT32_TYPE: write_int32(name, data, length); break;
case B_INT64_TYPE: write_int64(name, data, length); break;
case B_UINT8_TYPE: write_uint8(name, data, length); break;
case B_UINT16_TYPE: write_uint16(name, data, length); break;
case B_UINT32_TYPE: write_uint32(name, data, length); break;
case B_UINT64_TYPE: write_uint64(name, data, length); break;
case B_FLOAT_TYPE: write_float(name, data, length); break;
case B_DOUBLE_TYPE: write_double(name, data, length); break;
case B_SIZE_T_TYPE: write_size(name, data, length); break;
case B_SSIZE_T_TYPE: write_ssize(name, data, length); break;
case B_OFF_T_TYPE: write_off(name, data, length); break;
case B_TIME_TYPE: write_time(name, data, length); break;
case B_POINT_TYPE: write_point(name, data); break;
case B_RECT_TYPE: write_rect(name, data); break;
case B_RGB_COLOR_TYPE: write_rgb(name, data); break;
case B_MIME_STRING_TYPE: write_string(name, type, data, length); break;
case B_STRING_TYPE: write_string(name, type, data, length); break;
case B_POINTER_TYPE: write_raw(name, type, data, length); break;
case 'MICN': write_raw(name, type, data, length, 16); break;
case 'ICON': write_raw(name, type, data, length); break;
default: write_other(name, type, data, length); break;
}
}
//------------------------------------------------------------------------------
static void examine_file(char* file_name)
{
BFile file(file_name, B_READ_ONLY);
if (file.InitCheck() != B_OK)
{
strcpy(rdef_err_file, file_name);
rdef_err = RDEF_FILE_NOT_FOUND;
return;
}
BResources res;
if (res.SetTo(&file) != B_OK)
{
strcpy(rdef_err_file, file_name);
rdef_err = RDEF_NO_RESOURCES;
return;
}
int32 t = 0;
type_code type;
int32 id;
const char* name;
size_t length;
const void* data;
while (res.GetResourceInfo(t, &type, &id, &name, &length))
{
tabs = 0;
data = res.LoadResource(type, id, NULL);
if (data != NULL)
{
fprintf(rdef_file, "\n");
write_rsrc(type, id, name);
examine_data(NULL, type, data, length);
fprintf(rdef_file, ";\n");
}
++t;
}
}
//------------------------------------------------------------------------------
static status_t open_output_files()
{
rdef_file = fopen(rdef_name, "w");
if (rdef_file == NULL)
{
strcpy(rdef_err_msg, strerror(errno));
strcpy(rdef_err_file, rdef_name);
return RDEF_WRITE_ERR;
}
if (flags & RDEF_AUTO_NAMES)
{
header_file = fopen(header_name, "w");
if (header_file == NULL)
{
strcpy(rdef_err_msg, strerror(errno));
strcpy(rdef_err_file, header_name);
fclose(rdef_file);
return RDEF_WRITE_ERR;
}
fprintf(rdef_file, "\n#include \"%s\"\n", header_name);
#ifdef PUSSY_CODER_STYLE
fprintf(header_file, "\nenum {\n");
#else
fprintf(header_file, "\nenum\n{\n");
#endif
}
return B_OK;
}
//------------------------------------------------------------------------------
static void close_output_files()
{
if (flags & RDEF_AUTO_NAMES)
{
fprintf(header_file, "};\n");
fclose(header_file);
if (rdef_err != B_OK)
{
unlink(header_name);
}
}
fclose(rdef_file);
if (rdef_err != B_OK)
{
unlink(rdef_name);
}
}
//------------------------------------------------------------------------------
status_t rdef_decompile(const char* output_file)
{
clear_error();
if ((output_file == NULL) || (output_file[0] == '\0'))
{
rdef_err = B_BAD_VALUE;
return rdef_err;
}
rdef_name = output_file;
if (flags & RDEF_AUTO_NAMES)
{
sprintf(header_name, "%s.h", output_file);
}
rdef_err = open_output_files();
if (rdef_err != B_OK)
{
return rdef_err;
}
for (ptr_iter_t i = input_files.begin();
(i != input_files.end()) && (rdef_err == B_OK); ++i)
{
examine_file((char*) *i);
}
close_output_files();
return rdef_err;
}
//------------------------------------------------------------------------------
+103
View File
@@ -0,0 +1,103 @@
<HTML>
<HEAD>
<TITLE>Differences with beres/deres</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<H1>Differences with beres/deres</H1>
<P>Some of your old rdef files may fail to compile with rc. Besides different
command line arguments, rc also has slightly different syntax and semantics.
These changes were made to allow for the future expansion of the rdef grammar
and to make resource scripts easier to write and understand. The compiler
should be backwards compatible with the majority of old scripts, but in some
cases it was necessary to break stuff.</P>
<H2>Differences with beres</H2>
<UL>
<LI>We allow the \0 escape in string literals.</LI>
<LI>Our handling of the minus sign is more restrictive; we don't treat it like
a unary minus operator, which means you may only put one minus in front of a
number to negate it (i.e. "- -10" is an error).</LI>
<LI>beres allows #define statements, but apparently ignores them. The compiler
reports no error, but any symbols you define are not recognized later on. We
don't allow #defines (yet).</LI>
<LI>beres allows you to put enum symbols in resource data, and replaces the
symbol with its value. For some reason, it lets you assign any kind of data to
enum symbols, such as strings and floats. Since that is not valid C/C++ syntax,
librdef does not allow this. As a result, it does not make much sense for us
to support enum symbols in resource data.</LI>
<LI>We only allow a few type casts, but enough to be backwards compatible.
beres allows you to cast from bool to all other types, between strings and
numeric types, etc. The usefulness of this is limited, so to keep things simple
librdef doesn't allow that.</LI>
<LI>There is no need to put parentheses around a type code, even for simple
data; beres sometimes requires the parens and sometimes it doesn't. With rc,
they are always optional (preferred notation is without the parens).</LI>
<LI>beres allows multiple type codes and/or type casts per resource
statement/data field, but we allow only one of each. Because we don't associate
type codes with data (but only with the resource itself or with individual
message fields), we don't allow the shortcut notation that lets you put a type
code and cast inside one set of parentheses.</LI>
<LI>We do not allow arrays to have named fields, nor do we allow messages (and
archives) to have unnamed fields. beres apparently treats all compound data the
same, but we don't, because not all compound data is the same.</LI>
<LI>When specifying array data, the "array" keyword is required. beres allows
you to omit the array keyword and just put the data between braces, but that
conflicts with our handling of user-defined types.</LI>
<LI>Field names in message resources may only be string literals. beres allows
identifiers but it converts them to string literals anyway. Just like normal
data, you may cast the field's data to a different type, but not to a different
type code. Specifying a non-standard type code is fine, but it goes in front of
the type name. Just like beres, rc considers "array", "message", and "archive"
to be valid data type names, but "message" and "archive" cannot be followed by
a "what" code (beres ignores that anyway). When you cast an archive to a
message, we don't strip the "class" field (in fact, we don't perform any
conversion).</LI>
<LI>We allow users to define their own types. The built-in types from beres
(point, rect, and rgb_color) are re-implemented as such user-defined types. The
syntax for these three built-ins should still be backwards compatible with old
scripts.</LI>
<LI>beres automatically adds names for resources that are specified as
"resource(R_Symbol)", unless the "explicit names only" option is set. We do
that the other way around: we don't automatically add names unless the user
sets the "auto names" option.</LI>
</UL>
<H2>Differences with deres:</H2>
<UL>
<LI>We do not write the "generated at" time into the files.</LI>
<LI>We put opening braces on the next line (heh heh).</LI>
<LI>Type codes that cannot be represented as #'xxxx' are written as #num where
num is a decimal number, not hexadecimal.</LI>
<LI>Floats and doubles have a bunch of extra zeroes.</LI>
<LI>Hex numbers are always uppercase.</LI>
<LI>We may render string literals somewhat differently.</LI>
<LI>We only write a header file if the "auto names" option is set.</LI>
</UL>
</BODY>
</HTML>
+437
View File
@@ -0,0 +1,437 @@
<HTML>
<HEAD>
<TITLE>rdef grammar</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<H1>rdef grammar</H1>
<P>This is the (somewhat boring) specification of the rdef file format as it is
understood by librdef. It also describes to a certain extent how the compiler
works. You don't need to read this unless you want to hack librdef. Knowledge
of compiler theory and lex/yacc is assumed.</P>
<H2>The lexer</H2>
<P>Like any compiler, librdef contains a lexer (aka scanner) and a parser. The
lexer reads the input file and chops it up into tokens. The lexer ignores
single-line // comments and /* ... */ multi-line comments. It also ignores
whitespace and newlines.</P>
<P>The lexer recognizes the following tokens:</P>
<BLOCKQUOTE>
<TABLE BORDER="1">
<TR><TD WIDTH="20%">BOOL</TD><TD>true or false</TD></TR>
<TR><TD>INTEGER</TD><TD>You can specify integers as decimal numbers,
hexadecimal numbers (starting with 0x or 0X, alpha digits are case
insensitive), octal numbers (starting with a leading 0), binary numbers
(starting with 0b or 0B), or as a four character code ('CCCC'). Valid range is
64 bits. At this point, numbers are always unsigned. The minus sign is treated
as a separate token, and is dealt with by the parser.</TD></TR>
<TR><TD>FLOAT</TD><TD>A floating point literal. Must contain a decimal point,
may contain a signed exponent. Stored internally as a double.</TD></TR>
<TR><TD>STRING</TD><TD>UTF-8 compatible string literal, enclosed by double
quotes. Can contain escape sequences (\b \f \n \r \t \v \" \\ \0), octal
escapes (\000) and hex escapes (\0x00 or \x00). May not span more than one
line, although you are allowed to specify multiple string literals in a row and
the lexer will automatically concatenate them. There is no maximum length.</TR>
<TR><TD>RAW</TD><TD>Hexadecimal representation of raw data, enclosed by double
quotes, and prefixed by a dollar sign: $"12FFAB". Each byte is represented by
two hex characters, so there must be an even number of characters between the
quotes. The alpha digits are not case sensitive. Like STRING, a RAW token may
not span more than one line, but multiple consecutive RAW tokens are
automatically concatenated. No maximum length.</TD></TR>
<TR><TD>IDENT</TD><TD>C/C++ identifier. First character is alphabetic or
underscore. Other characters are alphanumeric or underscore.</TD></TR>
<TR><TD>TYPECODE</TD><TD>A hash sign followed by a 32-bit unsigned decimal
number, hex number, or four character code. Examples: #200, #0x00C8,
#'MIMS'</TD></TR>
</TABLE>
</BLOCKQUOTE>
<P>The following are treated as keywords and special symbols:</P>
<BLOCKQUOTE><CODE>enum resource array message archive type { } ( ) , ; = -
</CODE></BLOCKQUOTE>
<P>The lexer also deals with #include statements, which look like: #include
"filename"\n. When you #include a file, the lexer expects it to contain valid
rdef syntax. So even though the include file is probably a C/C++ header, it
should not contain anything but the enum statement and/or comments. The lexer
only looks for include files in the include search paths that you have
specified, so if you want it to look in the current working directory you have
to explicitly specify that. You may nest #includes.</P>
<P>A note about UTF-8. Since the double quote (hex 0x22) is never part of the
second or third byte of a UTF-8 character, the lexer can safely deal with UTF-8
characters inside string literals. That is also the reason that the decompiler
does not escape characters that are not human-readable (except the ones in the
7-bit ASCII range), because they could be part of a UTF-8 encoding. The current
version of librdef does not handle L"..." (wide char) strings, but nobody uses
them anyway.</P>
<H2>The parser</H2>
<P>The parser takes the tokens from the lexer and matches them against the
rules of the grammar. What follows is the grammar in a simplified variation of
BNF, so the actual bison source file may look a little different. Legend:</P>
<BLOCKQUOTE>
<TABLE BORDER="1">
<TR><TD>[ a ]</TD><TD>match a 0 or 1 times</TD></TR>
<TR><TD>{ b }</TD><TD>match b 0 or more times</TD></TR>
<TR><TD>c | d</TD><TD>match either c or d</TD></TR>
<TR><TD>( e f )</TD><TD>group e and f together</TD></TR>
<TR><TD>lowercase</TD><TD>nonterminal</TD></TR>
<TR><TD>UPPER</TD><TD>token from the lexer</TD></TR>
<TR><TD>'c'</TD><TD>token from the lexer</TD></TR>
</TABLE>
</BLOCKQUOTE>
<P>The rdef grammar consists of the following rules:</P>
<BLOCKQUOTE>
<TABLE BORDER="1">
<TR><TD>script</TD><TD>{enum | typedef | resource}</TD></TR>
<TR><TD>enum</TD><TD> ENUM '{' [symboldef {',' symboldef} [',']] '}'
';'</TD></TR>
<TR><TD>symboldef</TD><TD>IDENT ['=' integer]</TD></TR>
<TR><TD>typedef</TD><TD>TYPE [id] [TYPECODE] IDENT '{' fielddef {',' fieldef}
'}' ';'</TD></TR>
<TR><TD>fielddef</TD><TD>datatype IDENT ['=' data]</TD></TR>
<TR><TD>resource</TD><TD>RESOURCE [id] [typecode] data ';'</TD></TR>
<TR><TD>id</TD><TD>'(' [(integer | IDENT) [',' STRING] | STRING] ')'</TD></TR>
<TR><TD>typecode</TD><TD>['('] TYPECODE [')']</TD></TR>
<TR><TD>data</TD><TD>[typecast] (BOOL | integer | float | STRING | RAW | array
| message | archive | type)</TD></TR>
<TR><TD>typecast</TD><TD>['(' datatype ')']</TD></TR>
<TR><TD>datatype</TD><TD>ARRAY | MESSAGE | ARCHIVE IDENT | IDENT</TD></TR>
<TR><TD>integer</TD><TD>['-'] INTEGER</TD></TR>
<TR><TD>float</TD><TD>['-'] FLOAT</TD></TR>
<TR><TD>array</TD><TD>ARRAY ['{' [data {',' data}] '}']</TD></TR>
<TR><TD>message</TD><TD>MESSAGE ['(' integer ')'] ['{' [msgfield {','
msgfield}] '}']</TD></TR>
<TR><TD>msgfield</TD><TD>[TYPECODE] [datatype] STRING '=' data</TD></TR>
<TR><TD>archive</TD><TD>ARCHIVE [archiveid] IDENT '{' msgfield {',' msgfield}
'}'</TD></TR>
<TR><TD>archiveid</TD><TD>'(' [STRING] [',' integer] ')'</TD></TR>
<TR><TD>type</TD><TD>IDENT [data | '{' [typefield {',' typefield}]
'}']</TD></TR>
<TR><TD>typefield</TD><TD>[IDENT '='] data</TD></TR>
</TABLE>
</BLOCKQUOTE>
<H2>Semantics</H2>
<H3>Resource names</H3>
<P>There are several different ways to specify the ID and name of a new
resource:</P>
<BLOCKQUOTE>
<TABLE BORDER="1">
<TR><TD WIDTH="25%">resource</TD><TD>The resource is assigned the default name
and ID of its data type.</TD></TR>
<TR><TD>resource()</TD><TD>The resource is assigned the default name and ID of
its data type.</TD></TR>
<TR><TD>resource(1)</TD><TD>The resource is assigned the numeric ID 1, and the
default name of its data type.</TD></TR>
<TR><TD>resource("xxx")</TD><TD>The resource is assigned the name "xxx" and the
default ID of its data type.</TD></TR>
<TR><TD>resource(1, "xxx")</TD><TD>The resource is assigned the numeric ID 1,
and the name "xxx".</TD></TR>
<TR><TD>resource(sss)</TD><TD>The resource is assigned the numeric ID that
corresponds with the symbol sss, which should have been defined in an enum
earlier. If the "auto names" option is passed to the compiler, the resource is
also given the name "sss", otherwise the default name from its data type is
used.</TD></TR>
<TR><TD>resource(sss, "xxx")</TD><TD>The resource is assigned the numeric ID
that corresponds with the symbol sss, and the name "xxx".</TD></TR>
</TABLE>
</BLOCKQUOTE>
<H3>Data types and type casts</H3>
<P>Resources (and message fields) have a type code and a data type. The data
type determines the format the data is stored in, while the type code tells the
user how to interpret the data. Typically, there is some kind of relation
between the two, otherwise the resource will be a little hard to read.</P>
<P>The following table lists the compiler's built-in data types. (Users can
also define their own types; this is described in a later section.)</P>
<BLOCKQUOTE>
<TABLE BORDER="0"><TR><TD VALIGN="top">
<TABLE BORDER="1">
<TR><TD>bool</TD><TD>B_BOOL_TYPE</TD></TR>
<TR><TD>int8</TD><TD>B_INT8_TYPE</TD></TR>
<TR><TD>uint8</TD><TD>B_UINT8_TYPE</TD></TR>
<TR><TD>int16</TD><TD>B_INT16_TYPE</TD></TR>
<TR><TD>uint16</TD><TD>B_UINT16_TYPE</TD></TR>
<TR><TD>int32</TD><TD>B_INT32_TYPE</TD></TR>
<TR><TD>uint32</TD><TD>B_UINT32_TYPE</TD></TR>
<TR><TD>int64</TD><TD>B_INT64_TYPE</TD></TR>
<TR><TD>uint64</TD><TD>B_UINT64_TYPE</TD></TR>
<TR><TD>size_t</TD><TD>B_SIZE_T_TYPE</TD></TR>
<TR><TD>ssize_t</TD><TD>B_SSIZE_T_TYPE</TD></TR>
</TABLE>
</TD><TD VALIGN="top">
<TABLE BORDER="1">
<TR><TD>off_t</TD><TD>B_OFF_T_TYPE</TD></TR>
<TR><TD>time_t</TD><TD>B_TIME_TYPE</TD></TR>
<TR><TD>float</TD><TD>B_FLOAT_TYPE</TD></TR>
<TR><TD>double</TD><TD>B_DOUBLE_TYPE</TD></TR>
<TR><TD>string</TD><TD>B_STRING_TYPE</TD></TR>
<TR><TD>raw</TD><TD>B_RAW_TYPE</TD></TR>
<TR><TD>array</TD><TD>B_RAW_TYPE</TD></TR>
<TR><TD>buffer</TD><TD>B_RAW_TYPE</TD></TR>
<TR><TD>message</TD><TD>B_MESSAGE_TYPE</TD></TR>
<TR><TD>archive</TD><TD>B_MESSAGE_TYPE</TD></TR>
</TABLE>
</TD></TR></TABLE>
</BLOCKQUOTE>
<P>The type code has no effect on how the data is stored. For example, if you
do this: "resource(x) #'LONG' true", then the data will not automatically be
stored as a 32-bit number! If you don't specify an explicit type code, the
compiler uses the type of the data for that.</P>
<P>You can change the data type with a type cast. The following casts are
allowed:</P>
<BLOCKQUOTE>
<TABLE BORDER="1">
<TR><TD WIDTH="20%">bool</TD><TD>You cannot cast bool data.</TD></TR>
<TR><TD>integer</TD><TD>You can cast to all numeric data types. Casts to
smaller datatypes will truncate the number. Casting negative numbers to
unsigned datatypes (and vice versa) will wrap them, i.e. (uint8) -1 becomes
255.</TD></TR>
<TR><TD>floating point</TD><TD>You can only cast to float or double.</TD></TR>
<TR><TD>string</TD><TD>You cannot cast string data.</TD></TR>
<TR><TD>raw, buffer, array</TD><TD>You can cast anything to raw, but not the
other way around.</TD></TR>
<TR><TD>message, archive</TD><TD>You cannot cast message data.</TD></TR>
<TR><TD>type</TD><TD>You cannot cast user-defined types.</TD></TR>
</TABLE>
</BLOCKQUOTE>
<P>In addition to the "simple" built-in data types, the compiler also natively
supports several data structures from the BeOS API (point, rect, rgb_color) and
a few convenience types (app_signature, app_flags, etc). These types all follow
the same rules as user-defined types.</P>
<H3>Arrays</H3>
<P>The following definitions are semantically
equivalent:</P>
<BLOCKQUOTE><PRE>resource(x) $"AABB";
resource(x) array { $"AA" $"BB" };
resource(x) array { $"AA", $"BB" };</PRE></BLOCKQUOTE>
<P>The comma is optional and simply concatenates the two literals. When you
decompile this code, it always looks like:</P>
<BLOCKQUOTE><PRE>resource(x) $"AABB";</PRE></BLOCKQUOTE>
<P>Strings behave differently. The following two definitions are equivalent,
and concatenate the two literals into one string:</P>
<BLOCKQUOTE><PRE>resource(x) "AA" "BB";
resource(x) #'CSTR' array { "AA" "BB" };</PRE></BLOCKQUOTE>
<P>However, if you put a comma between the the strings, the compiler will still
glue them together but with a '\0' character in the middle. Now the resource
contains <I>two</I> strings: "AA" and "BB". You can also specify the '\0'
character yourself:</P>
<BLOCKQUOTE><PRE>resource(x) "AA\0BB";
resource(x) #'CSTR' array { "AA", "BB" };</PRE></BLOCKQUOTE>
<P>The following is not proper grammar; use an array instead:</P>
<BLOCKQUOTE><PRE>resource(x) "AA", "BB";
resource(x) $"AA", $"BB";</PRE></BLOCKQUOTE>
<P>Note that the data type of an array is always raw data, no matter how you
specify its contents. Because raw literals may be empty ($""), so may
arrays.</P>
<H3>Messages and archives</H3>
<P>A message resource is a flattened BMessage. By default it has the data type
B_MESSAGE_TYPE and corresponding type code #'MSGG'. If you don't specify a
"what" code for the message, it defaults to 0.</P>
<P>Message fields assume the type of their data, unless you specify a different
type in front of the field name. (Normal casting rules apply here.) You can
also give the field a different type code, which tells the BMessage how to
interpret the data, but not how it is stored in the message. This type code
also goes in front of the field name. You can give the same name to multiple
fields, provided that they all have the same type. (The data of these fields
does not have to be the same size.) A message may be empty; it is still a valid
BMessage, but it contains no fields.</P>
<P>An archive is also a flattened BMessage, but one that was made by
Archive()'ing a BArchivable class, such as BBitmap. The name of the archive, in
this case BBitmap, is automatically added to the message in a field called
"class". The "archive" keyword is optionally followed by a set of parentheses
that enclose a string and/or an integer. The int is the "what" code, the string
is stored in a field called "add_on" (used for dynamic loading of
BArchivables). Other than that, archives and messages are identical. The
compiler does not check whether the contents of the archive actually make
sense, so if you don't structure the data properly you may be unable to
unarchive the object later. Unlike a message, an archive may not be empty,
because that is pointless.</P>
<H3>User-defined types</H3>
<P>We allow users to define their own types. A "type" is just a fancy array,
because the data from the various fields is simply concatenated into one big
block of bytes. The difference is that user-defined types are much easier to
fill in.</P>
<P>A user-defined type has a symbolic name, a type code, and a number of data
fields. After all the fields have been concatenated, the type code is applied
to the whole block. So, the data type of this resource is always the same as
its type code (unlike arrays, which are always raw data). If no type code is
specified, it defaults to B_RAW_TYPE.</P>
<P>The data fields always have a default value. For simple fields this is
typically 0 (numeric types) or empty (string, raw, message). The default value
of a user-defined type as a whole is the combination of the default values of
its fields. Of course, the user can specify other defaults. (When a user
creates a new resource that uses such a type, he is basically overriding the
default values with his own.)</P>
<P>The user may fill in the data fields by name, by order, or using a
combination of both. Every time the compiler sees an unnamed data item, it
stuffs it into the next available field. Named data items are simply assigned
to the field with the same name, and may overwrite a value that was previously
put there "by order". Any fields that are not filled in keep their default
value. For example:</P>
<BLOCKQUOTE><PRE>type vector { int32 x, int32 y, int32 z, int32 w = 4 };
resource(1) vector { 1, 3, x = 2 };</PRE></BLOCKQUOTE>
<P>Here, x is first set to 1, y is set to 3, x is now overwritten by the value
2, z is given the default value 0, and w defaults to 4.</P>
<P>Note: if a user-defined type contains string, raw, or message fields, the
size of the type depends on the data that the user puts into it, because these
fields have a variable size. In a future version we will add "constraints" that
let you force the size of a field to a fixed number of bytes. (And possibly
other constraints as well, such as a valid data range.)</P>
<P>A type definition may also contain a default resource ID and name. The
default ID of built-in types is usually 1 and the name is empty (NULL). For
example:</P>
<BLOCKQUOTE><PRE>type(10, "MyName") mytype { int32 a };
resource mytype 123;</PRE></BLOCKQUOTE>
<P>The resource is now called "MyName" and has ID 10. Obviously you can only do
this once or you will receive a duplicate resource error. If this type is used
inside an array or other compound type, the default ID and resource name are
ignored. Note: this feature introduces a shift/reduce conflict in the
compiler:</P>
<BLOCKQUOTE><PRE>resource (int8) 123;</PRE></BLOCKQUOTE>
<P>This probably doesn't do what you expect. The compiler now considers the
"(int8)" to be the resource ID, not a typecast. If you did not declare "int8"
in an enum (probably not), this gives a compiler error. Not a big problem,
because it is unlikely that you will ever do this. Here is a workaround:</P>
<BLOCKQUOTE><PRE>resource() (int8) 123;</PRE></BLOCKQUOTE>
<H3>Symbol table</H3>
<P>The compiler uses two symbol tables: one for the enum symbols, and one with
the data type definitions. We need those tables to find the numeric ID/type
definition that corresponds with an identifier, and to make sure that there are
no duplicate or missing identifiers. These two symbol tables are independent,
so you may use the same identifier both as an enum symbol and a type name.</P>
<P>The compiler does not need to keep a symbol table for the resources.
Although the combination of a resource's ID and its type code must be unique,
we can use the BResources class to check for this when we add a resource. There
is no point in duplicating this functionality in the compiler. (However, if we
are merging the new resources into an existing resource file, we will simply
overwrite duplicates.)</P>
<H3>Misc remarks</H3>
<UL>
<LI><P>As the grammar shows, the last field in an enum statement may be
followed by a comma. This is valid C/C++ syntax, and since the enum will
typically end up in a header file, we support that feature as well. For
anything else between braces, the last item may not be followed by a
comma.</P></LI>
<LI><P>The type code that follows the "resource" keyword may be enclosed by
parens for historical reasons. The preferred notation is without, just like in
front of field names (where no parens are allowed).</P></LI>
<LI><P>Even though "ARCHIVE IDENT" is a valid data type, we simply ignore the
identifier for now. Maybe later we will support casting between different
archives or whatever. For now, casting to an archive is the same as casting to
a message, since an archive is really a message.</P></LI>
</UL>
</BODY>
</HTML>
+18
View File
@@ -0,0 +1,18 @@
<HTML>
<HEAD>
<TITLE>History</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<H1>History</H1>
<P>This is the change history of the rc resource compiler and librdef.</P>
<P><I>Version 1.0 (February 16, 2003):</I></P>
<UL>
<LI>Initial release</LI>
</UL>
</BODY>
</HTML>
+88
View File
@@ -0,0 +1,88 @@
<HTML>
<HEAD>
<TITLE>The librdef library</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<H1>The librdef library</H1>
<P>Of course, it would be cool if other applications (such as GUI resource
editors) could also import and export rdef files. That is why the bulk of rc's
functionality is implemented in a separate shared library, librdef.so.</P>
<P>Using the library in your own applications is very simple. Here are some
quick instructions to get you started:</P>
<OL>
<LI><CODE>#include "rdef.h"</CODE> in your sources</LI>
<LI>link your app to librdef.so</LI>
</OL>
<P>The API is rather bare-bones, but it gets the job done. The library uses
files to transfer data to and from your application. This may seem odd, but it
is actually a big advantage. After calling the API functions to compile an rdef
file, you can use the standard BResources class to read the resources from the
output file. Chances are high that your application already knows how to do
this.</P>
<P>To compile a resource file, the steps are typically this:</P>
<OL>
<LI>Call <CODE>rdef_add_include_dir()</CODE> one or more times to add include
file search paths.</LI>
<LI>Call <CODE>rdef_add_input_file()</CODE> one or more times to add the rdef
files that you want to compile.</LI>
<LI>Call <CODE>rdef_set_flags()</CODE> to toggle compiler options.</LI>
<LI>Call <CODE>rdef_compile()</CODE> with the name of the output file. This
performs the actual compilation.</LI>
<LI>Call <CODE>rdef_free_input_files()</CODE> to clear the list of input files
that you added earlier.</LI>
<LI>Call <CODE>rdef_free_include_dirs()</CODE> to clear the list of include
directories that you added earlier.</LI>
</OL>
<P>Decompiling is very similar, although include directories are not used
here:</P>
<OL>
<LI>Call <CODE>rdef_add_input_file()</CODE> one or more times to add the
resource files that you want to decompile.</LI>
<LI>Call <CODE>rdef_set_flags()</CODE> to toggle compiler options.</LI>
<LI>Call <CODE>rdef_decompile()</CODE> with the name of the output file. The
name of the header file (if any) will be automatically constructed by appending
".h" to the output file name.</LI>
<LI>Call <CODE>rdef_free_input_files()</CODE> to clear the list of input files
that you added earlier.</LI>
</OL>
<P>If one of these functions returns something other than B_OK, an error
occurred. You can look at the following variables to find out more about the
error, and construct meaningul error messages:</P>
<UL>
<LI><CODE>rdef_err</CODE> The error code that was returned.</LI>
<LI><CODE>rdef_err_line</CODE> The line number where compilation failed.</LI>
<LI><CODE>rdef_err_file</CODE> The file where the error occurred.</LI>
<LI><CODE>rdef_err_msg</CODE> The error message from the compiler.</LI>
</UL>
<P>For more information about using librdef, see "rdef.h", which explains the
available functions and data structures in more depth. For a real-world
example, take a look at "rc.cpp", which contains the complete implementation of
the rc compiler. As you'll see, there really isn't much to it, because librdef
already does all the work.</P>
</BODY>
</HTML>
+472
View File
@@ -0,0 +1,472 @@
<HTML>
<HEAD>
<TITLE>Resource Compiler</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<H1>The rc resource compiler</H1>
<H2>Table of contents</H2>
<UL>
<LI><A HREF="#intro">Introduction</A></LI>
<LI><A HREF="#install">How to install</A></LI>
<LI><A HREF="#scripts">Writing resource scripts</A></LI>
<LI><A HREF="#advanced">Big fat resources</A></LI>
<LI><A HREF="#app">Application resources</A></LI>
<LI><A HREF="#compile">Compiling</A></LI>
<LI><A HREF="#decompile">Decompiling</A></LI>
<LI><A HREF="#authors">Authors</A></LI>
<LI><A HREF="#license">License</A></LI>
</UL>
<!-- *********************************************************************** -->
<A NAME="intro"></A>
<H2>Introduction</H2>
<P>In the world of BeOS programming, a "resource" is data that is bundled with
your application. Typical examples are the application's icons and its
signature, but you can attach any data you want (bitmaps, text, cursors, etc).
You stuff this data into a .rsrc file that will be linked to your application
when it is compiled.</P>
<P>Because .rsrc files have a binary file format, you need to use special tools
to edit them, such as FileTypes, QuickRes, or Resourcer. Alternatively, you can
use a "resource compiler". This is a command line tool that takes a text-based
resource script and turns it into a .rsrc file.</P>
<P>With a resource compiler, you express your resources as ASCII text using a
special definition language, which makes the resource files much easier to edit
and maintain. You no longer need separate GUI tools to build your .rsrc files,
and you can even automate the whole process by calling the compiler from your
Makefile or Jamfile. Resource scripts will also make your life easier if you
use CVS, because CVS doesn't handle .rsrc files very well.</P>
<P>BeOS R5 comes with an (experimental) resource compiler called "beres", and a
corresponding decompiler called "deres". rc is an open source replacement (and
enhancement) of these tools. It is (mostly) backwards compatible, so you should
be able to compile your old .rdef files without any problems.</P>
<!-- *********************************************************************** -->
<A NAME="install"></A>
<H2>How to install</H2>
<OL>
<LI>Copy <CODE>rc</CODE> into <CODE>/boot/home/config/bin</CODE></LI>
<LI>Copy <CODE>librdef.so</CODE> into <CODE>/boot/home/config/lib</CODE></LI>
<LI>Let's party!</LI>
</OL>
<!-- *********************************************************************** -->
<A NAME="scripts"></A>
<H2>Writing resource scripts</H2>
<P>Writing resource scripts is not difficult, although the syntax may take some
getting used to. A resource script is a plain text file with one or more
resource definition statements. In addition, it may contain C or C++ style
comments. By convention, resource script files have the extension ".rdef".</P>
<P>Here is an example of a simple resource script:</P>
<BLOCKQUOTE><PRE>resource(1) true; /* this is a comment */
resource(2) 123; // and so is this
resource(3) 3.14;
resource(4) "hello world";
resource(5) $"0123456789ABCDEF";</PRE></BLOCKQUOTE>
<P>When compiled, this script produces a resource file with five resources. The
above example also illustrates the types of data that resources are allowed to
have: boolean, integer, floating point, character string (UTF-8), and raw data
buffer (hexadecimal).</P>
<P>By default, integer data is stored as a 32-bit int, and floating point data
is stored as a 4-byte float. If you want to change the way the data is stored,
you have to cast it:</P>
<BLOCKQUOTE><PRE>resource(6) (int8) 123;
resource(7) (double) 3.14;</PRE></BLOCKQUOTE>
<P>You can cast integer data to the following types: int8, uint8, int16,
uint16, int32, uint32, int64, uint64, ssize_t, size_t, off_t, time_t, float,
double, raw. You can cast floating point data to: float, double, raw. You are
not allowed to cast boolean, string, or raw data to other types.</P>
<P>In addition to casting, you can also change the resource's type code. This
does not change the way the data is stored, only what it is called. To change
the type code of a resource:</P>
<BLOCKQUOTE><PRE>resource(8) #'dude' 123;</PRE></BLOCKQUOTE>
<P>This changes the type of resource 8 to the four-character-code 'dude'. If
you did not change it, it would be 'LONG', which stands for 32-bit integer. By
changing the type code, you assign a new meaning to the resource. You can also
specify type codes as decimal or hexadecimal numbers:</P>
<BLOCKQUOTE><PRE>resource(9) #200 123;
resource(10) #0xC8 123;</PRE></BLOCKQUOTE>
<P>For historical reasons, you may also enclose the type code in parens, but
that is not the preferred notation. Type casts and type codes can be
combined:</P>
<BLOCKQUOTE><PRE>resource(11) #'dude' (int8) 123;
resource(11) (#'dude') (int8) 123;</PRE></BLOCKQUOTE>
<P>In the above examples, we have given the resources numeric IDs. The
combination of ID and type code must be unique in the resource file; you cannot
have two int32 resources with ID 1, for example. However, it is perfectly fine
(but not necessarily a good idea) to do the following, because the data types
are different:</P>
<BLOCKQUOTE><PRE>resource(12) 123;
resource(12) "w00t!";</PRE></BLOCKQUOTE>
<P>For your own convenience, you can also name resources. Unlike the ID/type
code combination, names do not have to be unique. </P>
<BLOCKQUOTE><PRE>resource(13, "Friday") "Bad Luck";</PRE></BLOCKQUOTE>
<P>Since it is likely that you will be using these resources from a C/C++
program, it may be convenient to refer to them by symbolic names instead of
hardcoded numeric ID's. The rdef format allows you to do this:</P>
<BLOCKQUOTE><PRE>enum
{
R_AppName = 1,
R_SomeOtherThing = 2
};
resource(R_AppName) "MyKillerApp";</PRE></BLOCKQUOTE>
<P>The compiler will automatically substitute the symbol R_AppName with the
number 1. (You don't have to start these symbol names with the prefix R_, but
it is somewhat of a convention.)</P>
<P>Now how do you tell your C/C++ app about these symbolic names? You simply
put the enum into a header file that you include both from your application's
source code and your rdef file. The header file, which we'll call
"myresources.h", now looks like this:</P>
<BLOCKQUOTE><PRE>enum
{
R_AppName = 1,
R_SomeOtherThing = 2
};</PRE></BLOCKQUOTE>
<P>And the rdef file becomes this:</P>
<BLOCKQUOTE><PRE>#include "myresources.h"
resource(R_AppName) "MyKillerApp";</PRE></BLOCKQUOTE>
<P>Don't let the .h suffix fool you: the header file is still considered to be
an rdef file, and must contain valid rdef syntax. If you add any other C/C++
code, your resource script will fail to compile. Of course, you shouldn't add
any other rdef syntax to the header either (unless you want your C++ compiler
to start complaining). Besides comments, the only safe thing to put in that
header file is the enum statement, because both rdef and C/C++ understand
it.</P>
<P>Just like IDs, symbolic identifiers can be combined with a name:</P>
<BLOCKQUOTE><PRE>resource(R_AppName, "AppName") "MyKillerApp";</PRE></BLOCKQUOTE>
<P>If you don't specify a name, and invoke the compiler with the
<CODE>--auto-names</CODE> option, it automatically uses the symbolic ID for the
name as well. So the ID of the following resource is 1 (because that is what
R_AppName corresponds to) and its name becomes "R_AppName":</P>
<BLOCKQUOTE><PRE>resource(R_AppName) "MyKillerApp";</PRE></BLOCKQUOTE>
<!-- *********************************************************************** -->
<A NAME="advanced"></A>
<H2>Big fat resources</H2>
<P>The resources we have made so far consisted of a single data item, but you
can also supply a collection of data values. The simplest of these compound
data structures is the array:</P>
<BLOCKQUOTE><PRE>resource(20) array { 1234, 5678 };</PRE></BLOCKQUOTE>
<P>An array is nothing more than a raw buffer. The above statement takes the
two 32-bit integers 1234 and 5678 and stuffs them into a new 64-bit buffer. You
can put any kind of data into an array, even other arrays:</P>
<BLOCKQUOTE><PRE>resource(21) array
{
"hello",
3.14,
true,
array { "a", "nested", "array" },
$"AABB"
};</PRE></BLOCKQUOTE>
<P>It is up to you to remember the structure of this array, because array
resources don't keep track of what kind of values you put into them and where
you put these values. For that, we have messages. A message resource is a
flattened BMessage:</P>
<BLOCKQUOTE><PRE>resource(22) message('blah')
{
"Name" = "Santa Claus",
"Number" = 3.14,
"Array" = array { "a", "nested", "array" },
"Other Msg" = message { "field" = "value" }
};</PRE></BLOCKQUOTE>
<P>A message has an optional "what" code, in this case 'blah', and one or more
fields. A field has a name (between double quotes), a value, and a data type.
By default, the field assumes the type of its data, but you can also specify an
explicit data type and type code in front of the field name:</P>
<BLOCKQUOTE><PRE>resource(23) message('bla2')
{
"integer1" = (int8) 123, // use cast to change data type
int16 "integer2" = 12345, // specify data type
#'dude' "buffer1" = $"aabbccdd", // specify a new type code
#'dude' raw "buffer2" = $"aabbccdd" // you can also combine them
};</PRE></BLOCKQUOTE>
<P>A special type of message is the "archive". The BeOS API allows you to take
a BArchivable class and flatten it into a BMessage. You can also add such
archives to your resource scripts:</P>
<BLOCKQUOTE><PRE>resource(24) #'BBMP' archive BBitmap
{
"_frame" = rect { 0.0, 0.0, 63.0, 31.0 },
"_cspace" = 8200,
"_bmflags" = 1,
"_rowbytes" = 256,
"_data" = array
{
... /* here goes the bitmap data */ ...
}
};</PRE></BLOCKQUOTE>
<P>So what's this "rect" thing in the "_frame" field? Besides arrays and
messages, the compiler also supports a number of other data structures from the
BeAPI:</P>
<BLOCKQUOTE><TABLE BORDER="1">
<TR><TH>type</TH><TH>corresponds to</TH><TH>fields</TH></TR>
<TR><TD>point</TD><TD>BPoint, B_POINT_TYPE</TD><TD>float x, y</TD></TR>
<TR><TD>rect</TD><TD>BRect, B_RECT_TYPE</TD><TD>float left, top, right, bottom</TD></TR>
<TR><TD>rgb_color</TD><TD>rgb_color, B_RGB_COLOR_TYPE</TD><TD>uint8 red, green, blue, alpha</TD></TR>
</TABLE></BLOCKQUOTE>
<P>To add a color resource to your script, you can do:</P>
<BLOCKQUOTE><PRE>resource(25) rgb_color { 255, 128, 0, 0 };</PRE></BLOCKQUOTE>
<P>Or you can use the field names, in which case the order of the fields does
not matter:</P>
<BLOCKQUOTE><PRE>resource(26) rgb_color
{
blue = 0, green = 128, alpha = 0, red = 255
};</PRE></BLOCKQUOTE>
<P>You can also make your own data structures, or as we refer to them,
"user-defined types". Suppose that your application wants to store its GUI
elements in the resources:</P>
<BLOCKQUOTE><PRE>type #'menu' menu
{
string name,
int32 count, // how many items
array items // the menu items
};
type #'item' menuitem
{
string name,
message msg,
bool enabled = true // default value is "true"
};</PRE></BLOCKQUOTE>
<P>A type has a name, an optional type code, and one or more fields. You are
advised not to pick a type code that already belongs to one of the built-in
types, to avoid any confusion. Each field has a data type, a name, and a
default value. If you don't specify a default, it is typically 0 or empty. To
create a new menu resource using the types from the above example, you might
do:</P>
<BLOCKQUOTE><PRE>resource(27) menu
{
name = "File",
count = 3,
items = array
{
menuitem { "New...", message('fnew') },
menuitem { "Print...", message('fprt'), false },
menuitem { "Exit", message('_QRQ') }
}
};</PRE></BLOCKQUOTE>
<P>Like an array, a type resource doesn't remember its internal structure. You
can regard types as fancy arrays that are easier to fill in, a template if you
will. User-defined types work under the same rules as the built-in types point,
rect, and rgb_color, so you can specify the fields in order or by their names.
If you don't specify a field, its default value will be used.</P>
<P>Types can also have a default resource ID and/or name. If you omit to give
the resource an ID or a name, it uses the defaults from its data type. For
example, this:</P>
<BLOCKQUOTE><PRE>type myint { int32 i };
resource(10, "MyName") myint { 123 };</PRE></BLOCKQUOTE>
<P>Is equivalent to this:</P>
<BLOCKQUOTE><PRE>type(10, "MyName") myint { int32 i };
resource myint { 123 };</PRE></BLOCKQUOTE>
<P>And to save you even more typing, simple types that have only one field can
also be specified as:</P>
<BLOCKQUOTE><PRE>resource myint 123;</PRE></BLOCKQUOTE>
<!-- *********************************************************************** -->
<A NAME="app"></A>
<H2>Application resources</H2>
<P>All BeOS applications (except command line apps) have a basic set of
resources, such as a MIME signature, launch flags, icons, and a few others.
Adding these kinds of resources is easy, because rc also has a number of
built-in types for that:</P>
<BLOCKQUOTE><TABLE BORDER="1">
<TR><TH>type</TH><TH>corresponds to</TH><TH>fields</TH></TR>
<TR><TD>app_signature</TD><TD>the app's MIME signature</TD><TD>string
signature</TD></TR>
<TR><TD>app_flags</TD><TD>application launch flags</TD><TD>uint32
flags</TD></TR>
<TR><TD>app_version</TD><TD>version information</TD><TD>uint32 major, middle,
minor, variety, internal<BR>string short_info, long_info</TD></TR>
<TR><TD>large_icon</TD><TD>32x32 icon</TD><TD>array of 1024 bytes</TD></TR>
<TR><TD>mini_icon</TD><TD>16x16 icon</TD><TD>array of 256 bytes</TD></TR>
<TR><TD>file_types</TD><TD>supported file types</TD><TD>message</TD></TR>
</TABLE></BLOCKQUOTE>
<!-- examples on how to fill in these resources -->
<P>Filling in these application resources is a little tricky with the current
version of rc. A future version will make this easier, when the user-defined
types mechanism becomes more powerful. For now, see the file
<CODE>tests/builtin.rdef</CODE> for more info.</P>
<!-- *********************************************************************** -->
<A NAME="compile"></A>
<H2>Compiling</H2>
<P>rc is a command line tool, which means you must run it from a Terminal
window. Typical usage example:</P>
<BLOCKQUOTE><PRE>rc -o things.rsrc things.rdef</PRE></BLOCKQUOTE>
<P>This tells rc that you wish to compile the script "things.rdef" to the
resource file "things.rsrc". The default name for the output file is
"out.rsrc", but you can change that with the <CODE>-o</CODE> or
<CODE>--output</CODE> switch, just like we did here.</P>
<P>You can specify multiple rdef files if you wish, and they will all be
compiled into one big resource file. If your rdef files #include files that are
not in the current working directory, you can add include paths with the
<CODE>-I</CODE> or <CODE>--include</CODE> option. For a complete list of
options, type <CODE>rc --help</CODE>.</P>
<P>If your project uses a Makefile, you can have rc automatically generate
the resource file for you:</P>
<BLOCKQUOTE><PRE>things.rsrc: things.rdef
rc -o $@ $^</PRE></BLOCKQUOTE>
<!-- also: how to integrate rc in jamfiles -->
<!-- *********************************************************************** -->
<A NAME="decompile"></A>
<H2>Decompiling</H2>
<P>Of course you can write the resource scripts by hand, but if you already
have a .rsrc file you can tell rc to decompile it. This will produce a
ready-to-go rdef script, and save you some trouble. (Although in some cases
it may be necessary to edit the script a little to suit your needs.) Note that
rc isn't limited to just .rsrc files; you can decompile any file that has
resources, including applications.</P>
<P>For example, to decompile the file "things.rsrc" into "things.rdef", do:</P>
<BLOCKQUOTE><PRE>rc --decompile -o things.rdef things.rsrc</PRE></BLOCKQUOTE>
<P>The decompiler produces an rdef resource script with the name "out.rdef",
but you can change that name with the <CODE>-o</CODE> or <CODE>--output</CODE>
switches. If you specify the <CODE>--auto-names</CODE> option, rc will also
write a C/C++ header file. Any resources whose name is a valid C/C++
identifier will be added to the header file. Now your program can access the
resource using this symbolic name.</P>
<P>Note: Even though rc can decompile multiple .rsrc files into one script, it
does not detect conflicts in resource names or IDs. In such cases, the
resulting .rdef and/or .h files may give errors when you try to compile
them.</P>
<!-- *********************************************************************** -->
<A NAME="authors"></A>
<H2>Authors</H2>
<P>The rc resource compiler and its companion library librdef were written by
<A HREF="mailto:[email protected]">Matthijs Hollemans</A> for the
<A HREF="http://www.openbeos.org">OpenBeOS</A> project. Comments, bug reports,
suggestions, and patches are welcome!</P>
<!-- *********************************************************************** -->
<A NAME="license"></A>
<H2>License</H2>
<P>Copyright (c) 2003 Matthijs Hollemans</P>
<P>Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:</P>
<P>The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.</P>
<P>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.</P>
</BODY>
</HTML>
+44
View File
@@ -0,0 +1,44 @@
<HTML>
<HEAD>
<TITLE>Planned features</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<H1>Planned features</H1>
<UL>
<LI><P>Simple integer expressions + - * / | & ~ ()</P></LI>
<LI><P>Make user-defined types more powerful. Some ideas: bitmask fields (for
app_flags), choice fields (for app_version), specify boolean fields as "name"
(true) or "!name" (false), conditional constructs, fixed-size strings and
arrays.</P></LI>
<LI><P>Importing files. Right now, you must specify the resource data in the
rdef script, which is messy for (large) binary files. The "import" feature lets
you copy the contents of such files (pictures, icons, etc.) straight into your
resources.</P></LI>
<LI><P>Attributes, so you can also use rdef scripts to add attributes to your
files instead of (or in addition to) resources.</P></LI>
<LI><P>In "auto names" mode, the decompiler currently does not use the enum
symbol table. So if two resources have the same name and that name is a valid
C/C++ identifier, the decompiler will add two conflicting symbols to the enum
statement. This can also happen when multiple input files have conflicting
resource IDs.</P></LI>
<LI><P>Support for the built-in types point, rect, and rgb_color is hardcoded
into the decompiler. The other types, app_flags etc, are not supported at all.
It would be better to use the type symbol table for this as well. Then the
decompiler can also support user-defined types (although these type definitions
must be provided to the decompiler somehow.)</P></LI>
<LI><P>Right now, archives are treated as messages. Maybe we should give them
their own type, B_ARCHIVED_OBJECT (type code 'ARCV').</P></LI>
</UL>
</BODY>
</HTML>
+295
View File
@@ -0,0 +1,295 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
%{
//------------------------------------------------------------------------------
#include <stack>
#include <string.h>
#include "rdef.h"
#include "compile.h"
#include "private.h"
#include "parser.cpp.h"
#define LEXERROR(msg) abort_compile(RDEF_COMPILE_ERR, msg);
// Initial size (and increment) of lexbuf.
#define LEX_BUF_SIZE (64*1024)
// Temporary buffer that the lexer uses to parse string and raw literals.
// The buffer will grow if necessary, to accommodate large data blocks.
static uint8* lexbuf;
static uint8* lexptr; // current write position in lexbuf
static size_t lexsize; // current size of the lex buffer
static size_t lexcnt; // how full lexbuf currently is
static void resetbuf(); // resets lexptr and lexcnt
static void addbuf(uint8); // appends byte to lexbuf
// When we encounter an #include directive, we push the current
// buffer, filename, and line number on the include stack, so we
// can resume lexing that file when we're done with the include.
struct include_t
{
YY_BUFFER_STATE buffer;
char* filename;
int lineno;
};
static std::stack<include_t> include_stack;
static void open_include();
static void close_include();
//------------------------------------------------------------------------------
%}
%option noyywrap
%option yylineno
LETTER [a-zA-Z]
BIN [01]
OCT [0-7]
DEC [0-9]
HEX [0-9a-fA-F]
IDENT [a-zA-Z_][a-zA-Z0-9_]*
WSPACE [ \r\t\n\f]
EXP [eE][+-]?{DEC}+
%x COMMENT
%x STRDATA
%x RAWDATA
%x INCLUDE
%%
enum return ENUM;
resource return RESOURCE;
array return ARRAY;
message return MESSAGE;
archive return ARCHIVE;
type return TYPE;
false yylval.b = false; return BOOL;
true yylval.b = true; return BOOL;
0[xX]{HEX}{1,16} { yylval.i = strtoull(yytext + 2, NULL, 16);
return INTEGER; }
0{OCT}{1,24} { yylval.i = strtoull(yytext, NULL, 8);
return INTEGER; }
0[bB]{BIN}{1,64} { yylval.i = strtoull(yytext + 2, NULL, 2);
return INTEGER; }
{DEC}+ { yylval.i = strtoull(yytext, NULL, 10);
return INTEGER; }
'....' { yylval.i = (yytext[1] << 24)
| (yytext[2] << 16)
| (yytext[3] << 8)
| yytext[4];
return INTEGER; }
{DEC}+{EXP} yylval.f = strtod(yytext, NULL); return FLOAT;
{DEC}*\.{DEC}+{EXP}? yylval.f = strtod(yytext, NULL); return FLOAT;
{DEC}+\.{DEC}*{EXP}? yylval.f = strtod(yytext, NULL); return FLOAT;
#{DEC}+ { yylval.t = strtoul(yytext + 1, NULL, 10);
return TYPECODE; }
#0[xX]{HEX}{1,8} { yylval.t = strtoul(yytext + 3, NULL, 16);
return TYPECODE; }
#'....' { yylval.t = (yytext[2] << 24)
| (yytext[3] << 16)
| (yytext[4] << 8)
| yytext[5];
return TYPECODE; }
{IDENT} { yylval.I = (char*) alloc_mem(yyleng + 1);
memcpy(yylval.I, yytext, yyleng + 1);
return IDENT; }
\" BEGIN(STRDATA); resetbuf();
<STRDATA>\"{WSPACE}+\" /* concatenate two literals */
<STRDATA>\" { BEGIN(INITIAL);
addbuf('\0');
yylval.d.type = get_type("string");
yylval.d.size = lexcnt;
yylval.d.ptr = alloc_mem(lexcnt);
memcpy(yylval.d.ptr, lexbuf, lexcnt);
return STRING; }
<STRDATA>\n LEXERROR("string not terminated")
<STRDATA>\\{OCT}{3} addbuf(strtol(yytext + 1, NULL, 8));
<STRDATA>\\0[xX]{HEX}{2} addbuf(strtol(yytext + 3, NULL, 16));
<STRDATA>\\[xX]{HEX}{2} addbuf(strtol(yytext + 2, NULL, 16));
<STRDATA>\\b addbuf('\b');
<STRDATA>\\f addbuf('\f');
<STRDATA>\\n addbuf('\n');
<STRDATA>\\r addbuf('\r');
<STRDATA>\\t addbuf('\t');
<STRDATA>\\v addbuf('\v');
<STRDATA>\\0 addbuf('\0');
<STRDATA>\\. addbuf(yytext[1]);
<STRDATA>. addbuf(yytext[0]);
$\" BEGIN(RAWDATA); resetbuf();
<RAWDATA>\"{WSPACE}+$\" /* concatenate two literals */
<RAWDATA>\" { BEGIN(INITIAL);
yylval.d.type = get_type("raw");
yylval.d.size = lexcnt;
yylval.d.ptr = alloc_mem(lexcnt);
memcpy(yylval.d.ptr, lexbuf, lexcnt);
return RAW; }
<RAWDATA>\n LEXERROR("raw data not terminated")
<RAWDATA>{HEX}{2} addbuf(strtol(yytext, NULL, 16));
<RAWDATA>{HEX} LEXERROR("number of characters must be even")
<RAWDATA>. LEXERROR("invalid character in raw data")
"/*" BEGIN(COMMENT); /* eat multi-line comment */
<COMMENT>[^*\n]* /* eat anything that is not a '*' */
<COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
<COMMENT>\n
<COMMENT>"*"+"/" BEGIN(INITIAL);
<COMMENT><<EOF>> LEXERROR("forgot to close /*..*/ comment")
"//"[^\n]* /* eat single-line comment */
{WSPACE}+ /* eat whitespace */
\#include[ \t]+\" BEGIN(INCLUDE);
<INCLUDE>[ \t]* /* eat the whitespace */
<INCLUDE>[^ \t\n\"]+\" open_include();
<INCLUDE>\n LEXERROR("error in include statement")
<INCLUDE><<EOF>> LEXERROR("error in include statement")
<<EOF>> { if (include_stack.empty())
yyterminate();
else
close_include(); }
. return yytext[0];
%%
//------------------------------------------------------------------------------
void resetbuf()
{
lexptr = lexbuf;
lexcnt = 0;
}
//------------------------------------------------------------------------------
void addbuf(uint8 b)
{
if (lexcnt == lexsize)
{
lexsize += LEX_BUF_SIZE;
lexbuf = (uint8*) realloc(lexbuf, lexsize);
if (lexbuf == NULL)
{
abort_compile(B_NO_MEMORY, "out of memory");
}
lexptr = lexbuf + lexcnt;
}
*lexptr++ = b;
++lexcnt;
}
//------------------------------------------------------------------------------
void open_include()
{
yytext[yyleng - 1] = '\0'; // remove trailing " quote
for (ptr_iter_t i = include_dirs.begin(); i != include_dirs.end(); ++i)
{
char tmpname[B_PATH_NAME_LENGTH];
strcpy(tmpname, (char*) *i);
strcat(tmpname, yytext);
yyin = fopen(tmpname, "r");
if (yyin != NULL)
{
include_t incl;
incl.buffer = YY_CURRENT_BUFFER;
incl.lineno = yylineno;
incl.filename = strdup(lexfile);
include_stack.push(incl);
strcpy(lexfile, tmpname);
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
yylineno = 1;
BEGIN(INITIAL);
return;
}
}
abort_compile(RDEF_COMPILE_ERR, "cannot open include %s", yytext);
}
//------------------------------------------------------------------------------
void close_include()
{
fclose(yyin);
yy_delete_buffer(YY_CURRENT_BUFFER);
include_t incl = include_stack.top();
include_stack.pop();
yy_switch_to_buffer(incl.buffer);
yylineno = incl.lineno;
strcpy(lexfile, incl.filename);
free(incl.filename);
}
//------------------------------------------------------------------------------
void init_lexer()
{
lexsize = LEX_BUF_SIZE;
lexbuf = (uint8*) malloc(lexsize);
if (lexbuf == NULL)
{
abort_compile(B_NO_MEMORY, "out of memory");
}
yyrestart(yyin); // necessary for multiple input files
}
//------------------------------------------------------------------------------
void clean_up_lexer()
{
while (!include_stack.empty())
{
close_include();
}
fclose(yyin);
yy_delete_buffer(YY_CURRENT_BUFFER);
free(lexbuf);
}
//------------------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef PRIVATE_H
#define PRIVATE_H
#include <list>
typedef std::list<void*> ptr_list_t;
typedef ptr_list_t::iterator ptr_iter_t;
// Configuration options for the (de)compiler.
extern uint32 flags;
// Where to look for #include files.
extern ptr_list_t include_dirs;
// The list of input files.
extern ptr_list_t input_files;
// free()'s all the elements from a list.
void free_ptr_list(ptr_list_t& list);
// Resets the rdef_err_* variables.
void clear_error();
#endif // PRIVATE_H
+354
View File
@@ -0,0 +1,354 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rdef.h"
#define TITLE "OpenBeOS Resource Compiler 1.0"
#define DEFAULT_OUT_RSRC "out.rsrc"
#define DEFAULT_OUT_RDEF "out.rdef"
static char* prog_name;
static bool quiet = false;
static bool should_decompile = false;
static uint32 flags = 0;
static char output_file[B_PATH_NAME_LENGTH] = { 0 };
//------------------------------------------------------------------------------
void warn(const char* format, ...)
{
va_list ap;
if (!quiet)
{
fprintf(stderr, "Warning! ");
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fprintf(stderr, "\n");
}
}
//------------------------------------------------------------------------------
void error(const char* format, ...)
{
va_list ap;
if (!quiet)
{
fprintf(stderr, "Error! ");
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
fprintf(stderr, "\n");
}
exit(EXIT_FAILURE);
}
//------------------------------------------------------------------------------
static void usage()
{
printf(
"%s\n\n"
"To compile an rdef script into a resource file:\n"
" %s [options] [-o <file>] <file>...\n\n"
"To convert a resource file back into an rdef script:\n"
" %s [options] [-o <file>] -d <file>...\n\n"
"Options:\n"
" -d --decompile create an rdef script from a resource file\n"
" --auto-names construct resource names from ID symbols\n"
" -h --help show this message\n"
" -I --include <dir> add <dir> to the list of include paths\n"
" -m --merge do not erase existing contents of output file\n"
" -o --output specify output file name, default is out.xxx\n"
" -q --quiet do not display any error messages\n"
" -V --version show software version and license\n",
TITLE, prog_name, prog_name);
exit(EXIT_SUCCESS);
}
//------------------------------------------------------------------------------
static void version()
{
printf(
"%s\n\n"
"Copyright (c) 2003 Matthijs Hollemans\n\n"
"Permission is hereby granted, free of charge, to any person obtaining a\n"
"copy of this software and associated documentation files (the \"Software\"),\n"
"to deal in the Software without restriction, including without limitation\n"
"the rights to use, copy, modify, merge, publish, distribute, sublicense,\n"
"and/or sell copies of the Software, and to permit persons to whom the\n"
"Software is furnished to do so, subject to the following conditions:\n\n"
"The above copyright notice and this permission notice shall be included in\n"
"all copies or substantial portions of the Software.\n\n"
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n"
"IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n"
"FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n"
"AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n"
"LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n"
"FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n"
"DEALINGS IN THE SOFTWARE.\n",
TITLE);
exit(EXIT_SUCCESS);
}
//------------------------------------------------------------------------------
static void get_program_name(char* argv[])
{
char* p;
prog_name = ((p = strrchr(argv[0], '/')) ? p + 1 : *argv);
}
//------------------------------------------------------------------------------
static void parse_options(int argc, char* argv[])
{
int32 args_left = argc - 1;
for (int32 i = 1; i < argc; ++i)
{
if ((strcmp(argv[i], "-o") == 0)
|| (strcmp(argv[i], "--output") == 0))
{
if (i + 1 >= argc)
{
error("%s should be followed by a file name", argv[i]);
}
strcpy(output_file, argv[i + 1]);
argv[i] = NULL;
argv[i + 1] = NULL;
++i; args_left -= 2;
}
else if ((strcmp(argv[i], "-I") == 0)
|| (strcmp(argv[i], "--include") == 0))
{
if (i + 1 >= argc)
{
error("%s should be followed by a directory name", argv[i]);
}
rdef_add_include_dir(argv[i + 1]);
argv[i] = NULL;
argv[i + 1] = NULL;
++i; args_left -= 2;
}
else if ((strcmp(argv[i], "-d") == 0)
|| (strcmp(argv[i], "--decompile") == 0))
{
should_decompile = true;
argv[i] = NULL;
--args_left;
}
else if ((strcmp(argv[i], "-m") == 0)
|| (strcmp(argv[i], "--merge") == 0))
{
flags |= RDEF_MERGE_RESOURCES;
argv[i] = NULL;
--args_left;
}
else if (strcmp(argv[i], "--auto-names") == 0)
{
flags |= RDEF_AUTO_NAMES;
argv[i] = NULL;
--args_left;
}
else if ((strcmp(argv[i], "-q") == 0)
|| (strcmp(argv[i], "--quiet") == 0))
{
quiet = true;
argv[i] = NULL;
--args_left;
}
else if ((strcmp(argv[i], "-h") == 0)
|| (strcmp(argv[i], "--help") == 0))
{
usage();
}
else if ((strcmp(argv[i], "-V") == 0)
|| (strcmp(argv[i], "--version") == 0))
{
version();
}
else if (argv[i][0] == '-')
{
error("unknown option %s", argv[i]);
argv[i] = NULL;
--args_left;
}
}
if (args_left < 1)
{
error("no input files");
}
for (int i = 1; i < argc; ++i)
{
if (argv[i] != NULL)
{
rdef_add_input_file(argv[i]);
}
}
}
//------------------------------------------------------------------------------
static bool has_extension(char* str, char* ext)
{
size_t str_len = strlen(str);
size_t ext_len = strlen(ext);
if (str_len > ext_len)
{
return (strcmp(str + str_len - ext_len, ext) == 0);
}
return false;
}
//------------------------------------------------------------------------------
static void compile()
{
if (output_file[0] == '\0')
{
rdef_compile(DEFAULT_OUT_RSRC);
}
else
{
if (!has_extension(output_file, ".rsrc"))
{
strcat(output_file, ".rsrc");
}
rdef_compile(output_file);
}
}
//------------------------------------------------------------------------------
static void decompile()
{
if (output_file[0] == '\0')
{
rdef_decompile(DEFAULT_OUT_RDEF);
}
else
{
if (!has_extension(output_file, ".rdef"))
{
strcat(output_file, ".rdef");
}
rdef_decompile(output_file);
}
}
//------------------------------------------------------------------------------
static void report_error()
{
switch (rdef_err)
{
case RDEF_COMPILE_ERR:
error("%s:%ld %s", rdef_err_file, rdef_err_line, rdef_err_msg);
break;
case RDEF_FILE_NOT_FOUND:
error("%s not found", rdef_err_file);
break;
case RDEF_NO_RESOURCES:
error("%s is not a resource file", rdef_err_file);
break;
case RDEF_WRITE_ERR:
error("error writing to %s (%s)", rdef_err_file, rdef_err_msg);
break;
case B_NO_MEMORY:
error("out of memory");
break;
case B_ERROR:
default:
error("unknown error: %lx (%s)", rdef_err, strerror(rdef_err));
break;
}
}
//------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
rdef_add_include_dir("."); // look in current dir first
get_program_name(argv);
parse_options(argc, argv);
rdef_set_flags(flags);
if (should_decompile)
{
decompile();
}
else
{
compile();
}
rdef_free_input_files();
rdef_free_include_dirs();
if (rdef_err != B_OK)
{
report_error();
}
return EXIT_SUCCESS;
}
//------------------------------------------------------------------------------
+134
View File
@@ -0,0 +1,134 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rdef.h"
#include "private.h"
ptr_list_t include_dirs;
ptr_list_t input_files;
uint32 flags = 0;
status_t rdef_err;
int32 rdef_err_line;
char rdef_err_file[B_PATH_NAME_LENGTH];
char rdef_err_msg[1024];
//------------------------------------------------------------------------------
void free_ptr_list(ptr_list_t& list)
{
for (ptr_iter_t i = list.begin(); i != list.end(); ++i)
{
free(*i);
}
list.clear();
}
//------------------------------------------------------------------------------
int32 rdef_get_version()
{
return 1;
}
//------------------------------------------------------------------------------
status_t rdef_add_include_dir(const char* dir)
{
clear_error();
char* temp = (char*) malloc(strlen(dir) + 2);
if (temp == NULL)
{
rdef_err = B_NO_MEMORY;
return B_NO_MEMORY;
}
strcpy(temp, dir);
strcat(temp, "/");
include_dirs.push_back(temp);
return B_OK;
}
//------------------------------------------------------------------------------
void rdef_free_include_dirs()
{
free_ptr_list(include_dirs);
}
//------------------------------------------------------------------------------
status_t rdef_add_input_file(const char* file)
{
clear_error();
char* temp = strdup(file);
if (temp == NULL)
{
rdef_err = B_NO_MEMORY;
return B_NO_MEMORY;
}
input_files.push_back(temp);
return B_OK;
}
//------------------------------------------------------------------------------
void rdef_free_input_files()
{
free_ptr_list(input_files);
}
//------------------------------------------------------------------------------
void rdef_set_flags(uint32 flags_)
{
flags = flags_;
}
//------------------------------------------------------------------------------
void rdef_clear_flags()
{
flags = 0;
}
//------------------------------------------------------------------------------
void clear_error()
{
rdef_err = B_OK;
rdef_err_line = 0;
rdef_err_file[0] = '\0';
rdef_err_msg[0] = '\0';
}
//------------------------------------------------------------------------------
+171
View File
@@ -0,0 +1,171 @@
/**
* @file rdef.h
*
* Public header file for the librdef shared library. Programs that want to
* use librdef should include this file, and link to librdef.so.
*
* @author Copyright (c) 2003 Matthijs Hollemans
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef RDEF_H
#define RDEF_H
#include <OS.h>
#ifdef __cplusplus
extern "C" {
#endif
#if __INTEL__
# ifdef _BUILDING_RDEF
# define _IMPEXP_RDEF __declspec(dllexport)
# else
# define _IMPEXP_RDEF __declspec(dllimport)
# endif
#else
# define _IMPEXP_RDEF
#endif
/**
* Whether to overwrite or merge with the output file. With this flag, the
* compiler will add the resources to the output file (if it exists). When
* something goes wrong, the output file is not deleted (although it may
* already contain some of the new resources). The default action is to clobber
* the contents of the output file if it already existed, and the file is
* deleted in case of an error. Not used for decompiling.
*/
#define RDEF_MERGE_RESOURCES (1 << 0)
/**
* Whether to generate resource names from symbolic identifiers, or vice versa.
* With this flag, the compiler will use symbolic names in statements such as
* "resource(R_Symbol)" to generate the resource name, in this case "R_Symbol".
* Otherwise, you must explicitly specify a name, such as "resource(R_Symbol,
* "Name") ..." If this option is set when decompiling, the decompiler will put
* resource names that are valid C/C++ identifiers in an enum statement in a
* new header file.
*/
#define RDEF_AUTO_NAMES (1 << 1)
/** Error codes returned by the librdef functions. */
enum
{
/** Syntax error or other compiler error. */
RDEF_COMPILE_ERR = B_ERRORS_END + 1,
/** Could not find one of the input files. */
RDEF_FILE_NOT_FOUND,
/** One of the input files has nothing to decompile. */
RDEF_NO_RESOURCES,
/** Could not write the output file. */
RDEF_WRITE_ERR,
/* B_OK */
/* B_ERROR */
/* B_NO_MEMORY */
};
/**
* The result of the most recent (de)compilation. B_OK if the operation
* was successful, a negative error code otherwise. This is the same as
* the value returned by any of the rdef_xxx functions.
*/
_IMPEXP_RDEF extern status_t rdef_err;
/**
* The line number where compilation failed. Valid line numbers start
* at 1. This is 0 if the error did not happen on a specific line.
*/
_IMPEXP_RDEF extern int32 rdef_err_line;
/**
* The file where the error occurred. This is an empty string if the
* error did not happen in a specific file.
*/
_IMPEXP_RDEF extern char rdef_err_file[];
/**
* The error message from the compiler. This is an empty string if there
* was no additional information to report.
*/
_IMPEXP_RDEF extern char rdef_err_msg[];
/**
* Returns the version number of the librdef API. You can use this to
* check which functions and variables are available.
*/
_IMPEXP_RDEF int32 rdef_get_version();
/**
* Adds a directory where the compiler will look for include files.
* Typically, you want to add the current directory to this list.
* Not used for decompilation.
*/
_IMPEXP_RDEF status_t rdef_add_include_dir(const char* dir);
/**
* Frees the list of include directories. If you call rdef_add_include_dir(),
* you should always call rdef_free_include_dirs() when the compiler is done.
*/
_IMPEXP_RDEF void rdef_free_include_dirs();
/**
* Adds an input file for the compiler or decompiler. Input files are not
* required to have a specific extension.
*/
_IMPEXP_RDEF status_t rdef_add_input_file(const char* file);
/**
* Frees the list of input files. If you call rdef_add_input_file(), you
* should always call rdef_free_input_files() when the compiler is done.
*/
_IMPEXP_RDEF void rdef_free_input_files();
/** Changes the configuration of the compiler or decompiler. */
_IMPEXP_RDEF void rdef_set_flags(uint32 flags);
/** Resets all the configuration options to their default values. */
_IMPEXP_RDEF void rder_clear_flags();
/**
* Invokes the rdef-to-rsrc compiler. Before you call rdef_compile(), you must
* have specified at least one input file with rdef_add_input_file(), and one
* include search path with rdef_add_include_dir().
*/
_IMPEXP_RDEF status_t rdef_compile(const char* output_file);
/**
* Invokes the rsrc-to-rdef decompiler. Just as with rdef_compile(), you must
* first add at least one input file with rdef_add_input_file(). Include dirs
* are not necessary, because the decompiler does not use them. The decompiler
* writes at least an rdef script file. In addition, if the "auto names" option
* is enabled it also writes a C/C++ header file. If these files already exist,
* they will be overwritten.
*/
_IMPEXP_RDEF status_t rdef_decompile(const char* output_file);
#ifdef __cplusplus
}
#endif
#endif /* RDEF_H */
+11
View File
@@ -0,0 +1,11 @@
/*
* Master test script for the resource compiler.
*/
#include "enum.rdef"
#include "simple.rdef"
#include "array.rdef"
#include "message.rdef"
#include "type.rdef"
//#include "defaults.rdef" // test separately
+127
View File
@@ -0,0 +1,127 @@
resource(301) array { $"41" };
resource(302) array { $"40" $"41" };
resource(303) array { $"42", $"43" };
resource(304) array { };
resource(305) array;
//resource(306) { }; // syntax error
//resource(307) { $"40" }; // syntax error
//resource(308) array { 100, }; // syntax error
resource(310) array { 1234, 5678 };
resource(311) array { (int16) 1234 };
resource(312) array { "wassup" };
resource(313) array { (string) "wassup" };
resource(320) #'CSTR' array { "wassup" };
resource(321) (#'CSTR') array { "wassup" };
resource(322) (buffer) array { "hello" };
resource(323) (raw) array { "there" };
//resource(324) (string) array { "wassup" }; // invalid cast
//resource(325) (#'CSTR' string) array { "wassup" }; // invalid cast
resource(330) array { "w00t", "dude" };
resource(331) #'CSTR' array { "w00t", "dude" };
resource(332) #'CSTR' array { "blah", "" };
resource(333) #'CSTR' array { "w00t" "dude" };
resource(334) #'CSTR' array { "blah" "" };
resource(335) array { 1234, "text", true, $"4041", 3.14e-1 };
resource(336) #'LLNG' array { (int64) 1234 }; // decompiles to (int64)1234
// The decompiler should not turn this back into a string, because
// it contains a non-human-readable character.
resource(337) array { "hey\0x01there" };
// Should decompile to $"405051416070"
resource(340) array
{
$"40", array { $"50", $"51" }, $"41", array { $"60", array { $"70" }}
};
resource(341) array { $"40", message { "field" = "value" }};
enum {
R_BeOSBitmap = 100,
R_Icon = 100,
R_Cursor = 100,
};
resource(1) #'PNG ' array {
$"89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF"
$"61000000096F464673000000000000000000DA2AB6CE00000009704859730000"
$"0FA000000FA001A06A8C770000019E49444154789CA593BF6BDB4018861FFD58"
$"8E8B34F51FE812E3D164C968E3C94BF0D041A55BC0244B372BD666BC092BD0B5"
$"2590ADD44307378BA7108F598247932CFD07324939B4482883CFE2126208E499"
$"8EE37DBFFB78EFFBACD17084499CC427401B686569DA00F07CFF1E5801CB288C"
$"7E997A6B5B204EE21670A6940AA494BC85520A29E50C984661B402704D33103C"
$"3E557CFFF18FDB878CBC7400104EC9E1BEC778D0454A02ED994661B4B275F133"
$"20B8BCBAA317CEB959E7E4A50B5880455EBADCAC737AE19CCBAB3B80407BB0AA"
$"AA3A514AFD7C7CAAE885736DDCF0FF7700C0E76FB3FA4E38058BA4CFA73D0B29"
$"E5A90DB4A5944C2EAE5F987791972E938B6B744E6D176801DC3E64DB486ACC97"
$"4D365A005A6E96A60DCFF7EBC05EB7FF56A1AD364BD386CD0E76BDFE1A5B0F09"
$"C229DF6530B59EEFDFDB6C268CC37DEFDD050CEDCA06964A29C6832EC2296A91"
$"998179164EC178D0452905B0B446C3117112FF410FD2F9DFF5CEEF144EC1F04B"
$"93E3A303805914465FB7214E81D9F1D1018BA44FA72974371550219C824E53B0"
$"48FAB5597B3EBE4CD647D7F919F31AB8B0697BD6410000000049454E44AE4260"
$"82"
};
resource(R_Cursor) #'CURS' array {
$"1001070707C0183027C859345014A10AA00AB45AA00AA10A5014593427C81830"
$"07C0000007C01FF03FF8793C701CE10EE00EF45EE00EE10E701C793C3FF81FF0"
$"07C00000"
};
resource(R_Icon) #'ICON' array {
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
};
resource(1) #'MICN' array {
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
};
+91
View File
@@ -0,0 +1,91 @@
/*
* Definitions for the types that are built into the compiler.
*/
/* BPoint object. */
type #'BPNT' point
{
float x,
float y
};
/* BRect object. */
type #'RECT' rect
{
float left,
float top,
float right,
float bottom
};
/* rgb_color object. */
type #'RGBC' rgb_color
{
uint8 red,
uint8 green,
uint8 blue,
uint8 alpha = 0xFF
};
/* Application signature. */
type(1, "BEOS:APP_SIG") #'MIMS' app_signature
{
string signature // max 240 bytes (including null)
};
/* Application launch flags */
type(1, "BEOS:APP_FLAGS") #'APPF' app_flags
{
// 0x00000000 B_SINGLE_LAUNCH
// 0x01000000 B_MULTIPLE_LAUNCH
// 0x02000000 B_EXCLUSIVE_LAUNCH
// 0x04000000 B_BACKGROUND_APP
// 0x08000000 B_ARGV_ONLY
uint32 flags
};
/*
* Application version info. Should always be 340 bytes. The system
* will automatically append 340 additional bytes with "system info".
*/
type(1, "BEOS:APP_VERSION") #'APPV' app_version
{
uint32 major,
uint32 middle,
uint32 minor,
// 0 = development 1 = alpha 2 = beta
// 3 = gamma 4 = golden master 5 = final
uint32 variety,
uint32 internal,
string short_info = // must be exactly 64 bytes (including null)
" ",
string long_info = // must be exactly 256 bytes (including null)
" "
" "
" "
" "
};
/* Large (32x32, 8-bit) application icon. */
type(101, "BEOS:L:STD_ICON") #'ICON' large_icon
{
array icon // 1024 bytes
};
/* Small (16x16, 8-bit) application icon. */
type(101, "BEOS:M:STD_ICON") #'MICN' mini_icon
{
array icon // 256 bytes
};
/* Supported file types. */
type(1, "BEOS:FILE_TYPES") #'MSGG' file_types
{
// contains one or more fields called "types", each of which
// has a MIME type value, for example: "types" = "text/plain"
message types
};
+70
View File
@@ -0,0 +1,70 @@
enum { R_Type1 = 30, R_Type2 };
type #'CSTR' teep1 { string x };
type(20) #'LONG' teep2 { int32 x };
type(21, "def name1") #'LONG' teep3 { int32 x };
type(R_Type1) #'LONG' teep4 { int32 x };
type(R_Type2, "def name2") #'LONG' teep5 { int32 x };
type("def name3") #'RAWT' teep6 { array x };
enum
{
R_Res1 = 4, R_Res2, R_Res3, R_Res4, R_Res5, R_Res6,
R_Res7, R_Res8, R_Res9, R_Res10, R_Res11, R_Res12
};
resource 123; // id 1, no name
resource(2) 123; // id 2, no name
resource(3, "over ride") 123; // id 3, name "over ride"
resource(R_Res1) 123; // id 4, no name
resource(R_Res2, "over ride") 123; // id 5, name "over ride"
resource("over ride") 10.0; // id 1, name "over ride"
resource teep1 "blah"; // id 1, no name
resource(2) teep1 "blah"; // id 2, no name
resource(3, "over ride") teep1 "blah"; // id 3, name "over ride"
resource(R_Res1) teep1 "blah"; // id 4, no name
resource(R_Res2, "over ride") teep1 "blah"; // id 5, name "over ride"
//resource("over ride") teep1 "blah"; // duplicate resource (1)
resource teep2 123; // id 20, no name
resource(40) teep2 123; // id 40, no name
resource(41, "over ride") teep2 123; // id 41, name "over ride"
resource(R_Res3) teep2 123; // id 6, no name
resource(R_Res4, "over ride") teep2 123; // id 7, name "over ride"
//resource("over ride") teep2 123; // duplicate resource (20)
resource teep3 123; // id 21, name "def name1"
resource(42) teep3 123; // id 42, name "def name1"
resource(43, "over ride") teep3 123; // id 43, name "over ride"
resource(R_Res5) teep3 123; // id 8, name "def name1" / R_Res5
resource(R_Res6, "over ride") teep3 123; // id 9, name "over ride"
//resource("over ride") teep3 123; // duplicate resource (21)
resource teep4 123; // id 30, no name / R_Type1
resource(44) teep4 123; // id 44, no name / R_Type1
resource(45, "over ride") teep4 123; // id 45, name "over ride"
resource(R_Res7) teep4 123; // id 10, no name
resource(R_Res8, "over ride") teep4 123; // id 11, name "over ride"
//resource("over ride") teep4 123; // duplicate resource (30)
resource teep5 123; // id 31, name "def name2"
resource(46) teep5 123; // id 46, name "def name2"
resource(47, "over ride") teep5 123; // id 47, name "over ride"
resource(R_Res9) teep5 123; // id 12, name "def name2" / R_Res9
resource(R_Res10, "over ride") teep5 123; // id 13, name "over ride"
//resource("over ride") teep5 123; // duplicate resource (31)
resource teep6 123; // id 1, name "def name3"
resource(48) teep6 123; // id 48, name "def name3"
resource(49, "over ride") teep6 123; // id 49, name "over ride"
resource(R_Res11) teep6 123; // id 14, name "def name3" / R_Res11
resource(R_Res12, "over ride") teep6 123; // id 15, name "over ride"
//resource("over ride") teep6 123; // duplicate resource (1)
//resource (int8) 123; // unknown type int8
resource() (int8) 123; // a possible workaround
type(0) teep7 { int32 x };
resource teep7 (int8) 123;
+34
View File
@@ -0,0 +1,34 @@
// Although useless, enums may be empty.
enum { };
enum
{
R_Test1, // starts at 0
R_Test2
};
enum
{
R_Test10, // is also 0
R_Test11 = 1000,
R_Test12 = 1111,
R_Test13, // should be 1112
R_Test14 = 999,
R_Test15 = -999, // may have comma
};
//enum { R_Test10 = 7 }; // duplicate symbol
resource(R_Test1) 123;
//resource(R_Test10) 123; // duplicate resource
resource(R_Test11) 123;
resource(R_Test15) 123;
resource(R_Test15) "123";
//resource(R_NotExists) 123; // unknown symbol
resource(R_Test12) 123;
resource(R_Test13) 123; // should have ID 1112
resource(R_Test13, "yeah") $"4041"; // R_RAWT_yeah
resource(R_Test13, "yeah\0what") 10.0; // R_FLOT_yeah
//resource(R_Test13, "yeah\0what") $"4041"; // duplicate resource
+208
View File
@@ -0,0 +1,208 @@
// "what" code should default to 0.
resource(401) message { "field1" = "value1" };
// Fields with casts, type codes, and nested compound data.
resource(402) message(1000)
{
"small1" = (int8) 257, // 1
int8 "small2" = 257, // 1
int8 "small3" = (int8) 257, // 1
uint8 "small4" = (int8) -1, // (uint8)255
int8 "small5" = (uint8) -1, // -1
int8 "small6" = (int8) -1, // -1
uint8 "small7" = (uint8) -1, // (uint8)255
"large1" = (int64) 3,
int64 "large2" = 3,
int64 "large3" = (int32) 3,
int32 "large4" = (int64) 3,
"string1" = "some text",
// string "string2" = 123, // invalid cast
// int32 "string3" = "text", // invalid cast
#'BYTE' "typecode1" = 1234, // does not become "(int8)-46"
#'blah' int16 "typecode2" = 1234, // becomes 16-bit, but raw encoded
"array1" = array { $"40", $"41" },
buffer "array2" = array { $"50" $"51" },
raw "array3" = array { "w00t", "dude" },
array "array4" = array { "w00t", 1234 },
array "array5" = (array) array { "w00t", 1234 },
//raw "array3" = { "w00t", "dude" }, // syntax error
"msg1" = message { "field" = "value" },
message "msg2" = message(2000) { "field" = "value" },
message "msg3" = (message) message(2000) { "field" = "value" },
#'blah' message "msg4" = message { "field" = "value" }
// ,message(2000) "msg5" = message(2000) { "fld" = "val" } // not supported
};
// "Arrays" of fields, i.e. multiple fields with the same name.
resource(403) message('blah')
{
"integer" = 1,
"integer" = 3,
"integer" = 2
// ,"integer" = "hi there" // type conflict
};
// Tests whether the decompiler correctly outputs nested messages.
resource(404) message('blah')
{
"sub1" = message('bla1') { "string1" = "value1" },
"sub1" = message('bla2') { "string2" = "value2" },
"sub1" = message('bla2') { "string2" = "value2", "string3" = "value3" },
"SomeField" = 2,
"sub2" = message('bla3') { "string3" = "value3" }
};
// Another comma test for the decompiler.
resource(405) #'w00t' message('blah')
{
"integer1" = 1,
"sub" = message { "string1" = "woot1" },
"integer2" = 2
};
// The decompiler should still recognize this as a message.
resource(406) #'RAWT' message { "field" = "value" };
//resource(407) (int32) message { "field" = "value" }; // invalid cast
//resource(407) (buffer) message { "field" = "value" }; // invalid cast
// beres allows you to specify a what code inside the cast,
// but we don't (beres ignores it anyway):
//resource(407) (message('blah')) message { "field" = "value"; }
// Decompiler turns the very long string into an array.
resource(408) message
{
"longstring" = "alongstring-alongstringg\000-alongstringg-alongstringg-alongstringgalongstringg-alongstringg-alongstringg-alongstringg-alongstring",
"longarray" = array { $"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb" },
#'blah' "longblah" = array { $"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabb" },
"textarray" = array { "pompiedom" }
};
// Note: negative "what" values are allowed, but the decompiler converts
// them to unsigned, just like type codes (which cannot be negative).
resource(409) message(-1) { "field" = "value" };
resource(410) message(0x80000000) { "field" = "value" };
resource(411) message(0x7FFFFFFF) { "field" = "value" };
resource(412) message(-100001) { "field" = "value" };
resource(413) #100001 message(-100001) { "field" = "value" };
//resource(414) #-100001 message { "f" = "v" }; // syntax error
resource(415) message { };
resource(416) message;
resource(417) message('blah') { };
resource(418) message('blah');
// Decompiles to an empty message.
resource(419) $"31424F460100001212000000000000000100";
resource(420) message('blah') {
"sub" = message('bla1') { "string1" = "woot1" },
"sub" = message('bla2') { "string2" = "woot2" },
int8 "small integer" = 1,
"integer" = 2,
"integer" = 3,
"large integer" = (int64)3,
"string" = "some text",
"sub2" = message('bla3') { "string3" = "woot3" }
};
resource(421) #'w00t' message('blah') {
"integer1" = 1,
"sub" = message('bla1') { "string1" = "woot1" },
"integer2" = 2
};
//------------------------------------------------------------------------------
resource(701) #'BBMP' archive BSomeClass { "data" = 123 };
resource(702) archive BSomeClass { "data" = 123 };
resource(703) archive("dynamic", 'blah') BSomeClass { "data" = 123 };
resource(704) archive("dynamic") BSomeClass { "data" = 123 };
resource(705) archive(, 200) BSomeClass { "data" = 123 };
resource(706) (archive BSomeClass) archive BSomeClass { "data" = 123 };
resource(707) archive(, -1) BSomeClass { "data" = 123 };
resource(700) archive BSomeClass { "" = $"" }; // empty archive trick
// When you cast an archive to a message, beres strips the
// "class" field from the message (so it will no longer be
// recognized as an archive), but we don't.
resource(708) (message) archive BSomeClass { "data" = 123 };
// beres allows you to specify the add_on name and what code
// inside the cast, but we don't (beres ignores it anyway).
//resource(709) (archive("t", 1) BSomeClass) archive BSomeClass { "d" = 123 };
//resource(709) (archive) archive BSomeClass { "d" = 123 }; // syntax error
//resource(709) archive("dynamic",) BSomeClass { "d" = 123 }; // syntax error
//------------------------------------------------------------------------------
enum {
R_BBMP_kLargeNewGroupIcon = 516,
R_BBMP_kSmallNewGroupIcon = 517,
};
resource(R_BBMP_kLargeNewGroupIcon) #'BBMP' archive BBitmap {
"_frame" = rect { 0.0, 0.0, 31.0, 31.0 },
"_cspace" = 4,
"_bmflags" = 1,
"_rowbytes" = 32,
"_data" = array {
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFF00FAFA0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFF00FAF8FAFA0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFF000000FAF8F8F8FAFA0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFF00FAFA0000F8F8F8F8F8FAFA00FFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFF00FAF8FAFA0000F8F8F8F8F800FFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFF00FAF8F8F8FAFA0000F8F8F800FFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFF00FAF8F8F8F8F8FAFA00F8F80000FFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFF001BF8F8F8F8F8F8F8000E0F1C1C0000FFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFF001B0F0F0FF8F8F8F8003F3F0E0F1C1C0000FFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFF001B0F3F3F0E0FF8F800003F3F3F0E0F1C1C0000FFFFFFFFFFFFFF"
$"FFFFFFFFFF001B0F3F3F3F3F0E0F1C1C00003F3F3F0E0F1A190000FFFFFFFFFF"
$"FFFFFFFFFF001B0F3F3F3F3F3F3F0E0F1C1C00003F3F3F0E1A1900FFFFFFFFFF"
$"FFFFFFFFFF001B0F3F3F3F3F3F3F3F3F0E0F1C1C00003F3F171900FFFFFFFFFF"
$"FFFFFFFFFF001B0F3F3F3F3F3F3F3F3F3F3F0E0F1A190000171900FFFFFFFFFF"
$"FFFFFFFFFF001B0F3F3F3F3F3F3F3F3F3F3F3F3F0E1A1900171900FFFFFFFFFF"
$"FFFFFFFFFF001B0F3F3F3F3F3F3F3F3F3F3F3F3F3F171900171900FFFFFFFFFF"
$"FFFFFFFFFF001B0F3F3F3F3F3F3F3F3F3F3F3F3F3F171900171900FFFFFFFFFF"
$"FFFFFFFFFF001B0F3F3F3F3F3F3F3F3F3F3F3F3F3F171900171900FFFFFFFFFF"
$"FFFFFFFFFF001B183F3F3F3F3F3F3F3F3F3F3F3F3F171900171900FFFFFFFFFF"
$"FFFFFFFFFF001B1C17183F3F3F3F3F3F3F3F3F3F3F171900171900FFFFFFFFFF"
$"FFFFFFFFFFFF00001B1C17183F3F3F3F3F3F3F3F3F171900171900FFFFFFFFFF"
$"FFFFFFFFFFFFFFFF0000191A17173F3F3F3F3F3F3F171900171900FFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFF0000191A17173F3F3F3F3F171900171A00FFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFF0000191A17173F3F3F1719001A1900FFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFF0000191A17173F171900001900FFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000191A17171A00FF0000FFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000191A1900FFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00001900FFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
}
};
resource(R_BBMP_kSmallNewGroupIcon) #'BBMP' archive BBitmap {
"_frame" = rect { 0.0, 0.0, 15.0, 15.0 },
"_cspace" = 4,
"_bmflags" = 1,
"_rowbytes" = 16,
"_data" = array {
$"FFFFFFFF0E0EFFFFFFFFFFFFFFFFFFFFFFFFFF0EFAFA0E0EFFFFFFFFFFFFFFFF"
$"FFFF0E0EF8F8FAFA0EFFFFFFFFFFFFFFFFFF0EFAFA0EF8F80EFFFFFFFFFFFFFF"
$"FFFF0EF8F8FAFA0E0E0EFFFFFFFFFFFFFFFF0E1818F8F80E3F3F0E0EFFFFFFFF"
$"FFFF0E183F18180F0F3F3F0E12FFFFFFFFFF0E183F3F3F18180F0F0E12FFFFFF"
$"FFFF0E183F3F3F3F3F18180E12FFFFFFFFFF0E183F3F3F3F3F3F1C0E12FFFFFF"
$"FFFF0E0E181C3F3F3F3F1C0E12FFFFFFFFFFFFFF0E0E171C3F3F1C0E12FFFFFF"
$"FFFFFFFFFFFF0E0E171C1C0E12FFFFFFFFFFFFFFFFFFFFFF0E0E170E12FFFFFF"
$"FFFFFFFFFFFFFFFFFFFF0E0EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
}
};
+179
View File
@@ -0,0 +1,179 @@
resource(1) 100;
resource(1) "123"; // should be okay because types differ
//resource(1) 123; // duplicate resource 1
//resource(0x100000001) 100; // duplicate resource 1
///* this is a /* nested */ comment */
resource(-1) 100;
resource(0xFFFFFFFE) 101; // -2
resource(- 0x7FFFFFFF) 102; // -2147483647
resource(-0x80000000) 103; // -2147483648
resource( 0x80000001) "104"; // -2147483647
resource(-0x80000001) 105; // 2147483647
resource(-3, "name") 106;
resource(10, "nom") "hello";
resource(11, "") 123; // should ignore name
//------------------------------------------------------------------------------
resource(20) true;
resource(21) false;
//resource(22) (int32) true; // invalid cast
resource(30) 12345;
resource(31) (int32) 12345;
resource(32) (uint32) 12345;
resource(33) (size_t) 12345;
resource(34) (ssize_t) 12345;
resource(35) (time_t) 12345;
resource(36) (int64) 1234;
resource(37) (uint64) 1234;
resource(38) (off_t) 0xffaa;
resource(39) (int8) 12345;
resource(40) (uint8) 12345;
resource(41) (int16) 12345;
resource(42) (uint16) 12345;
resource(43) (float) 12345;
resource(44) (double) 12345;
resource(44) (raw) 12345;
resource(45) -123;
resource(46) - 123;
resource(47) -0xFFFF; // -65535
resource(48) -0xFFFFFFFF; // 1
resource(49) -0x7FFFFFFF; // -2147483647
resource(50) -0x80000000; // -2147483648
resource(51) 0x80000001; // -2147483647
resource(52) -0x80000001; // 2147483647
resource(53) (uint64) -0xFFFFFFFF; // 18446744069414584321
resource(54) -1;
resource(55) 'what'; // 2003329396
resource(56) -'what'; // -2003329396
resource(57) 0b1;
resource(58) 0b11111111111111111111111111111111; // -1
resource(59) (uint64) 0b1111111111111111111111111111111111111111111111111111111111111111; // 18446744073709551615
//resource(59) - -123; // syntax error
resource(60) 10.0;
resource(61) (float) 10.0;
resource(62) (double) 10.0;
resource(63) -10.0;
resource(64) - 10.0;
resource(65) (raw) 10.0;
//resource(69) - -10.0; // syntax error
resource(70) "fancy";
resource(71) (string) "pants";
resource(72) "w00t\0dude";
resource(73) "fancy" "pants";
resource(74) "";
resource(75) "" "this" "wont" "" "scare" "" "me" "";
resource(76) (raw) "fancy";
//resource(79) "hi", "ho"; // , not allowed
resource(80) $"4041";
resource(81) (buffer) $"4041";
resource(82) (raw) $"4041";
resource(83) $"4041" $"4243";
resource(84) $"";
resource(85) $"" $"40" $"" $"41" $"";
resource(86) (array) $"4041";
//resource(89) $"0"; // too few digits
//resource(89) $"GA"; // invalid digit
//resource(89) $"FF", $"AA"; // , not allowed
resource(90) (#'blah') $"4041";
resource(91) (#'blah') (uint16) 1234;
resource(92) #'blah' 1234;
resource(93) #'blah' (uint16) 1234;
//resource(95) (#'blah' uint16) 1234; // we don't allow this notation
//------------------------------------------------------------------------------
enum {
R_Boolean = 100,
R_Int8 = 100,
R_Character = 100,
R_String = 100,
R_Double = 100,
R_Float = 100,
R_Int64 = 100,
R_Int32 = 100,
R_MIMEString = 100,
R_Offset = 100,
R_Pointer = 100,
R_Raw = 100,
R_Int16 = 100,
R_Size = 100,
R_Status = 100,
R_Time = 100,
R_UInt8 = 100,
R_UInt64 = 100,
R_UInt32 = 100,
R_UInt16 = 100
};
resource(R_Boolean) false;
resource(R_Int8) (int8)4;
resource(R_Character) (#'CHAR') $"28";
resource(R_String) "Dance and song";
resource(R_Double) (double)0.0;
resource(R_Float) 0.0;
resource(R_Int64) (int64)-125829120;
resource(R_Int32) -123450;
resource(R_MIMEString) (#'MIMS') "application/octet-stream";
resource(R_Offset) (off_t)0;
resource(R_Pointer) (#'PNTR') $"00000000";
resource(R_Raw) $"";
resource(R_Int16) (int16)-1234;
resource(R_Size) (size_t)0;
resource(R_Status) (ssize_t)0;
resource(R_Time) (time_t)0;
resource(R_UInt8) (uint8)200;
resource(R_UInt64) (uint64)17293822569102704640;
resource(R_UInt32) (uint32)251658240;
resource(R_UInt16) (uint16)61440;
resource(120) $"40414243";
resource(121) (#200)
$"DE8765005507E15BC8033E2CD6BFB72620DD87F9780325D0BB2DAC7DAEE9AC9B"
$"6C7398DB05ADC01C5E41CBC0CCDA19DBE9FFEF7430BE3525C5FCBC419BB90000";
//------------------------------------------------------------------------------
// The decompile should escape the special characters, except \P, which
// is not special (the \ is dropped). Unlike deres, rc does not split the
// string literal into two parts at the newline.
resource(200) "a \tshort string\nwith \bplenty\fof\r\vescapes\P";
// More stuff that should be escaped.
resource(201) "some other \"special\" characters like \\ and \0x01 and \002";
// Decompiling should create a "#'CSTR' array" with two items, because the
// string contains an embedded null character. By the way, beres does not
// recognize \0 as null, but rc does.
resource(202) "alongstring-alongstringg\000-alongstringg-alongstringg-alongstringgalongstringg-alongstringg-alongstringg-alongstringg-alongstring";
// Don't do the following in your own resource files. It should not crash
// the compiler or decompiler, but pretending that non-string data is a
// null-terminated string is A Bad Thing (tm).
resource(210) (#'CSTR') $"4041";
resource(212) (#'CSTR') (uint64) 5678;
// Should decompile as raw, not as string.
resource(213) (#200) 100;
// The decompiler sees this as a string literal.
resource(214) (#200) $"6400";
// The decompiler creates the symbolic names R_BOOL_MyName and R_CSTR_MyName,
// with values 215 and 216, respectively.
resource(215, "MyName") true;
resource(216, "MyName") "true";
// The decompiler creates the symbol R_200_MyName.
resource(217, "MyName") (#200) 123;
+223
View File
@@ -0,0 +1,223 @@
type #'smpl' simple { int8 x };
resource(801) simple { 4 };
resource(802) simple { 257 };
resource(803) simple { (int64)-1 };
// Type codes do not have to be unique, so even though #'BYTE' is used
// for the int8 built-in type, we can also use it for our own types.
type #'BYTE' mybyte { int8 x };
resource(805) mybyte { 4 };
resource(806) mybyte { 257 };
resource(807) mybyte { (int64)-1 };
//resource(808) (mybyte) 123; // invalid cast
//resource(809) (mybyte) "yeah"; // invalid cast
type #'RAWT' myraw { array x };
resource(810) myraw { array { $"1234" } };
resource(811) myraw { x = array { $"1234" } };
resource(812) myraw { $"1234" };
resource(813) (raw) myraw { $"1234" };
resource(814) (myraw) myraw { $"1234" };
resource(815) myraw;
//resource(816) (myraw) array { $"1234" }; // invalid cast
// all resources become "0100000002000000000300"
type #'what' type1 { int32 a, int32 b, bool d, int16 e }; // size 11
resource(810) type1 { 1, 2, false, 3 };
resource(811) type1 { d = false, 1, 2, 3 };
resource(812) type1 { d = false, e = 3, b = 2, 1 };
resource(813) type1 { d = false, e = 3, 6, 7, a = 1, b = 2 };
resource(814) type1 { 6, 7, false, 9, d = false, e = 3, a = 1, b = 2 };
type #'RECT' myrect { float left, float top, float bottom, float right };
// becomes { 1.00000, 2.00000, 3.00000, 4.00000 }
resource(820) myrect { 1, 2, 3, 4 };
// becomes { 1.00000, 2.00000, 3.00000, 4.00000 }
resource(821) myrect { left = 1, 2, 3, 4 };
// becomes { 3.00000, 2.00000, 4.00000, 5.00000 }
resource(822) myrect { 1, 2, left = 3, 4, 5 };
// becomes { 3.00000, 2.00000, 4.00000, 0 }
resource(823) myrect { 1, 2, left = 3, 4 };
// becomes { 2.00000, 1.00000, 3.00000, 4.00000 }
resource(824) myrect { top = 1, 2, 3, 4 };
// becomes { 1.00000, 0.00000, 0.00000, 0.00000 }
resource(825) myrect { 1 };
// becomes $"0000803F000000400000404000008040"
resource(826) (raw) myrect { 1, 2, 3, 4 };
// becomes { 1.00000, 2.00000, 3.00000, 4.00000 }
resource(827) #'RECT' (raw) myrect { 1, 2, 3, 4 };
resource(828) #'RECT' $"0000803F000000400000404000008040";
//resource(829) myrect { left = 1, 2, 3, 4, 5 }; // too many fields
//resource(829) myrect { dude = 1, 2, 3, 4, 5 }; // unknown field
//resource(829) myrect { (float) top = 1, 2, 3, 4 }; // unknown type top
enum { NoConflict = 100 };
type #'RAWT' NoConflict { int32 a };
// Types are not identified by their type_code, but by their name, so the
// size of typ3 should be 5, even though typ1 and 2 have the same code.
type #'same' typ1 { int8 x };
type #'same' typ2 { int32 x };
type #'diff' typ3 { typ1 a, typ2 b };
resource(830) typ3 { typ1 { 1 }, typ2 { 2 } };
resource(831) typ3 { b = typ2 { 1 }, a = typ1 { 2 } };
resource(832) typ3 { b = typ2 1, a = typ1 2 };
resource(833) typ3 { typ1 1, typ2 2 };
//resource(834) typ3 { typ2 { 1 }, typ1 { 2 } }; // invalid cast
//resource(834) typ3 { a = typ2 { 1 }, b = typ1 { 2 } }; // invalid cast
//resource(834) typ3 { a = { 1 }, b = { 2 } }; // invalid cast
// Size of this type's data should still be 8, even though the default
// value for one of the fields is an int8.
type #'RAWT' rect2 { float a, float b = (int8) 12 };
resource(835) rect2 { 1 };
type #'cmpd' compound { int16 a = 100, int16 b = 0x80 };
type #'nest' nested { compound c = compound { 16, 32 }, int8 i = 4 };
type #'nst2' nested2 { compound c, int8 i };
resource(840) compound { };
resource(841) compound;
resource(842) nested { compound { }, 1 };
resource(843) nested2 { compound, 1 };
resource(844) nested;
resource(845) nested2;
type #'CSTR' strings { string a, string b = "yo" };
resource(850) strings;
resource(851) strings { a = "long", b = "longer" };
resource(852) strings { b = "long" };
//resource(859) (string) strings { "long", "longer" }; // invalid cast
type #'RAWT' msgs { archive BBitmap a };
resource(860) msgs;
resource(861) msgs { a = archive BBitmap { "field" = "value" } };
type #'MSGG' msgs2 { message m = message('yeah') { "fld" = "val" } };
resource(862) msgs2;
// When you decompile these, it only sees the first message.
type #'RAWT' msgs3 { message m, archive BBitmap a };
type #'zzzz' msgs4
{
message m = message { "f" = "v" },
message n = message { "v" = "f" }
};
resource(863) msgs3;
resource(864) msgs4;
type #'zzzz' msgs5 { int8 x, message m, message n };
resource(865) msgs5;
resource(866) msgs5 { 4, message('yoyo') { "f" = "v" } };
type #'what' onefield { int32 flags };
resource(870) onefield 100;
type ye_olde_raw { int32 a };
resource(871) ye_olde_raw 64;
//type #'what' sometype { UnKnOwN x }; // unknown type
//type #'what' B_INT8_TYPE { int8 x }; // duplicate type (built-in)
//type #'RECT' myrect { float x }; // duplicate type
//type #'RAWT' whoops { float x = "wrong" } // invalid cast
//type #'jump' jump { int8 x, jump j }; // unknown type jump
//resource(890) tooSoon 123; // unknown type (must
//type #'soon' tooSoon { int32 x }; // be defined first)
//resource(890) UnKnOwN { 123 }; // unknown type
//resource(890) (UnKnOwN) { 123 }; // unknown type
//resource(890) message('blah') { UnKnOwN x }; // unknown type
//resource(890) myraw { 123 }; // invalid cast
//resource(890) (myrect) { 123 }; // invalid cast
enum {
R_Point = 100,
R_Rect = 100,
R_Color = 100,
};
resource(R_Point) point { -8.30573e+26, -1.0977e+37 };
resource(880) point;
resource(R_Rect) rect { 0.0, 0.0, -1.0, -1.0 };
resource(881) rect;
resource(R_Color) rgb_color { 0xaa, 0xbb, 0x88, 0x80 };
resource(882) rgb_color;
resource app_signature "application/x-vnd.vendor.appname";
resource app_flags;
resource app_version;
resource large_icon array
{
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
};
resource mini_icon array
{
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
};
resource file_types message
{
"types" = "text/plain",
"types" = "text/x-source-code"
};