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