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