Added resattr, a small tool that converts resources into attributes and vice versa.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10785 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
60027f7eac
commit
8dbd1340a3
@ -6,6 +6,7 @@ SubInclude OBOS_TOP src tools elfsymbolpatcher ;
|
||||
SubInclude OBOS_TOP src tools gensyscalls ;
|
||||
SubInclude OBOS_TOP src tools hey ;
|
||||
SubInclude OBOS_TOP src tools rc ;
|
||||
SubInclude OBOS_TOP src tools resattr ;
|
||||
SubInclude OBOS_TOP src tools translation ;
|
||||
SubInclude OBOS_TOP src tools unflatten ;
|
||||
|
||||
|
4
src/tools/resattr/Jamfile
Normal file
4
src/tools/resattr/Jamfile
Normal file
@ -0,0 +1,4 @@
|
||||
SubDir OBOS_TOP src tools resattr ;
|
||||
|
||||
BuildPlatformMain resattr : resattr.cpp ;
|
||||
LinkSharedOSLibs resattr : be ;
|
311
src/tools/resattr/resattr.cpp
Normal file
311
src/tools/resattr/resattr.cpp
Normal file
@ -0,0 +1,311 @@
|
||||
// resattr.cpp
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <fs_attr.h>
|
||||
#include <Resources.h>
|
||||
|
||||
// usage
|
||||
static const char *kUsage =
|
||||
"Usage: %s [ <options> ] -o <outFile> [ <inFile> ... ]\n"
|
||||
"\n"
|
||||
"Reads resources from zero or more input files and adds them as attributes\n"
|
||||
"to the specified output file, or (in reverse mode) reads attributes from\n"
|
||||
"zero or more input files and adds them as resources to the specified output\n"
|
||||
"file. If not existent the output file is created as an empty file.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -h, --help - Print this text.\n"
|
||||
" -o <outfile> - Specifies the output file.\n"
|
||||
" -O, --overwrite - Overwrite existing attributes. regardless of whether\n"
|
||||
" an attribute does already exist, it is always written\n"
|
||||
" when a respective resource is encountered in an input\n"
|
||||
" file. The last input file specifying the attribute\n"
|
||||
" wins. If the options is not given, already existing\n"
|
||||
" attributes remain untouched. Otherwise the first input\n"
|
||||
" file specifying an attribute wins.\n"
|
||||
" -r, --reverse - Reverse mode: Reads attributes from input files and\n"
|
||||
" writes resources. A unique resource ID is assigned to\n"
|
||||
" each attribute, so there will be no conflicts if two\n"
|
||||
" input files feature the same attribute.\n"
|
||||
;
|
||||
|
||||
// command line args
|
||||
static int sArgc;
|
||||
static const char *const *sArgv;
|
||||
|
||||
// print_usage
|
||||
void
|
||||
print_usage(bool error)
|
||||
{
|
||||
// get nice program name
|
||||
const char *programName = (sArgc > 0 ? sArgv[0] : "resattr");
|
||||
if (const char *lastSlash = strrchr(programName, '/'))
|
||||
programName = lastSlash + 1;
|
||||
|
||||
// print usage
|
||||
fprintf((error ? stderr : stdout), kUsage, programName);
|
||||
}
|
||||
|
||||
// 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 argc, const char* const* argv, int& argi, bool dontFail = false)
|
||||
{
|
||||
if (argi + 1 >= argc) {
|
||||
if (dontFail)
|
||||
return NULL;
|
||||
print_usage_and_exit(true);
|
||||
}
|
||||
|
||||
return argv[++argi];
|
||||
}
|
||||
|
||||
// write_attributes
|
||||
static
|
||||
void
|
||||
write_attributes(BNode &out, const char *inFileName, BResources &resources,
|
||||
bool overwrite)
|
||||
{
|
||||
// iterate through the resources
|
||||
type_code type;
|
||||
int32 id;
|
||||
const char *name;
|
||||
size_t size;
|
||||
for (int resIndex = 0;
|
||||
resources.GetResourceInfo(resIndex, &type, &id, &name, &size);
|
||||
resIndex++) {
|
||||
// if we shall not overwrite attributes, we skip the attribute, if it
|
||||
// already exists
|
||||
attr_info attrInfo;
|
||||
if (!overwrite && out.GetAttrInfo(name, &attrInfo) == B_OK)
|
||||
continue;
|
||||
|
||||
// get the resource
|
||||
const void *data = resources.LoadResource(type, id, &size);
|
||||
if (!data && size > 0) {
|
||||
// should not happen
|
||||
fprintf(stderr, "Failed to get resource `%s', type: %lx, id: %ld "
|
||||
"from input file `%s'\n", name, type, id, inFileName);
|
||||
continue;
|
||||
}
|
||||
|
||||
// construct a name, if the resource doesn't have one
|
||||
char nameBuffer[32];
|
||||
if (!name) {
|
||||
sprintf(nameBuffer, "unnamed_%d\n", resIndex);
|
||||
name = nameBuffer;
|
||||
}
|
||||
|
||||
// write the attribute
|
||||
ssize_t bytesWritten = out.WriteAttr(name, type, 0LL, data, size);
|
||||
if (bytesWritten < 0) {
|
||||
fprintf(stderr, "Failed to write attribute `%s' to output file: "
|
||||
"%s\n", name, strerror(bytesWritten));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// write_resources
|
||||
static
|
||||
void
|
||||
write_resources(BResources &resources, const char *inFileName, BNode &in,
|
||||
int32 &resID)
|
||||
{
|
||||
// iterate through the attributes
|
||||
char name[B_ATTR_NAME_LENGTH];
|
||||
while (in.GetNextAttrName(name) == B_OK) {
|
||||
// get attribute info
|
||||
attr_info attrInfo;
|
||||
status_t error = in.GetAttrInfo(name, &attrInfo);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to get info for attribute `%s' of input "
|
||||
"file `%s': %s\n", name, inFileName, strerror(error));
|
||||
continue;
|
||||
}
|
||||
|
||||
// read attribute
|
||||
char *data = new char[attrInfo.size];
|
||||
ssize_t bytesRead = in.ReadAttr(name, attrInfo.type, 0LL, data,
|
||||
attrInfo.size);
|
||||
if (bytesRead < 0) {
|
||||
fprintf(stderr, "Failed to read attribute `%s' of input "
|
||||
"file `%s': %s\n", name, inFileName, strerror(bytesRead));
|
||||
delete[] data;
|
||||
continue;
|
||||
}
|
||||
|
||||
// find unique ID
|
||||
const char *existingName;
|
||||
size_t existingSize;
|
||||
while (resources.GetResourceInfo(attrInfo.type, resID, &existingName,
|
||||
&existingSize)) {
|
||||
resID++;
|
||||
}
|
||||
|
||||
// write resource
|
||||
error = resources.AddResource(attrInfo.type, resID++, data,
|
||||
attrInfo.size, name);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to write resource `%s' to output "
|
||||
"file: %s\n", name, strerror(error));
|
||||
}
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
// resources_to_attributes
|
||||
static
|
||||
void
|
||||
resources_to_attributes(const char *outputFile, const char **inputFiles,
|
||||
int inputFileCount, bool overwrite)
|
||||
{
|
||||
// create output file, if it doesn't exist
|
||||
if (!BEntry(outputFile).Exists()) {
|
||||
BFile createdOut;
|
||||
status_t error = createdOut.SetTo(outputFile,
|
||||
B_READ_WRITE | B_CREATE_FILE);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to create output file `%s': %s\n",
|
||||
outputFile, strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// open output file
|
||||
BNode out;
|
||||
status_t error = out.SetTo(outputFile);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to open output file `%s': %s\n", outputFile,
|
||||
strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// iterate through the input files
|
||||
for (int i = 0; i < inputFileCount; i++) {
|
||||
// open input file
|
||||
BFile in;
|
||||
error = in.SetTo(inputFiles[i], B_READ_ONLY);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to open input file `%s': %s\n",
|
||||
inputFiles[i], strerror(error));
|
||||
continue;
|
||||
}
|
||||
|
||||
// open resources
|
||||
BResources resources;
|
||||
error = resources.SetTo(&in, false);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to read resources of input file `%s': %s\n",
|
||||
inputFiles[i], strerror(error));
|
||||
continue;
|
||||
}
|
||||
|
||||
// add the attributes
|
||||
write_attributes(out, inputFiles[i], resources, overwrite);
|
||||
}
|
||||
}
|
||||
|
||||
// resources_to_attributes
|
||||
static
|
||||
void
|
||||
attributes_to_resources(const char *outputFile, const char **inputFiles,
|
||||
int inputFileCount)
|
||||
{
|
||||
// open output file
|
||||
BFile out;
|
||||
status_t error = out.SetTo(outputFile, B_READ_WRITE | B_CREATE_FILE);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to open output file `%s': %s\n", outputFile,
|
||||
strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// init output resources
|
||||
BResources resources;
|
||||
error = resources.SetTo(&out, false);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to init resources of output file `%s': %s\n",
|
||||
outputFile, strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int32 resID = 0;
|
||||
|
||||
// iterate through the input files
|
||||
for (int i = 0; i < inputFileCount; i++) {
|
||||
// open input file
|
||||
BNode in;
|
||||
error = in.SetTo(inputFiles[i]);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to open input file `%s': %s\n",
|
||||
inputFiles[i], strerror(error));
|
||||
continue;
|
||||
}
|
||||
|
||||
// add the resources
|
||||
|
||||
write_resources(resources, inputFiles[i], in, resID);
|
||||
}
|
||||
}
|
||||
|
||||
// main
|
||||
int
|
||||
main(int argc, const char *const *argv)
|
||||
{
|
||||
sArgc = argc;
|
||||
sArgv = argv;
|
||||
|
||||
// parameters
|
||||
const char *outputFile = NULL;
|
||||
bool overwrite = false;
|
||||
bool reverse = false;
|
||||
const char **inputFiles = new const char*[argc];
|
||||
int inputFileCount = 0;
|
||||
|
||||
// parse arguments
|
||||
for (int argi = 1; argi < argc; argi++) {
|
||||
const char *arg = argv[argi];
|
||||
if (arg[0] == '-') {
|
||||
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
|
||||
print_usage_and_exit(false);
|
||||
} else if (strcmp(arg, "-o") == 0) {
|
||||
outputFile = next_arg(argc, argv, argi);
|
||||
} else if (strcmp(arg, "-O") == 0) {
|
||||
overwrite = true;
|
||||
} else if (strcmp(arg, "-r") == 0
|
||||
|| strcmp(arg, "--reverse") == 0) {
|
||||
reverse = true;
|
||||
} else {
|
||||
print_usage_and_exit(true);
|
||||
}
|
||||
} else {
|
||||
inputFiles[inputFileCount++] = arg;
|
||||
}
|
||||
}
|
||||
|
||||
// check parameters
|
||||
if (!outputFile)
|
||||
print_usage_and_exit(true);
|
||||
|
||||
if (reverse) {
|
||||
attributes_to_resources(outputFile, inputFiles, inputFileCount);
|
||||
} else {
|
||||
resources_to_attributes(outputFile, inputFiles, inputFileCount,
|
||||
overwrite);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user