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