Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / bin / resattr.cpp
blobec02f48daf812f971883868e182fedc124b8b539
1 // resattr.cpp
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
7 #include <Entry.h>
8 #include <File.h>
9 #include <fs_attr.h>
10 #include <Resources.h>
12 // usage
13 static const char *kUsage =
14 "Usage: %s [ <options> ] -o <outFile> [ <inFile> ... ]\n"
15 "\n"
16 "Reads resources from zero or more input files and adds them as attributes\n"
17 "to the specified output file, or (in reverse mode) reads attributes from\n"
18 "zero or more input files and adds them as resources to the specified output\n"
19 "file. If not existent the output file is created as an empty file.\n"
20 "\n"
21 "Options:\n"
22 " -h, --help - Print this text.\n"
23 " -o <outfile> - Specifies the output file.\n"
24 " -O, --overwrite - Overwrite existing attributes. regardless of whether\n"
25 " an attribute does already exist, it is always written\n"
26 " when a respective resource is encountered in an input\n"
27 " file. The last input file specifying the attribute\n"
28 " wins. If the options is not given, already existing\n"
29 " attributes remain untouched. Otherwise the first input\n"
30 " file specifying an attribute wins.\n"
31 " -r, --reverse - Reverse mode: Reads attributes from input files and\n"
32 " writes resources. A unique resource ID is assigned to\n"
33 " each attribute, so there will be no conflicts if two\n"
34 " input files feature the same attribute.\n"
37 // command line args
38 static int sArgc;
39 static const char *const *sArgv;
41 // print_usage
42 void
43 print_usage(bool error)
45 // get nice program name
46 const char *programName = (sArgc > 0 ? sArgv[0] : "resattr");
47 if (const char *lastSlash = strrchr(programName, '/'))
48 programName = lastSlash + 1;
50 // print usage
51 fprintf((error ? stderr : stdout), kUsage, programName);
54 // print_usage_and_exit
55 static
56 void
57 print_usage_and_exit(bool error)
59 print_usage(error);
60 exit(error ? 1 : 0);
63 // next_arg
64 static
65 const char*
66 next_arg(int argc, const char* const* argv, int& argi, bool dontFail = false)
68 if (argi + 1 >= argc) {
69 if (dontFail)
70 return NULL;
71 print_usage_and_exit(true);
74 return argv[++argi];
77 // write_attributes
78 static
79 void
80 write_attributes(BNode &out, const char *inFileName, BResources &resources,
81 bool overwrite)
83 // iterate through the resources
84 type_code type;
85 int32 id;
86 const char *name;
87 size_t size;
88 for (int resIndex = 0;
89 resources.GetResourceInfo(resIndex, &type, &id, &name, &size);
90 resIndex++) {
91 // if we shall not overwrite attributes, we skip the attribute, if it
92 // already exists
93 attr_info attrInfo;
94 if (!overwrite && out.GetAttrInfo(name, &attrInfo) == B_OK)
95 continue;
97 // get the resource
98 const void *data = resources.LoadResource(type, id, &size);
99 if (!data && size > 0) {
100 // should not happen
101 fprintf(stderr, "Failed to get resource `%s', type: %" B_PRIx32
102 ", id: %" B_PRId32 " from input file `%s'\n", name, type, id,
103 inFileName);
104 exit(1);
107 // construct a name, if the resource doesn't have one
108 char nameBuffer[32];
109 if (!name) {
110 sprintf(nameBuffer, "unnamed_%d\n", resIndex);
111 name = nameBuffer;
114 // write the attribute
115 ssize_t bytesWritten = out.WriteAttr(name, type, 0LL, data, size);
116 if (bytesWritten < 0) {
117 fprintf(stderr, "Failed to write attribute `%s' to output file: "
118 "%s\n", name, strerror(bytesWritten));
123 // write_resources
124 static
125 void
126 write_resources(BResources &resources, const char *inFileName, BNode &in,
127 int32 &resID)
129 // iterate through the attributes
130 char name[B_ATTR_NAME_LENGTH];
131 while (in.GetNextAttrName(name) == B_OK) {
132 // get attribute info
133 attr_info attrInfo;
134 status_t error = in.GetAttrInfo(name, &attrInfo);
135 if (error != B_OK) {
136 fprintf(stderr, "Failed to get info for attribute `%s' of input "
137 "file `%s': %s\n", name, inFileName, strerror(error));
138 exit(1);
141 // read attribute
142 char *data = new char[attrInfo.size];
143 ssize_t bytesRead = in.ReadAttr(name, attrInfo.type, 0LL, data,
144 attrInfo.size);
145 if (bytesRead < 0) {
146 fprintf(stderr, "Failed to read attribute `%s' of input "
147 "file `%s': %s\n", name, inFileName, strerror(bytesRead));
148 delete[] data;
149 exit(1);
152 // find unique ID
153 const char *existingName;
154 size_t existingSize;
155 while (resources.GetResourceInfo(attrInfo.type, resID, &existingName,
156 &existingSize)) {
157 resID++;
160 // write resource
161 error = resources.AddResource(attrInfo.type, resID++, data,
162 attrInfo.size, name);
163 if (error != B_OK) {
164 fprintf(stderr, "Failed to write resource `%s' to output "
165 "file: %s\n", name, strerror(error));
167 delete[] data;
171 // resources_to_attributes
172 static
173 void
174 resources_to_attributes(const char *outputFile, const char **inputFiles,
175 int inputFileCount, bool overwrite)
177 // create output file, if it doesn't exist
178 if (!BEntry(outputFile).Exists()) {
179 BFile createdOut;
180 status_t error = createdOut.SetTo(outputFile,
181 B_READ_WRITE | B_CREATE_FILE);
182 if (error != B_OK) {
183 fprintf(stderr, "Failed to create output file `%s': %s\n",
184 outputFile, strerror(error));
185 exit(1);
189 // open output file
190 BNode out;
191 status_t error = out.SetTo(outputFile);
192 if (error != B_OK) {
193 fprintf(stderr, "Failed to open output file `%s': %s\n", outputFile,
194 strerror(error));
195 exit(1);
198 // iterate through the input files
199 for (int i = 0; i < inputFileCount; i++) {
200 // open input file
201 BFile in;
202 error = in.SetTo(inputFiles[i], B_READ_ONLY);
203 if (error != B_OK) {
204 fprintf(stderr, "Failed to open input file `%s': %s\n",
205 inputFiles[i], strerror(error));
206 exit(1);
209 // open resources
210 BResources resources;
211 error = resources.SetTo(&in, false);
212 if (error != B_OK) {
213 fprintf(stderr, "Failed to read resources of input file `%s': %s\n",
214 inputFiles[i], strerror(error));
215 exit(1);
218 // add the attributes
219 write_attributes(out, inputFiles[i], resources, overwrite);
223 // resources_to_attributes
224 static
225 void
226 attributes_to_resources(const char *outputFile, const char **inputFiles,
227 int inputFileCount)
229 // open output file
230 BFile out;
231 status_t error = out.SetTo(outputFile, B_READ_WRITE | B_CREATE_FILE);
232 if (error != B_OK) {
233 fprintf(stderr, "Failed to open output file `%s': %s\n", outputFile,
234 strerror(error));
235 exit(1);
238 // init output resources
239 BResources resources;
240 error = resources.SetTo(&out, false);
241 if (error != B_OK) {
242 fprintf(stderr, "Failed to init resources of output file `%s': %s\n",
243 outputFile, strerror(error));
244 exit(1);
247 int32 resID = 0;
249 // iterate through the input files
250 for (int i = 0; i < inputFileCount; i++) {
251 // open input file
252 BNode in;
253 error = in.SetTo(inputFiles[i]);
254 if (error != B_OK) {
255 fprintf(stderr, "Failed to open input file `%s': %s\n",
256 inputFiles[i], strerror(error));
257 exit(1);
260 // add the resources
262 write_resources(resources, inputFiles[i], in, resID);
266 // main
268 main(int argc, const char *const *argv)
270 sArgc = argc;
271 sArgv = argv;
273 // parameters
274 const char *outputFile = NULL;
275 bool overwrite = false;
276 bool reverse = false;
277 const char **inputFiles = new const char*[argc];
278 int inputFileCount = 0;
280 // parse arguments
281 for (int argi = 1; argi < argc; argi++) {
282 const char *arg = argv[argi];
283 if (arg[0] == '-') {
284 if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
285 print_usage_and_exit(false);
286 } else if (strcmp(arg, "-o") == 0) {
287 outputFile = next_arg(argc, argv, argi);
288 } else if (strcmp(arg, "-O") == 0) {
289 overwrite = true;
290 } else if (strcmp(arg, "-r") == 0
291 || strcmp(arg, "--reverse") == 0) {
292 reverse = true;
293 } else {
294 print_usage_and_exit(true);
296 } else {
297 inputFiles[inputFileCount++] = arg;
301 // check parameters
302 if (!outputFile)
303 print_usage_and_exit(true);
305 if (reverse) {
306 attributes_to_resources(outputFile, inputFiles, inputFileCount);
307 } else {
308 resources_to_attributes(outputFile, inputFiles, inputFileCount,
309 overwrite);
312 return 0;