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