xref: /haiku/src/bin/rc/decompile.cpp (revision 7f2d527a021c3498a01bed8c626981d99b842c44)
1 /*
2  * Copyright (c) 2003 Matthijs Hollemans
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  */
22 
23 
24 #include <AppFileInfo.h>
25 #include <Mime.h>
26 #include <Resources.h>
27 #include <Roster.h>
28 #include <TypeConstants.h>
29 
30 #include <ctype.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <unistd.h>
35 
36 #include "rdef.h"
37 #include "private.h"
38 
39 // What we add to the front of enum symbols.
40 #define PREFIX  "R_"
41 
42 
43 static FILE *sOutputFile;
44 static FILE *sHeaderFile;
45 
46 // Level of indentation (how many tabs).
47 static int32 sTabs;
48 static bool sBraceOnNextLine = false;
49 
50 
51 static void write_generic_data(const char *name, type_code type,
52 	const void *data, size_t length);
53 
54 
55 static void
indent()56 indent()
57 {
58 	for (int32 t = 0; t < sTabs; ++t) {
59 		fprintf(sOutputFile, "\t");
60 	}
61 }
62 
63 
64 void
open_brace()65 open_brace()
66 {
67 	if (sBraceOnNextLine) {
68 		fprintf(sOutputFile, "\n");
69 		indent();
70 		fprintf(sOutputFile, "{\n");
71 	} else
72 		fprintf(sOutputFile, " {\n");
73 
74 	++sTabs;
75 }
76 
77 
78 void
close_brace()79 close_brace()
80 {
81 	--sTabs;
82 
83 	fprintf(sOutputFile, "\n");
84 	indent();
85 	fprintf(sOutputFile, "}");
86 }
87 
88 
89 static bool
make_code(uint32 value,char * code)90 make_code(uint32 value, char *code)
91 {
92 	code[0] = (value >> 24) & 0xFF;
93 	if (isprint(code[0])) {
94 		code[1] = (value >> 16) & 0xFF;
95 		if (isprint(code[1])) {
96 			code[2] = (value >> 8) & 0xFF;
97 			if (isprint(code[2])) {
98 				code[3] = value & 0xFF;
99 				if (isprint(code[3])) {
100 					code[4] = '\0';
101 					return true;
102 				}
103 			}
104 		}
105 	}
106 
107 	return false;
108 }
109 
110 
111 static void
write_code(uint32 value)112 write_code(uint32 value)
113 {
114 	char code[5];
115 	if (make_code(value, code))
116 		fprintf(sOutputFile, "'%s'", code);
117 	else
118 		fprintf(sOutputFile, "%" B_PRIu32, value);
119 }
120 
121 
122 static void
write_field_name(const char * name)123 write_field_name(const char *name)
124 {
125 	// We call this from the write_xxx() functions to properly align a
126 	// field's type code (which goes to the left of the field name) and
127 	// the field's data (to right of the name). If we are not currently
128 	// writing a field (but the entire resource), name is NULL.
129 
130 	if (name != NULL)
131 		fprintf(sOutputFile, "\"%s\" = ", name);
132 }
133 
134 
135 static bool
is_ident(const char * name)136 is_ident(const char *name)
137 {
138 	if (name[0] != '_' && !isalpha(name[0]))
139 		return false;
140 
141 	for (size_t t = 1; t < strlen(name); ++t) {
142 		if (name[t] != '_' && !isalnum(name[t]))
143 			return false;
144 	}
145 
146 	return true;
147 }
148 
149 
150 static bool
has_prefix(const char * name)151 has_prefix(const char *name)
152 {
153 	size_t name_len = strlen(name);
154 	size_t prefix_len = strlen(PREFIX);
155 
156 	if (name_len > prefix_len) {
157 		if (strncmp(name, PREFIX, prefix_len) == 0)
158 			return true;
159 	}
160 
161 	return false;
162 }
163 
164 
165 static bool
is_string(const void * data,size_t length)166 is_string(const void *data, size_t length)
167 {
168 	// We consider the buffer a string if it contains only human readable
169 	// characters. The buffer should also end with a '\0'. Although the
170 	// compiler allows string literals to contain embedded '\0' chars as
171 	// well, we don't allow them here (because they may cause false hits).
172 
173 	if (length == 0)
174 		return false;
175 
176 	char *ptr = (char *)data;
177 
178 	for (size_t t = 0; t < length - 1; ++t) {
179 		if (!isprint(*ptr++))
180 			return false;
181 	}
182 
183 	return (*ptr == '\0');
184 }
185 
186 
187 static void
write_rsrc(type_code type,int32 id,const char * name)188 write_rsrc(type_code type, int32 id, const char *name)
189 {
190 	if (name[0] == '\0') {
191 		fprintf(sOutputFile, "resource(%" B_PRId32 ") ", id);
192 	} else if ((flags & RDEF_AUTO_NAMES) != 0&& is_ident(name)) {
193 		char code[5];
194 		if (has_prefix(name)) {
195 			fprintf(sOutputFile, "resource(%s) ", name);
196 			fprintf(sHeaderFile, "\t%s = %" B_PRId32 ",\n", name, id);
197 		} else if (make_code(type, code)) {
198 			fprintf(sOutputFile, "resource(%s%s_%s) ", PREFIX, code, name);
199 			fprintf(sHeaderFile, "\t%s%s_%s = %" B_PRId32 ",\n", PREFIX, code,
200 				name, id);
201 		} else {
202 			fprintf(sOutputFile, "resource(%s%" B_PRIu32 "_%s) ", PREFIX,
203 				(uint32)type, name);
204 			fprintf(sHeaderFile, "\t%s%" B_PRIu32 "_%s = %" B_PRId32 ",\n",
205 				PREFIX, (uint32)type, name, id);
206 		}
207 	} else {
208 		fprintf(sOutputFile, "resource(%" B_PRId32 ", \"%s\") ", id, name);
209 	}
210 }
211 
212 
213 //	#pragma mark - generic types
214 
215 
216 static uint8 *
write_raw_line(uint8 * ptr,uint8 * end,size_t bytesPerLine)217 write_raw_line(uint8 *ptr, uint8 *end, size_t bytesPerLine)
218 {
219 	uint32 count = 0;
220 
221 	fprintf(sOutputFile, "$\"");
222 
223 	while (ptr < end && count < bytesPerLine) {
224 		fprintf(sOutputFile, "%02X", *ptr++);
225 		++count;
226 	}
227 
228 	fprintf(sOutputFile, "\"");
229 
230 	return ptr;
231 }
232 
233 
234 static void
write_raw(const char * name,type_code type,const void * data,size_t length,size_t bytesPerLine=32)235 write_raw(const char *name, type_code type, const void *data,
236 	size_t length, size_t bytesPerLine = 32)
237 {
238 	uint8 *ptr = (uint8 *)data;
239 	uint8 *end = ptr + length;
240 
241 	if (length > bytesPerLine) {
242 		if (type != B_RAW_TYPE) {
243 			fprintf(sOutputFile, "#");
244 			write_code(type);
245 			fprintf(sOutputFile, " ");
246 		}
247 
248 		write_field_name(name);
249 		fprintf(sOutputFile, "array");
250 
251 		open_brace();
252 
253 		int32 item = 0;
254 		while (ptr < end) {
255 			if (item++ > 0)
256 				fprintf(sOutputFile, "\n");
257 
258 			indent();
259 			ptr = write_raw_line(ptr, end, bytesPerLine);
260 		}
261 
262 		close_brace();
263 	} else {
264 		if (type != B_RAW_TYPE) {
265 			fprintf(sOutputFile, "#");
266 			write_code(type);
267 			fprintf(sOutputFile, " ");
268 		}
269 
270 		write_field_name(name);
271 		write_raw_line(ptr, end, bytesPerLine);
272 	}
273 }
274 
275 
276 static void
write_bool(const char * name,const void * data,size_t length)277 write_bool(const char *name, const void *data, size_t length)
278 {
279 	if (length != sizeof(bool)) {
280 		write_raw(name, B_BOOL_TYPE, data, length);
281 	} else {
282 		write_field_name(name);
283 		fprintf(sOutputFile, "%s", *(bool *)data ? "true" : "false");
284 	}
285 }
286 
287 
288 static void
write_int8(const char * name,const void * data,size_t length)289 write_int8(const char *name, const void *data, size_t length)
290 {
291 	if (length != sizeof(int8)) {
292 		write_raw(name, B_INT8_TYPE, data, length);
293 	} else {
294 		write_field_name(name);
295 		fprintf(sOutputFile, "(int8)%d", *(int8 *)data);
296 	}
297 }
298 
299 
300 static void
write_int16(const char * name,const void * data,size_t length)301 write_int16(const char *name, const void *data, size_t length)
302 {
303 	if (length != sizeof(int16)) {
304 		write_raw(name, B_INT16_TYPE, data, length);
305 	} else {
306 		write_field_name(name);
307 		fprintf(sOutputFile, "(int16)%d", *(int16 *)data);
308 	}
309 }
310 
311 
312 static void
write_int32(const char * name,const void * data,size_t length)313 write_int32(const char *name, const void *data, size_t length)
314 {
315 	if (length != sizeof(int32)) {
316 		write_raw(name, B_INT32_TYPE, data, length);
317 	} else {
318 		write_field_name(name);
319 		fprintf(sOutputFile, "%" B_PRId32, *(int32 *)data);
320 	}
321 }
322 
323 
324 static void
write_int64(const char * name,const void * data,size_t length)325 write_int64(const char *name, const void *data, size_t length)
326 {
327 	if (length != sizeof(int64)) {
328 		write_raw(name, B_INT64_TYPE, data, length);
329 	} else {
330 		write_field_name(name);
331 		fprintf(sOutputFile, "(int64)%" B_PRId64, *(int64 *)data);
332 	}
333 }
334 
335 
336 static void
write_uint8(const char * name,const void * data,size_t length)337 write_uint8(const char *name, const void *data, size_t length)
338 {
339 	if (length != sizeof(uint8)) {
340 		write_raw(name, B_UINT8_TYPE, data, length);
341 	} else {
342 		write_field_name(name);
343 		fprintf(sOutputFile, "(uint8)%u", *(uint8 *)data);
344 	}
345 }
346 
347 
348 static void
write_uint16(const char * name,const void * data,size_t length)349 write_uint16(const char *name, const void *data, size_t length)
350 {
351 	if (length != sizeof(uint16)) {
352 		write_raw(name, B_UINT16_TYPE, data, length);
353 	} else {
354 		write_field_name(name);
355 		fprintf(sOutputFile, "(uint16)%u", *(uint16 *)data);
356 	}
357 }
358 
359 
360 static void
write_uint32(const char * name,const void * data,size_t length)361 write_uint32(const char *name, const void *data, size_t length)
362 {
363 	if (length != sizeof(uint32)) {
364 		write_raw(name, B_UINT32_TYPE, data, length);
365 	} else {
366 		write_field_name(name);
367 		fprintf(sOutputFile, "(uint32)%" B_PRIu32, *(uint32 *)data);
368 	}
369 }
370 
371 
372 static void
write_uint64(const char * name,const void * data,size_t length)373 write_uint64(const char *name, const void *data, size_t length)
374 {
375 	if (length != sizeof(uint64)) {
376 		write_raw(name, B_UINT64_TYPE, data, length);
377 	} else {
378 		write_field_name(name);
379 		fprintf(sOutputFile, "(uint64)%" B_PRIu64, *(uint64 *)data);
380 	}
381 }
382 
383 
384 static void
write_float(const char * name,const void * data,size_t length)385 write_float(const char *name, const void *data, size_t length)
386 {
387 	if (length != sizeof(float)) {
388 		write_raw(name, B_FLOAT_TYPE, data, length);
389 	} else {
390 		write_field_name(name);
391 		fprintf(sOutputFile, "%#g", *(float *)data);
392 	}
393 }
394 
395 
396 static void
write_double(const char * name,const void * data,size_t length)397 write_double(const char *name, const void *data, size_t length)
398 {
399 	if (length != sizeof(double)) {
400 		write_raw(name, B_DOUBLE_TYPE, data, length);
401 	} else {
402 		write_field_name(name);
403 		fprintf(sOutputFile, "(double)%#g", *(double *)data);
404 	}
405 }
406 
407 
408 static void
write_size(const char * name,const void * data,size_t length)409 write_size(const char *name, const void *data, size_t length)
410 {
411 	if (length != sizeof(size_t)) {
412 		write_raw(name, B_SIZE_T_TYPE, data, length);
413 	} else {
414 		write_field_name(name);
415 		fprintf(sOutputFile, "(size_t)%lu", (unsigned long)*(size_t *)data);
416 	}
417 }
418 
419 
420 static void
write_ssize(const char * name,const void * data,size_t length)421 write_ssize(const char *name, const void *data, size_t length)
422 {
423 	if (length != sizeof(ssize_t)) {
424 		write_raw(name, B_SSIZE_T_TYPE, data, length);
425 	} else {
426 		write_field_name(name);
427 		fprintf(sOutputFile, "(ssize_t)%ld", (long)*(ssize_t *)data);
428 	}
429 }
430 
431 
432 static void
write_off(const char * name,const void * data,size_t length)433 write_off(const char *name, const void *data, size_t length)
434 {
435 	if (length != sizeof(off_t)) {
436 		write_raw(name, B_OFF_T_TYPE, data, length);
437 	} else {
438 		write_field_name(name);
439 		fprintf(sOutputFile, "(off_t)%" B_PRIdOFF, *(off_t *)data);
440 	}
441 }
442 
443 
444 static void
write_time(const char * name,const void * data,size_t length)445 write_time(const char *name, const void *data, size_t length)
446 {
447 	if (length != sizeof(time_t)) {
448 		write_raw(name, B_TIME_TYPE, data, length);
449 	} else {
450 		write_field_name(name);
451 		fprintf(sOutputFile, "(time_t)%ld", (long)*(time_t *)data);
452 	}
453 }
454 
455 
456 static void
write_point(const char * name,const void * data)457 write_point(const char *name, const void *data)
458 {
459 	///TODO: using built-in type table
460 
461 	write_field_name(name);
462 	float *f = (float *)data;
463 	fprintf(sOutputFile, "point { %#g, %#g }", f[0], f[1]);
464 }
465 
466 
467 static void
write_rect(const char * name,const void * data)468 write_rect(const char *name, const void *data)
469 {
470 	///TODO: using built-in type table
471 
472 	write_field_name(name);
473 	float *f = (float *)data;
474 	fprintf(sOutputFile, "rect { %#g, %#g, %#g, %#g }", f[0], f[1], f[2], f[3]);
475 }
476 
477 
478 static void
write_rgb(const char * name,const void * data)479 write_rgb(const char *name, const void *data)
480 {
481 	///TODO: using built-in type table
482 
483 	write_field_name(name);
484 	uint8 *b = (uint8 *)data;
485 
486 	fprintf(sOutputFile, "rgb_color { 0x%02X, 0x%02X, 0x%02X, 0x%02X }",
487 		b[0], b[1], b[2], b[3]);
488 }
489 
490 
491 static const char *
write_string_line(const char * ptr,const char * end,size_t charsPerLine)492 write_string_line(const char *ptr, const char *end, size_t charsPerLine)
493 {
494 	uint32 count = 0;
495 	bool end_of_item = false;
496 
497 	fprintf(sOutputFile, "\"");
498 
499 	while (ptr < end && count < charsPerLine && !end_of_item) {
500 		char c = *ptr++;
501 
502 		switch (c) {
503 			case '\b': fprintf(sOutputFile, "\\b");  count += 2; break;
504 			case '\f': fprintf(sOutputFile, "\\f");  count += 2; break;
505 			case '\n': fprintf(sOutputFile, "\\n");  count += 2; break;
506 			case '\r': fprintf(sOutputFile, "\\r");  count += 2; break;
507 			case '\t': fprintf(sOutputFile, "\\t");  count += 2; break;
508 			case '\v': fprintf(sOutputFile, "\\v");  count += 2; break;
509 			case '\"': fprintf(sOutputFile, "\\\""); count += 2; break;
510 			case '\\': fprintf(sOutputFile, "\\\\"); count += 2; break;
511 
512 			case '\0': end_of_item = true; break;
513 
514 			default:
515 			{
516 				if ((uint8)c < 128 && !isprint(c)) {
517 					fprintf(sOutputFile, "\\0x%02X", (uint8)c); count += 5;
518 				} else {
519 					fprintf(sOutputFile, "%c", c); ++count;
520 				}
521 			}
522 		}
523 	}
524 
525 	fprintf(sOutputFile, "\"");
526 
527 	if (end_of_item && ptr < end)
528 		fprintf(sOutputFile, ",");
529 
530 	return ptr;
531 }
532 
533 
534 static void
write_string(const char * name,type_code type,const void * data,size_t length)535 write_string(const char *name, type_code type,
536 	const void *data, size_t length)
537 {
538 	const char *ptr = (const char *)data;
539 	const char *end = ptr + length;
540 	size_t charsPerLine = 64;
541 
542 	// We write an "array" resource if the string has more than 64
543 	// characters. A string resource may also be comprised of multiple
544 	// substrings, each terminated by a '\0' char. In that case, we
545 	// must write an "array" resource as well. Sneaky as we are, we use
546 	// strlen() to check for that, because it also looks for a '\0'.
547 
548 	if (length > charsPerLine || strlen(ptr) < length - 1) {
549 		fprintf(sOutputFile, "#");
550 		write_code(type);
551 		fprintf(sOutputFile, " array");
552 
553 		if (name != NULL) {
554 			fprintf(sOutputFile, " ");
555 			write_field_name(name);
556 			fprintf(sOutputFile, " array");
557 		}
558 
559 		open_brace();
560 
561 		int32 item = 0;
562 		while (ptr < end) {
563 			if (item++ > 0)
564 				fprintf(sOutputFile, "\n");
565 
566 			indent();
567 			ptr = write_string_line(ptr, end, charsPerLine);
568 		}
569 
570 		close_brace();
571 	} else {
572 		if (type != B_STRING_TYPE) {
573 			fprintf(sOutputFile, "#");
574 			write_code(type);
575 			fprintf(sOutputFile, " ");
576 		}
577 
578 		write_field_name(name);
579 		write_string_line(ptr, end, charsPerLine);
580 	}
581 }
582 
583 
584 static void
write_fields(BMessage & msg)585 write_fields(BMessage &msg)
586 {
587 	int32 t = 0;
588 	int32 item = 0;
589 
590 #ifdef B_BEOS_VERSION_DANO
591 	const char *name;
592 #else
593 	char *name;
594 #endif
595 	type_code type;
596 	int32 count;
597 	const void *data;
598 	size_t length;
599 
600 	open_brace();
601 
602 	while (msg.GetInfo(B_ANY_TYPE, t, &name, &type, &count) == B_OK) {
603 		for (int32 k = 0; k < count; ++k) {
604 			if (msg.FindData(name, type, k, &data, (ssize_t*) &length) == B_OK) {
605 				if (item++ > 0)
606 					fprintf(sOutputFile, ",\n");
607 
608 				indent();
609 				write_generic_data(name, type, data, length);
610 			}
611 		}
612 
613 		++t;
614 	}
615 
616 	close_brace();
617 }
618 
619 
620 static void
write_message(const char * name,BMessage & msg,type_code type)621 write_message(const char *name, BMessage &msg, type_code type)
622 {
623 	if (type != B_MESSAGE_TYPE) {
624 		fprintf(sOutputFile, "#");
625 		write_code(type);
626 		fprintf(sOutputFile, " ");
627 	}
628 
629 	write_field_name(name);
630 
631 	const char *class_;
632 	if (msg.FindString("class", &class_) == B_OK) {
633 		fprintf(sOutputFile, "archive");
634 
635 		const char *add_on;
636 		if (msg.FindString("add_on", &add_on) == B_OK) {
637 			fprintf(sOutputFile, "(\"%s\"", add_on);
638 			if (msg.what != 0) {
639 				fprintf(sOutputFile, ", ");
640 				write_code(msg.what);
641 			}
642 			fprintf(sOutputFile, ")");
643 
644 			msg.RemoveName("add_on");
645 		} else if (msg.what != 0) {
646 			fprintf(sOutputFile, "(, ");
647 			write_code(msg.what);
648 			fprintf(sOutputFile, ")");
649 		}
650 
651 		fprintf(sOutputFile, " %s", class_);
652 		msg.RemoveName("class");
653 	} else if (msg.what == 0) {
654 		fprintf(sOutputFile, "message");
655 	} else {
656 		fprintf(sOutputFile, "message(");
657 		write_code(msg.what);
658 		fprintf(sOutputFile, ")");
659 	}
660 
661 	if (msg.CountNames(B_ANY_TYPE) > 0)
662 		write_fields(msg);
663 }
664 
665 
666 static void
write_other(const char * name,type_code type,const void * data,size_t length)667 write_other(const char *name, type_code type,
668 	const void *data, size_t length)
669 {
670 	BMessage msg;
671 	if (msg.Unflatten((const char *)data) == B_OK)
672 		write_message(name, msg, type);
673 	else if (is_string(data, length))
674 		write_string(name, type, data, length);
675 	else
676 		write_raw(name, type, data, length);
677 }
678 
679 
680 //	#pragma mark - special types
681 
682 
683 static void
write_app_signature(const void * data,size_t length)684 write_app_signature(const void *data, size_t length)
685 {
686 	fprintf(sOutputFile, "resource app_signature ");
687 	write_string_line((const char *)data, (const char *)data + length, length * 2);
688 }
689 
690 
691 static void
write_app_flags(const void * data,size_t length)692 write_app_flags(const void *data, size_t length)
693 {
694 	fprintf(sOutputFile, "resource app_flags ");
695 
696 	uint32 flags = *(uint32 *)data;
697 	switch (flags & B_LAUNCH_MASK) {
698 		case B_SINGLE_LAUNCH:
699 			fputs("B_SINGLE_LAUNCH", sOutputFile);
700 			break;
701 		case B_MULTIPLE_LAUNCH:
702 			fputs("B_MULTIPLE_LAUNCH", sOutputFile);
703 			break;
704 		case B_EXCLUSIVE_LAUNCH:
705 			fputs("B_EXCLUSIVE_LAUNCH", sOutputFile);
706 			break;
707 	}
708 
709 	if (flags & B_BACKGROUND_APP)
710 		fputs(" | B_BACKGROUND_APP", sOutputFile);
711 	if (flags & B_ARGV_ONLY)
712 		fputs(" | B_ARGV_ONLY", sOutputFile);
713 }
714 
715 
716 static void
write_app_icon(uint32 which,const void * data,size_t length)717 write_app_icon(uint32 which, const void *data, size_t length)
718 {
719 	int32 lineWidth = 32;
720 	const char* type = "";
721 	switch (which) {
722 		case B_MINI_ICON:
723 			type = "mini";
724 			lineWidth = 16;
725 			break;
726 		case B_LARGE_ICON:
727 			type = "large";
728 			break;
729 		case 'VICN':
730 			type = "vector";
731 			break;
732 		case 'PNG ':
733 			type = "png";
734 			break;
735 		default:
736 			fprintf(stderr, "write_app_icon() called with invalid type!\n");
737 			break;
738 	}
739 	fprintf(sOutputFile, "resource %s_icon ", type);
740 	write_raw(NULL, B_RAW_TYPE, data, length, lineWidth);
741 }
742 
743 
744 static void
write_app_file_types(const void * data,size_t length)745 write_app_file_types(const void *data, size_t length)
746 {
747 	fputs("resource file_types ", sOutputFile);
748 	write_other(NULL, B_MESSAGE_TYPE, data, length);
749 }
750 
751 
752 static void
write_app_version(const void * data,size_t length)753 write_app_version(const void *data, size_t length)
754 {
755 	const version_info *version = (const version_info *)data;
756 	//const version_info *systemVersion = version + 1;
757 
758 	fputs("resource app_version", sOutputFile);
759 	open_brace();
760 
761 	fprintf(sOutputFile, "\tmajor  = %" B_PRIu32 ",\n"
762 		"\tmiddle = %" B_PRIu32 ",\n"
763 		"\tminor  = %" B_PRIu32 ",\n\n", version->major, version->middle,
764 		version->minor);
765 
766 	const char *variety = "B_APPV_DEVELOPMENT";
767 	switch (version->variety) {
768 		case 1:
769 			variety = "B_APPV_ALPHA";
770 			break;
771 		case 2:
772 			variety = "B_APPV_BETA";
773 			break;
774 		case 3:
775 			variety = "B_APPV_GAMMA";
776 			break;
777 		case 4:
778 			variety = "B_APPV_GOLDEN_MASTER";
779 			break;
780 		case 5:
781 			variety = "B_APPV_FINAL";
782 			break;
783 	}
784 	fprintf(sOutputFile, "\tvariety = %s,\n"
785 		"\tinternal = %" B_PRIu32 ",\n\n", variety, version->internal);
786 
787 	fprintf(sOutputFile, "\tshort_info = ");
788 	write_string(NULL, B_STRING_TYPE, version->short_info, strlen(version->short_info));
789 
790 	fprintf(sOutputFile, ",\n\tlong_info = ");
791 	write_string(NULL, B_STRING_TYPE, version->long_info, strlen(version->long_info));
792 
793 	close_brace();
794 }
795 
796 
797 //	#pragma mark - file examination
798 
799 
800 static void
write_generic_data(const char * name,type_code type,const void * data,size_t length)801 write_generic_data(const char *name, type_code type,
802 	const void *data, size_t length)
803 {
804 	switch (type) {
805 		case B_BOOL_TYPE:    write_bool(name, data, length);   break;
806 		case B_INT8_TYPE:    write_int8(name, data, length);   break;
807 		case B_INT16_TYPE:   write_int16(name, data, length);  break;
808 		case B_INT32_TYPE:   write_int32(name, data, length);  break;
809 		case B_INT64_TYPE:   write_int64(name, data, length);  break;
810 		case B_UINT8_TYPE:   write_uint8(name, data, length);  break;
811 		case B_UINT16_TYPE:  write_uint16(name, data, length); break;
812 		case B_UINT32_TYPE:  write_uint32(name, data, length); break;
813 		case B_UINT64_TYPE:  write_uint64(name, data, length); break;
814 		case B_FLOAT_TYPE:   write_float(name, data, length);  break;
815 		case B_DOUBLE_TYPE:  write_double(name, data, length); break;
816 		case B_SIZE_T_TYPE:  write_size(name, data, length);   break;
817 		case B_SSIZE_T_TYPE: write_ssize(name, data, length);  break;
818 		case B_OFF_T_TYPE:   write_off(name, data, length);    break;
819 		case B_TIME_TYPE:    write_time(name, data, length);   break;
820 
821 		case B_POINT_TYPE:     write_point(name, data);  break;
822 		case B_RECT_TYPE:      write_rect(name, data);   break;
823 		case B_RGB_COLOR_TYPE: write_rgb(name, data);    break;
824 
825 		case B_MIME_STRING_TYPE:
826 		case B_STRING_TYPE:
827 			write_string(name, type, data, length);
828 			break;
829 
830 		case 'MICN':
831 			write_raw(name, type, data, length, 16);
832 			break;
833 		case B_POINTER_TYPE:
834 		case 'ICON':
835 		case 'VICN':
836 			write_raw(name, type, data, length);
837 			break;
838 
839 		default:
840 			write_other(name, type, data, length);
841 			break;
842 	}
843 }
844 
845 
846 static void
write_data(int32 id,const char * name,type_code type,const void * data,size_t length)847 write_data(int32 id, const char *name, type_code type,
848 	const void *data, size_t length)
849 {
850 	// check for special types
851 
852 	switch (type) {
853 		case B_MIME_STRING_TYPE:
854 			if (!strcmp(name, "BEOS:APP_SIG")) {
855 				write_app_signature(data, length);
856 				return;
857 			}
858 			break;
859 
860 		case 'VICN':
861 			if (!strcmp(name, "BEOS:ICON")) {
862 				write_app_icon('VICN', data, length);
863 				return;
864 			}
865 			break;
866 
867 		case 'PNG ':
868 			if (!strcmp(name, "BEOS:ICON")) {
869 				write_app_icon('PNG ', data, length);
870 				return;
871 			}
872 			break;
873 
874 		case 'MICN':
875 			if (!strcmp(name, "BEOS:M:STD_ICON")) {
876 				write_app_icon(B_MINI_ICON, data, length);
877 				return;
878 			}
879 			break;
880 
881 		case 'ICON':
882 			if (!strcmp(name, "BEOS:L:STD_ICON")) {
883 				write_app_icon(B_LARGE_ICON, data, length);
884 				return;
885 			}
886 			break;
887 
888 		case B_MESSAGE_TYPE:
889 			if (!strcmp(name, "BEOS:FILE_TYPES")) {
890 				write_app_file_types(data, length);
891 				return;
892 			}
893 			break;
894 
895 		case 'APPF':
896 			if (!strcmp(name, "BEOS:APP_FLAGS") && length == 4) {
897 				write_app_flags(data, length);
898 				return;
899 			}
900 			break;
901 
902 		case 'APPV':
903 			if (!strcmp(name, "BEOS:APP_VERSION") && length == sizeof(version_info) * 2) {
904 				write_app_version(data, length);
905 				return;
906 			}
907 			break;
908 	}
909 
910 	// write generic types
911 
912 	write_rsrc(type, id, name);
913 	write_generic_data(NULL, type, data, length);
914 }
915 
916 
917 static void
examine_file(char * fileName)918 examine_file(char *fileName)
919 {
920 	BFile file(fileName, B_READ_ONLY);
921 	if (file.InitCheck() != B_OK) {
922 		strcpy(rdef_err_file, fileName);
923 		rdef_err = RDEF_FILE_NOT_FOUND;
924 		return;
925 	}
926 
927 	BResources res;
928 	if (res.SetTo(&file) != B_OK) {
929 		strcpy(rdef_err_file, fileName);
930 		rdef_err = RDEF_NO_RESOURCES;
931 		return;
932 	}
933 
934 	int32 t = 0;
935 	type_code type;
936 	int32 id;
937 	const char *name;
938 	size_t length;
939 	const void *data;
940 
941 	while (res.GetResourceInfo(t, &type, &id, &name, &length)) {
942 		sTabs = 0;
943 
944 		data = res.LoadResource(type, id, NULL);
945 		if (data != NULL) {
946 			fprintf(sOutputFile, "\n");
947 			write_data(id, name, type, data, length);
948 			fprintf(sOutputFile, ";\n");
949 		}
950 
951 		++t;
952 	}
953 }
954 
955 
956 static status_t
open_output_files(const char * fileName,const char * headerName)957 open_output_files(const char *fileName, const char *headerName)
958 {
959 	sOutputFile = fopen(fileName, "w");
960 	if (sOutputFile == NULL) {
961 		strcpy(rdef_err_msg, strerror(errno));
962 		strcpy(rdef_err_file, fileName);
963 		return RDEF_WRITE_ERR;
964 	}
965 
966 	if (flags & RDEF_AUTO_NAMES) {
967 		sHeaderFile = fopen(headerName, "w");
968 		if (sHeaderFile == NULL) {
969 			strcpy(rdef_err_msg, strerror(errno));
970 			strcpy(rdef_err_file, headerName);
971 			fclose(sOutputFile);
972 			return RDEF_WRITE_ERR;
973 		}
974 
975 		fprintf(sOutputFile, "\n#include \"%s\"\n", headerName);
976 
977 		if (sBraceOnNextLine)
978 			fprintf(sHeaderFile, "\nenum\n{\n");
979 		else
980 			fprintf(sHeaderFile, "\nenum {\n");
981 	}
982 
983 	return B_OK;
984 }
985 
986 
987 static void
close_output_files(const char * fileName,const char * headerName)988 close_output_files(const char *fileName, const char *headerName)
989 {
990 	if (flags & RDEF_AUTO_NAMES) {
991 		fprintf(sHeaderFile, "};\n");
992 		fclose(sHeaderFile);
993 
994 		if (rdef_err != B_OK)
995 			unlink(headerName);
996 	}
997 
998 	fclose(sOutputFile);
999 
1000 	if (rdef_err != B_OK)
1001 		unlink(fileName);
1002 }
1003 
1004 
1005 status_t
rdef_decompile(const char * fileName)1006 rdef_decompile(const char *fileName)
1007 {
1008 	clear_error();
1009 
1010 	if (fileName == NULL || fileName[0] == '\0') {
1011 		rdef_err = B_BAD_VALUE;
1012 		return rdef_err;
1013 	}
1014 
1015 	char headerName[B_PATH_NAME_LENGTH + 1];
1016 	if ((flags & RDEF_AUTO_NAMES) != 0)
1017 		sprintf(headerName, "%s.h", fileName);
1018 
1019 	rdef_err = open_output_files(fileName, headerName);
1020 	if (rdef_err != B_OK)
1021 		return rdef_err;
1022 
1023 	for (ptr_iter_t i = input_files.begin();
1024 			(i != input_files.end()) && (rdef_err == B_OK); ++i) {
1025 		examine_file((char *)*i);
1026 	}
1027 
1028 	close_output_files(fileName, headerName);
1029 	return rdef_err;
1030 }
1031 
1032