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