Merged changes from branch build_system_redesign at revision 14573.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@14574 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,883 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <List.h>
|
||||
#include <Resources.h>
|
||||
#include <StorageDefs.h>
|
||||
#include <TypeConstants.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static const char *kCommandName = "xres";
|
||||
static const char *kDefaultResourceName = NULL;
|
||||
static const char *kDefaultOutputFile = "xres.output.rsrc";
|
||||
static const int kMaxSaneResourceSize = 100 * 1024 * 1024; // 100 MB
|
||||
|
||||
static int kArgc;
|
||||
static const char *const *kArgv;
|
||||
|
||||
// usage
|
||||
const char *kUsage =
|
||||
"Usage: %s ( -h | --help )\n"
|
||||
" %s -l <file> ...\n"
|
||||
" %s <command> ...\n"
|
||||
"\n"
|
||||
"The first form prints this help text and exits.\n"
|
||||
"\n"
|
||||
"The second form lists the resources of all given files.\n"
|
||||
"\n"
|
||||
"The third form manipulates the resources of one or more files according to\n"
|
||||
"the given commands.\n"
|
||||
"\n"
|
||||
"Valid commands are:\n"
|
||||
" <input file>\n"
|
||||
" - Add the resources read from file <input file> to the current\n"
|
||||
" output file. The file can either be a resource file or an\n"
|
||||
" executable file.\n"
|
||||
" -a <type>:<id>[:<name>] ( <file> | -s <data> )\n"
|
||||
" - Add a resource to the current output file. The added resource is\n"
|
||||
" of type <type> and has the ID <id>. If given the resource will\n"
|
||||
" have name <name>, otherwise it won't have a name. The resource\n"
|
||||
" data will either be the string <data> provided on the command\n"
|
||||
" line or the data read from file <file> (the whole contents).\n"
|
||||
" -d <type>[:<id>]\n"
|
||||
" - Excludes resources with type <type> and, if given, ID <id> from\n"
|
||||
" being written to the output file. This applies to all resources\n"
|
||||
" read from input files or directly specified via command \"-a\"\n"
|
||||
" following this command until the next \"-d\" command.\n"
|
||||
" -o <output file>\n"
|
||||
" - Changes the output file to <output file>. All resources specified\n"
|
||||
" by subsequent <input file> or \"-a\" commands will be written\n"
|
||||
" to this file until the next output file is specified via the\n"
|
||||
" \"-o\" command. Resources specified later overwrite earlier ones\n"
|
||||
" with the same type and ID. If <output file> doesn't exist yet, \n"
|
||||
" a resource file with the name will be created. If it exists and\n"
|
||||
" is an executable file, the resources will be added to it (if the\n"
|
||||
" file already has resources, they will be removed before). If it\n"
|
||||
" is a resource file or a file of unknown type, it will be\n"
|
||||
" overwritten with a resource file containing the specified\n"
|
||||
" resources. The initial output file is \"xres.output.rsrc\".\n"
|
||||
" Note that an output file will only be created or modified, if at\n"
|
||||
" least one <input file> or \"-a\" command is given for it.\n"
|
||||
" -x <type>[:<id>]\n"
|
||||
" - Only resources with type <type> and, if given, ID <id> will be\n"
|
||||
" written to the output file. This applies to all resources\n"
|
||||
" read from input files or directly specified via command \"-a\"\n"
|
||||
" following this command until the next \"-x\" command.\n"
|
||||
" -- - All following arguments, even if starting with a \"-\" character,\n"
|
||||
" are treated as input file names.\n"
|
||||
"\n"
|
||||
"Parameters:\n"
|
||||
" <type> - A type constant consisting of exactly four characters.\n"
|
||||
" <id> - A positive or negative integer.\n"
|
||||
;
|
||||
|
||||
// resource_type
|
||||
static const char *
|
||||
resource_type(type_code type)
|
||||
{
|
||||
static char typeString[5];
|
||||
|
||||
typeString[0] = type >> 24;
|
||||
typeString[1] = (type >> 16) & 0xff;
|
||||
typeString[2] = (type >> 8) & 0xff;
|
||||
typeString[3] = type & 0xff;
|
||||
typeString[4] = '\0';
|
||||
|
||||
return typeString;
|
||||
}
|
||||
|
||||
// ResourceID
|
||||
struct ResourceID {
|
||||
type_code type;
|
||||
int32 id;
|
||||
bool wildcardID;
|
||||
|
||||
ResourceID(type_code type = B_ANY_TYPE, int32 id = 0,
|
||||
bool wildcardID = true)
|
||||
: type(type),
|
||||
id(id),
|
||||
wildcardID(wildcardID)
|
||||
{
|
||||
}
|
||||
|
||||
ResourceID(const ResourceID &other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
bool Matches(const ResourceID &other) const
|
||||
{
|
||||
return ((type == other.type || type == B_ANY_TYPE)
|
||||
&& (wildcardID || id == other.id));
|
||||
}
|
||||
|
||||
ResourceID &operator=(const ResourceID &other)
|
||||
{
|
||||
type = other.type;
|
||||
id = other.id;
|
||||
wildcardID = other.wildcardID;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
// ResourceDataSource
|
||||
struct ResourceDataSource {
|
||||
ResourceDataSource()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~ResourceDataSource()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void GetData(const void *&data, size_t &size) = 0;
|
||||
|
||||
virtual void Flush()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// MemoryResourceDataSource
|
||||
struct MemoryResourceDataSource : ResourceDataSource {
|
||||
MemoryResourceDataSource(const void *data, size_t size, bool clone)
|
||||
{
|
||||
_Init(data, size, clone);
|
||||
}
|
||||
|
||||
MemoryResourceDataSource(const char *data, bool clone)
|
||||
{
|
||||
_Init(data, strlen(data) + 1, clone);
|
||||
}
|
||||
|
||||
virtual ~MemoryResourceDataSource()
|
||||
{
|
||||
if (fOwner)
|
||||
delete[] fData;
|
||||
}
|
||||
|
||||
virtual void GetData(const void *&data, size_t &size)
|
||||
{
|
||||
data = fData;
|
||||
size = fSize;
|
||||
}
|
||||
|
||||
private:
|
||||
void _Init(const void *data, size_t size, bool clone)
|
||||
{
|
||||
if (clone) {
|
||||
fData = new uint8[size];
|
||||
memcpy(fData, data, size);
|
||||
fSize = size;
|
||||
fOwner = true;
|
||||
} else {
|
||||
fData = (uint8*)data;
|
||||
fSize = size;
|
||||
fOwner = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 *fData;
|
||||
size_t fSize;
|
||||
bool fOwner;
|
||||
};
|
||||
|
||||
// FileResourceDataSource
|
||||
struct FileResourceDataSource : ResourceDataSource {
|
||||
FileResourceDataSource(const char *path)
|
||||
: fPath(path),
|
||||
fData(NULL),
|
||||
fSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~FileResourceDataSource()
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
|
||||
virtual void GetData(const void *&_data, size_t &_size)
|
||||
{
|
||||
if (!fData) {
|
||||
// open the file for reading
|
||||
BFile file;
|
||||
status_t error = file.SetTo(fPath.c_str(), B_READ_ONLY);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to open file \"%s\": %s\n",
|
||||
fPath.c_str(), strerror(error));
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// get size
|
||||
off_t size;
|
||||
error = file.GetSize(&size);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to get size of file \"%s\": "
|
||||
"%s\n", fPath.c_str(), strerror(error));
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// check size
|
||||
if (size > kMaxSaneResourceSize) {
|
||||
fprintf(stderr, "Error: Resource data file \"%s\" is too big\n",
|
||||
fPath.c_str());
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// read the data
|
||||
fData = new uint8[size];
|
||||
fSize = size;
|
||||
ssize_t bytesRead = file.ReadAt(0, fData, fSize);
|
||||
if (bytesRead < 0) {
|
||||
fprintf(stderr, "Error: Failed to read data size from file "
|
||||
"\"%s\": %s\n", fPath.c_str(), strerror(bytesRead));
|
||||
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
_data = fData;
|
||||
_size = fSize;
|
||||
}
|
||||
|
||||
virtual void Flush()
|
||||
{
|
||||
if (fData) {
|
||||
delete[] fData;
|
||||
fData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
string fPath;
|
||||
uint8 *fData;
|
||||
size_t fSize;
|
||||
};
|
||||
|
||||
// State
|
||||
struct State {
|
||||
State()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~State()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void SetOutput(const char *path)
|
||||
{
|
||||
(void)path;
|
||||
}
|
||||
|
||||
virtual void ProcessInput(const char *path)
|
||||
{
|
||||
(void)path;
|
||||
}
|
||||
|
||||
virtual void SetInclusionPattern(const ResourceID &pattern)
|
||||
{
|
||||
(void)pattern;
|
||||
}
|
||||
|
||||
virtual void SetExclusionPattern(const ResourceID &pattern)
|
||||
{
|
||||
(void)pattern;
|
||||
}
|
||||
|
||||
virtual void AddResource(const ResourceID &id, const char *name,
|
||||
ResourceDataSource *dataSource)
|
||||
{
|
||||
(void)id;
|
||||
(void)name;
|
||||
(void)dataSource;
|
||||
}
|
||||
};
|
||||
|
||||
// ListState
|
||||
struct ListState : State {
|
||||
ListState()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~ListState()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void ProcessInput(const char *path)
|
||||
{
|
||||
// open the file for reading
|
||||
BFile file;
|
||||
status_t error = file.SetTo(path, B_READ_ONLY);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to open file \"%s\": %s\n", path,
|
||||
strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// open the resources
|
||||
BResources resources;
|
||||
error = resources.SetTo(&file, false);
|
||||
if (error != B_OK) {
|
||||
if (error == B_ERROR) {
|
||||
fprintf(stderr, "Error: File \"%s\" is not a resource file.\n",
|
||||
path);
|
||||
} else {
|
||||
fprintf(stderr, "Error: Failed to read resources from file "
|
||||
"\"%s\": %s\n", path, strerror(error));
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// print resources
|
||||
printf("\n%s resources:\n\n", path);
|
||||
printf(" type ID size name\n");
|
||||
printf("------ ----------- ----------- --------------------\n");
|
||||
|
||||
type_code type;
|
||||
int32 id;
|
||||
const char *name;
|
||||
size_t size;
|
||||
for (int32 i = 0;
|
||||
resources.GetResourceInfo(i, &type, &id, &name, &size);
|
||||
i++) {
|
||||
|
||||
printf("'%s' %11ld %11lu %s\n", resource_type(type), id, size,
|
||||
(name && strlen(name) > 0 ? name : "(no name)"));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// WriteFileState
|
||||
struct WriteFileState : State {
|
||||
WriteFileState()
|
||||
: fOutputFilePath(kDefaultOutputFile),
|
||||
fResources(NULL),
|
||||
fInclusionPattern(NULL),
|
||||
fExclusionPattern(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~WriteFileState()
|
||||
{
|
||||
_FlushOutput();
|
||||
}
|
||||
|
||||
virtual void SetOutput(const char *path)
|
||||
{
|
||||
_FlushOutput();
|
||||
|
||||
fOutputFilePath = path;
|
||||
}
|
||||
|
||||
virtual void ProcessInput(const char *path)
|
||||
{
|
||||
// open the file for reading
|
||||
BFile file;
|
||||
status_t error = file.SetTo(path, B_READ_ONLY);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to open input file \"%s\": %s\n",
|
||||
path, strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// open the resources
|
||||
BResources resources;
|
||||
error = resources.SetTo(&file, false);
|
||||
if (error != B_OK) {
|
||||
if (error == B_ERROR) {
|
||||
fprintf(stderr, "Error: Input file \"%s\" is not a resource "
|
||||
"file.\n", path);
|
||||
} else {
|
||||
fprintf(stderr, "Error: Failed to read resources from input "
|
||||
"file \"%s\": %s\n", path, strerror(error));
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
resources.PreloadResourceType();
|
||||
|
||||
// add resources
|
||||
type_code type;
|
||||
int32 id;
|
||||
const char *name;
|
||||
size_t size;
|
||||
for (int32 i = 0;
|
||||
resources.GetResourceInfo(i, &type, &id, &name, &size);
|
||||
i++) {
|
||||
// load the resource
|
||||
const void *data = resources.LoadResource(type, id, &size);
|
||||
if (!data) {
|
||||
fprintf(stderr, "Error: Failed to read resources from input "
|
||||
"file \"%s\".\n", path);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// add it
|
||||
MemoryResourceDataSource dataSource(data, size, false);
|
||||
AddResource(ResourceID(type, id), name, &dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetInclusionPattern(const ResourceID &pattern)
|
||||
{
|
||||
if (!fInclusionPattern)
|
||||
fInclusionPattern = new ResourceID;
|
||||
*fInclusionPattern = pattern;
|
||||
}
|
||||
|
||||
virtual void SetExclusionPattern(const ResourceID &pattern)
|
||||
{
|
||||
if (!fExclusionPattern)
|
||||
fExclusionPattern = new ResourceID;
|
||||
*fExclusionPattern = pattern;
|
||||
}
|
||||
|
||||
virtual void AddResource(const ResourceID &id, const char *name,
|
||||
ResourceDataSource *dataSource)
|
||||
{
|
||||
_PrepareOutput();
|
||||
|
||||
// filter resource
|
||||
if (fInclusionPattern && !fInclusionPattern->Matches(id)
|
||||
|| fExclusionPattern && fExclusionPattern->Matches(id)) {
|
||||
// not included or explicitly excluded
|
||||
return;
|
||||
}
|
||||
|
||||
// get resource data
|
||||
const void *data;
|
||||
size_t size;
|
||||
dataSource->GetData(data, size);
|
||||
|
||||
// add the resource
|
||||
status_t error = fResources->AddResource(id.type, id.id, data, size,
|
||||
name);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to add resource type '%s', ID %ld "
|
||||
"to output file \"%s\": %s\n", resource_type(id.type), id.id,
|
||||
fOutputFilePath.c_str(), strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void _FlushOutput()
|
||||
{
|
||||
if (fResources) {
|
||||
status_t error = fResources->Sync();
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to write resources to output "
|
||||
"file \"%s\": %s\n", fOutputFilePath.c_str(),
|
||||
strerror(error));
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
delete fResources;
|
||||
fResources = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void _PrepareOutput()
|
||||
{
|
||||
if (fResources)
|
||||
return;
|
||||
|
||||
// open the file for writing
|
||||
BFile file;
|
||||
status_t error = file.SetTo(fOutputFilePath.c_str(),
|
||||
B_READ_WRITE | B_CREATE_FILE);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to open output file \"%s\": %s\n",
|
||||
fOutputFilePath.c_str(), strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// open the resources
|
||||
fResources = new BResources;
|
||||
error = fResources->SetTo(&file, true);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Error: Failed to init resources for output "
|
||||
"file \"%s\": %s\n", fOutputFilePath.c_str(), strerror(error));
|
||||
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
string fOutputFilePath;
|
||||
BResources *fResources;
|
||||
ResourceID *fInclusionPattern;
|
||||
ResourceID *fExclusionPattern;
|
||||
};
|
||||
|
||||
// Command
|
||||
struct Command {
|
||||
Command()
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Command()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Do(State *state) = 0;
|
||||
};
|
||||
|
||||
// SetOutputCommand
|
||||
struct SetOutputCommand : Command {
|
||||
SetOutputCommand(const char *path)
|
||||
: Command(),
|
||||
fPath(path)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Do(State *state)
|
||||
{
|
||||
state->SetOutput(fPath.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
string fPath;
|
||||
};
|
||||
|
||||
// ProcessInputCommand
|
||||
struct ProcessInputCommand : Command {
|
||||
ProcessInputCommand(const char *path)
|
||||
: Command(),
|
||||
fPath(path)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Do(State *state)
|
||||
{
|
||||
state->ProcessInput(fPath.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
string fPath;
|
||||
};
|
||||
|
||||
// SetResourcePatternCommand
|
||||
struct SetResourcePatternCommand : Command {
|
||||
SetResourcePatternCommand(const ResourceID &pattern, bool inclusion)
|
||||
: Command(),
|
||||
fPattern(pattern),
|
||||
fInclusion(inclusion)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Do(State *state)
|
||||
{
|
||||
if (fInclusion)
|
||||
state->SetInclusionPattern(fPattern);
|
||||
else
|
||||
state->SetExclusionPattern(fPattern);
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceID fPattern;
|
||||
bool fInclusion;
|
||||
};
|
||||
|
||||
// AddResourceCommand
|
||||
struct AddResourceCommand : Command {
|
||||
AddResourceCommand(const ResourceID &id, const char *name,
|
||||
ResourceDataSource *dataSource)
|
||||
: Command(),
|
||||
fID(id),
|
||||
fHasName(name),
|
||||
fDataSource(dataSource)
|
||||
{
|
||||
if (fHasName)
|
||||
fName = name;
|
||||
}
|
||||
|
||||
virtual ~AddResourceCommand()
|
||||
{
|
||||
delete fDataSource;
|
||||
}
|
||||
|
||||
virtual void Do(State *state)
|
||||
{
|
||||
state->AddResource(fID, (fHasName ? fName.c_str() : NULL),
|
||||
fDataSource);
|
||||
fDataSource->Flush();
|
||||
}
|
||||
|
||||
private:
|
||||
ResourceID fID;
|
||||
string fName;
|
||||
bool fHasName;
|
||||
ResourceDataSource *fDataSource;
|
||||
};
|
||||
|
||||
|
||||
// print_usage
|
||||
static void
|
||||
print_usage(bool error)
|
||||
{
|
||||
// get command name
|
||||
const char *commandName = NULL;
|
||||
if (kArgc > 0) {
|
||||
if (const char *lastSlash = strchr(kArgv[0], '/'))
|
||||
commandName = lastSlash + 1;
|
||||
else
|
||||
commandName = kArgv[0];
|
||||
}
|
||||
|
||||
if (!commandName || strlen(commandName) == 0)
|
||||
commandName = kCommandName;
|
||||
|
||||
// print usage
|
||||
fprintf((error ? stderr : stdout), kUsage, commandName, commandName,
|
||||
commandName);
|
||||
}
|
||||
|
||||
// print_usage_and_exit
|
||||
static void
|
||||
print_usage_and_exit(bool error)
|
||||
{
|
||||
print_usage(error);
|
||||
exit(error ? 1 : 0);
|
||||
}
|
||||
|
||||
// next_arg
|
||||
static const char *
|
||||
next_arg(int &argi, bool optional = false)
|
||||
{
|
||||
if (argi >= kArgc) {
|
||||
if (!optional)
|
||||
print_usage_and_exit(true);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return kArgv[argi++];
|
||||
}
|
||||
|
||||
// parse_resource_id
|
||||
static void
|
||||
parse_resource_id(const char *toParse, ResourceID &resourceID,
|
||||
const char **name = NULL)
|
||||
{
|
||||
int len = strlen(toParse);
|
||||
|
||||
// type
|
||||
if (len < 4)
|
||||
print_usage_and_exit(true);
|
||||
|
||||
resourceID.type = ((int32)toParse[0] << 24) | ((int32)toParse[1] << 16)
|
||||
| ((int32)toParse[2] << 8) | (int32)toParse[3];
|
||||
|
||||
if (toParse[4] == '\0') {
|
||||
// if a name can be provided, the ID is mandatory
|
||||
if (name)
|
||||
print_usage_and_exit(true);
|
||||
|
||||
resourceID.id = 0;
|
||||
resourceID.wildcardID = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (toParse[4] != ':')
|
||||
print_usage_and_exit(true);
|
||||
|
||||
toParse += 5;
|
||||
len -= 5;
|
||||
|
||||
// ID
|
||||
bool negative = false;
|
||||
if (*toParse == '-') {
|
||||
negative = true;
|
||||
toParse++;
|
||||
len--;
|
||||
}
|
||||
|
||||
if (*toParse < '0' || *toParse > '9')
|
||||
print_usage_and_exit(true);
|
||||
|
||||
int id = 0;
|
||||
while (*toParse >= '0' && *toParse <= '9') {
|
||||
id = 10 * id + (*toParse - '0');
|
||||
toParse++;
|
||||
len--;
|
||||
}
|
||||
|
||||
resourceID.wildcardID = false;
|
||||
resourceID.id = (negative ? -id : id);
|
||||
|
||||
if (*toParse == '\0') {
|
||||
if (name)
|
||||
*name = kDefaultResourceName;
|
||||
return;
|
||||
}
|
||||
|
||||
if (*toParse != ':')
|
||||
print_usage_and_exit(true);
|
||||
|
||||
// the remainder is name
|
||||
*name = toParse + 1;
|
||||
}
|
||||
|
||||
// main
|
||||
int
|
||||
main(int argc, const char *const *argv)
|
||||
{
|
||||
kArgc = argc;
|
||||
kArgv = argv;
|
||||
|
||||
if (argc < 2)
|
||||
print_usage_and_exit(true);
|
||||
|
||||
BList commandList;
|
||||
|
||||
// parse the arguments
|
||||
bool noMoreOptions = false;
|
||||
bool list = false;
|
||||
bool noList = false;
|
||||
bool hasInputFiles = false;
|
||||
for (int argi = 1; argi < argc; ) {
|
||||
const char *arg = argv[argi++];
|
||||
if (!noMoreOptions && arg[0] == '-') {
|
||||
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
|
||||
print_usage_and_exit(false);
|
||||
|
||||
if (strlen(arg) != 2)
|
||||
print_usage_and_exit(true);
|
||||
|
||||
switch (arg[1]) {
|
||||
case 'a':
|
||||
{
|
||||
noList = true;
|
||||
|
||||
// get id
|
||||
const char *typeString = next_arg(argi);
|
||||
ResourceID resourceID;
|
||||
const char *name = NULL;
|
||||
parse_resource_id(typeString, resourceID, &name);
|
||||
|
||||
// get data
|
||||
const char *file = next_arg(argi);
|
||||
ResourceDataSource *dataSource;
|
||||
if (strcmp(file, "-s") == 0) {
|
||||
const char *data = next_arg(argi);
|
||||
dataSource = new MemoryResourceDataSource(data, false);
|
||||
|
||||
} else {
|
||||
dataSource = new FileResourceDataSource(file);
|
||||
}
|
||||
|
||||
// add command
|
||||
Command *command = new AddResourceCommand(resourceID,
|
||||
name, dataSource);
|
||||
commandList.AddItem(command);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd':
|
||||
{
|
||||
noList = true;
|
||||
|
||||
// get pattern
|
||||
const char *typeString = next_arg(argi);
|
||||
ResourceID pattern;
|
||||
parse_resource_id(typeString, pattern);
|
||||
|
||||
// add command
|
||||
Command *command = new SetResourcePatternCommand(pattern,
|
||||
false);
|
||||
commandList.AddItem(command);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'l':
|
||||
{
|
||||
list = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'o':
|
||||
{
|
||||
noList = true;
|
||||
|
||||
// get file name
|
||||
const char *out = next_arg(argi);
|
||||
|
||||
// add command
|
||||
Command *command = new SetOutputCommand(out);
|
||||
commandList.AddItem(command);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'x':
|
||||
{
|
||||
noList = true;
|
||||
|
||||
// get pattern
|
||||
const char *typeString = next_arg(argi);
|
||||
ResourceID pattern;
|
||||
parse_resource_id(typeString, pattern);
|
||||
|
||||
// add command
|
||||
Command *command = new SetResourcePatternCommand(pattern,
|
||||
true);
|
||||
commandList.AddItem(command);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case '-':
|
||||
noMoreOptions = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
print_usage_and_exit(true);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
// input file
|
||||
hasInputFiles = true;
|
||||
Command *command = new ProcessInputCommand(arg);
|
||||
commandList.AddItem(command);
|
||||
}
|
||||
}
|
||||
|
||||
// don't allow "-l" together with other comands or without at least one
|
||||
// input file
|
||||
if (list && noList || list && !hasInputFiles)
|
||||
print_usage_and_exit(true);
|
||||
|
||||
// create a state
|
||||
State *state;
|
||||
if (list)
|
||||
state = new ListState();
|
||||
else
|
||||
state = new WriteFileState();
|
||||
|
||||
// process commands
|
||||
for (int32 i = 0; Command *command = (Command*)commandList.ItemAt(i); i++)
|
||||
command->Do(state);
|
||||
|
||||
// delete state (will flush resources)
|
||||
delete state;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user