xref: /haiku/src/kits/media/ParameterWeb.cpp (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
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,
1260 				NULL);
1261 
1262 		case BParameter::B_CONTINUOUS_PARAMETER:
1263 			return new BContinuousParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL,
1264 				NULL, NULL, 0, 0, 0);
1265 
1266 		case BParameter::B_TEXT_PARAMETER:
1267 			return new BTextParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL, NULL, 0);
1268 
1269 		default:
1270 			ERROR("BParameterGroup::MakeControl unknown type %ld\n", type);
1271 			return NULL;
1272 	}
1273 }
1274 
1275 
1276 //	#pragma mark -
1277 
1278 /*************************************************************
1279  * public BParameter
1280  *************************************************************/
1281 
1282 
1283 BParameter::media_parameter_type
1284 BParameter::Type() const
1285 {
1286 	return mType;
1287 }
1288 
1289 
1290 BParameterWeb *
1291 BParameter::Web() const
1292 {
1293 	return mWeb;
1294 }
1295 
1296 
1297 BParameterGroup *
1298 BParameter::Group() const
1299 {
1300 	return mGroup;
1301 }
1302 
1303 
1304 const char *
1305 BParameter::Name() const
1306 {
1307 	return mName;
1308 }
1309 
1310 
1311 const char *
1312 BParameter::Kind() const
1313 {
1314 	return mKind;
1315 }
1316 
1317 
1318 const char *
1319 BParameter::Unit() const
1320 {
1321 	return mUnit;
1322 }
1323 
1324 
1325 int32
1326 BParameter::ID() const
1327 {
1328 	return mID;
1329 }
1330 
1331 
1332 void
1333 BParameter::SetFlags(uint32 flags)
1334 {
1335 	mFlags = flags;
1336 }
1337 
1338 
1339 uint32
1340 BParameter::Flags() const
1341 {
1342 	return mFlags;
1343 }
1344 
1345 
1346 status_t
1347 BParameter::GetValue(void *buffer, size_t *_ioSize, bigtime_t *_when)
1348 {
1349 	CALLED();
1350 
1351 	if (buffer == NULL || _ioSize == NULL)
1352 		return B_BAD_VALUE;
1353 
1354 	size_t ioSize = *_ioSize;
1355 	if (ioSize <= 0)
1356 		return B_NO_MEMORY;
1357 
1358 	if (mWeb == NULL) {
1359 		ERROR("BParameter::GetValue: no parent BParameterWeb\n");
1360 		return B_NO_INIT;
1361 	}
1362 
1363 	media_node node = mWeb->Node();
1364 	if (IS_INVALID_NODE(node)) {
1365 		ERROR("BParameter::GetValue: the parent BParameterWeb is not assigned to a BMediaNode\n");
1366 		return B_NO_INIT;
1367 	}
1368 
1369 	controllable_get_parameter_data_request request;
1370 	controllable_get_parameter_data_reply reply;
1371 
1372 	area_id area;
1373 	void *data;
1374 	if (ioSize > MAX_PARAMETER_DATA) {
1375 		// create an area if large data needs to be transfered
1376 		area = create_area("get parameter data", &data, B_ANY_ADDRESS, ROUND_UP_TO_PAGE(ioSize),
1377 			B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1378 		if (area < B_OK) {
1379 			ERROR("BParameter::GetValue can't create area of %ld bytes\n", ioSize);
1380 			return B_NO_MEMORY;
1381 		}
1382 	} else {
1383 		area = -1;
1384 		data = reply.rawdata;
1385 	}
1386 
1387 	request.parameter_id = mID;
1388 	request.requestsize = ioSize;
1389 	request.area = area;
1390 
1391 	status_t status = QueryPort(node.port, CONTROLLABLE_GET_PARAMETER_DATA, &request,
1392 		sizeof(request), &reply, sizeof(reply));
1393 	if (status == B_OK) {
1394 		// we don't want to copy more than the buffer provides
1395 		if (reply.size < ioSize)
1396 			ioSize = reply.size;
1397 
1398 		memcpy(buffer, data, ioSize);
1399 
1400 		// store reported values
1401 
1402 		*_ioSize = reply.size;
1403 		if (_when != NULL)
1404 			*_when = reply.last_change;
1405 	} else
1406 		ERROR("BParameter::GetValue parameter '%s' querying node %d, "
1407 			"port %d failed: %s\n",  mName, (int)node.node, (int)node.port,
1408 			strerror(status));
1409 
1410 	if (area >= B_OK)
1411 		delete_area(area);
1412 
1413 	return status;
1414 }
1415 
1416 
1417 status_t
1418 BParameter::SetValue(const void *buffer, size_t size, bigtime_t when)
1419 {
1420 	CALLED();
1421 
1422 	controllable_set_parameter_data_request request;
1423 	controllable_set_parameter_data_reply reply;
1424 	media_node node;
1425 	area_id area;
1426 	status_t rv;
1427 	void *data;
1428 
1429 	if (buffer == 0)
1430 		return B_BAD_VALUE;
1431 	if (size <= 0)
1432 		return B_NO_MEMORY;
1433 
1434 	if (mWeb == 0) {
1435 		ERROR("BParameter::SetValue: no parent BParameterWeb\n");
1436 		return B_NO_INIT;
1437 	}
1438 
1439 	node = mWeb->Node();
1440 	if (IS_INVALID_NODE(node)) {
1441 		ERROR("BParameter::SetValue: the parent BParameterWeb is not assigned to a BMediaNode\n");
1442 		return B_NO_INIT;
1443 	}
1444 
1445 	if (size > MAX_PARAMETER_DATA) {
1446 		// create an area if large data needs to be transfered
1447 		area = create_area("set parameter data", &data, B_ANY_ADDRESS, ROUND_UP_TO_PAGE(size), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
1448 		if (area < B_OK) {
1449 			ERROR("BParameter::SetValue can't create area of %ld bytes\n", size);
1450 			return B_NO_MEMORY;
1451 		}
1452 	} else {
1453 		area = -1;
1454 		data = request.rawdata;
1455 	}
1456 
1457 	memcpy(data, buffer, size);
1458 	request.parameter_id = mID;
1459 	request.when = when;
1460 	request.area = area;
1461 	request.size = size;
1462 
1463 	rv = QueryPort(node.port, CONTROLLABLE_SET_PARAMETER_DATA, &request, sizeof(request), &reply, sizeof(reply));
1464 	if (rv != B_OK)
1465 		ERROR("BParameter::SetValue querying node failed\n");
1466 
1467 	if (area != -1)
1468 		delete_area(area);
1469 
1470 	return rv;
1471 }
1472 
1473 
1474 int32
1475 BParameter::CountChannels()
1476 {
1477 	return mChannels;
1478 }
1479 
1480 
1481 void
1482 BParameter::SetChannelCount(int32 channel_count)
1483 {
1484 	mChannels = channel_count;
1485 }
1486 
1487 
1488 media_type
1489 BParameter::MediaType()
1490 {
1491 	return mMediaType;
1492 }
1493 
1494 
1495 void
1496 BParameter::SetMediaType(media_type m_type)
1497 {
1498 	mMediaType = m_type;
1499 }
1500 
1501 
1502 int32
1503 BParameter::CountInputs()
1504 {
1505 	ASSERT(mInputs != NULL);
1506 
1507 	return mInputs->CountItems();
1508 }
1509 
1510 
1511 BParameter *
1512 BParameter::InputAt(int32 index)
1513 {
1514 	ASSERT(mInputs != NULL);
1515 
1516 	return static_cast<BParameter *>(mInputs->ItemAt(index));
1517 }
1518 
1519 
1520 void
1521 BParameter::AddInput(BParameter *input)
1522 {
1523 	CALLED();
1524 
1525 	// BeBook has this method returning a status value,
1526 	// but it should be updated
1527 	if (input == NULL)
1528 		return;
1529 
1530 	ASSERT(mInputs != NULL);
1531 
1532 	if (mInputs->HasItem(input)) {
1533 		// if already in input list, don't duplicate.
1534 		return;
1535 	}
1536 
1537 	mInputs->AddItem(input);
1538 	input->AddOutput(this);
1539 }
1540 
1541 
1542 int32
1543 BParameter::CountOutputs()
1544 {
1545 	ASSERT(mOutputs != NULL);
1546 
1547 	return mOutputs->CountItems();
1548 }
1549 
1550 
1551 BParameter *
1552 BParameter::OutputAt(int32 index)
1553 {
1554 	ASSERT(mOutputs != NULL);
1555 
1556 	return static_cast<BParameter *>(mOutputs->ItemAt(index));
1557 }
1558 
1559 
1560 void
1561 BParameter::AddOutput(BParameter *output)
1562 {
1563 	CALLED();
1564 
1565 	// BeBook has this method returning a status value,
1566 	// but it should be updated
1567 	if (output == NULL)
1568 		return;
1569 
1570 	ASSERT(mOutputs != NULL);
1571 
1572 	if (mOutputs->HasItem(output)) {
1573 		// if already in output list, don't duplicate.
1574 		return;
1575 	}
1576 
1577 	mOutputs->AddItem(output);
1578 	output->AddInput(this);
1579 }
1580 
1581 
1582 bool
1583 BParameter::IsFixedSize() const
1584 {
1585 	return false;
1586 }
1587 
1588 
1589 type_code
1590 BParameter::TypeCode() const
1591 {
1592 	return B_MEDIA_PARAMETER_TYPE;
1593 }
1594 
1595 
1596 ssize_t
1597 BParameter::FlattenedSize() const
1598 {
1599 	CALLED();
1600 	/*
1601 		?? (0x02040607): 4 bytes
1602 		BParameter Struct Size (in bytes): 4 bytes
1603 		ID: 4 bytes
1604 		Name String Length: 1 byte (??)
1605 			Name String: 'Name String Length' bytes
1606 		Kind String Length: 1 byte (??)
1607 			Kind String: 'Kind String Length' bytes
1608 		Unit String Length: 1 byte (??)
1609 			Unit String: 'Unit String Length' bytes
1610 		Inputs Count: 4 bytes
1611 			Inputs (pointers): ('Inputs Count')*4 bytes
1612 		Outputs Count: 4 bytes
1613 			Outputs (pointers): ('Outputs Count')*4 bytes
1614 		Media Type: 4 bytes
1615 		ChannelCount: 4 bytes
1616 		Flags: 4 bytes
1617 	*/
1618 	//35 bytes are guaranteed, after that, add the variable length parts.
1619 	ssize_t size = 35;
1620 
1621 	if (mName != NULL)
1622 		size += strlen(mName);
1623 	if (mKind != NULL)
1624 		size += strlen(mKind);
1625 	if (mUnit != NULL)
1626 		size += strlen(mUnit);
1627 
1628 	if (mInputs != NULL)
1629 		size += mInputs->CountItems() * sizeof(BParameter *);
1630 
1631 	if (mOutputs != NULL)
1632 		size += mOutputs->CountItems() * sizeof(BParameter *);
1633 
1634 	return size;
1635 }
1636 
1637 
1638 status_t
1639 BParameter::Flatten(void *buffer, ssize_t size) const
1640 {
1641 	CALLED();
1642 
1643 	if (buffer == NULL) {
1644 		ERROR("BParameter::Flatten buffer is NULL\n");
1645 		return B_NO_INIT;
1646 	}
1647 
1648 	// NOTICE: It is important that this value is the size returned by
1649 	// BParameter::FlattenedSize(), not by a descendent's override of this method.
1650 	ssize_t actualSize = BParameter::FlattenedSize();
1651 	if (size < actualSize) {
1652 		ERROR("BParameter::Flatten(): size too small\n");
1653 		return B_NO_MEMORY;
1654 	}
1655 
1656 	write_to_buffer<uint32>(&buffer, kParameterMagic);
1657 	write_to_buffer<ssize_t>(&buffer, actualSize);
1658 	write_to_buffer<int32>(&buffer, mID);
1659 
1660 	write_string_to_buffer(&buffer, mName);
1661 	write_string_to_buffer(&buffer, mKind);
1662 	write_string_to_buffer(&buffer, mUnit);
1663 
1664 	// flatten and write the list of inputs
1665 	ssize_t count = mInputs ? mInputs->CountItems() : 0;
1666 	write_to_buffer<ssize_t>(&buffer, count);
1667 
1668 	if (count > 0) {
1669 		memcpy(buffer, mInputs->Items(), sizeof(BParameter *) * count);
1670 		skip_in_buffer(&buffer, sizeof(BParameter *) * count);
1671 	}
1672 
1673 	// flatten and write the list of outputs
1674 	count = mOutputs ? mOutputs->CountItems() : 0;
1675 	write_to_buffer<ssize_t>(&buffer, count);
1676 
1677 	if (count > 0) {
1678 		memcpy(buffer, mOutputs->Items(), sizeof(BParameter *) * count);
1679 		skip_in_buffer(&buffer, sizeof(BParameter *) * count);
1680 	}
1681 
1682 	write_to_buffer<media_type>(&buffer, mMediaType);
1683 	write_to_buffer<int32>(&buffer, mChannels);
1684 	write_to_buffer<uint32>(&buffer, mFlags);
1685 
1686 	return B_OK;
1687 }
1688 
1689 
1690 bool
1691 BParameter::AllowsTypeCode(type_code code) const
1692 {
1693 	return (code == TypeCode());
1694 }
1695 
1696 
1697 status_t
1698 BParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
1699 {
1700 	CALLED();
1701 
1702 	if (!AllowsTypeCode(code)) {
1703 		ERROR("BParameter::Unflatten(): wrong type code\n");
1704 		return B_BAD_TYPE;
1705 	}
1706 
1707 	if (buffer == NULL) {
1708 		ERROR("BParameter::Unflatten(): buffer is NULL\n");
1709 		return B_NO_INIT;
1710 	}
1711 
1712 	// if the buffer is smaller than the size needed to read the
1713 	// signature and struct size fields, then there is a problem
1714 	if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(ssize_t))) {
1715 		ERROR("BParameter::Unflatten() size too small\n");
1716 		return B_BAD_VALUE;
1717 	}
1718 
1719 	const void *bufferStart = buffer;
1720 
1721 	// check magic
1722 
1723 	uint32 magic = read_from_buffer<uint32>(&buffer);
1724 	if (magic == B_SWAP_INT32(kParameterMagic))
1725 		mSwapDetected = true;
1726 	else if (magic == kParameterMagic)
1727 		mSwapDetected = false;
1728 	else {
1729 		ERROR("BParameter::Unflatten(): bad magic\n");
1730 		return B_BAD_TYPE;
1731 	}
1732 
1733 	ssize_t parameterSize = read_from_buffer_swap32<ssize_t>(&buffer, mSwapDetected);
1734 	if (parameterSize > size) {
1735 		ERROR("BParameter::Unflatten(): buffer too small (%ld > %ld)\n", parameterSize, size);
1736 		return B_BAD_VALUE;
1737 	}
1738 
1739 	//if the struct doesn't meet the minimum size for
1740 	//a flattened BParameter, then return an error.
1741 	//MinFlattenedParamSize =
1742 	//ID (4 bytes)
1743 	//Name String Length (1 byte)
1744 	//Kind String Length (1 byte)
1745 	//Unit String Length (1 byte)
1746 	//Inputs Count (4 bytes)
1747 	//Outputs Count (4 bytes)
1748 	//Media Type (4 bytes)
1749 	//Channel Count (4 bytes)
1750 	//Flags (4 bytes)
1751 	//TOTAL: 27 bytes
1752 	const ssize_t MinFlattenedParamSize(27);
1753 	if (parameterSize < MinFlattenedParamSize) {
1754 		ERROR("BParameter::Unflatten out of memory (2)\n");
1755 		return B_ERROR;
1756 	}
1757 
1758 	mID = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
1759 
1760 	if (read_string_from_buffer(&buffer, &mName, size_left(size, bufferStart, buffer)) < B_OK
1761 		|| read_string_from_buffer(&buffer, &mKind, size_left(size, bufferStart, buffer)) < B_OK
1762 		|| read_string_from_buffer(&buffer, &mUnit, size_left(size, bufferStart, buffer)) < B_OK)
1763 		return B_NO_MEMORY;
1764 
1765 	// read the list of inputs
1766 
1767 	// it will directly add the pointers in the flattened message to the list;
1768 	// these will be fixed to point to the real inputs/outputs later in FixRefs()
1769 
1770 	int32 count = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
1771 
1772 	if (mInputs == NULL)
1773 		mInputs = new BList();
1774 	else
1775 		mInputs->MakeEmpty();
1776 
1777 	for (int32 i = 0; i < count; i++) {
1778 		mInputs->AddItem(read_from_buffer_swap32<BParameter * const>(&buffer, mSwapDetected));
1779 	}
1780 
1781 	// read the list of outputs
1782 
1783 	count = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
1784 
1785 	if (mOutputs == NULL)
1786 		mOutputs = new BList();
1787 	else
1788 		mOutputs->MakeEmpty();
1789 
1790 	for (int32 i = 0; i < count; i++) {
1791 		mOutputs->AddItem(read_from_buffer_swap32<BParameter * const>(&buffer, mSwapDetected));
1792 	}
1793 
1794 	mMediaType = read_from_buffer_swap32<media_type>(&buffer, mSwapDetected);
1795 	mChannels = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
1796 	mFlags = read_from_buffer_swap32<uint32>(&buffer, mSwapDetected);
1797 
1798 	return B_OK;
1799 }
1800 
1801 
1802 /*************************************************************
1803  * private BParameter
1804  *************************************************************/
1805 
1806 
1807 BParameter::BParameter(int32 id, media_type mediaType, media_parameter_type type,
1808 	BParameterWeb *web, const char *name, const char *kind, const char *unit)
1809 	:
1810 	mID(id),
1811 	mType(type),
1812 	mWeb(web),
1813 	mGroup(NULL),
1814 	mSwapDetected(true),
1815 	mMediaType(mediaType),
1816 	mChannels(1),
1817 	mFlags(0)
1818 {
1819 	CALLED();
1820 
1821 	mName = strndup(name, 256);
1822 	mKind = strndup(kind, 256);
1823 	mUnit = strndup(unit, 256);
1824 
1825 	// create empty input/output lists
1826 	mInputs = new BList();
1827 	mOutputs = new BList();
1828 }
1829 
1830 
1831 BParameter::~BParameter()
1832 {
1833 	CALLED();
1834 
1835 	// don't worry about the mWeb/mGroup properties, you don't need
1836 	// to remove yourself from a web/group since the only way in which
1837 	// a parameter is destroyed is when the owner web/group destroys it
1838 
1839 	free(mName);
1840 	free(mKind);
1841 	free(mUnit);
1842 
1843 	delete mInputs;
1844 	delete mOutputs;
1845 
1846 	mName = NULL; mKind = NULL; mUnit = NULL; mInputs = NULL; mOutputs = NULL;
1847 }
1848 
1849 
1850 /** Replaces references to items in the old list with the corresponding
1851  *	items in the updated list. The references are replaced in the input
1852  *	and output lists.
1853  *	This is called by BParameterWeb::Unflatten().
1854  */
1855 
1856 void
1857 BParameter::FixRefs(BList &old, BList &updated)
1858 {
1859 	CALLED();
1860 	ASSERT(mInputs != NULL);
1861 	ASSERT(mOutputs != NULL);
1862 
1863 	// update inputs
1864 
1865 	void **items = static_cast<void **>(mInputs->Items());
1866 	int32 count = mInputs->CountItems();
1867 
1868 	for (int32 i = 0; i < count; i++) {
1869 		int32 index = old.IndexOf(items[i]);
1870 		if (index >= 0)
1871 			items[i] = updated.ItemAt(index);
1872 		else {
1873 			ERROR("BParameter::FixRefs(): No mapping found for input");
1874 			items[i] = NULL;
1875 		}
1876 	}
1877 
1878 	// remove all NULL inputs (those which couldn't be mapped)
1879 
1880 	for (int32 i = count; i-- > 0;) {
1881 		if (items[i] == NULL)
1882 			mInputs->RemoveItem(i);
1883 	}
1884 
1885 	// update outputs
1886 
1887 	items = static_cast<void **>(mOutputs->Items());
1888 	count = mOutputs->CountItems();
1889 
1890 	for (int32 i = 0; i < count; i++) {
1891 		int32 index = old.IndexOf(items[i]);
1892 		if (index >= 0)
1893 			items[i] = updated.ItemAt(index);
1894 		else {
1895 			ERROR("BParameter::FixRefs(): No mapping found for output");
1896 			items[i] = NULL;
1897 		}
1898 	}
1899 
1900 	// remove all NULL outputs (those which couldn't be mapped)
1901 
1902 	for (int32 i = count; i-- > 0;) {
1903 		if (items[i] == NULL)
1904 			mOutputs->RemoveItem(i);
1905 	}
1906 }
1907 
1908 
1909 //	#pragma mark -
1910 
1911 /*************************************************************
1912  * public BContinuousParameter
1913  *************************************************************/
1914 
1915 
1916 type_code
1917 BContinuousParameter::ValueType()
1918 {
1919 	return B_FLOAT_TYPE;
1920 }
1921 
1922 
1923 float
1924 BContinuousParameter::MinValue()
1925 {
1926 	return mMinimum;
1927 }
1928 
1929 
1930 float
1931 BContinuousParameter::MaxValue()
1932 {
1933 	return mMaximum;
1934 }
1935 
1936 
1937 float
1938 BContinuousParameter::ValueStep()
1939 {
1940 	return mStepping;
1941 }
1942 
1943 
1944 void
1945 BContinuousParameter::SetResponse(int resp, float factor, float offset)
1946 {
1947 	mResponse = static_cast<response>(resp);
1948 	mFactor = factor;
1949 	mOffset = offset;
1950 }
1951 
1952 
1953 void
1954 BContinuousParameter::GetResponse(int *resp, float *factor, float *offset)
1955 {
1956 	if (resp != NULL)
1957 		*resp = mResponse;
1958 	if (factor != NULL)
1959 		*factor = mFactor;
1960 	if (offset != NULL)
1961 		*offset = mOffset;
1962 }
1963 
1964 
1965 ssize_t
1966 BContinuousParameter::FlattenedSize() const
1967 {
1968 	CALLED();
1969 
1970 	// only adds a fixed amount of bytes
1971 	return BParameter::FlattenedSize() + kAdditionalContinuousParameterSize;
1972 }
1973 
1974 
1975 status_t
1976 BContinuousParameter::Flatten(void *buffer, ssize_t size) const
1977 {
1978 	CALLED();
1979 
1980 	if (buffer == NULL) {
1981 		ERROR("BContinuousParameter::Flatten(): buffer is NULL\n");
1982 		return B_NO_INIT;
1983 	}
1984 
1985 	ssize_t parameterSize = BParameter::FlattenedSize();
1986 	if (size < (parameterSize + kAdditionalContinuousParameterSize)) {
1987 		ERROR("BContinuousParameter::Flatten(): size to small\n");
1988 		return B_NO_MEMORY;
1989 	}
1990 
1991 	status_t status = BParameter::Flatten(buffer, size);
1992 	if (status != B_OK) {
1993 		ERROR("BContinuousParameter::Flatten(): BParameter::Flatten() failed\n");
1994 		return status;
1995 	}
1996 
1997 	// add our data to the general flattened BParameter
1998 
1999 	skip_in_buffer(&buffer, parameterSize);
2000 
2001 	write_to_buffer<float>(&buffer, mMinimum);
2002 	write_to_buffer<float>(&buffer, mMaximum);
2003 	write_to_buffer<float>(&buffer, mStepping);
2004 	write_to_buffer<response>(&buffer, mResponse);
2005 	write_to_buffer<float>(&buffer, mFactor);
2006 	write_to_buffer<float>(&buffer, mOffset);
2007 
2008 	return B_OK;
2009 }
2010 
2011 
2012 status_t
2013 BContinuousParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
2014 {
2015 	CALLED();
2016 
2017 	// we try to check if the buffer size is long enough to hold an object
2018 	// as early as possible.
2019 
2020 	if (!AllowsTypeCode(code)) {
2021 		ERROR("BContinuousParameter::Unflatten wrong type code\n");
2022 		return B_BAD_TYPE;
2023 	}
2024 
2025 	if (buffer == NULL) {
2026 		ERROR("BContinuousParameter::Unflatten buffer is NULL\n");
2027 		return B_NO_INIT;
2028 	}
2029 
2030 	// if the buffer is smaller than the size needed to read the
2031 	// signature and struct size fields, then there is a problem
2032 	if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(ssize_t))) {
2033 		ERROR("BContinuousParameter::Unflatten size too small\n");
2034 		return B_ERROR;
2035 	}
2036 
2037 	status_t status = BParameter::Unflatten(code, buffer, size);
2038 	if (status != B_OK) {
2039 		ERROR("BContinuousParameter::Unflatten(): BParameter::Unflatten failed\n");
2040 		return status;
2041 	}
2042 
2043 	ssize_t parameterSize = BParameter::FlattenedSize();
2044 	skip_in_buffer(&buffer, parameterSize);
2045 
2046 	if (size < (parameterSize + kAdditionalContinuousParameterSize)) {
2047 		ERROR("BContinuousParameter::Unflatten(): buffer too small\n");
2048 		return B_BAD_VALUE;
2049 	}
2050 
2051 	mMinimum = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2052 	mMaximum = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2053 	mStepping = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2054 	mResponse = read_from_buffer_swap32<response>(&buffer, SwapOnUnflatten());
2055 	mFactor = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2056 	mOffset = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
2057 
2058 	return B_OK;
2059 }
2060 
2061 
2062 /*************************************************************
2063  * private BContinuousParameter
2064  *************************************************************/
2065 
2066 
2067 BContinuousParameter::BContinuousParameter(int32 id, media_type m_type,
2068 	BParameterWeb *web, const char *name, const char *kind, const char *unit,
2069 	float minimum, float maximum, float stepping)
2070 	:	BParameter(id, m_type, B_CONTINUOUS_PARAMETER, web, name, kind, unit),
2071 	mMinimum(minimum), mMaximum(maximum), mStepping(stepping),
2072 	mResponse(B_LINEAR), mFactor(1.0), mOffset(0.0)
2073 {
2074 	CALLED();
2075 }
2076 
2077 
2078 BContinuousParameter::~BContinuousParameter()
2079 {
2080 	CALLED();
2081 }
2082 
2083 
2084 //	#pragma mark -
2085 
2086 /*************************************************************
2087  * public BDiscreteParameter
2088  *************************************************************/
2089 
2090 
2091 type_code
2092 BDiscreteParameter::ValueType()
2093 {
2094 	return B_INT32_TYPE;
2095 }
2096 
2097 
2098 int32
2099 BDiscreteParameter::CountItems()
2100 {
2101 	ASSERT(mValues != NULL);
2102 
2103 	return mValues->CountItems();
2104 }
2105 
2106 
2107 const char *
2108 BDiscreteParameter::ItemNameAt(int32 index)
2109 {
2110 	ASSERT(mSelections != NULL);
2111 
2112 	return reinterpret_cast<const char *>(mSelections->ItemAt(index));
2113 }
2114 
2115 
2116 int32
2117 BDiscreteParameter::ItemValueAt(int32 index)
2118 {
2119 	ASSERT(mValues != NULL);
2120 
2121 	int32 *item = static_cast<int32 *>(mValues->ItemAt(index));
2122 	if (item == NULL)
2123 		return 0;
2124 
2125 	return *item;
2126 }
2127 
2128 
2129 status_t
2130 BDiscreteParameter::AddItem(int32 value, const char *name)
2131 {
2132 	CALLED();
2133 	//TRACE("\tthis = %p, value = %ld, name = \"%s\"\n", this, value, name);
2134 	ASSERT(mValues != NULL);
2135 	ASSERT(mSelections != NULL);
2136 
2137 	int32 *valueCopy = new int32(value);
2138 	char *nameCopy = strndup(name, 256);
2139 	if (name != NULL && nameCopy == NULL)
2140 		return B_NO_MEMORY;
2141 
2142 	if (!mValues->AddItem(valueCopy)
2143 		|| !mSelections->AddItem(nameCopy))
2144 		return B_NO_MEMORY;
2145 
2146 	return B_OK;
2147 }
2148 
2149 
2150 status_t
2151 BDiscreteParameter::MakeItemsFromInputs()
2152 {
2153 	CALLED();
2154 	ASSERT(mValues != NULL);
2155 	ASSERT(mSelections != NULL);
2156 	ASSERT(mInputs != NULL);
2157 
2158 	int32 count = mInputs->CountItems();
2159 	for(int32 i = 0; i < count; i++) {
2160 		BParameter *parameter = static_cast<BParameter *>(mInputs->ItemAt(i));
2161 		AddItem(i, parameter->Name());
2162 	}
2163 
2164 	return B_OK;
2165 }
2166 
2167 
2168 status_t
2169 BDiscreteParameter::MakeItemsFromOutputs()
2170 {
2171 	CALLED();
2172 	ASSERT(mValues != NULL);
2173 	ASSERT(mSelections != NULL);
2174 	ASSERT(mOutputs != NULL);
2175 
2176 	int32 count = mOutputs->CountItems();
2177 	for(int32 i = 0; i < count; i++) {
2178 		BParameter *parameter = static_cast<BParameter *>(mOutputs->ItemAt(i));
2179 		AddItem(i, parameter->Name());
2180 	}
2181 
2182 	return B_OK;
2183 }
2184 
2185 
2186 void
2187 BDiscreteParameter::MakeEmpty()
2188 {
2189 	CALLED();
2190 	ASSERT(mValues != NULL);
2191 	ASSERT(mSelections != NULL);
2192 
2193 	for (int32 i = mValues->CountItems(); i-- > 0;) {
2194 		delete static_cast<int32 *>(mValues->ItemAt(i));
2195 	}
2196 	mValues->MakeEmpty();
2197 
2198 	for(int32 i = mSelections->CountItems(); i-- > 0;) {
2199 		free(static_cast<char *>(mSelections->ItemAt(i)));
2200 	}
2201 	mSelections->MakeEmpty();
2202 }
2203 
2204 
2205 ssize_t
2206 BDiscreteParameter::FlattenedSize() const
2207 {
2208 	CALLED();
2209 
2210 	ssize_t size = BParameter::FlattenedSize() + kAdditionalDiscreteParameterSize;
2211 
2212 	int32 count = mValues ? mValues->CountItems() : 0;
2213 	for (int32 i = 0; i < count; i++) {
2214 		char *selection = static_cast<char *>(mSelections->ItemAt(i));
2215 
2216 		if (selection != NULL)
2217 			size += min_c(strlen(selection), 255);
2218 
2219 		size += 5;
2220 			// string length + value
2221 	}
2222 
2223 	return size;
2224 }
2225 
2226 
2227 status_t
2228 BDiscreteParameter::Flatten(void *buffer, ssize_t size) const
2229 {
2230 	CALLED();
2231 
2232 	if (buffer == NULL) {
2233 		ERROR("BDiscreteParameter::Flatten(): buffer is NULL\n");
2234 		return B_NO_INIT;
2235 	}
2236 
2237 	ssize_t parameterSize = BParameter::FlattenedSize();
2238 
2239 	if (size < FlattenedSize()) {
2240 		ERROR("BDiscreteParameter::Flatten(): size too small\n");
2241 		return B_NO_MEMORY;
2242 	}
2243 
2244 	status_t status = BParameter::Flatten(buffer, size);
2245 	if (status != B_OK) {
2246 		ERROR("BDiscreteParameter::Flatten(): BParameter::Flatten failed\n");
2247 		return status;
2248 	}
2249 
2250 	skip_in_buffer(&buffer, parameterSize);
2251 
2252 	int32 count = mValues ? mValues->CountItems() : 0;
2253 	write_to_buffer<int32>(&buffer, count);
2254 
2255 	// write out all value/name pairs
2256 	for (int32 i = 0; i < count; i++) {
2257 		const char *selection = static_cast<char *>(mSelections->ItemAt(i));
2258 		const int32 *value = static_cast<int32 *>(mValues->ItemAt(i));
2259 
2260 		write_string_to_buffer(&buffer, selection);
2261 		write_to_buffer<int32>(&buffer, value ? *value : 0);
2262 	}
2263 
2264 	return B_OK;
2265 }
2266 
2267 
2268 status_t
2269 BDiscreteParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
2270 {
2271 	CALLED();
2272 
2273 	if (!AllowsTypeCode(code)) {
2274 		ERROR("BDiscreteParameter::Unflatten(): bad type code\n");
2275 		return B_BAD_TYPE;
2276 	}
2277 
2278 	if (buffer == NULL) {
2279 		ERROR("BDiscreteParameter::Unflatten(): buffer is NULL\n");
2280 		return B_NO_INIT;
2281 	}
2282 
2283 	// if the buffer is smaller than the size needed to read the
2284 	// signature and struct size fields, then there is a problem
2285 	if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(ssize_t))) {
2286 		ERROR("BDiscreteParameter::Unflatten(): size too small\n");
2287 		return B_ERROR;
2288 	}
2289 
2290 	const void *bufferStart = buffer;
2291 
2292 	status_t status = BParameter::Unflatten(code, buffer, size);
2293 	if (status != B_OK) {
2294 		ERROR("BDiscreteParameter::Unflatten(): BParameter::Unflatten failed\n");
2295 		return status;
2296 	}
2297 
2298 	ssize_t parameterSize = BParameter::FlattenedSize();
2299 	skip_in_buffer(&buffer, parameterSize);
2300 
2301 	if (size < (parameterSize + kAdditionalDiscreteParameterSize)) {
2302 		ERROR("BDiscreteParameter::Unflatten(): buffer too small\n");
2303 		return B_BAD_VALUE;
2304 	}
2305 
2306 	int32 count = read_from_buffer_swap32<int32>(&buffer, SwapOnUnflatten());
2307 
2308 	// clear any existing name/value pairs
2309 	MakeEmpty();
2310 
2311 	for (int32 i = 0; i < count; i++) {
2312 		char *name;
2313 		if (read_string_from_buffer(&buffer, &name, size_left(size, bufferStart, buffer)) < B_OK)
2314 			return B_BAD_DATA;
2315 
2316 		if (size_left(size, bufferStart, buffer) < (int)sizeof(int32))
2317 			return B_BAD_DATA;
2318 
2319 		int32 value = read_from_buffer_swap32<int32>(&buffer, SwapOnUnflatten());
2320 
2321 		AddItem(value, name);
2322 	}
2323 
2324 	return B_OK;
2325 }
2326 
2327 
2328 /*************************************************************
2329  * private BDiscreteParameter
2330  *************************************************************/
2331 
2332 
2333 BDiscreteParameter::BDiscreteParameter(int32 id, media_type mediaType,
2334 	BParameterWeb *web, const char *name, const char *kind)
2335 	:	BParameter(id, mediaType, B_DISCRETE_PARAMETER, web, name, kind, NULL)
2336 {
2337 	CALLED();
2338 
2339 	mSelections = new BList();
2340 	mValues = new BList();
2341 }
2342 
2343 
2344 BDiscreteParameter::~BDiscreteParameter()
2345 {
2346 	CALLED();
2347 
2348 	MakeEmpty();
2349 
2350 	delete mSelections;
2351 	delete mValues;
2352 
2353 	mSelections = NULL; mValues = NULL;
2354 }
2355 
2356 
2357 //	#pragma mark -
2358 
2359 /*************************************************************
2360  * public BNullParameter
2361  *************************************************************/
2362 
2363 
2364 type_code
2365 BNullParameter::ValueType()
2366 {
2367 	// NULL parameters have no value type
2368 	return 0;
2369 }
2370 
2371 
2372 ssize_t
2373 BNullParameter::FlattenedSize() const
2374 {
2375 	return BParameter::FlattenedSize();
2376 }
2377 
2378 
2379 status_t
2380 BNullParameter::Flatten(void *buffer, ssize_t size) const
2381 {
2382 	return BParameter::Flatten(buffer, size);
2383 }
2384 
2385 
2386 status_t
2387 BNullParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
2388 {
2389 	return BParameter::Unflatten(code, buffer, size);
2390 }
2391 
2392 
2393 /*************************************************************
2394  * private BNullParameter
2395  *************************************************************/
2396 
2397 
2398 BNullParameter::BNullParameter(int32 id, media_type mediaType, BParameterWeb *web,
2399 	const char *name, const char *kind)
2400 	: BParameter(id, mediaType, B_NULL_PARAMETER, web, name, kind, NULL)
2401 {
2402 }
2403 
2404 
2405 BNullParameter::~BNullParameter()
2406 {
2407 }
2408 
2409 
2410 //	#pragma mark -
2411 
2412 /*************************************************************
2413  * public BTextParameter
2414  *************************************************************/
2415 
2416 
2417 size_t
2418 BTextParameter::MaxBytes() const
2419 {
2420 	// NULL parameters have no value type
2421 	return mMaxBytes;
2422 }
2423 
2424 
2425 type_code
2426 BTextParameter::ValueType()
2427 {
2428 	// NULL parameters have no value type
2429 	return 0;
2430 }
2431 
2432 
2433 ssize_t
2434 BTextParameter::FlattenedSize() const
2435 {
2436 	return BParameter::FlattenedSize() + sizeof(mMaxBytes);
2437 }
2438 
2439 
2440 status_t
2441 BTextParameter::Flatten(void *buffer, ssize_t size) const
2442 {
2443 	if (buffer == NULL) {
2444 		ERROR("BTextParameter::Flatten(): buffer is NULL\n");
2445 		return B_NO_INIT;
2446 	}
2447 
2448 	ssize_t parameterSize = BParameter::FlattenedSize();
2449 	if (size < static_cast<ssize_t>(parameterSize + sizeof(mMaxBytes))) {
2450 		ERROR("BContinuousParameter::Flatten(): size to small\n");
2451 		return B_NO_MEMORY;
2452 	}
2453 
2454 	status_t status = BParameter::Flatten(buffer, size);
2455 	if (status != B_OK) {
2456 		ERROR("BTextParameter::Flatten(): BParameter::Flatten() failed\n");
2457 		return status;
2458 	}
2459 
2460 	// add our data to the general flattened BParameter
2461 
2462 	skip_in_buffer(&buffer, parameterSize);
2463 
2464 	write_to_buffer<uint32>(&buffer, mMaxBytes);
2465 
2466 	return B_OK;
2467 }
2468 
2469 
2470 status_t
2471 BTextParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
2472 {
2473 	// we try to check if the buffer size is long enough to hold an object
2474 	// as early as possible.
2475 
2476 	if (!AllowsTypeCode(code)) {
2477 		ERROR("BTextParameter::Unflatten wrong type code\n");
2478 		return B_BAD_TYPE;
2479 	}
2480 
2481 	if (buffer == NULL) {
2482 		ERROR("BTextParameter::Unflatten buffer is NULL\n");
2483 		return B_NO_INIT;
2484 	}
2485 
2486 	if (size < static_cast<ssize_t>(sizeof(mMaxBytes))) {
2487 		ERROR("BTextParameter::Unflatten size too small\n");
2488 		return B_ERROR;
2489 	}
2490 
2491 	status_t status = BParameter::Unflatten(code, buffer, size);
2492 	if (status != B_OK) {
2493 		ERROR("BTextParameter::Unflatten(): BParameter::Unflatten failed\n");
2494 		return status;
2495 	}
2496 
2497 	ssize_t parameterSize = BParameter::FlattenedSize();
2498 	skip_in_buffer(&buffer, parameterSize);
2499 
2500 	if (size < static_cast<ssize_t>(parameterSize + sizeof(mMaxBytes))) {
2501 		ERROR("BTextParameter::Unflatten(): buffer too small\n");
2502 		return B_BAD_VALUE;
2503 	}
2504 
2505 	mMaxBytes = read_from_buffer_swap32<uint32>(&buffer, SwapOnUnflatten());
2506 
2507 	return B_OK;
2508 }
2509 
2510 
2511 /*************************************************************
2512  * private BTextParameter
2513  *************************************************************/
2514 
2515 
2516 BTextParameter::BTextParameter(int32 id, media_type mediaType, BParameterWeb *web,
2517 	const char *name, const char *kind, size_t max_bytes)
2518 	: BParameter(id, mediaType, B_NULL_PARAMETER, web, name, kind, NULL)
2519 {
2520 	mMaxBytes = max_bytes;
2521 }
2522 
2523 
2524 BTextParameter::~BTextParameter()
2525 {
2526 }
2527 
2528 
2529 //	#pragma mark -
2530 //	reserved functions
2531 
2532 
2533 status_t BParameterWeb::_Reserved_ControlWeb_0(void *) { return B_ERROR; }
2534 status_t BParameterWeb::_Reserved_ControlWeb_1(void *) { return B_ERROR; }
2535 status_t BParameterWeb::_Reserved_ControlWeb_2(void *) { return B_ERROR; }
2536 status_t BParameterWeb::_Reserved_ControlWeb_3(void *) { return B_ERROR; }
2537 status_t BParameterWeb::_Reserved_ControlWeb_4(void *) { return B_ERROR; }
2538 status_t BParameterWeb::_Reserved_ControlWeb_5(void *) { return B_ERROR; }
2539 status_t BParameterWeb::_Reserved_ControlWeb_6(void *) { return B_ERROR; }
2540 status_t BParameterWeb::_Reserved_ControlWeb_7(void *) { return B_ERROR; }
2541 
2542 status_t BParameterGroup::_Reserved_ControlGroup_0(void *) { return B_ERROR; }
2543 status_t BParameterGroup::_Reserved_ControlGroup_1(void *) { return B_ERROR; }
2544 status_t BParameterGroup::_Reserved_ControlGroup_2(void *) { return B_ERROR; }
2545 status_t BParameterGroup::_Reserved_ControlGroup_3(void *) { return B_ERROR; }
2546 status_t BParameterGroup::_Reserved_ControlGroup_4(void *) { return B_ERROR; }
2547 status_t BParameterGroup::_Reserved_ControlGroup_5(void *) { return B_ERROR; }
2548 status_t BParameterGroup::_Reserved_ControlGroup_6(void *) { return B_ERROR; }
2549 status_t BParameterGroup::_Reserved_ControlGroup_7(void *) { return B_ERROR; }
2550 
2551 status_t BParameter::_Reserved_Control_0(void *) { return B_ERROR; }
2552 status_t BParameter::_Reserved_Control_1(void *) { return B_ERROR; }
2553 status_t BParameter::_Reserved_Control_2(void *) { return B_ERROR; }
2554 status_t BParameter::_Reserved_Control_3(void *) { return B_ERROR; }
2555 status_t BParameter::_Reserved_Control_4(void *) { return B_ERROR; }
2556 status_t BParameter::_Reserved_Control_5(void *) { return B_ERROR; }
2557 status_t BParameter::_Reserved_Control_6(void *) { return B_ERROR; }
2558 status_t BParameter::_Reserved_Control_7(void *) { return B_ERROR; }
2559 
2560 status_t BContinuousParameter::_Reserved_ContinuousParameter_0(void *) { return B_ERROR; }
2561 status_t BContinuousParameter::_Reserved_ContinuousParameter_1(void *) { return B_ERROR; }
2562 status_t BContinuousParameter::_Reserved_ContinuousParameter_2(void *) { return B_ERROR; }
2563 status_t BContinuousParameter::_Reserved_ContinuousParameter_3(void *) { return B_ERROR; }
2564 status_t BContinuousParameter::_Reserved_ContinuousParameter_4(void *) { return B_ERROR; }
2565 status_t BContinuousParameter::_Reserved_ContinuousParameter_5(void *) { return B_ERROR; }
2566 status_t BContinuousParameter::_Reserved_ContinuousParameter_6(void *) { return B_ERROR; }
2567 status_t BContinuousParameter::_Reserved_ContinuousParameter_7(void *) { return B_ERROR; }
2568 
2569 status_t BDiscreteParameter::_Reserved_DiscreteParameter_0(void *) { return B_ERROR; }
2570 status_t BDiscreteParameter::_Reserved_DiscreteParameter_1(void *) { return B_ERROR; }
2571 status_t BDiscreteParameter::_Reserved_DiscreteParameter_2(void *) { return B_ERROR; }
2572 status_t BDiscreteParameter::_Reserved_DiscreteParameter_3(void *) { return B_ERROR; }
2573 status_t BDiscreteParameter::_Reserved_DiscreteParameter_4(void *) { return B_ERROR; }
2574 status_t BDiscreteParameter::_Reserved_DiscreteParameter_5(void *) { return B_ERROR; }
2575 status_t BDiscreteParameter::_Reserved_DiscreteParameter_6(void *) { return B_ERROR; }
2576 status_t BDiscreteParameter::_Reserved_DiscreteParameter_7(void *) { return B_ERROR; }
2577 
2578 status_t BNullParameter::_Reserved_NullParameter_0(void *) { return B_ERROR; }
2579 status_t BNullParameter::_Reserved_NullParameter_1(void *) { return B_ERROR; }
2580 status_t BNullParameter::_Reserved_NullParameter_2(void *) { return B_ERROR; }
2581 status_t BNullParameter::_Reserved_NullParameter_3(void *) { return B_ERROR; }
2582 status_t BNullParameter::_Reserved_NullParameter_4(void *) { return B_ERROR; }
2583 status_t BNullParameter::_Reserved_NullParameter_5(void *) { return B_ERROR; }
2584 status_t BNullParameter::_Reserved_NullParameter_6(void *) { return B_ERROR; }
2585 status_t BNullParameter::_Reserved_NullParameter_7(void *) { return B_ERROR; }
2586 
2587 status_t BTextParameter::_Reserved_TextParameter_0(void *) { return B_ERROR; }
2588 status_t BTextParameter::_Reserved_TextParameter_1(void *) { return B_ERROR; }
2589 status_t BTextParameter::_Reserved_TextParameter_2(void *) { return B_ERROR; }
2590 status_t BTextParameter::_Reserved_TextParameter_3(void *) { return B_ERROR; }
2591 status_t BTextParameter::_Reserved_TextParameter_4(void *) { return B_ERROR; }
2592 status_t BTextParameter::_Reserved_TextParameter_5(void *) { return B_ERROR; }
2593 status_t BTextParameter::_Reserved_TextParameter_6(void *) { return B_ERROR; }
2594 status_t BTextParameter::_Reserved_TextParameter_7(void *) { return B_ERROR; }
2595 
2596 
2597