xref: /haiku/src/kits/app/PropertyInfo.cpp (revision 3e216965baa8d58a67bf7372e2bfa13d999f5a9d)
1 /*
2  * Copyright 2001-2005, Haiku.
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 
20 BPropertyInfo::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 
41 BPropertyInfo::~BPropertyInfo()
42 {
43 	FreeMem();
44 }
45 
46 
47 int32 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 
70 bool
71 BPropertyInfo::IsFixedSize() const
72 {
73 	return false;
74 }
75 
76 
77 type_code
78 BPropertyInfo::TypeCode() const
79 {
80 	return B_PROPERTY_INFO_TYPE;
81 }
82 
83 
84 ssize_t
85 BPropertyInfo::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 && fPropInfo[pi].ctypes[i].pairs[0].name != 0; i++) {
117 				for (int32 j = 0; j < 5 && fPropInfo[pi].ctypes[i].pairs[j].name != 0; j++) {
118 					size += strlen(fPropInfo[pi].ctypes[i].pairs[j].name) + 1;
119 					size += sizeof(int32);
120 				}
121 				size += sizeof(int32);
122 			}
123 			size += sizeof(int32);
124 		}
125 	}
126 
127 	if (fValueInfo) {
128 		size += sizeof(int16);
129 
130 		// Chunks
131 		for (int32 vi = 0; fValueInfo[vi].name != NULL; vi++) {
132 			size += sizeof(int32);
133 			size += sizeof(int32);
134 
135 			size += strlen(fValueInfo[vi].name) + 1;
136 
137 			if (fValueInfo[vi].usage)
138 				size += strlen(fValueInfo[vi].usage) + 1;
139 			else
140 				size += sizeof(char);
141 
142 			size += sizeof(int32);
143 		}
144 	}
145 
146 	return size;
147 }
148 
149 
150 status_t
151 BPropertyInfo::Flatten(void* buffer, ssize_t numBytes) const
152 {
153 	if (numBytes < FlattenedSize())
154 		return B_NO_MEMORY;
155 
156 	if (buffer == NULL)
157 		return B_BAD_VALUE;
158 
159 	BMemoryIO flatData(buffer, numBytes);
160 
161 	char tmpChar = B_HOST_IS_BENDIAN;
162 	int32 tmpInt;
163 
164 	flatData.Write(&tmpChar, sizeof(tmpChar));
165 	flatData.Write(&fPropCount, sizeof(fPropCount));
166 	tmpInt = 0x01 | (fValueInfo ? 0x2 : 0x0);
167 	flatData.Write(&tmpInt, sizeof(tmpInt));
168 
169 	if (fPropInfo) {
170 		// Main chunks
171 		for (int32 pi = 0; fPropInfo[pi].name != NULL; pi++) {
172 			flatData.Write(fPropInfo[pi].name, strlen(fPropInfo[pi].name) + 1);
173 			if (fPropInfo[pi].usage != NULL) {
174 				flatData.Write(fPropInfo[pi].usage, strlen(fPropInfo[pi].usage) + 1);
175 			} else {
176 				tmpChar = 0;
177 				flatData.Write(&tmpChar, sizeof(tmpChar));
178 			}
179 
180 			flatData.Write(&fPropInfo[pi].extra_data, sizeof(fPropInfo[pi].extra_data));
181 
182 			for (int32 i = 0; i < 10 && fPropInfo[pi].commands[i] != 0; i++) {
183 				flatData.Write(&fPropInfo[pi].commands[i], sizeof(fPropInfo[pi].commands[i]));
184 			}
185 			tmpInt = 0;
186 			flatData.Write(&tmpInt, sizeof(tmpInt));
187 
188 			for (int32 i = 0; i < 10 && fPropInfo[pi].specifiers[i] != 0; i++) {
189 				flatData.Write(&fPropInfo[pi].specifiers[i], sizeof(fPropInfo[pi].specifiers[i]));
190 			}
191 			tmpInt = 0;
192 			flatData.Write(&tmpInt, sizeof(tmpInt));
193 		}
194 
195 		// Type chunks
196 		for (int32 pi = 0; fPropInfo[pi].name != NULL; pi++) {
197 			for (int32 i = 0; i < 10 && fPropInfo[pi].types[i] != 0; i++) {
198 				flatData.Write(&fPropInfo[pi].types[i], sizeof(fPropInfo[pi].types[i]));
199 			}
200 			tmpInt = 0;
201 			flatData.Write(&tmpInt, sizeof(tmpInt));
202 
203 			for (int32 i = 0; i < 3 && fPropInfo[pi].ctypes[i].pairs[0].name != 0; i++) {
204 				for (int32 j = 0; j < 5 && fPropInfo[pi].ctypes[i].pairs[j].name != 0; j++) {
205 					flatData.Write(fPropInfo[pi].ctypes[i].pairs[j].name,
206 						strlen(fPropInfo[pi].ctypes[i].pairs[j].name) + 1);
207 					flatData.Write(&fPropInfo[pi].ctypes[i].pairs[j].type,
208 						sizeof(fPropInfo[pi].ctypes[i].pairs[j].type));
209 				}
210 				tmpInt = 0;
211 				flatData.Write(&tmpInt, sizeof(tmpInt));
212 			}
213 			tmpInt = 0;
214 			flatData.Write(&tmpInt, sizeof(tmpInt));
215 		}
216 	}
217 
218 	if (fValueInfo) {
219 		// Value Chunks
220 		flatData.Write(&fValueCount, sizeof(fValueCount));
221 		for (int32 vi = 0; fValueInfo[vi].name != NULL; vi++) {
222 			flatData.Write(&fValueInfo[vi].kind, sizeof(fValueInfo[vi].kind));
223 			flatData.Write(&fValueInfo[vi].value, sizeof(fValueInfo[vi].value));
224 			flatData.Write(fValueInfo[vi].name, strlen(fValueInfo[vi].name) + 1);
225 			if (fValueInfo[vi].usage) {
226 				flatData.Write(fValueInfo[vi].usage, strlen(fValueInfo[vi].usage) + 1);
227 			} else {
228 				tmpChar = 0;
229 				flatData.Write(&tmpChar, sizeof(tmpChar));
230 			}
231 			flatData.Write(&fValueInfo[vi].extra_data, sizeof(fValueInfo[vi].extra_data));
232 		}
233 	}
234 
235 	return B_OK;
236 }
237 
238 
239 bool
240 BPropertyInfo::AllowsTypeCode(type_code code) const
241 {
242 	return code == B_PROPERTY_INFO_TYPE;
243 }
244 
245 
246 status_t
247 BPropertyInfo::Unflatten(type_code code, const void* buffer,
248 	ssize_t numBytes)
249 {
250 	if (!AllowsTypeCode(code))
251 		return B_BAD_TYPE;
252 
253 	if (buffer == NULL)
254 		return B_BAD_VALUE;
255 
256 	FreeMem();
257 
258 	BMemoryIO flatData(buffer, numBytes);
259 	char tmpChar = B_HOST_IS_BENDIAN;
260 	int32 tmpInt;
261 
262 	flatData.Read(&tmpChar, sizeof(tmpChar));
263 	bool swapRequired = (tmpChar != B_HOST_IS_BENDIAN);
264 
265 	flatData.Read(&fPropCount, sizeof(fPropCount));
266 
267 	int32 flags;
268 	flatData.Read(&flags, sizeof(flags));
269 	if (swapRequired) {
270 		fPropCount = B_SWAP_INT32(fPropCount);
271 		flags = B_SWAP_INT32(flags);
272 	}
273 
274 	if (flags & 1) {
275 		fPropInfo = static_cast<property_info *>(malloc(sizeof(property_info) * (fPropCount + 1)));
276 		memset(fPropInfo, 0, (fPropCount + 1) * sizeof(property_info));
277 
278 		// Main chunks
279 		for (int32 pi = 0; pi < fPropCount; pi++) {
280 			fPropInfo[pi].name = strdup(static_cast<const char*>(buffer) + flatData.Position());
281 			flatData.Seek(strlen(fPropInfo[pi].name) + 1, SEEK_CUR);
282 
283 			fPropInfo[pi].usage = strdup(static_cast<const char *>(buffer) + flatData.Position());
284 			flatData.Seek(strlen(fPropInfo[pi].usage) + 1, SEEK_CUR);
285 
286 			flatData.Read(&fPropInfo[pi].extra_data, sizeof(fPropInfo[pi].extra_data));
287 			if (swapRequired) {
288 				fPropInfo[pi].extra_data = B_SWAP_INT32(fPropInfo[pi].extra_data);
289 			}
290 
291 			flatData.Read(&tmpInt, sizeof(tmpInt));
292 			for (int32 i = 0; tmpInt != 0; i++) {
293 				if (swapRequired) {
294 					tmpInt = B_SWAP_INT32(tmpInt);
295 				}
296 				fPropInfo[pi].commands[i] = tmpInt;
297 				flatData.Read(&tmpInt, sizeof(tmpInt));
298 			}
299 
300 			flatData.Read(&tmpInt, sizeof(tmpInt));
301 			for (int32 i = 0; tmpInt != 0; i++) {
302 				if (swapRequired) {
303 					tmpInt = B_SWAP_INT32(tmpInt);
304 				}
305 				fPropInfo[pi].specifiers[i] = tmpInt;
306 				flatData.Read(&tmpInt, sizeof(tmpInt));
307 			}
308 		}
309 
310 		// Type chunks
311 		for (int32 pi = 0; pi < fPropCount; pi++) {
312 			flatData.Read(&tmpInt, sizeof(tmpInt));
313 			for (int32 i = 0; tmpInt != 0; i++) {
314 				if (swapRequired) {
315 					tmpInt = B_SWAP_INT32(tmpInt);
316 				}
317 				fPropInfo[pi].types[i] = tmpInt;
318 				flatData.Read(&tmpInt, sizeof(tmpInt));
319 			}
320 
321 			flatData.Read(&tmpInt, sizeof(tmpInt));
322 			for (int32 i = 0; tmpInt != 0; i++) {
323 				for (int32 j = 0; tmpInt != 0; j++) {
324 					flatData.Seek(-sizeof(tmpInt), SEEK_CUR);
325 					fPropInfo[pi].ctypes[i].pairs[j].name =
326 						strdup(static_cast<const char *>(buffer) + flatData.Position());
327 					flatData.Seek(strlen(fPropInfo[pi].ctypes[i].pairs[j].name) + 1, SEEK_CUR);
328 
329 					flatData.Read(&fPropInfo[pi].ctypes[i].pairs[j].type,
330 						sizeof(fPropInfo[pi].ctypes[i].pairs[j].type));
331 					if (swapRequired) {
332 						fPropInfo[pi].ctypes[i].pairs[j].type =
333 							B_SWAP_INT32(fPropInfo[pi].ctypes[i].pairs[j].type);
334 					}
335 					flatData.Read(&tmpInt, sizeof(tmpInt));
336 				}
337 				flatData.Read(&tmpInt, sizeof(tmpInt));
338 			}
339 		}
340 	}
341 
342 	if (flags & 2) {
343 		flatData.Read(&fValueCount, sizeof(fValueCount));
344 		if (swapRequired) {
345 			fValueCount = B_SWAP_INT16(fValueCount);
346 		}
347 
348 		fValueInfo = static_cast<value_info *>(malloc(sizeof(value_info) * (fValueCount + 1)));
349 		memset(fValueInfo, 0, (fValueCount + 1) * sizeof(value_info));
350 
351 		for (int32 vi = 0; vi < fValueCount; vi++) {
352 			flatData.Read(&fValueInfo[vi].kind, sizeof(fValueInfo[vi].kind));
353 			flatData.Read(&fValueInfo[vi].value, sizeof(fValueInfo[vi].value));
354 
355 			fValueInfo[vi].name = strdup(static_cast<const char *>(buffer) + flatData.Position());
356 			flatData.Seek(strlen(fValueInfo[vi].name) + 1, SEEK_CUR);
357 
358 			fValueInfo[vi].usage = strdup(static_cast<const char *>(buffer) + flatData.Position());
359 			flatData.Seek(strlen(fValueInfo[vi].usage) + 1, SEEK_CUR);
360 
361 			flatData.Read(&fValueInfo[vi].extra_data, sizeof(fValueInfo[vi].extra_data));
362 			if (swapRequired) {
363 				fValueInfo[vi].kind = static_cast<value_kind>(B_SWAP_INT32(fValueInfo[vi].kind));
364 				fValueInfo[vi].value = B_SWAP_INT32(fValueInfo[vi].value);
365 				fValueInfo[vi].extra_data = B_SWAP_INT32(fValueInfo[vi].extra_data);
366 			}
367 		}
368 	}
369 
370 	return B_OK;
371 }
372 
373 
374 const property_info*
375 BPropertyInfo::Properties() const
376 {
377 	return fPropInfo;
378 }
379 
380 
381 const value_info*
382 BPropertyInfo::Values() const
383 {
384 	return fValueInfo;
385 }
386 
387 
388 int32
389 BPropertyInfo::CountProperties() const
390 {
391 	return fPropCount;
392 }
393 
394 
395 int32
396 BPropertyInfo::CountValues() const
397 {
398 	return fValueCount;
399 }
400 
401 
402 void
403 BPropertyInfo::PrintToStream() const
404 {
405 	printf("      property   commands                       types                specifiers\n");
406 	printf("--------------------------------------------------------------------------------\n");
407 
408 	for (int32 pi = 0; fPropInfo[pi].name != 0; pi++) {
409 		// property
410 		printf("%14s", fPropInfo[pi].name);
411 		// commands
412 		for (int32 i = 0; i < 10 && fPropInfo[pi].commands[i] != 0; i++) {
413 			uint32 command = fPropInfo[pi].commands[i];
414 
415 			printf("   %c%c%c%-28c", int(command & 0xFF000000) >> 24,
416 				int(command & 0xFF0000) >> 16, int(command & 0xFF00) >> 8,
417 				int(command) & 0xFF);
418 		}
419 		// types
420 		for (int32 i = 0; i < 10 && fPropInfo[pi].types[i] != 0; i++) {
421 			uint32 type = fPropInfo[pi].types[i];
422 
423 			printf("%c%c%c%c", int(type & 0xFF000000) >> 24,
424 				int(type & 0xFF0000) >> 16, int(type & 0xFF00) >> 8, (int)type & 0xFF);
425 		}
426 		// specifiers
427 		for (int32 i = 0; i < 10 && fPropInfo[pi].specifiers[i] != 0; i++) {
428 			uint32 spec = fPropInfo[pi].specifiers[i];
429 			printf("%lu", spec);
430 		}
431 		printf("\n");
432 	}
433 }
434 
435 
436 bool
437 BPropertyInfo::FindCommand(uint32 what, int32 index, property_info *propertyInfo)
438 {
439 	bool result = false;
440 
441 	if (propertyInfo->commands[0] == 0) {
442 		result = true;
443 	} else if (index == 0) {
444 		for (int32 i = 0; i < 10 && propertyInfo->commands[i] != 0; i++) {
445 			if (propertyInfo->commands[i] == what) {
446 				result = true;
447 				break;
448 			}
449 		}
450 	}
451 
452 	return result;
453 }
454 
455 
456 bool
457 BPropertyInfo::FindSpecifier(uint32 form, property_info *propertyInfo)
458 {
459 	bool result = false;
460 
461 	if (propertyInfo->specifiers[0] == 0) {
462 		result = true;
463 	} else {
464 		for (int32 i = 0; i < 10 && propertyInfo->specifiers[i] != 0; i++) {
465 			if (propertyInfo->specifiers[i] == form) {
466 				result = true;
467 				break;
468 			}
469 		}
470 	}
471 
472 	return result;
473 }
474 
475 
476 void BPropertyInfo::_ReservedPropertyInfo1() {}
477 void BPropertyInfo::_ReservedPropertyInfo2() {}
478 void BPropertyInfo::_ReservedPropertyInfo3() {}
479 void BPropertyInfo::_ReservedPropertyInfo4() {}
480 
481 
482 BPropertyInfo::BPropertyInfo(const BPropertyInfo &)
483 {
484 }
485 
486 
487 BPropertyInfo&
488 BPropertyInfo::operator=(const BPropertyInfo &)
489 {
490 	return *this;
491 }
492 
493 
494 void
495 BPropertyInfo::FreeMem()
496 {
497 	int i, j, k;
498 
499 	if (!fInHeap)
500 		return;
501 
502 	if (fPropInfo != NULL) {
503 		for (i = 0; i < fPropCount; i++) {
504 			free(fPropInfo[i].name);
505 			free(fPropInfo[i].usage);
506 
507 			for (j = 0; j < 3; j++) {
508 				for (k = 0; k < 5; k++) {
509 					if (fPropInfo[i].ctypes[j].pairs[k].name == NULL)
510 						break;
511 
512 					free(fPropInfo[i].ctypes[j].pairs[k].name);
513 				}
514 
515 				if (fPropInfo[i].ctypes[j].pairs[0].name == NULL)
516 					break;
517 			}
518 		}
519 		free(fPropInfo);
520 		fPropInfo = NULL;
521 		fPropCount = 0;
522 	}
523 
524 	if (fValueInfo != NULL) {
525 		for (i = 0; i < fValueCount; i++) {
526 			free(fValueInfo[i].name);
527 			free(fValueInfo[i].usage);
528 		}
529 		free(fValueInfo);
530 		fValueInfo = NULL;
531 		fValueCount = 0;
532 	}
533 
534 	fInHeap = false;
535 }
536 
537