1#include <string.h>
2#include <stdio.h>
3#include <ctype.h>
4#include <BeBuild.h>
5#include <Font.h>
6#include <Message.h>
7#include <String.h>
8#include "DumpMessage.h"
9
10//#define WHAT_ALWAYS_HEX 1
11
12const char *msg_header_comment = "// new BMessage\n"; // avoids mime to think it's a .bmp ("BM")
13
14// '_' also widely used in what codes
15inline int myisprint(int c)
16{
17	if (isalnum(c))
18		return 1;
19	return (c == '_')?1:0;
20}
21
22status_t HexDumpToStream(const void *data, size_t len, BDataIO &stream, const char *prefix = NULL)
23{
24	const unsigned char *p = (unsigned char *)data;
25	char buffer[100];
26	size_t i, j;
27	for (i=0; i<len; i+=16) {
28		if (prefix) stream.Write(prefix, strlen(prefix));
29		sprintf(buffer, "0x%06lx: ", i);
30		stream.Write(buffer, strlen(buffer));
31		for (j=0; j<16; j++) {
32			if (i+j < len)
33				sprintf(buffer, "%02x", p[i+j]);
34			else
35				sprintf(buffer, "  ");
36			if (j % 4 == 3)
37				sprintf(buffer+strlen(buffer), " ");
38			stream.Write(buffer, strlen(buffer));
39		}
40		sprintf(buffer, " '");
41		stream.Write(buffer, strlen(buffer));
42		for (j=0; j<16; j++) {
43			if (i+j >= len)
44				sprintf(buffer, " ");
45			//else if (p[i+j] < 255 && p[i+j] >= 0x20)
46			else if (isalpha(p[i+j]))
47				sprintf(buffer, "%c", p[i+j]);
48			else
49				sprintf(buffer, ".");
50			stream.Write(buffer, 1);
51		}
52		sprintf(buffer, "'\n");
53		stream.Write(buffer, strlen(buffer));
54	}
55	return B_OK;
56}
57
58/* look up human readable names from an other BMessage */
59bool LookUpFieldName(const char **name, const char *field_name, BMessage *names)
60{
61	if (names == NULL)
62		return false;
63	if (names->FindString(field_name, name) == B_OK)
64		return true;
65	return false;
66}
67
68status_t DumpMessageToStream(BMessage *message, BDataIO &stream, int tabCount, BMessage *names)
69{
70	int32 index;
71	void *cookie = NULL;
72	const char *field_name;
73	type_code field_code;
74	int32 field_count;
75	char buffer[80];
76	char tabs[20];
77	const char *easy_name;
78
79	if (message == NULL)
80		return EINVAL;
81
82	if (tabCount < 1)
83		stream.Write(msg_header_comment, strlen(msg_header_comment));
84
85	memset(tabs, '\t', (++tabCount) + 1);
86	tabs[tabCount+1] = '\0';
87	//tabCount;
88
89#ifndef WHAT_ALWAYS_HEX
90	if (	myisprint(message->what & 0x0ff) &&
91		myisprint((message->what >> 8) & 0x0ff) &&
92		myisprint((message->what >> 16) & 0x0ff) &&
93		myisprint((message->what >> 24) & 0x0ff))
94		sprintf(buffer, "BMessage('%c%c%c%c') {\n",
95			(char)(message->what >> 24) & 0x0ff,
96			(char)(message->what >> 16) & 0x0ff,
97			(char)(message->what >> 8) & 0x0ff,
98			(char)message->what & 0x0ff);
99	else
100#endif
101		sprintf(buffer, "BMessage(0x%08lx) {\n", message->what);
102//	stream.Write(tabs+2, tabCount-2);
103	stream.Write(buffer, strlen(buffer));
104
105#ifdef B_BEOS_VERSION_DANO
106	while (message->GetNextName(&cookie,
107				&field_name,
108				&field_code,
109				&field_count) == B_OK) {
110#else
111#warning mem leak likely! (name=char *)
112	for (int which=0; message->GetInfo(B_ANY_TYPE, which,
113			(char **)&field_name, &field_code, &field_count) == B_OK; which++) {
114#endif
115		if (LookUpFieldName(&easy_name, field_name, names)) {
116			stream.Write(tabs+1, tabCount);
117			stream.Write("// ", 3);
118			stream.Write(easy_name, strlen(easy_name));
119			stream.Write("\n", 1);
120		}
121
122		for (index=0; index < field_count; index++) {
123			stream.Write(tabs+1, tabCount);
124			stream.Write(field_name, strlen(field_name));
125			if (field_count > 1) {
126				sprintf(buffer, "[%ld]", index);
127				stream.Write(buffer, strlen(buffer));
128			}
129			stream.Write(" = ", 3);
130
131			switch (field_code) {
132			case 'MSGG':
133				{
134					BMessage m;
135					if (message->FindMessage(field_name, index, &m) >= B_OK)
136						DumpMessageToStream(&m, stream, tabCount, names);
137				}
138				break;
139#ifdef B_BEOS_VERSION_DANO
140			case 'FONt':
141				{
142					BFont f;
143					if (message->FindFlat(field_name, index, &f) >= B_OK)
144						stream << f;
145					stream.Write("\n", 1);
146				}
147				break;
148			case B_RGB_COLOR_TYPE:
149				{
150					rgb_color c;
151					if (message->FindRGBColor(field_name, index, &c) >= B_OK) {
152						sprintf(buffer, "rgb_color(%d,%d,%d,%d)",
153							c.red, c.green, c.blue, c.alpha);
154						stream.Write(buffer, strlen(buffer));
155					}
156					stream.Write("\n", 1);
157				}
158				break;
159#else
160#warning IMPLEMENT ME
161#endif
162			case B_BOOL_TYPE:
163				{
164					bool value;
165					if (message->FindBool(field_name, index, &value) >= B_OK) {
166						sprintf(buffer, "bool(%s)", value?"true":"false");
167						stream.Write(buffer, strlen(buffer));
168					}
169					stream.Write("\n", 1);
170				}
171				break;
172			case B_INT32_TYPE:
173				{
174					int32 value;
175					if (message->FindInt32(field_name, index, &value) >= B_OK) {
176#if 1
177						if (value == 0)
178							sprintf(buffer, "int32(0 or (nil))");
179						else
180#endif
181//							sprintf(buffer, "int32(%d)", value);
182							sprintf(buffer, "int32(%ld or 0x%lx)", value, value);
183						stream.Write(buffer, strlen(buffer));
184					}
185					stream.Write("\n", 1);
186				}
187				break;
188			case B_FLOAT_TYPE:
189				{
190					float value;
191					if (message->FindFloat(field_name, index, &value) >= B_OK) {
192							sprintf(buffer, "float(%f)", value);
193						stream.Write(buffer, strlen(buffer));
194					}
195					stream.Write("\n", 1);
196				}
197				break;
198			case B_STRING_TYPE:
199				{
200					const char *value;
201					if (message->FindString(field_name, index, &value) >= B_OK) {
202						BString str(value);
203						str.CharacterEscape("\\\"\n", '\\');
204						//sprintf(buffer, "string(\"%s\", %ld bytes)", str.String(), strlen(value));
205						// DO NOT use buffer!
206						str.Prepend("string(\"");
207						str << "\", " << strlen(value) << " bytes)";
208						stream.Write(str.String(), strlen(str.String()));
209					}
210					stream.Write("\n", 1);
211				}
212				break;
213			case B_POINT_TYPE:
214				{
215					BPoint value;
216					if (message->FindPoint(field_name, index, &value) >= B_OK) {
217						sprintf(buffer, "BPoint(%1.1f, %1.1f)", value.x, value.y);
218						stream.Write(buffer, strlen(buffer));
219					}
220					stream.Write("\n", 1);
221				}
222				break;
223			default:
224				{
225					const void *data;
226					ssize_t numBytes = 0;
227					if (message->FindData(field_name, field_code, index, &data, &numBytes) != B_OK) {
228						//stream.Write("\n", 1);
229						break;
230					}
231
232					if (	isalnum(field_code & 0x0ff) &&
233						isalnum((field_code >> 8) & 0x0ff) &&
234						isalnum((field_code >> 16) & 0x0ff) &&
235						isalnum((field_code >> 24) & 0x0ff))
236						sprintf(buffer, "'%c%c%c%c' %ld bytes:\n",
237							(char)(field_code >> 24) & 0x0ff,
238							(char)(field_code >> 16) & 0x0ff,
239							(char)(field_code >> 8) & 0x0ff,
240							(char)field_code & 0x0ff,
241							numBytes);
242					else
243						sprintf(buffer, "0x%08lx %ld bytes:\n", field_code, numBytes);
244					stream.Write(buffer, strlen(buffer));
245					stream.Write("\n", 1);
246					HexDumpToStream(data, numBytes, stream, tabs);
247				}
248				break;
249			}
250		}
251	}
252	stream.Write(tabs+2, tabCount-1);
253	stream.Write("}\n", 2);
254	return B_OK;
255}
256
257