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