Author: bonefish Date: 2010-02-04 13:59:37 +0100 (Thu, 04 Feb 2010) New Revision: 35406 Changeset: http://dev.haiku-os.org/changeset/35406/haiku Added: haiku/trunk/src/bin/resattr.cpp Removed: haiku/trunk/src/tools/resattr/resattr.cpp Modified: haiku/trunk/src/bin/Jamfile haiku/trunk/src/tools/resattr/Jamfile Log: Moved resattr.cpp to src/bin, made it buildable for Haiku, and fixed a warning. Modified: haiku/trunk/src/bin/Jamfile =================================================================== --- haiku/trunk/src/bin/Jamfile 2010-02-04 09:28:27 UTC (rev 35405) +++ haiku/trunk/src/bin/Jamfile 2010-02-04 12:59:37 UTC (rev 35406) @@ -113,6 +113,7 @@ dstcheck.cpp hey.cpp reindex.cpp + resattr.cpp settype.cpp spybmessage.cpp urlwrapper.cpp Copied: haiku/trunk/src/bin/resattr.cpp (from rev 35396, haiku/trunk/src/tools/resattr/resattr.cpp) =================================================================== --- haiku/trunk/src/bin/resattr.cpp (rev 0) +++ haiku/trunk/src/bin/resattr.cpp 2010-02-04 12:59:37 UTC (rev 35406) @@ -0,0 +1,313 @@ +// resattr.cpp + +#include <stdio.h> +#include <stdlib.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: %" B_PRIx32 + ", id: %" B_PRId32 " from input file `%s'\n", name, type, id, + inFileName); + exit(1); + } + + // 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)); + exit(1); + } + + // 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; + exit(1); + } + + // 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)); + exit(1); + } + + // 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)); + exit(1); + } + + // 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)); + exit(1); + } + + // 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; +} Modified: haiku/trunk/src/tools/resattr/Jamfile =================================================================== --- haiku/trunk/src/tools/resattr/Jamfile 2010-02-04 09:28:27 UTC (rev 35405) +++ haiku/trunk/src/tools/resattr/Jamfile 2010-02-04 12:59:37 UTC (rev 35406) @@ -2,6 +2,7 @@ USES_BE_API on <build>resattr = true ; -BuildPlatformMain <build>resattr : resattr.cpp ; -LinkAgainst <build>resattr : $(HOST_LIBBE) $(HOST_LIBSTDC++) $(HOST_LIBSUPC++) ; +BuildPlatformMain <build>resattr : resattr.cpp + : $(HOST_LIBBE) $(HOST_LIBSUPC++) ; +SEARCH on [ FGristFiles resattr.cpp ] = [ FDirName $(HAIKU_TOP) src bin ] ;