xref: /haiku/src/bin/rc/decompile.cpp (revision c9060eb991e10e477ece52478d6743fc7691c143)
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
56 indent()
57 {
58 	for (int32 t = 0; t < sTabs; ++t) {
59 		fprintf(sOutputFile, "\t");
60 	}
61 }
62 
63 
64 void
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
79 close_brace()
80 {
81 	--sTabs;
82 
83 	fprintf(sOutputFile, "\n");
84 	indent();
85 	fprintf(sOutputFile, "}");
86 }
87 
88 
89 static bool
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
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, "%lu", value);
119 }
120 
121 
122 static void
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
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
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
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
188 write_rsrc(type_code type, int32 id, const char *name)
189 {
190 	if (name[0] == '\0') {
191 		fprintf(sOutputFile, "resource(%ld) ", 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 = %ld,\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 = %ld,\n", PREFIX, code, name, id);
200 		} else {
201 			fprintf(sOutputFile, "resource(%s%ld_%s) ", PREFIX, type, name);
202 			fprintf(sHeaderFile, "\t%s%ld_%s = %ld,\n", PREFIX, type, name, id);
203 		}
204 	} else {
205 		fprintf(sOutputFile, "resource(%ld, \"%s\") ", id, name);
206 	}
207 }
208 
209 
210 //	#pragma mark - generic types
211 
212 
213 static uint8 *
214 write_raw_line(uint8 *ptr, uint8 *end, size_t bytesPerLine)
215 {
216 	uint32 count = 0;
217 
218 	fprintf(sOutputFile, "$\"");
219 
220 	while (ptr < end && count < bytesPerLine) {
221 		fprintf(sOutputFile, "%02X", *ptr++);
222 		++count;
223 	}
224 
225 	fprintf(sOutputFile, "\"");
226 
227 	return ptr;
228 }
229 
230 
231 static void
232 write_raw(const char *name, type_code type, const void *data,
233 	size_t length, size_t bytesPerLine = 32)
234 {
235 	uint8 *ptr = (uint8 *)data;
236 	uint8 *end = ptr + length;
237 
238 	if (length > bytesPerLine) {
239 		if (type != B_RAW_TYPE) {
240 			fprintf(sOutputFile, "#");
241 			write_code(type);
242 			fprintf(sOutputFile, " ");
243 		}
244 
245 		write_field_name(name);
246 		fprintf(sOutputFile, "array");
247 
248 		open_brace();
249 
250 		int32 item = 0;
251 		while (ptr < end) {
252 			if (item++ > 0)
253 				fprintf(sOutputFile, "\n");
254 
255 			indent();
256 			ptr = write_raw_line(ptr, end, bytesPerLine);
257 		}
258 
259 		close_brace();
260 	} else {
261 		if (type != B_RAW_TYPE) {
262 			fprintf(sOutputFile, "#");
263 			write_code(type);
264 			fprintf(sOutputFile, " ");
265 		}
266 
267 		write_field_name(name);
268 		write_raw_line(ptr, end, bytesPerLine);
269 	}
270 }
271 
272 
273 static void
274 write_bool(const char *name, const void *data, size_t length)
275 {
276 	if (length != sizeof(bool)) {
277 		write_raw(name, B_BOOL_TYPE, data, length);
278 	} else {
279 		write_field_name(name);
280 		fprintf(sOutputFile, "%s", *(bool *)data ? "true" : "false");
281 	}
282 }
283 
284 
285 static void
286 write_int8(const char *name, const void *data, size_t length)
287 {
288 	if (length != sizeof(int8)) {
289 		write_raw(name, B_INT8_TYPE, data, length);
290 	} else {
291 		write_field_name(name);
292 		fprintf(sOutputFile, "(int8)%d", *(int8 *)data);
293 	}
294 }
295 
296 
297 static void
298 write_int16(const char *name, const void *data, size_t length)
299 {
300 	if (length != sizeof(int16)) {
301 		write_raw(name, B_INT16_TYPE, data, length);
302 	} else {
303 		write_field_name(name);
304 		fprintf(sOutputFile, "(int16)%d", *(int16 *)data);
305 	}
306 }
307 
308 
309 static void
310 write_int32(const char *name, const void *data, size_t length)
311 {
312 	if (length != sizeof(int32)) {
313 		write_raw(name, B_INT32_TYPE, data, length);
314 	} else {
315 		write_field_name(name);
316 		fprintf(sOutputFile, "%ld", *(int32 *)data);
317 	}
318 }
319 
320 
321 static void
322 write_int64(const char *name, const void *data, size_t length)
323 {
324 	if (length != sizeof(int64)) {
325 		write_raw(name, B_INT64_TYPE, data, length);
326 	} else {
327 		write_field_name(name);
328 		fprintf(sOutputFile, "(int64)%lld", *(int64 *)data);
329 	}
330 }
331 
332 
333 static void
334 write_uint8(const char *name, const void *data, size_t length)
335 {
336 	if (length != sizeof(uint8)) {
337 		write_raw(name, B_UINT8_TYPE, data, length);
338 	} else {
339 		write_field_name(name);
340 		fprintf(sOutputFile, "(uint8)%u", *(uint8 *)data);
341 	}
342 }
343 
344 
345 static void
346 write_uint16(const char *name, const void *data, size_t length)
347 {
348 	if (length != sizeof(uint16)) {
349 		write_raw(name, B_UINT16_TYPE, data, length);
350 	} else {
351 		write_field_name(name);
352 		fprintf(sOutputFile, "(uint16)%u", *(uint16 *)data);
353 	}
354 }
355 
356 
357 static void
358 write_uint32(const char *name, const void *data, size_t length)
359 {
360 	if (length != sizeof(uint32)) {
361 		write_raw(name, B_UINT32_TYPE, data, length);
362 	} else {
363 		write_field_name(name);
364 		fprintf(sOutputFile, "(uint32)%lu", *(uint32 *)data);
365 	}
366 }
367 
368 
369 static void
370 write_uint64(const char *name, const void *data, size_t length)
371 {
372 	if (length != sizeof(uint64)) {
373 		write_raw(name, B_UINT64_TYPE, data, length);
374 	} else {
375 		write_field_name(name);
376 		fprintf(sOutputFile, "(uint64)%llu", *(uint64 *)data);
377 	}
378 }
379 
380 
381 static void
382 write_float(const char *name, const void *data, size_t length)
383 {
384 	if (length != sizeof(float)) {
385 		write_raw(name, B_FLOAT_TYPE, data, length);
386 	} else {
387 		write_field_name(name);
388 		fprintf(sOutputFile, "%#g", *(float *)data);
389 	}
390 }
391 
392 
393 static void
394 write_double(const char *name, const void *data, size_t length)
395 {
396 	if (length != sizeof(double)) {
397 		write_raw(name, B_DOUBLE_TYPE, data, length);
398 	} else {
399 		write_field_name(name);
400 		fprintf(sOutputFile, "(double)%#g", *(double *)data);
401 	}
402 }
403 
404 
405 static void
406 write_size(const char *name, const void *data, size_t length)
407 {
408 	if (length != sizeof(size_t)) {
409 		write_raw(name, B_SIZE_T_TYPE, data, length);
410 	} else {
411 		write_field_name(name);
412 		fprintf(sOutputFile, "(size_t)%lu", *(size_t *)data);
413 	}
414 }
415 
416 
417 static void
418 write_ssize(const char *name, const void *data, size_t length)
419 {
420 	if (length != sizeof(ssize_t)) {
421 		write_raw(name, B_SSIZE_T_TYPE, data, length);
422 	} else {
423 		write_field_name(name);
424 		fprintf(sOutputFile, "(ssize_t)%ld", *(ssize_t *)data);
425 	}
426 }
427 
428 
429 static void
430 write_off(const char *name, const void *data, size_t length)
431 {
432 	if (length != sizeof(off_t)) {
433 		write_raw(name, B_OFF_T_TYPE, data, length);
434 	} else {
435 		write_field_name(name);
436 		fprintf(sOutputFile, "(off_t)%lld", *(off_t *)data);
437 	}
438 }
439 
440 
441 static void
442 write_time(const char *name, const void *data, size_t length)
443 {
444 	if (length != sizeof(time_t)) {
445 		write_raw(name, B_TIME_TYPE, data, length);
446 	} else {
447 		write_field_name(name);
448 		fprintf(sOutputFile, "(time_t)%ld", *(time_t *)data);
449 	}
450 }
451 
452 
453 static void
454 write_point(const char *name, const void *data)
455 {
456 	///TODO: using built-in type table
457 
458 	write_field_name(name);
459 	float *f = (float *)data;
460 	fprintf(sOutputFile, "point { %#g, %#g }", f[0], f[1]);
461 }
462 
463 
464 static void
465 write_rect(const char *name, const void *data)
466 {
467 	///TODO: using built-in type table
468 
469 	write_field_name(name);
470 	float *f = (float *)data;
471 	fprintf(sOutputFile, "rect { %#g, %#g, %#g, %#g }", f[0], f[1], f[2], f[3]);
472 }
473 
474 
475 static void
476 write_rgb(const char *name, const void *data)
477 {
478 	///TODO: using built-in type table
479 
480 	write_field_name(name);
481 	uint8 *b = (uint8 *)data;
482 
483 	fprintf(sOutputFile, "rgb_color { 0x%02X, 0x%02X, 0x%02X, 0x%02X }",
484 		b[0], b[1], b[2], b[3]);
485 }
486 
487 
488 static const char *
489 write_string_line(const char *ptr, const char *end, size_t charsPerLine)
490 {
491 	uint32 count = 0;
492 	bool end_of_item = false;
493 
494 	fprintf(sOutputFile, "\"");
495 
496 	while (ptr < end && count < charsPerLine && !end_of_item) {
497 		char c = *ptr++;
498 
499 		switch (c) {
500 			case '\b': fprintf(sOutputFile, "\\b");  count += 2; break;
501 			case '\f': fprintf(sOutputFile, "\\f");  count += 2; break;
502 			case '\n': fprintf(sOutputFile, "\\n");  count += 2; break;
503 			case '\r': fprintf(sOutputFile, "\\r");  count += 2; break;
504 			case '\t': fprintf(sOutputFile, "\\t");  count += 2; break;
505 			case '\v': fprintf(sOutputFile, "\\v");  count += 2; break;
506 			case '\"': fprintf(sOutputFile, "\\\""); count += 2; break;
507 			case '\\': fprintf(sOutputFile, "\\\\"); count += 2; break;
508 
509 			case '\0': end_of_item = true; break;
510 
511 			default:
512 			{
513 				if ((uint8)c < 128 && !isprint(c)) {
514 					fprintf(sOutputFile, "\\0x%02X", (uint8)c); count += 5;
515 				} else {
516 					fprintf(sOutputFile, "%c", c); ++count;
517 				}
518 			}
519 		}
520 	}
521 
522 	fprintf(sOutputFile, "\"");
523 
524 	if (end_of_item && ptr < end)
525 		fprintf(sOutputFile, ",");
526 
527 	return ptr;
528 }
529 
530 
531 static void
532 write_string(const char *name, type_code type,
533 	const void *data, size_t length)
534 {
535 	const char *ptr = (const char *)data;
536 	const char *end = ptr + length;
537 	size_t charsPerLine = 64;
538 
539 	// We write an "array" resource if the string has more than 64
540 	// characters. A string resource may also be comprised of multiple
541 	// substrings, each terminated by a '\0' char. In that case, we
542 	// must write an "array" resource as well. Sneaky as we are, we use
543 	// strlen() to check for that, because it also looks for a '\0'.
544 
545 	if (length > charsPerLine || strlen(ptr) < length - 1) {
546 		fprintf(sOutputFile, "#");
547 		write_code(type);
548 		fprintf(sOutputFile, " array");
549 
550 		if (name != NULL) {
551 			fprintf(sOutputFile, " ");
552 			write_field_name(name);
553 			fprintf(sOutputFile, " array");
554 		}
555 
556 		open_brace();
557 
558 		int32 item = 0;
559 		while (ptr < end) {
560 			if (item++ > 0)
561 				fprintf(sOutputFile, "\n");
562 
563 			indent();
564 			ptr = write_string_line(ptr, end, charsPerLine);
565 		}
566 
567 		close_brace();
568 	} else {
569 		if (type != B_STRING_TYPE) {
570 			fprintf(sOutputFile, "#");
571 			write_code(type);
572 			fprintf(sOutputFile, " ");
573 		}
574 
575 		write_field_name(name);
576 		write_string_line(ptr, end, charsPerLine);
577 	}
578 }
579 
580 
581 static void
582 write_fields(BMessage &msg)
583 {
584 	int32 t = 0;
585 	int32 item = 0;
586 
587 #ifdef B_BEOS_VERSION_DANO
588 	const char *name;
589 #else
590 	char *name;
591 #endif
592 	type_code type;
593 	int32 count;
594 	const void *data;
595 	size_t length;
596 
597 	open_brace();
598 
599 	while (msg.GetInfo(B_ANY_TYPE, t, &name, &type, &count) == B_OK) {
600 		for (int32 k = 0; k < count; ++k) {
601 			if (msg.FindData(name, type, k, &data, (ssize_t*) &length) == B_OK) {
602 				if (item++ > 0)
603 					fprintf(sOutputFile, ",\n");
604 
605 				indent();
606 				write_generic_data(name, type, data, length);
607 			}
608 		}
609 
610 		++t;
611 	}
612 
613 	close_brace();
614 }
615 
616 
617 static void
618 write_message(const char *name, BMessage &msg, type_code type)
619 {
620 	if (type != B_MESSAGE_TYPE) {
621 		fprintf(sOutputFile, "#");
622 		write_code(type);
623 		fprintf(sOutputFile, " ");
624 	}
625 
626 	write_field_name(name);
627 
628 	const char *class_;
629 	if (msg.FindString("class", &class_) == B_OK) {
630 		fprintf(sOutputFile, "archive");
631 
632 		const char *add_on;
633 		if (msg.FindString("add_on", &add_on) == B_OK) {
634 			fprintf(sOutputFile, "(\"%s\"", add_on);
635 			if (msg.what != 0) {
636 				fprintf(sOutputFile, ", ");
637 				write_code(msg.what);
638 			}
639 			fprintf(sOutputFile, ")");
640 
641 			msg.RemoveName("add_on");
642 		} else if (msg.what != 0) {
643 			fprintf(sOutputFile, "(, ");
644 			write_code(msg.what);
645 			fprintf(sOutputFile, ")");
646 		}
647 
648 		fprintf(sOutputFile, " %s", class_);
649 		msg.RemoveName("class");
650 	} else if (msg.what == 0) {
651 		fprintf(sOutputFile, "message");
652 	} else {
653 		fprintf(sOutputFile, "message(");
654 		write_code(msg.what);
655 		fprintf(sOutputFile, ")");
656 	}
657 
658 	if (msg.CountNames(B_ANY_TYPE) > 0)
659 		write_fields(msg);
660 }
661 
662 
663 static void
664 write_other(const char *name, type_code type,
665 	const void *data, size_t length)
666 {
667 	BMessage msg;
668 	if (msg.Unflatten((const char *)data) == B_OK)
669 		write_message(name, msg, type);
670 	else if (is_string(data, length))
671 		write_string(name, type, data, length);
672 	else
673 		write_raw(name, type, data, length);
674 }
675 
676 
677 //	#pragma mark - special types
678 
679 
680 static void
681 write_app_signature(const void *data, size_t length)
682 {
683 	fprintf(sOutputFile, "resource app_signature ");
684 	write_string_line((const char *)data, (const char *)data + length, length * 2);
685 }
686 
687 
688 static void
689 write_app_flags(const void *data, size_t length)
690 {
691 	fprintf(sOutputFile, "resource app_flags ");
692 
693 	uint32 flags = *(uint32 *)data;
694 	switch (flags & B_LAUNCH_MASK) {
695 		case B_SINGLE_LAUNCH:
696 			fputs("B_SINGLE_LAUNCH", sOutputFile);
697 			break;
698 		case B_MULTIPLE_LAUNCH:
699 			fputs("B_MULTIPLE_LAUNCH", sOutputFile);
700 			break;
701 		case B_EXCLUSIVE_LAUNCH:
702 			fputs("B_EXCLUSIVE_LAUNCH", sOutputFile);
703 			break;
704 	}
705 
706 	if (flags & B_BACKGROUND_APP)
707 		fputs(" | B_BACKGROUND_APP", sOutputFile);
708 	if (flags & B_ARGV_ONLY)
709 		fputs(" | B_ARGV_ONLY", sOutputFile);
710 }
711 
712 
713 static void
714 write_app_icon(uint32 which, const void *data, size_t length)
715 {
716 	int32 lineWidth = 32;
717 	const char* type = "";
718 	switch (which) {
719 		case B_MINI_ICON:
720 			type = "mini";
721 			lineWidth = 16;
722 			break;
723 		case B_LARGE_ICON:
724 			type = "large";
725 			break;
726 		case 'VICN':
727 			type = "vector";
728 			break;
729 		case 'PNG ':
730 			type = "png";
731 			break;
732 		default:
733 			fprintf(stderr, "write_app_icon() called with invalid type!\n");
734 			break;
735 	}
736 	fprintf(sOutputFile, "resource %s_icon ", type);
737 	write_raw(NULL, B_RAW_TYPE, data, length, lineWidth);
738 }
739 
740 
741 static void
742 write_app_file_types(const void *data, size_t length)
743 {
744 	fputs("resource file_types ", sOutputFile);
745 	write_other(NULL, B_MESSAGE_TYPE, data, length);
746 }
747 
748 
749 static void
750 write_app_version(const void *data, size_t length)
751 {
752 	const version_info *version = (const version_info *)data;
753 	//const version_info *systemVersion = version + 1;
754 
755 	fputs("resource app_version", sOutputFile);
756 	open_brace();
757 
758 	fprintf(sOutputFile, "\tmajor  = %ld,\n"
759 		"\tmiddle = %ld,\n"
760 		"\tminor  = %ld,\n\n", version->major, version->middle, version->minor);
761 
762 	const char *variety = "B_APPV_DEVELOPMENT";
763 	switch (version->variety) {
764 		case 1:
765 			variety = "B_APPV_ALPHA";
766 			break;
767 		case 2:
768 			variety = "B_APPV_BETA";
769 			break;
770 		case 3:
771 			variety = "B_APPV_GAMMA";
772 			break;
773 		case 4:
774 			variety = "B_APPV_GOLDEN_MASTER";
775 			break;
776 		case 5:
777 			variety = "B_APPV_FINAL";
778 			break;
779 	}
780 	fprintf(sOutputFile, "\tvariety = %s,\n"
781 		"\tinternal = %ld,\n\n", variety, version->internal);
782 
783 	fprintf(sOutputFile, "\tshort_info = ");
784 	write_string(NULL, B_STRING_TYPE, version->short_info, strlen(version->short_info));
785 
786 	fprintf(sOutputFile, ",\n\tlong_info = ");
787 	write_string(NULL, B_STRING_TYPE, version->long_info, strlen(version->long_info));
788 
789 	close_brace();
790 }
791 
792 
793 //	#pragma mark - file examination
794 
795 
796 static void
797 write_generic_data(const char *name, type_code type,
798 	const void *data, size_t length)
799 {
800 	switch (type) {
801 		case B_BOOL_TYPE:    write_bool(name, data, length);   break;
802 		case B_INT8_TYPE:    write_int8(name, data, length);   break;
803 		case B_INT16_TYPE:   write_int16(name, data, length);  break;
804 		case B_INT32_TYPE:   write_int32(name, data, length);  break;
805 		case B_INT64_TYPE:   write_int64(name, data, length);  break;
806 		case B_UINT8_TYPE:   write_uint8(name, data, length);  break;
807 		case B_UINT16_TYPE:  write_uint16(name, data, length); break;
808 		case B_UINT32_TYPE:  write_uint32(name, data, length); break;
809 		case B_UINT64_TYPE:  write_uint64(name, data, length); break;
810 		case B_FLOAT_TYPE:   write_float(name, data, length);  break;
811 		case B_DOUBLE_TYPE:  write_double(name, data, length); break;
812 		case B_SIZE_T_TYPE:  write_size(name, data, length);   break;
813 		case B_SSIZE_T_TYPE: write_ssize(name, data, length);  break;
814 		case B_OFF_T_TYPE:   write_off(name, data, length);    break;
815 		case B_TIME_TYPE:    write_time(name, data, length);   break;
816 
817 		case B_POINT_TYPE:     write_point(name, data);  break;
818 		case B_RECT_TYPE:      write_rect(name, data);   break;
819 		case B_RGB_COLOR_TYPE: write_rgb(name, data);    break;
820 
821 		case B_MIME_STRING_TYPE:
822 		case B_STRING_TYPE:
823 			write_string(name, type, data, length);
824 			break;
825 
826 		case 'MICN':
827 			write_raw(name, type, data, length, 16);
828 			break;
829 		case B_POINTER_TYPE:
830 		case 'ICON':
831 		case 'VICN':
832 			write_raw(name, type, data, length);
833 			break;
834 
835 		default:
836 			write_other(name, type, data, length);
837 			break;
838 	}
839 }
840 
841 
842 static void
843 write_data(int32 id, const char *name, type_code type,
844 	const void *data, size_t length)
845 {
846 	// check for special types
847 
848 	switch (type) {
849 		case B_MIME_STRING_TYPE:
850 			if (!strcmp(name, "BEOS:APP_SIG")) {
851 				write_app_signature(data, length);
852 				return;
853 			}
854 			break;
855 
856 		case 'VICN':
857 			if (!strcmp(name, "BEOS:ICON")) {
858 				write_app_icon('VICN', data, length);
859 				return;
860 			}
861 			break;
862 
863 		case 'PNG ':
864 			if (!strcmp(name, "BEOS:ICON")) {
865 				write_app_icon('PNG ', data, length);
866 				return;
867 			}
868 			break;
869 
870 		case 'MICN':
871 			if (!strcmp(name, "BEOS:M:STD_ICON")) {
872 				write_app_icon(B_MINI_ICON, data, length);
873 				return;
874 			}
875 			break;
876 
877 		case 'ICON':
878 			if (!strcmp(name, "BEOS:L:STD_ICON")) {
879 				write_app_icon(B_LARGE_ICON, data, length);
880 				return;
881 			}
882 			break;
883 
884 		case B_MESSAGE_TYPE:
885 			if (!strcmp(name, "BEOS:FILE_TYPES")) {
886 				write_app_file_types(data, length);
887 				return;
888 			}
889 			break;
890 
891 		case 'APPF':
892 			if (!strcmp(name, "BEOS:APP_FLAGS") && length == 4) {
893 				write_app_flags(data, length);
894 				return;
895 			}
896 			break;
897 
898 		case 'APPV':
899 			if (!strcmp(name, "BEOS:APP_VERSION") && length == sizeof(version_info) * 2) {
900 				write_app_version(data, length);
901 				return;
902 			}
903 			break;
904 	}
905 
906 	// write generic types
907 
908 	write_rsrc(type, id, name);
909 	write_generic_data(NULL, type, data, length);
910 }
911 
912 
913 static void
914 examine_file(char *fileName)
915 {
916 	BFile file(fileName, B_READ_ONLY);
917 	if (file.InitCheck() != B_OK) {
918 		strcpy(rdef_err_file, fileName);
919 		rdef_err = RDEF_FILE_NOT_FOUND;
920 		return;
921 	}
922 
923 	BResources res;
924 	if (res.SetTo(&file) != B_OK) {
925 		strcpy(rdef_err_file, fileName);
926 		rdef_err = RDEF_NO_RESOURCES;
927 		return;
928 	}
929 
930 	int32 t = 0;
931 	type_code type;
932 	int32 id;
933 	const char *name;
934 	size_t length;
935 	const void *data;
936 
937 	while (res.GetResourceInfo(t, &type, &id, &name, &length)) {
938 		sTabs = 0;
939 
940 		data = res.LoadResource(type, id, NULL);
941 		if (data != NULL) {
942 			fprintf(sOutputFile, "\n");
943 			write_data(id, name, type, data, length);
944 			fprintf(sOutputFile, ";\n");
945 		}
946 
947 		++t;
948 	}
949 }
950 
951 
952 static status_t
953 open_output_files(const char *fileName, const char *headerName)
954 {
955 	sOutputFile = fopen(fileName, "w");
956 	if (sOutputFile == NULL) {
957 		strcpy(rdef_err_msg, strerror(errno));
958 		strcpy(rdef_err_file, fileName);
959 		return RDEF_WRITE_ERR;
960 	}
961 
962 	if (flags & RDEF_AUTO_NAMES) {
963 		sHeaderFile = fopen(headerName, "w");
964 		if (sHeaderFile == NULL) {
965 			strcpy(rdef_err_msg, strerror(errno));
966 			strcpy(rdef_err_file, headerName);
967 			fclose(sOutputFile);
968 			return RDEF_WRITE_ERR;
969 		}
970 
971 		fprintf(sOutputFile, "\n#include \"%s\"\n", headerName);
972 
973 		if (sBraceOnNextLine)
974 			fprintf(sHeaderFile, "\nenum\n{\n");
975 		else
976 			fprintf(sHeaderFile, "\nenum {\n");
977 	}
978 
979 	return B_OK;
980 }
981 
982 
983 static void
984 close_output_files(const char *fileName, const char *headerName)
985 {
986 	if (flags & RDEF_AUTO_NAMES) {
987 		fprintf(sHeaderFile, "};\n");
988 		fclose(sHeaderFile);
989 
990 		if (rdef_err != B_OK)
991 			unlink(headerName);
992 	}
993 
994 	fclose(sOutputFile);
995 
996 	if (rdef_err != B_OK)
997 		unlink(fileName);
998 }
999 
1000 
1001 status_t
1002 rdef_decompile(const char *fileName)
1003 {
1004 	clear_error();
1005 
1006 	if (fileName == NULL || fileName[0] == '\0') {
1007 		rdef_err = B_BAD_VALUE;
1008 		return rdef_err;
1009 	}
1010 
1011 	char headerName[B_PATH_NAME_LENGTH + 1];
1012 	if ((flags & RDEF_AUTO_NAMES) != 0)
1013 		sprintf(headerName, "%s.h", fileName);
1014 
1015 	rdef_err = open_output_files(fileName, headerName);
1016 	if (rdef_err != B_OK)
1017 		return rdef_err;
1018 
1019 	for (ptr_iter_t i = input_files.begin();
1020 			(i != input_files.end()) && (rdef_err == B_OK); ++i) {
1021 		examine_file((char *)*i);
1022 	}
1023 
1024 	close_output_files(fileName, headerName);
1025 	return rdef_err;
1026 }
1027 
1028