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