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:
@@ -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 =
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -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';
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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"
|
||||
};
|
||||
@@ -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
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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"
|
||||
}
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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"
|
||||
};
|
||||
Reference in New Issue
Block a user