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
43static FILE *sOutputFile;
44static FILE *sHeaderFile;
45
46// Level of indentation (how many tabs).
47static int32 sTabs;
48static bool sBraceOnNextLine = false;
49
50
51static void write_generic_data(const char *name, type_code type,
52	const void *data, size_t length);
53
54
55static void
56indent()
57{
58	for (int32 t = 0; t < sTabs; ++t) {
59		fprintf(sOutputFile, "\t");
60	}
61}
62
63
64void
65open_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
78void
79close_brace()
80{
81	--sTabs;
82
83	fprintf(sOutputFile, "\n");
84	indent();
85	fprintf(sOutputFile, "}");
86}
87
88
89static bool
90make_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
111static void
112write_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
122static void
123write_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
135static bool
136is_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
150static bool
151has_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
165static bool
166is_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
187static void
188write_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
216static uint8 *
217write_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
234static void
235write_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
276static void
277write_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
288static void
289write_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
300static void
301write_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
312static void
313write_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
324static void
325write_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
336static void
337write_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
348static void
349write_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
360static void
361write_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
372static void
373write_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
384static void
385write_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
396static void
397write_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
408static void
409write_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
420static void
421write_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
432static void
433write_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
444static void
445write_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
456static void
457write_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
467static void
468write_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
478static void
479write_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
491static const char *
492write_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
534static void
535write_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
584static void
585write_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
620static void
621write_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
666static void
667write_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
683static void
684write_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
691static void
692write_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
716static void
717write_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
744static void
745write_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
752static void
753write_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
800static void
801write_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
846static void
847write_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
917static void
918examine_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
956static status_t
957open_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
987static void
988close_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
1005status_t
1006rdef_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