xref: /haiku/src/kits/media/ParameterWeb.cpp (revision 6dcd0ccf238263a3e5eb2e2a44e2ed0da1617a42)
1 /* ParameterWeb - implements the following classes:
2 **		BParameterWeb, BParameterGroup, BParameter, BNullParameter,
3 **		BContinuousParameter, BDiscreteParameter
4 **
5 ** Author: Zousar Shaker
6 **         Axel Dörfler, axeld@pinc-software.de
7 **         Marcus Overhagen
8 **
9 ** This file may be used under the terms of the OpenBeOS License.
10 */
11 
12 
13 #include <ParameterWeb.h>
14 #include <MediaNode.h>
15 #include <string.h>
16 #include "DataExchange.h"
17 #include "MediaMisc.h"
18 
19 
20 #include "debug.h"
21 
22 
23 /*
24 	The following is documentation on the flattened format
25 	of structures/classes in this module:
26 
27 	//--------BEGIN-CORE-BPARAMETER-STRUCT---------------------
28 	?? (0x02040607): 4 bytes
29 	BParameter Struct Size (in bytes): 4 bytes
30 	ID: 4 bytes
31 	Name String Length: 1 byte (??)
32 		Name String: 'Name String Length' bytes
33 	Kind String Length: 1 byte (??)
34 		Kind String: 'Kind String Length' bytes
35 	Unit String Length: 1 byte (??)
36 		Unit String: 'Unit String Length' bytes
37 	Inputs Count: 4 bytes
38 		Inputs (pointers): ('Inputs Count')*4 bytes
39 	Outputs Count: 4 bytes
40 		Outputs (pointers): ('Outputs Count')*4 bytes
41 	Media Type: 4 bytes
42 	ChannelCount: 4 bytes
43 	Flags: 4 bytes
44 	//---------END-CORE-BPARAMETER-STRUCT-----------------------
45 	//--------BEGIN-BCONTINUOUSPARAMETER-STRUCT---------
46 	Min: 4 bytes (as float)
47 	Max: 4 bytes (as float)
48 	Stepping: 4 bytes (as float)
49 	Response: 4 bytes (as int or enum)
50 	Factor: 4 bytes (as float)
51 	Offset: 4 bytes (as float)
52 	//--------END-BCONTINUOUSPARAMETER-STRUCT-------------
53 	//--------BEGIN-BDISCRETEPARAMETER-STRUCT----------------
54 	NumItems: 4 bytes (as int)
55 		//for each item BEGIN
56 		Item Name String Length: 1 byte
57 			Item Name String: 'Item Name String Length' bytes
58 		Item Value: 4 bytes (as int)
59 		//for each item END
60 	//--------END-BDISCRETEPARAMETER-STRUCT-------------------
61 
62 	//--------BEGIN-CORE-BPARAMETERGROUP-STRUCT-----------
63 	?? (0x03040507 OR 0x03040509 depending if the flags field is included or not???): 4 bytes
64 	(possible) Flags: 4 bytes
65 	Name String Length: 1 byte (??)
66 		Name String: 'Name String Length' bytes
67 	Param Count: 4 bytes
68 		//for each Param BEGIN
69 		Pointer: 4 bytes
70 		Parameter Type: 4 bytes
71 		Flattened Parameter Size: 4 bytes
72 		Flattened Parameter: 'Flattened Parameter Size' bytes
73 		//for each Param END
74 	Subgroup Count: 4 bytes
75 		//for each SubGroup BEGIN
76 		Pointer: 4 bytes
77 		MEDIA PARAMETER GROUP TYPE('BMCG' (opposite byte order in file)): 4 bytes
78 		Flattened Group Size: 4 bytes
79 		Flattened Group: 'Flattened Group Size' bytes
80 		//for each SubGroup END
81 
82 	//---------END-CORE-BPARAMETERGROUP-STRUCT--------------
83 
84 	//--------BEGIN-CORE-BPARAMETERWEB-STRUCT-----------
85 	?? 0x01030506: 4 bytes
86 	??: 4 bytes (is always 1)
87 	Group Count: 4 bytes
88 	Node (as media_node): 0x18 bytes (decimal 24 bytes)
89 		//for each Group BEGIN
90 		Flattened Group Size: 4 bytes
91 		Flattened Group: 'Flattened Group Size' bytes
92 		//for each Group END
93 		//for each Group BEGIN
94 		??: 4 bytes (never get written to (holds uninitialized value))
95 		//for each Group END
96 	//---------END-CORE-BPARAMETERWEB-STRUCT--------------
97 
98 */
99 
100 
101 const char * const B_GENERIC			 = "";
102 const char * const B_MASTER_GAIN		 = "Master";
103 const char * const B_GAIN				 = "Gain";
104 const char * const B_BALANCE			 = "Balance";
105 const char * const B_FREQUENCY			 = "Frequency";
106 const char * const B_LEVEL				 = "Level";
107 const char * const B_SHUTTLE_SPEED		 = "Speed";
108 const char * const B_CROSSFADE			 = "XFade";
109 const char * const B_EQUALIZATION		 = "EQ";
110 const char * const B_COMPRESSION		 = "Compression";
111 const char * const B_QUALITY			 = "Quality";
112 const char * const B_BITRATE			 = "Bitrate";
113 const char * const B_GOP_SIZE			 = "GOPSize";
114 const char * const B_MUTE				 = "Mute";
115 const char * const B_ENABLE				 = "Enable";
116 const char * const B_INPUT_MUX			 = "Input";
117 const char * const B_OUTPUT_MUX			 = "Output";
118 const char * const B_TUNER_CHANNEL		 = "Channel";
119 const char * const B_TRACK				 = "Track";
120 const char * const B_RECSTATE			 = "RecState";
121 const char * const B_SHUTTLE_MODE		 = "Shuttle";
122 const char * const B_RESOLUTION			 = "Resolution";
123 const char * const B_COLOR_SPACE		 = "Colorspace";
124 const char * const B_FRAME_RATE			 = "FrameRate";
125 const char * const B_VIDEO_FORMAT		 = "VideoFormat";
126 const char * const B_WEB_PHYSICAL_INPUT	 = "PhysInput";
127 const char * const B_WEB_PHYSICAL_OUTPUT = "PhysOutput";
128 const char * const B_WEB_ADC_CONVERTER	 = "ADC";
129 const char * const B_WEB_DAC_CONVERTER	 = "DAC";
130 const char * const B_WEB_LOGICAL_INPUT	 = "LogInput";
131 const char * const B_WEB_LOGICAL_OUTPUT	 = "LogOutput";
132 const char * const B_WEB_LOGICAL_BUS	 = "LogBus";
133 const char * const B_WEB_BUFFER_INPUT	 = "DataInput";
134 const char * const B_WEB_BUFFER_OUTPUT	 = "DataOutput";
135 const char * const B_SIMPLE_TRANSPORT	 = "SimpleTransport";
136 
137 // Flattened data
138 
139 static const int32 kCurrentParameterWebVersion = 1;
140 static const uint32 kParameterWebMagic = 0x01030506;
141 static const uint32 kBufferGroupMagic = 0x03040509;
142 static const uint32 kBufferGroupMagicNoFlags = 0x03040507;
143 static const uint32 kParameterMagic = 0x02040607;
144 
145 static const ssize_t kAdditionalParameterGroupSize = 12;
146 static const ssize_t kAdditionalParameterSize = 35;
147 
148 /* BContinuousParameter - FlattenedSize() fixed part
149  *	Min: 4 bytes (as float)
150  *	Max: 4 bytes (as float)
151  *	Stepping: 4 bytes (as float)
152  *	Response: 4 bytes (as int or enum)
153  *	Factor: 4 bytes (as float)
154  *	Offset: 4 bytes (as float)
155  */
156 static const ssize_t kAdditionalContinuousParameterSize = 24;
157 static const ssize_t kAdditionalDiscreteParameterSize = sizeof(ssize_t);
158 
159 
160 // helper functions
161 
162 
163 template<class Type> Type
164 read_from_buffer(const void **_buffer)
165 {
166 	const Type *typedBuffer = static_cast<const Type *>(*_buffer);
167 	Type value = *typedBuffer;
168 
169 	typedBuffer++;
170 	*_buffer = static_cast<const void *>(typedBuffer);
171 
172 	return value;
173 }
174 
175 
176 static status_t
177 read_string_from_buffer(const void **_buffer, char **_string, ssize_t size)
178 {
179 	if (size < 1)
180 		return B_BAD_VALUE;
181 
182 	const uint8 *buffer = static_cast<const uint8 *>(*_buffer);
183 	uint8 length = *buffer++;
184 	if (length > size - 1)
185 		return B_BAD_VALUE;
186 
187 	char *string = (char *)malloc(length + 1);
188 	if (string == NULL)
189 		return B_NO_MEMORY;
190 
191 	memcpy(string, buffer, length);
192 	string[length] = '\0';
193 
194 	*_buffer = static_cast<const void *>(buffer + length);
195 	*_string = string;
196 	return B_OK;
197 }
198 
199 
200 // currently unused
201 #if 0
202 template<class Type> Type *
203 reserve_in_buffer(void **_buffer)
204 {
205 	Type *typedBuffer = static_cast<Type *>(*_buffer);
206 
207 	*typedBuffer = 0;
208 	typedBuffer++;
209 
210 	*_buffer = static_cast<void *>(typedBuffer);
211 }
212 #endif
213 
214 template<class Type> void
215 write_to_buffer(void **_buffer, Type value)
216 {
217 	Type *typedBuffer = static_cast<Type *>(*_buffer);
218 
219 	*typedBuffer = value;
220 	typedBuffer++;
221 
222 	*_buffer = static_cast<void *>(typedBuffer);
223 }
224 
225 
226 void
227 write_string_to_buffer(void **_buffer, const char *string)
228 {
229 	uint8 *buffer = static_cast<uint8 *>(*_buffer);
230 	uint32 length = string ? strlen(string) : 0;
231 	if (length > 255)
232 		length = 255;
233 
234 	*buffer++ = static_cast<uint8>(length);
235 	if (length) {
236 		memcpy(buffer, string, length);
237 		buffer += length;
238 	}
239 
240 	*_buffer = static_cast<void *>(buffer);
241 }
242 
243 
244 static void
245 skip_in_buffer(const void **_buffer, uint32 bytes)
246 {
247 	const uint8 *buffer = static_cast<const uint8 *>(*_buffer);
248 
249 	buffer += bytes;
250 
251 	*_buffer = static_cast<const void *>(buffer);
252 }
253 
254 
255 static void inline
256 skip_in_buffer(void **_buffer, uint32 bytes)
257 {
258 	// This actually shouldn't be necessary, but I believe it's a
259 	// bug in Be's gcc - it complains about "adds cv-quals without intervening `const'"
260 	// when passing a "const void **" pointer as the first argument.
261 	// Maybe I am just stupid, though -- axeld.
262 
263 	skip_in_buffer((const void **)_buffer, bytes);
264 }
265 
266 
267 template<class Type> Type
268 swap32(Type value, bool doSwap)
269 {
270 	STATIC_ASSERT(sizeof(Type) == 4);
271 
272 	if (doSwap)
273 		return (Type)B_SWAP_INT32((int32)value);
274 
275 	return value;
276 }
277 
278 
279 template<class Type> Type
280 read_from_buffer_swap32(const void **_buffer, bool doSwap)
281 {
282 	return swap32<Type>(read_from_buffer<Type>(_buffer), doSwap);
283 }
284 
285 
286 static inline ssize_t
287 size_left(ssize_t size, const void *bufferStart, const void *buffer)
288 {
289 	return size - static_cast<ssize_t>((const uint8 *)buffer - (const uint8 *)bufferStart);
290 }
291 
292 
293 /** Copies the source string into a new buffer with the specified
294  *	maximum size. This always includes a trailing zero byte.
295  *	Returns NULL if the source string is either NULL or empty, or
296  *	if there wasn't enough memory to allocate the buffer.
297  *	The buffer returned is to be freed by the caller using free().
298  */
299 
300 static char *
301 strndup(const char *source, size_t maxBufferSize)
302 {
303 	if (source == NULL || source[0] == '\0')
304 		return NULL;
305 
306 	uint32 size = strlen(source) + 1;
307 	if (size > maxBufferSize)
308 		size = maxBufferSize;
309 
310 	char *target = (char *)malloc(size);
311 	if (target == NULL)
312 		return NULL;
313 
314 	memcpy(target, source, size - 1);
315 	target[size - 1] = '\0';
316 
317 	return target;
318 }
319 
320 
321 //	#pragma mark -
322 
323 /*************************************************************
324  * public BParameterWeb
325  *************************************************************/
326 
327 
328 BParameterWeb::BParameterWeb()
329 	:	mNode(media_node::null) // mNode is set in BControllable::SetParameterWeb()
330 {
331 	CALLED();
332 
333 	mGroups = new BList();
334 
335 	mOldRefs = new BList();
336 	mNewRefs = new BList();
337 
338 	ASSERT(mGroups != NULL && mOldRefs != NULL && mNewRefs != NULL);
339 }
340 
341 
342 BParameterWeb::~BParameterWeb()
343 {
344 	CALLED();
345 
346 	if (mGroups != NULL) {
347 		for(int32 i = mGroups->CountItems(); i-- > 0;) {
348 			delete static_cast<BParameterGroup *>(mGroups->ItemAt(i));
349 		}
350 
351 		delete mGroups;
352 	}
353 
354 	delete mOldRefs;
355 	delete mNewRefs;
356 }
357 
358 
359 media_node
360 BParameterWeb::Node()
361 {
362 	return mNode;
363 }
364 
365 
366 BParameterGroup *
367 BParameterWeb::MakeGroup(const char *name)
368 {
369 	CALLED();
370 	ASSERT(mGroups != NULL);
371 
372 	BParameterGroup *group = new BParameterGroup(this, name);
373 	mGroups->AddItem(group);
374 
375 	return group;
376 }
377 
378 
379 int32
380 BParameterWeb::CountGroups()
381 {
382 	ASSERT(mGroups != NULL);
383 
384 	return mGroups->CountItems();
385 }
386 
387 
388 BParameterGroup *
389 BParameterWeb::GroupAt(int32 index)
390 {
391 	ASSERT(mGroups != NULL);
392 
393 	return static_cast<BParameterGroup *>(mGroups->ItemAt(index));
394 }
395 
396 
397 int32
398 BParameterWeb::CountParameters()
399 {
400 	CALLED();
401 	ASSERT(mGroups != NULL);
402 
403 	// Counts over all groups (and sub-groups) in the web.
404 	// The "groups" list is used as count stack
405 
406 	BList groups(*mGroups);
407 	int32 count = 0;
408 
409 	for (int32 i = 0; i < groups.CountItems(); i++) {
410 		BParameterGroup *group = static_cast<BParameterGroup *>(groups.ItemAt(i));
411 
412 		count += group->CountParameters();
413 
414 		if (group->mGroups != NULL)
415 			groups.AddList(group->mGroups);
416 	}
417 
418 	return count;
419 }
420 
421 
422 BParameter *
423 BParameterWeb::ParameterAt(int32 index)
424 {
425 	CALLED();
426 	ASSERT(mGroups != NULL);
427 
428 	// Iterates over all groups (and sub-groups) in the web.
429 	// The "groups" list is used as iteration stack (breadth search style)
430 	// Maintains the same order as the Be implementation
431 
432 	BList groups(*mGroups);
433 
434 	for (int32 i = 0; i < groups.CountItems(); i++) {
435 		BParameterGroup *group = static_cast<BParameterGroup *>(groups.ItemAt(i));
436 		int32 count = group->CountParameters();
437 		if (index < count)
438 			return group->ParameterAt(index);
439 
440 		index -= count;
441 			// the index is always relative to the start of the current group
442 
443 		if (group->mGroups != NULL)
444 			groups.AddList(group->mGroups);
445 	}
446 
447 	TRACE("*** could not find parameter at %ld (count = %ld)\n", index, CountParameters());
448 	return NULL;
449 }
450 
451 
452 bool
453 BParameterWeb::IsFixedSize() const
454 {
455 	return false;
456 }
457 
458 
459 type_code
460 BParameterWeb::TypeCode() const
461 {
462 	return B_MEDIA_PARAMETER_WEB_TYPE;
463 }
464 
465 
466 ssize_t
467 BParameterWeb::FlattenedSize() const
468 {
469 	CALLED();
470 
471 /*
472 	//--------BEGIN-CORE-BPARAMETERWEB-STRUCT-----------
473 	?? 0x01030506: 4 bytes
474 	??: 4 bytes (is always 1)
475 	Group Count: 4 bytes
476 	Node (as media_node): 0x18 bytes (decimal 24 bytes)
477 		//for each Group BEGIN
478 		Flattened Group Size: 4 bytes
479 		Flattened Group: 'Flattened Group Size' bytes
480 		//for each Group END
481 		//for each Group BEGIN
482 		??: 4 bytes (never get written to (holds uninitialized value))
483 		//for each Group END
484 	//---------END-CORE-BPARAMETERWEB-STRUCT--------------
485 */
486 	//36 guaranteed bytes, variable after that.
487 	ssize_t size = sizeof(int32) + 2*sizeof(int32) + sizeof(media_node);
488 
489 	for (int32 i = mGroups->CountItems(); i-- > 0;) {
490 		BParameterGroup *group = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
491 		if (group != NULL) {
492 			size += 4 + group->FlattenedSize();
493 				// 4 bytes for the flattened size
494 		}
495 	}
496 
497 	return size;
498 }
499 
500 
501 status_t
502 BParameterWeb::Flatten(void *buffer, ssize_t size) const
503 {
504 	CALLED();
505 
506 	if (buffer == NULL)
507 		return B_NO_INIT;
508 
509 	ssize_t actualSize = BParameterWeb::FlattenedSize();
510 	if (size < actualSize)
511 		return B_NO_MEMORY;
512 
513 	void *bufferStart = buffer;
514 
515 	write_to_buffer<int32>(&buffer, kParameterWebMagic);
516 	write_to_buffer<int32>(&buffer, kCurrentParameterWebVersion);
517 
518 	// flatten all groups into this buffer
519 
520 	int32 count = mGroups ? mGroups->CountItems() : 0;
521 	write_to_buffer<int32>(&buffer, count);
522 
523 	write_to_buffer<media_node>(&buffer, mNode);
524 
525 	for (int32 i = 0; i < count; i++) {
526 		BParameterGroup *group = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
527 		if (group == NULL) {
528 			ERROR("BParameterWeb::Flatten(): group is NULL\n");
529 			continue;
530 		}
531 
532 		ssize_t groupSize = group->FlattenedSize();
533 		if (groupSize > size_left(size, bufferStart, buffer)) {
534 			ERROR("BParameterWeb::Flatten(): buffer too small\n");
535 			return B_BAD_VALUE;
536 		}
537 
538 		write_to_buffer<ssize_t>(&buffer, groupSize);
539 
540 		// write the flattened sub group
541 		status_t status = group->Flatten(buffer, groupSize);
542 		if (status < B_OK)
543 			return status;
544 
545 		skip_in_buffer(&buffer, groupSize);
546 	}
547 
548 	return B_OK;
549 }
550 
551 
552 bool
553 BParameterWeb::AllowsTypeCode(type_code code) const
554 {
555 	return code == TypeCode();
556 }
557 
558 
559 status_t
560 BParameterWeb::Unflatten(type_code code, const void *buffer, ssize_t size)
561 {
562 	CALLED();
563 
564 	if (!AllowsTypeCode(code)) {
565 		ERROR("BParameterWeb::Unflatten(): wrong type code\n");
566 		return B_BAD_TYPE;
567 	}
568 
569 	if (buffer == NULL) {
570 		ERROR("BParameterWeb::Unflatten(): NULL buffer pointer\n");
571 		return B_NO_INIT;
572 	}
573 
574 	// if the buffer is smaller than the size needed to read the
575 	// signature field, the mystery field, the group count, and the Node, then there is a problem
576 	if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(int32) + sizeof(ssize_t) + sizeof(media_node)) )
577 	{
578 		ERROR("BParameterWeb::Unflatten(): size to small\n");
579 		return B_ERROR;
580 	}
581 
582 	const void *bufferStart = buffer;
583 
584 	uint32 magic = read_from_buffer<uint32>(&buffer);
585 	bool isSwapped = false;
586 
587 	if (magic == B_SWAP_INT32(kParameterWebMagic)) {
588 		isSwapped = true;
589 		magic = B_SWAP_INT32(magic);
590 	}
591 	if (magic != kParameterWebMagic)
592 		return B_BAD_DATA;
593 
594 	// Note, it's not completely sure that this field is the version
595 	// information - but it doesn't seem to have another purpose
596 	int32 version = read_from_buffer_swap32<int32>(&buffer, isSwapped);
597 	if (version != kCurrentParameterWebVersion) {
598 		ERROR("BParameterWeb::Unflatten(): wrong version %ld (%lx)?!\n", version, version);
599 		return B_ERROR;
600 	}
601 
602 #if 0
603 	if(mGroups != NULL)
604 	{
605 		for (int32 i = 0; i < mGroups->CountItems(); i++)
606 		{
607 			BParameterGroup *CurrentItem = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
608 			if(CurrentItem != NULL)
609 			{
610 				delete CurrentItem;
611 			}
612 		}
613 		mGroups->MakeEmpty();
614 	}
615 	else
616 	{
617 		mGroups = new BList();
618 	}
619 #endif
620 
621 	int32 count = read_from_buffer_swap32<int32>(&buffer, isSwapped);
622 
623 	mNode = read_from_buffer<media_node>(&buffer);
624 	if (isSwapped)
625 		swap_data(B_INT32_TYPE, &mNode, sizeof(media_node), B_SWAP_ALWAYS);
626 
627 	for (int32 i = 0; i < count; i++) {
628 		ssize_t groupSize = read_from_buffer_swap32<ssize_t>(&buffer, isSwapped);
629 		if (groupSize > size_left(size, bufferStart, buffer)) {
630 			ERROR("BParameterWeb::Unflatten(): buffer too small\n");
631 			return B_BAD_DATA;
632 		}
633 
634 		BParameterGroup *group = new BParameterGroup(this, "unnamed");
635 		status_t status = group->Unflatten(group->TypeCode(), buffer, groupSize);
636 		if (status < B_OK) {
637 			ERROR("BParameterWeb::Unflatten(): unflatten group failed\n");
638 			delete group;
639 			return status;
640 		}
641 
642 		skip_in_buffer(&buffer, groupSize);
643 
644 		mGroups->AddItem(group);
645 	}
646 
647 	// fix all references (ParameterAt() style)
648 
649 	if ((mOldRefs != NULL) && (mNewRefs != NULL)) {
650 		BList groups(*mGroups);
651 
652 		for (int32 i = 0; i < groups.CountItems(); i++) {
653 			BParameterGroup *group = static_cast<BParameterGroup *>(groups.ItemAt(i));
654 
655 			for (int32 index = group->CountParameters(); index-- > 0;) {
656 				BParameter *parameter = static_cast<BParameter *>(group->ParameterAt(index));
657 
658 				parameter->FixRefs(*mOldRefs, *mNewRefs);
659 			}
660 
661 			if (group->mGroups != NULL)
662 				groups.AddList(group->mGroups);
663 		}
664 
665 		mOldRefs->MakeEmpty();
666 		mNewRefs->MakeEmpty();
667 	}
668 
669 	return B_OK;
670 }
671 
672 /*************************************************************
673  * private BParameterWeb
674  *************************************************************/
675 
676 /*
677 unimplemented
678 BParameterWeb::BParameterWeb(const BParameterWeb &clone)
679 BParameterWeb &BParameterWeb::operator=(const BParameterWeb &clone)
680 */
681 
682 
683 void
684 BParameterWeb::AddRefFix(void *oldItem, void *newItem)
685 {
686 	ASSERT(mOldRefs != NULL);
687 	ASSERT(mNewRefs != NULL);
688 
689 	mOldRefs->AddItem(oldItem);
690 	mNewRefs->AddItem(newItem);
691 }
692 
693 
694 //	#pragma mark -
695 
696 /*************************************************************
697  * private BParameterGroup
698  *************************************************************/
699 
700 
701 BParameterGroup::BParameterGroup(BParameterWeb *web, const char *name)
702 	:	mWeb(web),
703 	mFlags(0)
704 {
705 	CALLED();
706 	TRACE("BParameterGroup: web = %p, name = \"%s\"\n", web, name);
707 
708 	mName = strndup(name, 256);
709 
710 	mControls = new BList();
711 	mGroups = new BList();
712 }
713 
714 
715 BParameterGroup::~BParameterGroup()
716 {
717 	CALLED();
718 
719 	if (mControls) {
720 		BParameter **items = reinterpret_cast<BParameter **>(mControls->Items());
721 		for (int i = mControls->CountItems(); i-- > 0;)
722 			delete items[i];
723 
724 		delete mControls;
725 	}
726 
727 	if (mGroups) {
728 		BParameterGroup **items = reinterpret_cast<BParameterGroup **>(mGroups->Items());
729 		for (int i = mGroups->CountItems(); i-- > 0;)
730 			delete items[i];
731 
732 		delete mGroups;
733 	}
734 
735 	free(mName);
736 }
737 
738 /*************************************************************
739  * public BParameterGroup
740  *************************************************************/
741 
742 BParameterWeb *
743 BParameterGroup::Web() const
744 {
745 	return mWeb;
746 }
747 
748 
749 const char *
750 BParameterGroup::Name() const
751 {
752 	return mName;
753 }
754 
755 
756 void
757 BParameterGroup::SetFlags(uint32 flags)
758 {
759 	mFlags = flags;
760 }
761 
762 
763 uint32
764 BParameterGroup::Flags() const
765 {
766 	return mFlags;
767 }
768 
769 
770 BNullParameter *
771 BParameterGroup::MakeNullParameter(int32 id, media_type mediaType, const char *name,
772 	const char *kind)
773 {
774 	CALLED();
775 	ASSERT(mControls != NULL);
776 
777 	BNullParameter *parameter = new BNullParameter(id, mediaType, mWeb, name, kind);
778 	parameter->mGroup = this;
779 	mControls->AddItem(parameter);
780 
781 	return parameter;
782 }
783 
784 
785 BTextParameter *
786 BParameterGroup::MakeTextParameter(int32 id, media_type mediaType, const char *name,
787 	const char *kind, size_t max_bytes)
788 {
789 	CALLED();
790 	ASSERT(mControls != NULL);
791 
792 	BTextParameter *parameter = new BTextParameter(id, mediaType, mWeb, name, kind, max_bytes);
793 	parameter->mGroup = this;
794 	mControls->AddItem(parameter);
795 
796 	return parameter;
797 }
798 
799 
800 BContinuousParameter *
801 BParameterGroup::MakeContinuousParameter(int32 id, media_type mediaType,
802 	const char *name, const char *kind, const char *unit,
803 	float minimum, float maximum, float stepping)
804 {
805 	CALLED();
806 	ASSERT(mControls != NULL);
807 
808 	BContinuousParameter *parameter = new BContinuousParameter(id, mediaType, mWeb,
809 		name, kind, unit, minimum, maximum, stepping);
810 
811 	parameter->mGroup = this;
812 	mControls->AddItem(parameter);
813 
814 	return parameter;
815 }
816 
817 
818 BDiscreteParameter *
819 BParameterGroup::MakeDiscreteParameter(int32 id, media_type mediaType,
820 	const char *name, const char *kind)
821 {
822 	CALLED();
823 	ASSERT(mControls != NULL);
824 
825 	BDiscreteParameter *parameter = new BDiscreteParameter(id, mediaType, mWeb, name, kind);
826 	if (parameter == NULL)
827 		return NULL;
828 
829 	parameter->mGroup = this;
830 	mControls->AddItem(parameter);
831 
832 	return parameter;
833 }
834 
835 
836 BParameterGroup *
837 BParameterGroup::MakeGroup(const char *name)
838 {
839 	CALLED();
840 	ASSERT(mGroups != NULL);
841 
842 	BParameterGroup *group = new BParameterGroup(mWeb, name);
843 	if (group != NULL)
844 		mGroups->AddItem(group);
845 
846 	return group;
847 }
848 
849 
850 int32
851 BParameterGroup::CountParameters()
852 {
853 	ASSERT(mControls != NULL);
854 
855 	return mControls->CountItems();
856 }
857 
858 
859 BParameter *
860 BParameterGroup::ParameterAt(int32 index)
861 {
862 	ASSERT(mControls != NULL);
863 
864 	return static_cast<BParameter *>(mControls->ItemAt(index));
865 }
866 
867 
868 int32
869 BParameterGroup::CountGroups()
870 {
871 	ASSERT(mGroups != NULL);
872 
873 	return mGroups->CountItems();
874 }
875 
876 
877 BParameterGroup *
878 BParameterGroup::GroupAt(int32 index)
879 {
880 	ASSERT(mGroups != NULL);
881 
882 	return static_cast<BParameterGroup *>(mGroups->ItemAt(index));
883 }
884 
885 
886 bool
887 BParameterGroup::IsFixedSize() const
888 {
889 	return false;
890 }
891 
892 
893 type_code
894 BParameterGroup::TypeCode() const
895 {
896 	return B_MEDIA_PARAMETER_GROUP_TYPE;
897 }
898 
899 
900 ssize_t
901 BParameterGroup::FlattenedSize() const
902 {
903 	CALLED();
904 	ASSERT(mControls != NULL);
905 	ASSERT(mGroups != NULL);
906 
907 	/*
908 		//--------BEGIN-CORE-BPARAMETERGROUP-STRUCT-----------
909 		?? (0x03040507 OR 0x03040509 depending if the flags field is included or not???): 4 bytes
910 		(possible) Flags: 4 bytes
911 		Name String Length: 1 byte (??)
912 			Name String: 'Name String Length' bytes
913 		Param Count: 4 bytes
914 			//for each Param BEGIN
915 			Pointer: 4 bytes
916 			Parameter Type: 4 bytes
917 			Flattened Parameter Size: 4 bytes
918 			Flattened Parameter: 'Flattened Parameter Size' bytes
919 			//for each Param END
920 		Subgroup Count: 4 bytes
921 			//for each SubGroup BEGIN
922 			Pointer: 4 bytes
923 			MEDIA PARAMETER GROUP TYPE('BMCG' (opposite byte order in file)): 4 bytes
924 			Flattened Group Size: 4 bytes
925 			Flattened Group: 'Flattened Group Size' bytes
926 			//for each SubGroup END
927 
928 		//---------END-CORE-BPARAMETERGROUP-STRUCT--------------
929 	*/
930 	//13 guaranteed bytes, variable after that.
931 	ssize_t size = 13;
932 
933 	if(mFlags != 0)
934 	{
935 		size += 4;
936 	}
937 
938 	if(mName != NULL)
939 	{
940 		size += min_c(strlen(mName),255);
941 	}
942 
943 	int i;
944 	int limit;
945 
946 	limit = mControls->CountItems();
947 	for(i = 0; i < limit; i++)
948 	{
949 		BParameter *CurrentParameter = static_cast<BParameter *>(mControls->ItemAt(i));
950 		if(CurrentParameter != NULL)
951 		{
952 			//overhead for each parameter flattened
953 			size += 16 + CurrentParameter->FlattenedSize();
954 		}
955 	}
956 
957 	limit = mGroups->CountItems();
958 	for(i = 0; i < limit; i++)
959 	{
960 		BParameterGroup *CurrentGroup = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
961 		if(CurrentGroup != NULL)
962 		{
963 			//overhead for each group flattened
964 			size += 16 + CurrentGroup->FlattenedSize();
965 		}
966 	}
967 
968 	return size;
969 }
970 
971 
972 status_t
973 BParameterGroup::Flatten(void *buffer, ssize_t size) const
974 {
975 	CALLED();
976 
977 	if (buffer == NULL) {
978 		ERROR("BParameterGroup::Flatten buffer is NULL\n");
979 		return B_NO_INIT;
980 	}
981 
982 	// NOTICE: It is important that this value is the size returned by
983 	// BParameterGroup::FlattenedSize, not by a descendent's override of this method.
984 	ssize_t actualSize = BParameterGroup::FlattenedSize();
985 	if (size < actualSize) {
986 		ERROR("BParameterGroup::Flatten size to small\n");
987 		return B_NO_MEMORY;
988 	}
989 
990 	if (mFlags != 0) {
991 		write_to_buffer<int32>(&buffer, kBufferGroupMagic);
992 		write_to_buffer<uint32>(&buffer, mFlags);
993 	} else
994 		write_to_buffer<int32>(&buffer, kBufferGroupMagicNoFlags);
995 
996 	write_string_to_buffer(&buffer, mName);
997 
998 	int32 count = mControls ? mControls->CountItems() : 0;
999 	write_to_buffer<int32>(&buffer, count);
1000 
1001 	for (int32 i = 0; i < count; i++) {
1002 		BParameter *parameter = static_cast<BParameter *>(mControls->ItemAt(i));
1003 		if (parameter == NULL) {
1004 			ERROR("BParameterGroup::Flatten(): NULL parameter\n");
1005 			continue;
1006 		}
1007 
1008 		write_to_buffer<BParameter *>(&buffer, parameter);
1009 		write_to_buffer<BParameter::media_parameter_type>(&buffer, parameter->Type());
1010 
1011 		// flatten parameter into this buffer
1012 
1013 		ssize_t parameterSize = parameter->FlattenedSize();
1014 		write_to_buffer<ssize_t>(&buffer, parameterSize);
1015 
1016 		status_t status = parameter->Flatten(buffer, parameterSize);
1017 			// we have only that much bytes left to write in this buffer
1018 		if (status < B_OK)
1019 			return status;
1020 
1021 		skip_in_buffer(&buffer, parameterSize);
1022 	}
1023 
1024 	count = mGroups ? mGroups->CountItems() : 0;
1025 	write_to_buffer<int32>(&buffer, count);
1026 
1027 	for (int32 i = 0; i < count; i++) {
1028 		BParameterGroup *group = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
1029 		if (group == NULL) {
1030 			ERROR("BParameterGroup::Flatten(): NULL group\n");
1031 			continue;
1032 		}
1033 
1034 		write_to_buffer<BParameterGroup *>(&buffer, group);
1035 		write_to_buffer<type_code>(&buffer, group->TypeCode());
1036 
1037 		// flatten sub group into this buffer
1038 
1039 		ssize_t groupSize = group->FlattenedSize();
1040 		write_to_buffer<ssize_t>(&buffer, groupSize);
1041 
1042 		status_t status = group->Flatten(buffer, groupSize);
1043 			// we have only that much bytes left to write in this buffer
1044 		if (status < B_OK)
1045 			return status;
1046 
1047 		skip_in_buffer(&buffer, groupSize);
1048 	}
1049 
1050 	return B_OK;
1051 }
1052 
1053 
1054 bool
1055 BParameterGroup::AllowsTypeCode(type_code code) const
1056 {
1057 	return code == TypeCode();
1058 }
1059 
1060 
1061 status_t
1062 BParameterGroup::Unflatten(type_code code, const void *buffer, ssize_t size)
1063 {
1064 	CALLED();
1065 
1066 	if (!AllowsTypeCode(code)) {
1067 		ERROR("BParameterGroup::Unflatten() wrong type code\n");
1068 		return B_BAD_TYPE;
1069 	}
1070 
1071 	if (buffer == NULL) {
1072 		ERROR("BParameterGroup::Unflatten() buffer is NULL\n");
1073 		return B_NO_INIT;
1074 	}
1075 
1076 	// if the buffer is smaller than the size needed to read the
1077 	// signature field, then there is a problem
1078 	if (size < static_cast<ssize_t>(sizeof(int32))) {
1079 		ERROR("BParameterGroup::Unflatten() size to small\n");
1080 		return B_ERROR;
1081 	}
1082 
1083 	const void *bufferStart = buffer;
1084 		// used to compute the rest length of the buffer when needed
1085 
1086 	uint32 magic = read_from_buffer<uint32>(&buffer);
1087 	bool isSwapped = false;
1088 
1089 	if (magic == B_SWAP_INT32(kBufferGroupMagic)
1090 		|| magic == B_SWAP_INT32(kBufferGroupMagicNoFlags)) {
1091 		isSwapped = true;
1092 		magic = B_SWAP_INT32(magic);
1093 	}
1094 
1095 	if (magic == kBufferGroupMagic)
1096 		mFlags = read_from_buffer_swap32<int32>(&buffer, isSwapped);
1097 	else if (magic == kBufferGroupMagicNoFlags)
1098 		mFlags = 0;
1099 	else
1100 		return B_BAD_TYPE;
1101 
1102 	if (read_string_from_buffer(&buffer, &mName,
1103 			size - static_cast<ssize_t>((uint8 *)buffer - (uint8 *)bufferStart)) < B_OK)
1104 		return B_BAD_VALUE;
1105 
1106 	// Currently disabled since it's not really used -- axeld.
1107 #if 0
1108 	//Clear all existing parameters/subgroups
1109 	int i;
1110 	if(mControls != NULL)
1111 	{
1112 		for(i = 0; i < mControls->CountItems(); i++)
1113 		{
1114 			BParameter *CurrentItem = static_cast<BParameter *>(mControls->ItemAt(i));
1115 			if(CurrentItem != NULL)
1116 			{
1117 				delete CurrentItem;
1118 			}
1119 		}
1120 		mControls->MakeEmpty();
1121 	}
1122 	else
1123 	{
1124 		mControls = new BList();
1125 	}
1126 
1127 	if(mGroups != NULL)
1128 	{
1129 		for(i = 0; i < mGroups->CountItems(); i++)
1130 		{
1131 			BParameterGroup *CurrentItem = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
1132 			if(CurrentItem != NULL)
1133 			{
1134 				delete CurrentItem;
1135 			}
1136 		}
1137 		mGroups->MakeEmpty();
1138 	}
1139 	else
1140 	{
1141 		mGroups = new BList();
1142 	}
1143 #endif
1144 
1145 	// unflatten parameter list
1146 
1147 	int32 count = read_from_buffer_swap32<int32>(&buffer, isSwapped);
1148 	if (count < 0 || count * kAdditionalParameterSize > size_left(size, bufferStart, buffer))
1149 		return B_BAD_VALUE;
1150 
1151 	for (int32 i = 0; i < count; i++) {
1152 		// make sure we can read as many bytes
1153 		if (size_left(size, bufferStart, buffer) < 12)
1154 			return B_BAD_VALUE;
1155 
1156 		BParameter *oldPointer = read_from_buffer_swap32<BParameter *>(&buffer, isSwapped);
1157 		BParameter::media_parameter_type mediaType =
1158 			read_from_buffer_swap32<BParameter::media_parameter_type>(&buffer, isSwapped);
1159 
1160 		ssize_t parameterSize = read_from_buffer_swap32<ssize_t>(&buffer, isSwapped);
1161 		if (parameterSize > size_left(size, bufferStart, buffer))
1162 			return B_BAD_VALUE;
1163 
1164 		BParameter *parameter = MakeControl(mediaType);
1165 		if (parameter == NULL) {
1166 			ERROR("BParameterGroup::Unflatten(): MakeControl() failed\n");
1167 			return B_ERROR;
1168 		}
1169 
1170 		status_t status = parameter->Unflatten(parameter->TypeCode(), buffer, parameterSize);
1171 		if (status < B_OK) {
1172 			ERROR("BParameterGroup::Unflatten(): parameter->Unflatten() failed\n");
1173 			delete parameter;
1174 			return status;
1175 		}
1176 
1177 		skip_in_buffer(&buffer, parameterSize);
1178 
1179 		// add the item to the list
1180 		parameter->mGroup = this;
1181 		parameter->mWeb = mWeb;
1182 		mControls->AddItem(parameter);
1183 
1184 		// add it's old pointer value to the RefFix list kept by the owner web
1185 		if (mWeb != NULL)
1186 			mWeb->AddRefFix(oldPointer, parameter);
1187 	}
1188 
1189 	// unflatten sub groups
1190 
1191 	count = read_from_buffer_swap32<int32>(&buffer, isSwapped);
1192 	if (count < 0 || count * kAdditionalParameterGroupSize > size_left(size, bufferStart, buffer))
1193 		return B_BAD_VALUE;
1194 
1195 	for (int32 i = 0; i < count; i++) {
1196 		// make sure we can read as many bytes
1197 		if (size_left(size, bufferStart, buffer) < 12)
1198 			return B_BAD_VALUE;
1199 
1200 		BParameterGroup *oldPointer = read_from_buffer_swap32<BParameterGroup *>(&buffer, isSwapped);
1201 		type_code type = read_from_buffer_swap32<type_code>(&buffer, isSwapped);
1202 
1203 		ssize_t groupSize = read_from_buffer_swap32<ssize_t>(&buffer, isSwapped);
1204 		if (groupSize > size_left(size, bufferStart, buffer))
1205 			return B_BAD_VALUE;
1206 
1207 		BParameterGroup *group = new BParameterGroup(mWeb, "sub-unnamed");
1208 		if (group == NULL) {
1209 			ERROR("BParameterGroup::Unflatten(): MakeGroup() failed\n");
1210 			return B_ERROR;
1211 		}
1212 
1213 		status_t status = group->Unflatten(type, buffer, groupSize);
1214 		if (status != B_OK) {
1215 			ERROR("BParameterGroup::Unflatten(): group->Unflatten() failed\n");
1216 			delete group;
1217 			return status;
1218 		}
1219 
1220 		skip_in_buffer(&buffer, groupSize);
1221 
1222 		mGroups->AddItem(group);
1223 
1224 		// add it's old pointer value to the RefFix list kept by the owner web
1225 		if (mWeb != NULL)
1226 			mWeb->AddRefFix(oldPointer, group);
1227 	}
1228 
1229 	return B_OK;
1230 }
1231 
1232 /*************************************************************
1233  * private BParameterGroup
1234  *************************************************************/
1235 
1236 /*
1237 // unimplemented
1238 BParameterGroup::BParameterGroup()
1239 BParameterGroup::BParameterGroup(const BParameterGroup &clone)
1240 BParameterGroup &BParameterGroup::operator=(const BParameterGroup &clone)
1241 */
1242 
1243 
1244 /** Creates an uninitialized parameter of the specified type.
1245  *	Unlike the BParameterGroup::MakeXXXParameter() type of methods, this
1246  *	method does not add the parameter to this group automatically.
1247  */
1248 
1249 BParameter *
1250 BParameterGroup::MakeControl(int32 type)
1251 {
1252 	CALLED();
1253 
1254 	switch (type) {
1255 		case BParameter::B_NULL_PARAMETER:
1256 			return new BNullParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL, NULL);
1257 
1258 		case BParameter::B_DISCRETE_PARAMETER:
1259 			return new BDiscreteParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL, NULL);
1260 
1261 		case BParameter::B_CONTINUOUS_PARAMETER:
1262 			return new BContinuousParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL, NULL, NULL, 0, 0, 0);
1263 
1264 		case BParameter::B_TEXT_PARAMETER:
1265 			return new BTextParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL, NULL, NULL);
1266 
1267 		default:
1268 			ERROR("BParameterGroup::MakeControl unknown type %ld\n", type);
1269 			return NULL;
1270 	}
1271 }
1272 
1273 
1274 //	#pragma mark -
1275 
1276 /*************************************************************
1277  * public BParameter
1278  *************************************************************/
1279 
1280 
1281 BParameter::media_parameter_type
1282 BParameter::Type() const
1283 {
1284 	return mType;
1285 }
1286 
1287 
1288 BParameterWeb *
1289 BParameter::Web() const
1290 {
1291 	return mWeb;
1292 }
1293 
1294 
1295 BParameterGroup *
1296 BParameter::Group() const
1297 {
1298 	return mGroup;
1299 }
1300 
1301 
1302 const char *
1303 BParameter::Name() const
1304 {
1305 	return mName;
1306 }
1307 
1308 
1309 const char *
1310 BParameter::Kind() const
1311 {
1312 	return mKind;
1313 }
1314 
1315 
1316 const char *
1317 BParameter::Unit() const
1318 {
1319 	return mUnit;
1320 }
1321 
1322 
1323 int32
1324 BParameter::ID() const
1325 {
1326 	return mID;
1327 }
1328 
1329 
1330 void
1331 BParameter::SetFlags(uint32 flags)
1332 {
1333 	mFlags = flags;
1334 }
1335 
1336 
1337 uint32
1338 BParameter::Flags() const
1339 {
1340 	return mFlags;
1341 }
1342 
1343 
1344 status_t
1345 BParameter::GetValue(void *buffer, size_t *_ioSize, bigtime_t *_when)
1346 {
1347 	CALLED();
1348 
1349 	if (buffer == NULL || _ioSize == NULL)
1350 		return B_BAD_VALUE;
1351 
1352 	size_t ioSize = *_ioSize;
1353 	if (ioSize <= 0)
1354 		return B_NO_MEMORY;
1355 
1356 	if (mWeb == NULL) {
1357 		ERROR("BParameter::GetValue: no parent BParameterWeb\n");
1358 		return B_NO_INIT;
1359 	}
1360 
1361 	media_node node = mWeb->Node();
1362 	if (IS_INVALID_NODE(node)) {
1363 		ERROR("BParameter::GetValue: the parent BParameterWeb is not assigned to a BMediaNode\n");
1364 		return B_NO_INIT;
1365 	}
1366 
1367 	controllable_get_parameter_data_request request;
1368 	controllable_get_parameter_data_reply reply;
1369 
1370 	area_id area;
1371 	void *data;
1372 	if (ioSize > MAX_PARAMETER_DATA) {
1373 		// create an area if large data needs to be transfered
1374 		area = create_area("get parameter data", &data, B_ANY_ADDRESS, ROUND_UP_TO_PAGE(ioSize),
1375 			B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1376 		if (area < B_OK) {
1377 			ERROR("BParameter::GetValue can't create area of %ld bytes\n", ioSize);
1378 			return B_NO_MEMORY;
1379 		}
1380 	} else {
1381 		area = -1;
1382 		data = reply.rawdata;
1383 	}
1384 
1385 	request.parameter_id = mID;
1386 	request.requestsize = ioSize;
1387 	request.area = area;
1388 
1389 	status_t status = QueryPort(node.port, CONTROLLABLE_GET_PARAMETER_DATA, &request,
1390 		sizeof(request), &reply, sizeof(reply));
1391 	if (status == B_OK) {
1392 		// we don't want to copy more than the buffer provides
1393 		if (reply.size < ioSize)
1394 			ioSize = reply.size;
1395 
1396 		memcpy(buffer, data, ioSize);
1397 
1398 		// store reported values
1399 
1400 		*_ioSize = reply.size;
1401 		if (_when != NULL)
1402 			*_when = reply.last_change;
1403 	} else
1404 		ERROR("BParameter::GetValue parameter '%s' querying node %d, port %d failed: %s\n",
1405 			mName, node.node, node.port, strerror(status));
1406 
1407 	if (area >= B_OK)
1408 		delete_area(area);
1409 
1410 	return status;
1411 }
1412 
1413 
1414 status_t
1415 BParameter::SetValue(const void *buffer, size_t size, bigtime_t when)
1416 {
1417 	CALLED();
1418 
1419 	controllable_set_parameter_data_request request;
1420 	controllable_set_parameter_data_reply reply;
1421 	media_node node;
1422 	area_id area;
1423 	status_t rv;
1424 	void *data;
1425 
1426 	if (buffer == 0)
1427 		return B_BAD_VALUE;
1428 	if (size <= 0)
1429 		return B_NO_MEMORY;
1430 
1431 	if (mWeb == 0) {
1432 		ERROR("BParameter::SetValue: no parent BParameterWeb\n");
1433 		return B_NO_INIT;
1434 	}
1435 
1436 	node = mWeb->Node();
1437 	if (IS_INVALID_NODE(node)) {
1438 		ERROR("BParameter::SetValue: the parent BParameterWeb is not assigned to a BMediaNode\n");
1439 		return B_NO_INIT;
1440 	}
1441 
1442 	if (size > MAX_PARAMETER_DATA) {
1443 		// create an area if large data needs to be transfered
1444 		area = create_area("set parameter data", &data, B_ANY_ADDRESS, ROUND_UP_TO_PAGE(size), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1445 		if (area < B_OK) {
1446 			ERROR("BParameter::SetValue can't create area of %ld bytes\n", size);
1447 			return B_NO_MEMORY;
1448 		}
1449 	} else {
1450 		area = -1;
1451 		data = request.rawdata;
1452 	}
1453 
1454 	memcpy(data, buffer, size);
1455 	request.parameter_id = mID;
1456 	request.when = when;
1457 	request.area = area;
1458 	request.size = size;
1459 
1460 	rv = QueryPort(node.port, CONTROLLABLE_SET_PARAMETER_DATA, &request, sizeof(request), &reply, sizeof(reply));
1461 	if (rv != B_OK)
1462 		ERROR("BParameter::SetValue querying node failed\n");
1463 
1464 	if (area != -1)
1465 		delete_area(area);
1466 
1467 	return rv;
1468 }
1469 
1470 
1471 int32
1472 BParameter::CountChannels()
1473 {
1474 	return mChannels;
1475 }
1476 
1477 
1478 void
1479 BParameter::SetChannelCount(int32 channel_count)
1480 {
1481 	mChannels = channel_count;
1482 }
1483 
1484 
1485 media_type
1486 BParameter::MediaType()
1487 {
1488 	return mMediaType;
1489 }
1490 
1491 
1492 void
1493 BParameter::SetMediaType(media_type m_type)
1494 {
1495 	mMediaType = m_type;
1496 }
1497 
1498 
1499 int32
1500 BParameter::CountInputs()
1501 {
1502 	ASSERT(mInputs != NULL);
1503 
1504 	return mInputs->CountItems();
1505 }
1506 
1507 
1508 BParameter *
1509 BParameter::InputAt(int32 index)
1510 {
1511 	ASSERT(mInputs != NULL);
1512 
1513 	return static_cast<BParameter *>(mInputs->ItemAt(index));
1514 }
1515 
1516 
1517 void
1518 BParameter::AddInput(BParameter *input)
1519 {
1520 	CALLED();
1521 
1522 	// BeBook has this method returning a status value,
1523 	// but it should be updated
1524 	if (input == NULL)
1525 		return;
1526 
1527 	ASSERT(mInputs != NULL);
1528 
1529 	if (mInputs->HasItem(input)) {
1530 		// if already in input list, don't duplicate.
1531 		return;
1532 	}
1533 
1534 	mInputs->AddItem(input);
1535 	input->AddOutput(this);
1536 }
1537 
1538 
1539 int32
1540 BParameter::CountOutputs()
1541 {
1542 	ASSERT(mOutputs != NULL);
1543 
1544 	return mOutputs->CountItems();
1545 }
1546 
1547 
1548 BParameter *
1549 BParameter::OutputAt(int32 index)
1550 {
1551 	ASSERT(mOutputs != NULL);
1552 
1553 	return static_cast<BParameter *>(mOutputs->ItemAt(index));
1554 }
1555 
1556 
1557 void
1558 BParameter::AddOutput(BParameter *output)
1559 {
1560 	CALLED();
1561 
1562 	// BeBook has this method returning a status value,
1563 	// but it should be updated
1564 	if (output == NULL)
1565 		return;
1566 
1567 	ASSERT(mOutputs != NULL);
1568 
1569 	if (mOutputs->HasItem(output)) {
1570 		// if already in output list, don't duplicate.
1571 		return;
1572 	}
1573 
1574 	mOutputs->AddItem(output);
1575 	output->AddInput(this);
1576 }
1577 
1578 
1579 bool
1580 BParameter::IsFixedSize() const
1581 {
1582 	return false;
1583 }
1584 
1585 
1586 type_code
1587 BParameter::TypeCode() const
1588 {
1589 	return B_MEDIA_PARAMETER_TYPE;
1590 }
1591 
1592 
1593 ssize_t
1594 BParameter::FlattenedSize() const
1595 {
1596 	CALLED();
1597 	/*
1598 		?? (0x02040607): 4 bytes
1599 		BParameter Struct Size (in bytes): 4 bytes
1600 		ID: 4 bytes
1601 		Name String Length: 1 byte (??)
1602 			Name String: 'Name String Length' bytes
1603 		Kind String Length: 1 byte (??)
1604 			Kind String: 'Kind String Length' bytes
1605 		Unit String Length: 1 byte (??)
1606 			Unit String: 'Unit String Length' bytes
1607 		Inputs Count: 4 bytes
1608 			Inputs (pointers): ('Inputs Count')*4 bytes
1609 		Outputs Count: 4 bytes
1610 			Outputs (pointers): ('Outputs Count')*4 bytes
1611 		Media Type: 4 bytes
1612 		ChannelCount: 4 bytes
1613 		Flags: 4 bytes
1614 	*/
1615 	//35 bytes are guaranteed, after that, add the variable length parts.
1616 	ssize_t size = 35;
1617 
1618 	if (mName != NULL)
1619 		size += strlen(mName);
1620 	if (mKind != NULL)
1621 		size += strlen(mKind);
1622 	if (mUnit != NULL)
1623 		size += strlen(mUnit);
1624 
1625 	if (mInputs != NULL)
1626 		size += mInputs->CountItems() * sizeof(BParameter *);
1627 
1628 	if (mOutputs != NULL)
1629 		size += mOutputs->CountItems() * sizeof(BParameter *);
1630 
1631 	return size;
1632 }
1633 
1634 
1635 status_t
1636 BParameter::Flatten(void *buffer, ssize_t size) const
1637 {
1638 	CALLED();
1639 
1640 	if (buffer == NULL) {
1641 		ERROR("BParameter::Flatten buffer is NULL\n");
1642 		return B_NO_INIT;
1643 	}
1644 
1645 	// NOTICE: It is important that this value is the size returned by
1646 	// BParameter::FlattenedSize(), not by a descendent's override of this method.
1647 	ssize_t actualSize = BParameter::FlattenedSize();
1648 	if (size < actualSize) {
1649 		ERROR("BParameter::Flatten(): size too small\n");
1650 		return B_NO_MEMORY;
1651 	}
1652 
1653 	write_to_buffer<uint32>(&buffer, kParameterMagic);
1654 	write_to_buffer<ssize_t>(&buffer, actualSize);
1655 	write_to_buffer<int32>(&buffer, mID);
1656 
1657 	write_string_to_buffer(&buffer, mName);
1658 	write_string_to_buffer(&buffer, mKind);
1659 	write_string_to_buffer(&buffer, mUnit);
1660 
1661 	// flatten and write the list of inputs
1662 	ssize_t count = mInputs ? mInputs->CountItems() : 0;
1663 	write_to_buffer<ssize_t>(&buffer, count);
1664 
1665 	if (count > 0) {
1666 		memcpy(buffer, mInputs->Items(), sizeof(BParameter *) * count);
1667 		skip_in_buffer(&buffer, sizeof(BParameter *) * count);
1668 	}
1669 
1670 	// flatten and write the list of outputs
1671 	count = mOutputs ? mOutputs->CountItems() : 0;
1672 	write_to_buffer<ssize_t>(&buffer, count);
1673 
1674 	if (count > 0) {
1675 		memcpy(buffer, mOutputs->Items(), sizeof(BParameter *) * count);
1676 		skip_in_buffer(&buffer, sizeof(BParameter *) * count);
1677 	}
1678 
1679 	write_to_buffer<media_type>(&buffer, mMediaType);
1680 	write_to_buffer<int32>(&buffer, mChannels);
1681 	write_to_buffer<uint32>(&buffer, mFlags);
1682 
1683 	return B_OK;
1684 }
1685 
1686 
1687 bool
1688 BParameter::AllowsTypeCode(type_code code) const
1689 {
1690 	return (code == TypeCode());
1691 }
1692 
1693 
1694 status_t
1695 BParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
1696 {
1697 	CALLED();
1698 
1699 	if (!AllowsTypeCode(code)) {
1700 		ERROR("BParameter::Unflatten(): wrong type code\n");
1701 		return B_BAD_TYPE;
1702 	}
1703 
1704 	if (buffer == NULL) {
1705 		ERROR("BParameter::Unflatten(): buffer is NULL\n");
1706 		return B_NO_INIT;
1707 	}
1708 
1709 	// if the buffer is smaller than the size needed to read the
1710 	// signature and struct size fields, then there is a problem
1711 	if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(ssize_t))) {
1712 		ERROR("BParameter::Unflatten() size too small\n");
1713 		return B_BAD_VALUE;
1714 	}
1715 
1716 	const void *bufferStart = buffer;
1717 
1718 	// check magic
1719 
1720 	uint32 magic = read_from_buffer<uint32>(&buffer);
1721 	if (magic == B_SWAP_INT32(kParameterMagic))
1722 		mSwapDetected = true;
1723 	else if (magic == kParameterMagic)
1724 		mSwapDetected = false;
1725 	else {
1726 		ERROR("BParameter::Unflatten(): bad magic\n");
1727 		return B_BAD_TYPE;
1728 	}
1729 
1730 	ssize_t parameterSize = read_from_buffer_swap32<ssize_t>(&buffer, mSwapDetected);
1731 	if (parameterSize > size) {
1732 		ERROR("BParameter::Unflatten(): buffer too small (%ld > %ld)\n", parameterSize, size);
1733 		return B_BAD_VALUE;
1734 	}
1735 
1736 	//if the struct doesn't meet the minimum size for
1737 	//a flattened BParameter, then return an error.
1738 	//MinFlattenedParamSize =
1739 	//ID (4 bytes)
1740 	//Name String Length (1 byte)
1741 	//Kind String Length (1 byte)
1742 	//Unit String Length (1 byte)
1743 	//Inputs Count (4 bytes)
1744 	//Outputs Count (4 bytes)
1745 	//Media Type (4 bytes)
1746 	//Channel Count (4 bytes)
1747 	//Flags (4 bytes)
1748 	//TOTAL: 27 bytes
1749 	const ssize_t MinFlattenedParamSize(27);
1750 	if (parameterSize < MinFlattenedParamSize) {
1751 		ERROR("BParameter::Unflatten out of memory (2)\n");
1752 		return B_ERROR;
1753 	}
1754 
1755 	mID = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
1756 
1757 	if (read_string_from_buffer(&buffer, &mName, size_left(size, bufferStart, buffer)) < B_OK
1758 		|| read_string_from_buffer(&buffer, &mKind, size_left(size, bufferStart, buffer)) < B_OK
1759 		|| read_string_from_buffer(&buffer, &mUnit, size_left(size, bufferStart, buffer)) < B_OK)
1760 		return B_NO_MEMORY;
1761 
1762 	// read the list of inputs
1763 
1764 	// it will directly add the pointers in the flattened message to the list;
1765 	// these will be fixed to point to the real inputs/outputs later in FixRefs()
1766 
1767 	int32 count = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
1768 
1769 	if (mInputs == NULL)
1770 		mInputs = new BList();
1771 	else
1772 		mInputs->MakeEmpty();
1773 
1774 	for (int32 i = 0; i < count; i++) {
1775 		mInputs->AddItem(read_from_buffer_swap32<BParameter * const>(&buffer, mSwapDetected));
1776 	}
1777 
1778 	// read the list of outputs
1779 
1780 	count = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
1781 
1782 	if (mOutputs == NULL)
1783 		mOutputs = new BList();
1784 	else
1785 		mOutputs->MakeEmpty();
1786 
1787 	for (int32 i = 0; i < count; i++) {
1788 		mOutputs->AddItem(read_from_buffer_swap32<BParameter * const>(&buffer, mSwapDetected));
1789 	}
1790 
1791 	mMediaType = read_from_buffer_swap32<media_type>(&buffer, mSwapDetected);
1792 	mChannels = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
1793 	mFlags = read_from_buffer_swap32<uint32>(&buffer, mSwapDetected);
1794 
1795 	return B_OK;
1796 }
1797 
1798 
1799 /*************************************************************
1800  * private BParameter
1801  *************************************************************/
1802 
1803 
1804 BParameter::BParameter(int32 id, media_type mediaType, media_parameter_type type,
1805 	BParameterWeb *web, const char *name, const char *kind, const char *unit)
1806 	:
1807 	mID(id),
1808 	mType(type),
1809 	mWeb(web),
1810 	mGroup(NULL),
1811 	mSwapDetected(true),
1812 	mMediaType(mediaType),
1813 	mChannels(1),
1814 	mFlags(0)
1815 {
1816 	CALLED();
1817 
1818 	mName = strndup(name, 256);
1819 	mKind = strndup(kind, 256);
1820 	mUnit = strndup(unit, 256);
1821 
1822 	// create empty input/output lists
1823 	mInputs = new BList();
1824 	mOutputs = new BList();
1825 }
1826 
1827 
1828 BParameter::~BParameter()
1829 {
1830 	CALLED();
1831 
1832 	// don't worry about the mWeb/mGroup properties, you don't need
1833 	// to remove yourself from a web/group since the only way in which
1834 	// a parameter is destroyed is when the owner web/group destroys it
1835 
1836 	free(mName);
1837 	free(mKind);
1838 	free(mUnit);
1839 
1840 	delete mInputs;
1841 	delete mOutputs;
1842 
1843 	mName = NULL; mKind = NULL; mUnit = NULL; mInputs = NULL; mOutputs = NULL;
1844 }
1845 
1846 
1847 /** Replaces references to items in the old list with the corresponding
1848  *	items in the updated list. The references are replaced in the input
1849  *	and output lists.
1850  *	This is called by BParameterWeb::Unflatten().
1851  */
1852 
1853 void
1854 BParameter::FixRefs(BList &old, BList &updated)
1855 {
1856 	CALLED();
1857 	ASSERT(mInputs != NULL);
1858 	ASSERT(mOutputs != NULL);
1859 
1860 	// update inputs
1861 
1862 	void **items = static_cast<void **>(mInputs->Items());
1863 	int32 count = mInputs->CountItems();
1864 
1865 	for (int32 i = 0; i < count; i++) {
1866 		int32 index = old.IndexOf(items[i]);
1867 		if (index >= 0)
1868 			items[i] = updated.ItemAt(index);
1869 		else {
1870 			ERROR("BParameter::FixRefs(): No mapping found for input");
1871 			items[i] = NULL;
1872 		}
1873 	}
1874 
1875 	// remove all NULL inputs (those which couldn't be mapped)
1876 
1877 	for (int32 i = count; i-- > 0;) {
1878 		if (items[i] == NULL)
1879 			mInputs->RemoveItem(i);
1880 	}
1881 
1882 	// update outputs
1883 
1884 	items = static_cast<void **>(mOutputs->Items());
1885 	count = mOutputs->CountItems();
1886 
1887 	for (int32 i = 0; i < count; i++) {
1888 		int32 index = old.IndexOf(items[i]);
1889 		if (index >= 0)
1890 			items[i] = updated.ItemAt(index);
1891 		else {
1892 			ERROR("BParameter::FixRefs(): No mapping found for output");
1893 			items[i] = NULL;
1894 		}
1895 	}
1896 
1897 	// remove all NULL outputs (those which couldn't be mapped)
1898 
1899 	for (int32 i = count; i-- > 0;) {
1900 		if (items[i] == NULL)
1901 			mOutputs->RemoveItem(i);
1902 	}
1903 }
1904 
1905 
1906 //	#pragma mark -
1907 
1908 /*************************************************************
1909  * public BContinuousParameter
1910  *************************************************************/
1911 
1912 
1913 type_code
1914 BContinuousParameter::ValueType()
1915 {
1916 	return B_FLOAT_TYPE;
1917 }
1918 
1919 
1920 float
1921 BContinuousParameter::MinValue()
1922 {
1923 	return mMinimum;
1924 }
1925 
1926 
1927 float
1928 BContinuousParameter::MaxValue()
1929 {
1930 	return mMaximum;
1931 }
1932 
1933 
1934 float
1935 BContinuousParameter::ValueStep()
1936 {
1937 	return mStepping;
1938 }
1939 
1940 
1941 void
1942 BContinuousParameter::SetResponse(int resp, float factor, float offset)
1943 {
1944 	mResponse = static_cast<response>(resp);
1945 	mFactor = factor;
1946 	mOffset = offset;
1947 }
1948 
1949 
1950 void
1951 BContinuousParameter::GetResponse(int *resp, float *factor, float *offset)
1952 {
1953 	if (resp != NULL)
1954 		*resp = mResponse;
1955 	if (factor != NULL)
1956 		*factor = mFactor;
1957 	if (offset != NULL)
1958 		*offset = mOffset;
1959 }
1960 
1961 
1962 ssize_t
1963 BContinuousParameter::FlattenedSize() const
1964 {
1965 	CALLED();
1966 
1967 	// only adds a fixed amount of bytes
1968 	return BParameter::FlattenedSize() + kAdditionalContinuousParameterSize;
1969 }
1970 
1971 
1972 status_t
1973 BContinuousParameter::Flatten(void *buffer, ssize_t size) const
1974 {
1975 	CALLED();
1976 
1977 	if (buffer == NULL) {
1978 		ERROR("BContinuousParameter::Flatten(): buffer is NULL\n");
1979 		return B_NO_INIT;
1980 	}
1981 
1982 	ssize_t parameterSize = BParameter::FlattenedSize();
1983 	if (size < (parameterSize + kAdditionalContinuousParameterSize)) {
1984 		ERROR("BContinuousParameter::Flatten(): size to small\n");
1985 		return B_NO_MEMORY;
1986 	}
1987 
1988 	status_t status = BParameter::Flatten(buffer, size);
1989 	if (status != B_OK) {
1990 		ERROR("BContinuousParameter::Flatten(): BParameter::Flatten() failed\n");
1991 		return status;
1992 	}
1993 
1994 	// add our data to the general flattened BParameter
1995 
1996 	skip_in_buffer(&buffer, parameterSize);
1997 
1998 	write_to_buffer<float>(&buffer, mMinimum);
1999 	write_to_buffer<float>(&buffer, mMaximum);
2000 	write_to_buffer<float>(&buffer, mStepping);
2001 	write_to_buffer<response>(&buffer, mResponse);
2002 	write_to_buffer<float>(&buffer, mFactor);
2003 	write_to_buffer<float>(&buffer, mOffset);
2004 
2005 	return B_OK;
2006 }
2007 
2008 
2009 status_t
2010 BContinuousParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
2011 {
2012 	CALLED();
2013 
2014 	// we try to check if the buffer size is long enough to hold an object
2015 	// as early as possible.
2016 
2017 	if (!AllowsTypeCode(code)) {
2018 		ERROR("BContinuousParameter::Unflatten wrong type code\n");
2019 		return B_BAD_TYPE;
2020 	}
2021 
2022 	if (buffer == NULL) {
2023 		ERROR("BContinuousParameter::Unflatten buffer is NULL\n");
2024 		return B_NO_INIT;
2025 	}
2026 
2027 	// if the buffer is smaller than the size needed to read the
2028 	// signature and struct size fields, then there is a problem
2029 	if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(ssize_t))) {
2030 		ERROR("BContinuousParameter::Unflatten size too small\n");
2031 		return B_ERROR;
2032 	}
2033 
2034 	status_t status = BParameter::Unflatten(code, buffer, size);
2035 	if (status != B_OK) {
2036 		ERROR("BContinuousParameter::Unflatten(): BParameter::Unflatten failed\n");
2037 		return status;
2038 	}
2039 
2040 	ssize_t parameterSize = BParameter::FlattenedSize();
2041 	skip_in_buffer(&buffer, parameterSize);
2042 
2043 	if (size < (parameterSize + kAdditionalContinuousParameterSize)) {
2044 		ERROR("BContinuousParameter::Unflatten(): buffer too small\n");
2045 		return B_BAD_VALUE;
2046 	}
2047 
2048 	mMinimum = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2049 	mMaximum = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2050 	mStepping = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2051 	mResponse = read_from_buffer_swap32<response>(&buffer, SwapOnUnflatten());
2052 	mFactor = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2053 	mOffset = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2054 
2055 	return B_OK;
2056 }
2057 
2058 
2059 /*************************************************************
2060  * private BContinuousParameter
2061  *************************************************************/
2062 
2063 
2064 BContinuousParameter::BContinuousParameter(int32 id, media_type m_type,
2065 	BParameterWeb *web, const char *name, const char *kind, const char *unit,
2066 	float minimum, float maximum, float stepping)
2067 	:	BParameter(id, m_type, B_CONTINUOUS_PARAMETER, web, name, kind, unit),
2068 	mMinimum(minimum), mMaximum(maximum), mStepping(stepping),
2069 	mResponse(B_LINEAR), mFactor(1.0), mOffset(0.0)
2070 {
2071 	CALLED();
2072 }
2073 
2074 
2075 BContinuousParameter::~BContinuousParameter()
2076 {
2077 	CALLED();
2078 }
2079 
2080 
2081 //	#pragma mark -
2082 
2083 /*************************************************************
2084  * public BDiscreteParameter
2085  *************************************************************/
2086 
2087 
2088 type_code
2089 BDiscreteParameter::ValueType()
2090 {
2091 	return B_INT32_TYPE;
2092 }
2093 
2094 
2095 int32
2096 BDiscreteParameter::CountItems()
2097 {
2098 	ASSERT(mValues != NULL);
2099 
2100 	return mValues->CountItems();
2101 }
2102 
2103 
2104 const char *
2105 BDiscreteParameter::ItemNameAt(int32 index)
2106 {
2107 	ASSERT(mSelections != NULL);
2108 
2109 	return reinterpret_cast<const char *>(mSelections->ItemAt(index));
2110 }
2111 
2112 
2113 int32
2114 BDiscreteParameter::ItemValueAt(int32 index)
2115 {
2116 	ASSERT(mValues != NULL);
2117 
2118 	int32 *item = static_cast<int32 *>(mValues->ItemAt(index));
2119 	if (item == NULL)
2120 		return 0;
2121 
2122 	return *item;
2123 }
2124 
2125 
2126 status_t
2127 BDiscreteParameter::AddItem(int32 value, const char *name)
2128 {
2129 	CALLED();
2130 	//TRACE("\tthis = %p, value = %ld, name = \"%s\"\n", this, value, name);
2131 	ASSERT(mValues != NULL);
2132 	ASSERT(mSelections != NULL);
2133 
2134 	int32 *valueCopy = new int32(value);
2135 	char *nameCopy = strndup(name, 256);
2136 	if (name != NULL && nameCopy == NULL)
2137 		return B_NO_MEMORY;
2138 
2139 	if (!mValues->AddItem(valueCopy)
2140 		|| !mSelections->AddItem(nameCopy))
2141 		return B_NO_MEMORY;
2142 
2143 	return B_OK;
2144 }
2145 
2146 
2147 status_t
2148 BDiscreteParameter::MakeItemsFromInputs()
2149 {
2150 	CALLED();
2151 	ASSERT(mValues != NULL);
2152 	ASSERT(mSelections != NULL);
2153 	ASSERT(mInputs != NULL);
2154 
2155 	int32 count = mInputs->CountItems();
2156 	for(int32 i = 0; i < count; i++) {
2157 		BParameter *parameter = static_cast<BParameter *>(mInputs->ItemAt(i));
2158 		AddItem(i, parameter->Name());
2159 	}
2160 
2161 	return B_OK;
2162 }
2163 
2164 
2165 status_t
2166 BDiscreteParameter::MakeItemsFromOutputs()
2167 {
2168 	CALLED();
2169 	ASSERT(mValues != NULL);
2170 	ASSERT(mSelections != NULL);
2171 	ASSERT(mOutputs != NULL);
2172 
2173 	int32 count = mOutputs->CountItems();
2174 	for(int32 i = 0; i < count; i++) {
2175 		BParameter *parameter = static_cast<BParameter *>(mOutputs->ItemAt(i));
2176 		AddItem(i, parameter->Name());
2177 	}
2178 
2179 	return B_OK;
2180 }
2181 
2182 
2183 void
2184 BDiscreteParameter::MakeEmpty()
2185 {
2186 	CALLED();
2187 	ASSERT(mValues != NULL);
2188 	ASSERT(mSelections != NULL);
2189 
2190 	for (int32 i = mValues->CountItems(); i-- > 0;) {
2191 		delete static_cast<int32 *>(mValues->ItemAt(i));
2192 	}
2193 	mValues->MakeEmpty();
2194 
2195 	for(int32 i = mSelections->CountItems(); i-- > 0;) {
2196 		free(static_cast<char *>(mSelections->ItemAt(i)));
2197 	}
2198 	mSelections->MakeEmpty();
2199 }
2200 
2201 
2202 ssize_t
2203 BDiscreteParameter::FlattenedSize() const
2204 {
2205 	CALLED();
2206 
2207 	ssize_t size = BParameter::FlattenedSize() + kAdditionalDiscreteParameterSize;
2208 
2209 	int32 count = mValues ? mValues->CountItems() : 0;
2210 	for (int32 i = 0; i < count; i++) {
2211 		char *selection = static_cast<char *>(mSelections->ItemAt(i));
2212 
2213 		if (selection != NULL)
2214 			size += min_c(strlen(selection), 255);
2215 
2216 		size += 5;
2217 			// string length + value
2218 	}
2219 
2220 	return size;
2221 }
2222 
2223 
2224 status_t
2225 BDiscreteParameter::Flatten(void *buffer, ssize_t size) const
2226 {
2227 	CALLED();
2228 
2229 	if (buffer == NULL) {
2230 		ERROR("BDiscreteParameter::Flatten(): buffer is NULL\n");
2231 		return B_NO_INIT;
2232 	}
2233 
2234 	ssize_t parameterSize = BParameter::FlattenedSize();
2235 
2236 	if (size < FlattenedSize()) {
2237 		ERROR("BDiscreteParameter::Flatten(): size too small\n");
2238 		return B_NO_MEMORY;
2239 	}
2240 
2241 	status_t status = BParameter::Flatten(buffer, size);
2242 	if (status != B_OK) {
2243 		ERROR("BDiscreteParameter::Flatten(): BParameter::Flatten failed\n");
2244 		return status;
2245 	}
2246 
2247 	skip_in_buffer(&buffer, parameterSize);
2248 
2249 	int32 count = mValues ? mValues->CountItems() : 0;
2250 	write_to_buffer<int32>(&buffer, count);
2251 
2252 	// write out all value/name pairs
2253 	for (int32 i = 0; i < count; i++) {
2254 		const char *selection = static_cast<char *>(mSelections->ItemAt(i));
2255 		const int32 *value = static_cast<int32 *>(mValues->ItemAt(i));
2256 
2257 		write_string_to_buffer(&buffer, selection);
2258 		write_to_buffer<int32>(&buffer, value ? *value : 0);
2259 	}
2260 
2261 	return B_OK;
2262 }
2263 
2264 
2265 status_t
2266 BDiscreteParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
2267 {
2268 	CALLED();
2269 
2270 	if (!AllowsTypeCode(code)) {
2271 		ERROR("BDiscreteParameter::Unflatten(): bad type code\n");
2272 		return B_BAD_TYPE;
2273 	}
2274 
2275 	if (buffer == NULL) {
2276 		ERROR("BDiscreteParameter::Unflatten(): buffer is NULL\n");
2277 		return B_NO_INIT;
2278 	}
2279 
2280 	// if the buffer is smaller than the size needed to read the
2281 	// signature and struct size fields, then there is a problem
2282 	if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(ssize_t))) {
2283 		ERROR("BDiscreteParameter::Unflatten(): size too small\n");
2284 		return B_ERROR;
2285 	}
2286 
2287 	const void *bufferStart = buffer;
2288 
2289 	status_t status = BParameter::Unflatten(code, buffer, size);
2290 	if (status != B_OK) {
2291 		ERROR("BDiscreteParameter::Unflatten(): BParameter::Unflatten failed\n");
2292 		return status;
2293 	}
2294 
2295 	ssize_t parameterSize = BParameter::FlattenedSize();
2296 	skip_in_buffer(&buffer, parameterSize);
2297 
2298 	if (size < (parameterSize + kAdditionalDiscreteParameterSize)) {
2299 		ERROR("BDiscreteParameter::Unflatten(): buffer too small\n");
2300 		return B_BAD_VALUE;
2301 	}
2302 
2303 	int32 count = read_from_buffer_swap32<int32>(&buffer, SwapOnUnflatten());
2304 
2305 	// clear any existing name/value pairs
2306 	MakeEmpty();
2307 
2308 	for (int32 i = 0; i < count; i++) {
2309 		char *name;
2310 		if (read_string_from_buffer(&buffer, &name, size_left(size, bufferStart, buffer)) < B_OK)
2311 			return B_BAD_DATA;
2312 
2313 		if (size_left(size, bufferStart, buffer) < (int)sizeof(int32))
2314 			return B_BAD_DATA;
2315 
2316 		int32 value = read_from_buffer_swap32<int32>(&buffer, SwapOnUnflatten());
2317 
2318 		AddItem(value, name);
2319 	}
2320 
2321 	return B_OK;
2322 }
2323 
2324 
2325 /*************************************************************
2326  * private BDiscreteParameter
2327  *************************************************************/
2328 
2329 
2330 BDiscreteParameter::BDiscreteParameter(int32 id, media_type mediaType,
2331 	BParameterWeb *web, const char *name, const char *kind)
2332 	:	BParameter(id, mediaType, B_DISCRETE_PARAMETER, web, name, kind, NULL)
2333 {
2334 	CALLED();
2335 
2336 	mSelections = new BList();
2337 	mValues = new BList();
2338 }
2339 
2340 
2341 BDiscreteParameter::~BDiscreteParameter()
2342 {
2343 	CALLED();
2344 
2345 	MakeEmpty();
2346 
2347 	delete mSelections;
2348 	delete mValues;
2349 
2350 	mSelections = NULL; mValues = NULL;
2351 }
2352 
2353 
2354 //	#pragma mark -
2355 
2356 /*************************************************************
2357  * public BNullParameter
2358  *************************************************************/
2359 
2360 
2361 type_code
2362 BNullParameter::ValueType()
2363 {
2364 	// NULL parameters have no value type
2365 	return 0;
2366 }
2367 
2368 
2369 ssize_t
2370 BNullParameter::FlattenedSize() const
2371 {
2372 	return BParameter::FlattenedSize();
2373 }
2374 
2375 
2376 status_t
2377 BNullParameter::Flatten(void *buffer, ssize_t size) const
2378 {
2379 	return BParameter::Flatten(buffer, size);
2380 }
2381 
2382 
2383 status_t
2384 BNullParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
2385 {
2386 	return BParameter::Unflatten(code, buffer, size);
2387 }
2388 
2389 
2390 /*************************************************************
2391  * private BNullParameter
2392  *************************************************************/
2393 
2394 
2395 BNullParameter::BNullParameter(int32 id, media_type mediaType, BParameterWeb *web,
2396 	const char *name, const char *kind)
2397 	: BParameter(id, mediaType, B_NULL_PARAMETER, web, name, kind, NULL)
2398 {
2399 }
2400 
2401 
2402 BNullParameter::~BNullParameter()
2403 {
2404 }
2405 
2406 
2407 //	#pragma mark -
2408 
2409 /*************************************************************
2410  * public BTextParameter
2411  *************************************************************/
2412 
2413 
2414 size_t
2415 BTextParameter::MaxBytes() const
2416 {
2417 	// NULL parameters have no value type
2418 	return mMaxBytes;
2419 }
2420 
2421 
2422 type_code
2423 BTextParameter::ValueType()
2424 {
2425 	// NULL parameters have no value type
2426 	return 0;
2427 }
2428 
2429 
2430 ssize_t
2431 BTextParameter::FlattenedSize() const
2432 {
2433 	return BParameter::FlattenedSize() + sizeof(mMaxBytes);
2434 }
2435 
2436 
2437 status_t
2438 BTextParameter::Flatten(void *buffer, ssize_t size) const
2439 {
2440 	if (buffer == NULL) {
2441 		ERROR("BTextParameter::Flatten(): buffer is NULL\n");
2442 		return B_NO_INIT;
2443 	}
2444 
2445 	ssize_t parameterSize = BParameter::FlattenedSize();
2446 	if (size < static_cast<ssize_t>(parameterSize + sizeof(mMaxBytes))) {
2447 		ERROR("BContinuousParameter::Flatten(): size to small\n");
2448 		return B_NO_MEMORY;
2449 	}
2450 
2451 	status_t status = BParameter::Flatten(buffer, size);
2452 	if (status != B_OK) {
2453 		ERROR("BTextParameter::Flatten(): BParameter::Flatten() failed\n");
2454 		return status;
2455 	}
2456 
2457 	// add our data to the general flattened BParameter
2458 
2459 	skip_in_buffer(&buffer, parameterSize);
2460 
2461 	write_to_buffer<uint32>(&buffer, mMaxBytes);
2462 
2463 	return B_OK;
2464 }
2465 
2466 
2467 status_t
2468 BTextParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
2469 {
2470 	// we try to check if the buffer size is long enough to hold an object
2471 	// as early as possible.
2472 
2473 	if (!AllowsTypeCode(code)) {
2474 		ERROR("BTextParameter::Unflatten wrong type code\n");
2475 		return B_BAD_TYPE;
2476 	}
2477 
2478 	if (buffer == NULL) {
2479 		ERROR("BTextParameter::Unflatten buffer is NULL\n");
2480 		return B_NO_INIT;
2481 	}
2482 
2483 	if (size < static_cast<ssize_t>(sizeof(mMaxBytes))) {
2484 		ERROR("BTextParameter::Unflatten size too small\n");
2485 		return B_ERROR;
2486 	}
2487 
2488 	status_t status = BParameter::Unflatten(code, buffer, size);
2489 	if (status != B_OK) {
2490 		ERROR("BTextParameter::Unflatten(): BParameter::Unflatten failed\n");
2491 		return status;
2492 	}
2493 
2494 	ssize_t parameterSize = BParameter::FlattenedSize();
2495 	skip_in_buffer(&buffer, parameterSize);
2496 
2497 	if (size < static_cast<ssize_t>(parameterSize + sizeof(mMaxBytes))) {
2498 		ERROR("BTextParameter::Unflatten(): buffer too small\n");
2499 		return B_BAD_VALUE;
2500 	}
2501 
2502 	mMaxBytes = read_from_buffer_swap32<uint32>(&buffer, SwapOnUnflatten());
2503 
2504 	return B_OK;
2505 }
2506 
2507 
2508 /*************************************************************
2509  * private BTextParameter
2510  *************************************************************/
2511 
2512 
2513 BTextParameter::BTextParameter(int32 id, media_type mediaType, BParameterWeb *web,
2514 	const char *name, const char *kind, size_t max_bytes)
2515 	: BParameter(id, mediaType, B_NULL_PARAMETER, web, name, kind, NULL)
2516 {
2517 	mMaxBytes = max_bytes;
2518 }
2519 
2520 
2521 BTextParameter::~BTextParameter()
2522 {
2523 }
2524 
2525 
2526 //	#pragma mark -
2527 //	reserved functions
2528 
2529 
2530 status_t BParameterWeb::_Reserved_ControlWeb_0(void *) { return B_ERROR; }
2531 status_t BParameterWeb::_Reserved_ControlWeb_1(void *) { return B_ERROR; }
2532 status_t BParameterWeb::_Reserved_ControlWeb_2(void *) { return B_ERROR; }
2533 status_t BParameterWeb::_Reserved_ControlWeb_3(void *) { return B_ERROR; }
2534 status_t BParameterWeb::_Reserved_ControlWeb_4(void *) { return B_ERROR; }
2535 status_t BParameterWeb::_Reserved_ControlWeb_5(void *) { return B_ERROR; }
2536 status_t BParameterWeb::_Reserved_ControlWeb_6(void *) { return B_ERROR; }
2537 status_t BParameterWeb::_Reserved_ControlWeb_7(void *) { return B_ERROR; }
2538 
2539 status_t BParameterGroup::_Reserved_ControlGroup_0(void *) { return B_ERROR; }
2540 status_t BParameterGroup::_Reserved_ControlGroup_1(void *) { return B_ERROR; }
2541 status_t BParameterGroup::_Reserved_ControlGroup_2(void *) { return B_ERROR; }
2542 status_t BParameterGroup::_Reserved_ControlGroup_3(void *) { return B_ERROR; }
2543 status_t BParameterGroup::_Reserved_ControlGroup_4(void *) { return B_ERROR; }
2544 status_t BParameterGroup::_Reserved_ControlGroup_5(void *) { return B_ERROR; }
2545 status_t BParameterGroup::_Reserved_ControlGroup_6(void *) { return B_ERROR; }
2546 status_t BParameterGroup::_Reserved_ControlGroup_7(void *) { return B_ERROR; }
2547 
2548 status_t BParameter::_Reserved_Control_0(void *) { return B_ERROR; }
2549 status_t BParameter::_Reserved_Control_1(void *) { return B_ERROR; }
2550 status_t BParameter::_Reserved_Control_2(void *) { return B_ERROR; }
2551 status_t BParameter::_Reserved_Control_3(void *) { return B_ERROR; }
2552 status_t BParameter::_Reserved_Control_4(void *) { return B_ERROR; }
2553 status_t BParameter::_Reserved_Control_5(void *) { return B_ERROR; }
2554 status_t BParameter::_Reserved_Control_6(void *) { return B_ERROR; }
2555 status_t BParameter::_Reserved_Control_7(void *) { return B_ERROR; }
2556 
2557 status_t BContinuousParameter::_Reserved_ContinuousParameter_0(void *) { return B_ERROR; }
2558 status_t BContinuousParameter::_Reserved_ContinuousParameter_1(void *) { return B_ERROR; }
2559 status_t BContinuousParameter::_Reserved_ContinuousParameter_2(void *) { return B_ERROR; }
2560 status_t BContinuousParameter::_Reserved_ContinuousParameter_3(void *) { return B_ERROR; }
2561 status_t BContinuousParameter::_Reserved_ContinuousParameter_4(void *) { return B_ERROR; }
2562 status_t BContinuousParameter::_Reserved_ContinuousParameter_5(void *) { return B_ERROR; }
2563 status_t BContinuousParameter::_Reserved_ContinuousParameter_6(void *) { return B_ERROR; }
2564 status_t BContinuousParameter::_Reserved_ContinuousParameter_7(void *) { return B_ERROR; }
2565 
2566 status_t BDiscreteParameter::_Reserved_DiscreteParameter_0(void *) { return B_ERROR; }
2567 status_t BDiscreteParameter::_Reserved_DiscreteParameter_1(void *) { return B_ERROR; }
2568 status_t BDiscreteParameter::_Reserved_DiscreteParameter_2(void *) { return B_ERROR; }
2569 status_t BDiscreteParameter::_Reserved_DiscreteParameter_3(void *) { return B_ERROR; }
2570 status_t BDiscreteParameter::_Reserved_DiscreteParameter_4(void *) { return B_ERROR; }
2571 status_t BDiscreteParameter::_Reserved_DiscreteParameter_5(void *) { return B_ERROR; }
2572 status_t BDiscreteParameter::_Reserved_DiscreteParameter_6(void *) { return B_ERROR; }
2573 status_t BDiscreteParameter::_Reserved_DiscreteParameter_7(void *) { return B_ERROR; }
2574 
2575 status_t BNullParameter::_Reserved_NullParameter_0(void *) { return B_ERROR; }
2576 status_t BNullParameter::_Reserved_NullParameter_1(void *) { return B_ERROR; }
2577 status_t BNullParameter::_Reserved_NullParameter_2(void *) { return B_ERROR; }
2578 status_t BNullParameter::_Reserved_NullParameter_3(void *) { return B_ERROR; }
2579 status_t BNullParameter::_Reserved_NullParameter_4(void *) { return B_ERROR; }
2580 status_t BNullParameter::_Reserved_NullParameter_5(void *) { return B_ERROR; }
2581 status_t BNullParameter::_Reserved_NullParameter_6(void *) { return B_ERROR; }
2582 status_t BNullParameter::_Reserved_NullParameter_7(void *) { return B_ERROR; }
2583 
2584 status_t BTextParameter::_Reserved_TextParameter_0(void *) { return B_ERROR; }
2585 status_t BTextParameter::_Reserved_TextParameter_1(void *) { return B_ERROR; }
2586 status_t BTextParameter::_Reserved_TextParameter_2(void *) { return B_ERROR; }
2587 status_t BTextParameter::_Reserved_TextParameter_3(void *) { return B_ERROR; }
2588 status_t BTextParameter::_Reserved_TextParameter_4(void *) { return B_ERROR; }
2589 status_t BTextParameter::_Reserved_TextParameter_5(void *) { return B_ERROR; }
2590 status_t BTextParameter::_Reserved_TextParameter_6(void *) { return B_ERROR; }
2591 status_t BTextParameter::_Reserved_TextParameter_7(void *) { return B_ERROR; }
2592 
2593 
2594