1/*
2 * Copyright 2001-2005 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Marc Flerackers (mflerackers@androme.be)
7 */
8
9
10#include <ByteOrder.h>
11#include <DataIO.h>
12#include <Message.h>
13#include <PropertyInfo.h>
14
15#include <string.h>
16#include <stdio.h>
17#include <stdlib.h>
18
19
20BPropertyInfo::BPropertyInfo(property_info* propertyInfo, value_info* valueInfo,
21	bool freeOnDelete)
22	:
23	fPropInfo(propertyInfo),
24	fValueInfo(valueInfo),
25	fPropCount(0),
26	fInHeap(freeOnDelete),
27	fValueCount(0)
28{
29	if (fPropInfo != NULL) {
30		while (fPropInfo[fPropCount].name)
31			fPropCount++;
32	}
33
34	if (fValueInfo != NULL) {
35		while (fValueInfo[fValueCount].name)
36			fValueCount++;
37	}
38}
39
40
41BPropertyInfo::~BPropertyInfo()
42{
43	FreeMem();
44}
45
46
47int32 BPropertyInfo::FindMatch(BMessage* message, int32 index,
48	BMessage* specifier, int32 form, const char* property, void* data) const
49{
50	int32 propertyIndex = 0;
51
52	while (fPropInfo != NULL && fPropInfo[propertyIndex].name != NULL) {
53		property_info* propertyInfo = fPropInfo + propertyIndex;
54
55		if (!strcmp(propertyInfo->name, property)
56			&& FindCommand(message->what, index, propertyInfo)
57			&& FindSpecifier(form, propertyInfo)) {
58			if (data)
59				*((uint32*)data) = propertyInfo->extra_data;
60
61			return propertyIndex;
62		}
63		propertyIndex++;
64	}
65
66	return B_ERROR;
67}
68
69
70bool
71BPropertyInfo::IsFixedSize() const
72{
73	return false;
74}
75
76
77type_code
78BPropertyInfo::TypeCode() const
79{
80	return B_PROPERTY_INFO_TYPE;
81}
82
83
84ssize_t
85BPropertyInfo::FlattenedSize() const
86{
87	size_t size = (2 * sizeof(int32)) + 1;
88
89	if (fPropInfo) {
90		// Main chunks
91		for (int32 pi = 0; fPropInfo[pi].name != NULL; pi++) {
92			size += strlen(fPropInfo[pi].name) + 1;
93
94			if (fPropInfo[pi].usage)
95				size += strlen(fPropInfo[pi].usage) + 1;
96			else
97				size += sizeof(char);
98
99			size += sizeof(int32);
100
101			for (int32 i = 0; i < 10 && fPropInfo[pi].commands[i] != 0; i++)
102				size += sizeof(int32);
103			size += sizeof(int32);
104
105			for (int32 i = 0; i < 10 && fPropInfo[pi].specifiers[i] != 0; i++)
106				size += sizeof(int32);
107			size += sizeof(int32);
108		}
109
110		// Type chunks
111		for (int32 pi = 0; fPropInfo[pi].name != NULL; pi++) {
112			for (int32 i = 0; i < 10 && fPropInfo[pi].types[i] != 0; i++)
113				size += sizeof(int32);
114			size += sizeof(int32);
115
116			for (int32 i = 0; i < 3
117					&& fPropInfo[pi].ctypes[i].pairs[0].name != 0; i++) {
118				for (int32 j = 0; j < 5
119						&& fPropInfo[pi].ctypes[i].pairs[j].name != 0; j++) {
120					size += strlen(fPropInfo[pi].ctypes[i].pairs[j].name) + 1;
121					size += sizeof(int32);
122				}
123				size += sizeof(int32);
124			}
125			size += sizeof(int32);
126		}
127	}
128
129	if (fValueInfo) {
130		size += sizeof(int16);
131
132		// Chunks
133		for (int32 vi = 0; fValueInfo[vi].name != NULL; vi++) {
134			size += sizeof(int32);
135			size += sizeof(int32);
136
137			size += strlen(fValueInfo[vi].name) + 1;
138
139			if (fValueInfo[vi].usage)
140				size += strlen(fValueInfo[vi].usage) + 1;
141			else
142				size += sizeof(char);
143
144			size += sizeof(int32);
145		}
146	}
147
148	return size;
149}
150
151
152status_t
153BPropertyInfo::Flatten(void* buffer, ssize_t numBytes) const
154{
155	if (numBytes < FlattenedSize())
156		return B_NO_MEMORY;
157
158	if (buffer == NULL)
159		return B_BAD_VALUE;
160
161	BMemoryIO flatData(buffer, numBytes);
162
163	char tmpChar = B_HOST_IS_BENDIAN;
164	int32 tmpInt;
165
166	flatData.Write(&tmpChar, sizeof(tmpChar));
167	flatData.Write(&fPropCount, sizeof(fPropCount));
168	tmpInt = 0x01 | (fValueInfo ? 0x2 : 0x0);
169	flatData.Write(&tmpInt, sizeof(tmpInt));
170
171	if (fPropInfo) {
172		// Main chunks
173		for (int32 pi = 0; fPropInfo[pi].name != NULL; pi++) {
174			flatData.Write(fPropInfo[pi].name, strlen(fPropInfo[pi].name) + 1);
175			if (fPropInfo[pi].usage != NULL) {
176				flatData.Write(fPropInfo[pi].usage, strlen(fPropInfo[pi].usage)
177					+ 1);
178			} else {
179				tmpChar = 0;
180				flatData.Write(&tmpChar, sizeof(tmpChar));
181			}
182
183			flatData.Write(&fPropInfo[pi].extra_data,
184				sizeof(fPropInfo[pi].extra_data));
185
186			for (int32 i = 0; i < 10 && fPropInfo[pi].commands[i] != 0; i++) {
187				flatData.Write(&fPropInfo[pi].commands[i],
188					sizeof(fPropInfo[pi].commands[i]));
189			}
190			tmpInt = 0;
191			flatData.Write(&tmpInt, sizeof(tmpInt));
192
193			for (int32 i = 0; i < 10 && fPropInfo[pi].specifiers[i] != 0; i++) {
194				flatData.Write(&fPropInfo[pi].specifiers[i],
195					sizeof(fPropInfo[pi].specifiers[i]));
196			}
197			tmpInt = 0;
198			flatData.Write(&tmpInt, sizeof(tmpInt));
199		}
200
201		// Type chunks
202		for (int32 pi = 0; fPropInfo[pi].name != NULL; pi++) {
203			for (int32 i = 0; i < 10 && fPropInfo[pi].types[i] != 0; i++) {
204				flatData.Write(&fPropInfo[pi].types[i],
205					sizeof(fPropInfo[pi].types[i]));
206			}
207			tmpInt = 0;
208			flatData.Write(&tmpInt, sizeof(tmpInt));
209
210			for (int32 i = 0; i < 3
211					&& fPropInfo[pi].ctypes[i].pairs[0].name != 0; i++) {
212				for (int32 j = 0; j < 5
213						&& fPropInfo[pi].ctypes[i].pairs[j].name != 0; j++) {
214					flatData.Write(fPropInfo[pi].ctypes[i].pairs[j].name,
215						strlen(fPropInfo[pi].ctypes[i].pairs[j].name) + 1);
216					flatData.Write(&fPropInfo[pi].ctypes[i].pairs[j].type,
217						sizeof(fPropInfo[pi].ctypes[i].pairs[j].type));
218				}
219				tmpInt = 0;
220				flatData.Write(&tmpInt, sizeof(tmpInt));
221			}
222			tmpInt = 0;
223			flatData.Write(&tmpInt, sizeof(tmpInt));
224		}
225	}
226
227	if (fValueInfo) {
228		// Value Chunks
229		flatData.Write(&fValueCount, sizeof(fValueCount));
230		for (int32 vi = 0; fValueInfo[vi].name != NULL; vi++) {
231			flatData.Write(&fValueInfo[vi].kind, sizeof(fValueInfo[vi].kind));
232			flatData.Write(&fValueInfo[vi].value, sizeof(fValueInfo[vi].value));
233			flatData.Write(fValueInfo[vi].name, strlen(fValueInfo[vi].name)
234				+ 1);
235			if (fValueInfo[vi].usage) {
236				flatData.Write(fValueInfo[vi].usage,
237					strlen(fValueInfo[vi].usage) + 1);
238			} else {
239				tmpChar = 0;
240				flatData.Write(&tmpChar, sizeof(tmpChar));
241			}
242			flatData.Write(&fValueInfo[vi].extra_data,
243				sizeof(fValueInfo[vi].extra_data));
244		}
245	}
246
247	return B_OK;
248}
249
250
251bool
252BPropertyInfo::AllowsTypeCode(type_code code) const
253{
254	return code == B_PROPERTY_INFO_TYPE;
255}
256
257
258status_t
259BPropertyInfo::Unflatten(type_code code, const void* buffer,
260	ssize_t numBytes)
261{
262	if (!AllowsTypeCode(code))
263		return B_BAD_TYPE;
264
265	if (buffer == NULL)
266		return B_BAD_VALUE;
267
268	FreeMem();
269
270	BMemoryIO flatData(buffer, numBytes);
271	char tmpChar = B_HOST_IS_BENDIAN;
272	int32 tmpInt;
273
274	flatData.Read(&tmpChar, sizeof(tmpChar));
275	bool swapRequired = (tmpChar != B_HOST_IS_BENDIAN);
276
277	flatData.Read(&fPropCount, sizeof(fPropCount));
278
279	int32 flags;
280	flatData.Read(&flags, sizeof(flags));
281	if (swapRequired) {
282		fPropCount = B_SWAP_INT32(fPropCount);
283		flags = B_SWAP_INT32(flags);
284	}
285
286	if (flags & 1) {
287		fPropInfo = static_cast<property_info *>(malloc(sizeof(property_info)
288			* (fPropCount + 1)));
289		memset(fPropInfo, 0, (fPropCount + 1) * sizeof(property_info));
290
291		// Main chunks
292		for (int32 pi = 0; pi < fPropCount; pi++) {
293			fPropInfo[pi].name = strdup(static_cast<const char*>(buffer)
294				+ flatData.Position());
295			flatData.Seek(strlen(fPropInfo[pi].name) + 1, SEEK_CUR);
296
297			fPropInfo[pi].usage = strdup(static_cast<const char *>(buffer)
298				+ flatData.Position());
299			flatData.Seek(strlen(fPropInfo[pi].usage) + 1, SEEK_CUR);
300
301			flatData.Read(&fPropInfo[pi].extra_data,
302				sizeof(fPropInfo[pi].extra_data));
303			if (swapRequired) {
304				fPropInfo[pi].extra_data
305					= B_SWAP_INT32(fPropInfo[pi].extra_data);
306			}
307
308			flatData.Read(&tmpInt, sizeof(tmpInt));
309			for (int32 i = 0; tmpInt != 0; i++) {
310				if (swapRequired) {
311					tmpInt = B_SWAP_INT32(tmpInt);
312				}
313				fPropInfo[pi].commands[i] = tmpInt;
314				flatData.Read(&tmpInt, sizeof(tmpInt));
315			}
316
317			flatData.Read(&tmpInt, sizeof(tmpInt));
318			for (int32 i = 0; tmpInt != 0; i++) {
319				if (swapRequired) {
320					tmpInt = B_SWAP_INT32(tmpInt);
321				}
322				fPropInfo[pi].specifiers[i] = tmpInt;
323				flatData.Read(&tmpInt, sizeof(tmpInt));
324			}
325		}
326
327		// Type chunks
328		for (int32 pi = 0; pi < fPropCount; pi++) {
329			flatData.Read(&tmpInt, sizeof(tmpInt));
330			for (int32 i = 0; tmpInt != 0; i++) {
331				if (swapRequired) {
332					tmpInt = B_SWAP_INT32(tmpInt);
333				}
334				fPropInfo[pi].types[i] = tmpInt;
335				flatData.Read(&tmpInt, sizeof(tmpInt));
336			}
337
338			flatData.Read(&tmpInt, sizeof(tmpInt));
339			for (int32 i = 0; tmpInt != 0; i++) {
340				for (int32 j = 0; tmpInt != 0; j++) {
341					flatData.Seek(-sizeof(tmpInt), SEEK_CUR);
342					fPropInfo[pi].ctypes[i].pairs[j].name =
343						strdup(static_cast<const char *>(buffer)
344							+ flatData.Position());
345					flatData.Seek(strlen(fPropInfo[pi].ctypes[i].pairs[j].name)
346						+ 1, SEEK_CUR);
347
348					flatData.Read(&fPropInfo[pi].ctypes[i].pairs[j].type,
349						sizeof(fPropInfo[pi].ctypes[i].pairs[j].type));
350					if (swapRequired) {
351						fPropInfo[pi].ctypes[i].pairs[j].type =
352							B_SWAP_INT32(fPropInfo[pi].ctypes[i].pairs[j].type);
353					}
354					flatData.Read(&tmpInt, sizeof(tmpInt));
355				}
356				flatData.Read(&tmpInt, sizeof(tmpInt));
357			}
358		}
359	}
360
361	if (flags & 2) {
362		flatData.Read(&fValueCount, sizeof(fValueCount));
363		if (swapRequired) {
364			fValueCount = B_SWAP_INT16(fValueCount);
365		}
366
367		fValueInfo = static_cast<value_info *>(malloc(sizeof(value_info)
368			* (fValueCount + 1)));
369		memset(fValueInfo, 0, (fValueCount + 1) * sizeof(value_info));
370
371		for (int32 vi = 0; vi < fValueCount; vi++) {
372			flatData.Read(&fValueInfo[vi].kind, sizeof(fValueInfo[vi].kind));
373			flatData.Read(&fValueInfo[vi].value, sizeof(fValueInfo[vi].value));
374
375			fValueInfo[vi].name = strdup(static_cast<const char *>(buffer)
376				+ flatData.Position());
377			flatData.Seek(strlen(fValueInfo[vi].name) + 1, SEEK_CUR);
378
379			fValueInfo[vi].usage = strdup(static_cast<const char *>(buffer)
380				+ flatData.Position());
381			flatData.Seek(strlen(fValueInfo[vi].usage) + 1, SEEK_CUR);
382
383			flatData.Read(&fValueInfo[vi].extra_data,
384				sizeof(fValueInfo[vi].extra_data));
385			if (swapRequired) {
386				fValueInfo[vi].kind = static_cast<value_kind>(
387					B_SWAP_INT32(fValueInfo[vi].kind));
388				fValueInfo[vi].value = B_SWAP_INT32(fValueInfo[vi].value);
389				fValueInfo[vi].extra_data
390					= B_SWAP_INT32(fValueInfo[vi].extra_data);
391			}
392		}
393	}
394
395	return B_OK;
396}
397
398
399const property_info*
400BPropertyInfo::Properties() const
401{
402	return fPropInfo;
403}
404
405
406const value_info*
407BPropertyInfo::Values() const
408{
409	return fValueInfo;
410}
411
412
413int32
414BPropertyInfo::CountProperties() const
415{
416	return fPropCount;
417}
418
419
420int32
421BPropertyInfo::CountValues() const
422{
423	return fValueCount;
424}
425
426
427void
428BPropertyInfo::PrintToStream() const
429{
430	printf("      property   commands                       types              "
431		"     specifiers\n");
432	printf("-------------------------------------------------------------------"
433		"-------------\n");
434
435	for (int32 pi = 0; fPropInfo[pi].name != 0; pi++) {
436		// property
437		printf("%14s", fPropInfo[pi].name);
438		// commands
439		for (int32 i = 0; i < 10 && fPropInfo[pi].commands[i] != 0; i++) {
440			uint32 command = fPropInfo[pi].commands[i];
441
442			printf("   %c%c%c%-28c", int(command & 0xFF000000) >> 24,
443				int(command & 0xFF0000) >> 16, int(command & 0xFF00) >> 8,
444				int(command) & 0xFF);
445		}
446		// types
447		for (int32 i = 0; i < 10 && fPropInfo[pi].types[i] != 0; i++) {
448			uint32 type = fPropInfo[pi].types[i];
449
450			printf("%c%c%c%c", int(type & 0xFF000000) >> 24,
451				int(type & 0xFF0000) >> 16, int(type & 0xFF00) >> 8,
452					(int)type & 0xFF);
453		}
454		// specifiers
455		for (int32 i = 0; i < 10 && fPropInfo[pi].specifiers[i] != 0; i++) {
456			uint32 spec = fPropInfo[pi].specifiers[i];
457			printf("%" B_PRIu32, spec);
458		}
459		printf("\n");
460	}
461}
462
463
464bool
465BPropertyInfo::FindCommand(uint32 what, int32 index,
466	property_info* propertyInfo)
467{
468	bool result = false;
469
470	if (propertyInfo->commands[0] == 0) {
471		result = true;
472	} else if (index == 0) {
473		for (int32 i = 0; i < 10 && propertyInfo->commands[i] != 0; i++) {
474			if (propertyInfo->commands[i] == what) {
475				result = true;
476				break;
477			}
478		}
479	}
480
481	return result;
482}
483
484
485bool
486BPropertyInfo::FindSpecifier(uint32 form, property_info* propertyInfo)
487{
488	bool result = false;
489
490	if (propertyInfo->specifiers[0] == 0) {
491		result = true;
492	} else {
493		for (int32 i = 0; i < 10 && propertyInfo->specifiers[i] != 0; i++) {
494			if (propertyInfo->specifiers[i] == form) {
495				result = true;
496				break;
497			}
498		}
499	}
500
501	return result;
502}
503
504
505void BPropertyInfo::_ReservedPropertyInfo1() {}
506void BPropertyInfo::_ReservedPropertyInfo2() {}
507void BPropertyInfo::_ReservedPropertyInfo3() {}
508void BPropertyInfo::_ReservedPropertyInfo4() {}
509
510
511BPropertyInfo::BPropertyInfo(const BPropertyInfo &)
512{
513}
514
515
516BPropertyInfo&
517BPropertyInfo::operator=(const BPropertyInfo &)
518{
519	return *this;
520}
521
522
523void
524BPropertyInfo::FreeMem()
525{
526	int i, j, k;
527
528	if (!fInHeap)
529		return;
530
531	if (fPropInfo != NULL) {
532		for (i = 0; i < fPropCount; i++) {
533			free((char *)fPropInfo[i].name);
534			free((char *)fPropInfo[i].usage);
535
536			for (j = 0; j < 3; j++) {
537				for (k = 0; k < 5; k++) {
538					if (fPropInfo[i].ctypes[j].pairs[k].name == NULL)
539						break;
540
541					free((char *)fPropInfo[i].ctypes[j].pairs[k].name);
542				}
543
544				if (fPropInfo[i].ctypes[j].pairs[0].name == NULL)
545					break;
546			}
547		}
548		free(fPropInfo);
549		fPropInfo = NULL;
550		fPropCount = 0;
551	}
552
553	if (fValueInfo != NULL) {
554		for (i = 0; i < fValueCount; i++) {
555			free((char *)fValueInfo[i].name);
556			free((char *)fValueInfo[i].usage);
557		}
558		free(fValueInfo);
559		fValueInfo = NULL;
560		fValueCount = 0;
561	}
562
563	fInHeap = false;
564}
565