Files
haiku-beta6/src/kits/media/ParameterWeb.cpp
T
Jérôme Duval a74d92608d style cleanup
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25173 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-26 11:31:00 +00:00

2576 lines
61 KiB
C++

/* ParameterWeb - implements the following classes:
** BParameterWeb, BParameterGroup, BParameter, BNullParameter,
** BContinuousParameter, BDiscreteParameter
**
** Author: Zousar Shaker
** Axel Dörfler, [email protected]
** Marcus Overhagen
**
** This file may be used under the terms of the OpenBeOS License.
*/
#include <ParameterWeb.h>
#include <MediaNode.h>
#include <string.h>
#include "DataExchange.h"
#include "MediaMisc.h"
#include "debug.h"
/*
The following is documentation on the flattened format
of structures/classes in this module:
//--------BEGIN-CORE-BPARAMETER-STRUCT---------------------
?? (0x02040607): 4 bytes
BParameter Struct Size (in bytes): 4 bytes
ID: 4 bytes
Name String Length: 1 byte (??)
Name String: 'Name String Length' bytes
Kind String Length: 1 byte (??)
Kind String: 'Kind String Length' bytes
Unit String Length: 1 byte (??)
Unit String: 'Unit String Length' bytes
Inputs Count: 4 bytes
Inputs (pointers): ('Inputs Count')*4 bytes
Outputs Count: 4 bytes
Outputs (pointers): ('Outputs Count')*4 bytes
Media Type: 4 bytes
ChannelCount: 4 bytes
Flags: 4 bytes
//---------END-CORE-BPARAMETER-STRUCT-----------------------
//--------BEGIN-BCONTINUOUSPARAMETER-STRUCT---------
Min: 4 bytes (as float)
Max: 4 bytes (as float)
Stepping: 4 bytes (as float)
Response: 4 bytes (as int or enum)
Factor: 4 bytes (as float)
Offset: 4 bytes (as float)
//--------END-BCONTINUOUSPARAMETER-STRUCT-------------
//--------BEGIN-BDISCRETEPARAMETER-STRUCT----------------
NumItems: 4 bytes (as int)
//for each item BEGIN
Item Name String Length: 1 byte
Item Name String: 'Item Name String Length' bytes
Item Value: 4 bytes (as int)
//for each item END
//--------END-BDISCRETEPARAMETER-STRUCT-------------------
//--------BEGIN-CORE-BPARAMETERGROUP-STRUCT-----------
?? (0x03040507 OR 0x03040509 depending if the flags field is included or not???): 4 bytes
(possible) Flags: 4 bytes
Name String Length: 1 byte (??)
Name String: 'Name String Length' bytes
Param Count: 4 bytes
//for each Param BEGIN
Pointer: 4 bytes
Parameter Type: 4 bytes
Flattened Parameter Size: 4 bytes
Flattened Parameter: 'Flattened Parameter Size' bytes
//for each Param END
Subgroup Count: 4 bytes
//for each SubGroup BEGIN
Pointer: 4 bytes
MEDIA PARAMETER GROUP TYPE('BMCG' (opposite byte order in file)): 4 bytes
Flattened Group Size: 4 bytes
Flattened Group: 'Flattened Group Size' bytes
//for each SubGroup END
//---------END-CORE-BPARAMETERGROUP-STRUCT--------------
//--------BEGIN-CORE-BPARAMETERWEB-STRUCT-----------
?? 0x01030506: 4 bytes
??: 4 bytes (is always 1)
Group Count: 4 bytes
Node (as media_node): 0x18 bytes (decimal 24 bytes)
//for each Group BEGIN
Flattened Group Size: 4 bytes
Flattened Group: 'Flattened Group Size' bytes
//for each Group END
//for each Group BEGIN
??: 4 bytes (never get written to (holds uninitialized value))
//for each Group END
//---------END-CORE-BPARAMETERWEB-STRUCT--------------
*/
const char * const B_GENERIC = "";
const char * const B_MASTER_GAIN = "Master";
const char * const B_GAIN = "Gain";
const char * const B_BALANCE = "Balance";
const char * const B_FREQUENCY = "Frequency";
const char * const B_LEVEL = "Level";
const char * const B_SHUTTLE_SPEED = "Speed";
const char * const B_CROSSFADE = "XFade";
const char * const B_EQUALIZATION = "EQ";
const char * const B_COMPRESSION = "Compression";
const char * const B_QUALITY = "Quality";
const char * const B_BITRATE = "Bitrate";
const char * const B_GOP_SIZE = "GOPSize";
const char * const B_MUTE = "Mute";
const char * const B_ENABLE = "Enable";
const char * const B_INPUT_MUX = "Input";
const char * const B_OUTPUT_MUX = "Output";
const char * const B_TUNER_CHANNEL = "Channel";
const char * const B_TRACK = "Track";
const char * const B_RECSTATE = "RecState";
const char * const B_SHUTTLE_MODE = "Shuttle";
const char * const B_RESOLUTION = "Resolution";
const char * const B_COLOR_SPACE = "Colorspace";
const char * const B_FRAME_RATE = "FrameRate";
const char * const B_VIDEO_FORMAT = "VideoFormat";
const char * const B_WEB_PHYSICAL_INPUT = "PhysInput";
const char * const B_WEB_PHYSICAL_OUTPUT = "PhysOutput";
const char * const B_WEB_ADC_CONVERTER = "ADC";
const char * const B_WEB_DAC_CONVERTER = "DAC";
const char * const B_WEB_LOGICAL_INPUT = "LogInput";
const char * const B_WEB_LOGICAL_OUTPUT = "LogOutput";
const char * const B_WEB_LOGICAL_BUS = "LogBus";
const char * const B_WEB_BUFFER_INPUT = "DataInput";
const char * const B_WEB_BUFFER_OUTPUT = "DataOutput";
const char * const B_SIMPLE_TRANSPORT = "SimpleTransport";
// Flattened data
static const int32 kCurrentParameterWebVersion = 1;
static const uint32 kParameterWebMagic = 0x01030506;
static const uint32 kBufferGroupMagic = 0x03040509;
static const uint32 kBufferGroupMagicNoFlags = 0x03040507;
static const uint32 kParameterMagic = 0x02040607;
static const ssize_t kAdditionalParameterGroupSize = 12;
static const ssize_t kAdditionalParameterSize = 35;
/* BContinuousParameter - FlattenedSize() fixed part
* Min: 4 bytes (as float)
* Max: 4 bytes (as float)
* Stepping: 4 bytes (as float)
* Response: 4 bytes (as int or enum)
* Factor: 4 bytes (as float)
* Offset: 4 bytes (as float)
*/
static const ssize_t kAdditionalContinuousParameterSize = 24;
static const ssize_t kAdditionalDiscreteParameterSize = sizeof(ssize_t);
// helper functions
template<class Type> Type
read_from_buffer(const void **_buffer)
{
const Type *typedBuffer = static_cast<const Type *>(*_buffer);
Type value = *typedBuffer;
typedBuffer++;
*_buffer = static_cast<const void *>(typedBuffer);
return value;
}
static status_t
read_string_from_buffer(const void **_buffer, char **_string, ssize_t size)
{
if (size < 1)
return B_BAD_VALUE;
const uint8 *buffer = static_cast<const uint8 *>(*_buffer);
uint8 length = *buffer++;
if (length > size - 1)
return B_BAD_VALUE;
char *string = (char *)malloc(length + 1);
if (string == NULL)
return B_NO_MEMORY;
memcpy(string, buffer, length);
string[length] = '\0';
*_buffer = static_cast<const void *>(buffer + length);
*_string = string;
return B_OK;
}
// currently unused
#if 0
template<class Type> Type *
reserve_in_buffer(void **_buffer)
{
Type *typedBuffer = static_cast<Type *>(*_buffer);
*typedBuffer = 0;
typedBuffer++;
*_buffer = static_cast<void *>(typedBuffer);
}
#endif
template<class Type> void
write_to_buffer(void **_buffer, Type value)
{
Type *typedBuffer = static_cast<Type *>(*_buffer);
*typedBuffer = value;
typedBuffer++;
*_buffer = static_cast<void *>(typedBuffer);
}
void
write_string_to_buffer(void **_buffer, const char *string)
{
uint8 *buffer = static_cast<uint8 *>(*_buffer);
uint32 length = string ? strlen(string) : 0;
if (length > 255)
length = 255;
*buffer++ = static_cast<uint8>(length);
if (length) {
memcpy(buffer, string, length);
buffer += length;
}
*_buffer = static_cast<void *>(buffer);
}
static void
skip_in_buffer(const void **_buffer, uint32 bytes)
{
const uint8 *buffer = static_cast<const uint8 *>(*_buffer);
buffer += bytes;
*_buffer = static_cast<const void *>(buffer);
}
static void inline
skip_in_buffer(void **_buffer, uint32 bytes)
{
// This actually shouldn't be necessary, but I believe it's a
// bug in Be's gcc - it complains about "adds cv-quals without intervening `const'"
// when passing a "const void **" pointer as the first argument.
// Maybe I am just stupid, though -- axeld.
skip_in_buffer((const void **)_buffer, bytes);
}
template<class Type> Type
swap32(Type value, bool doSwap)
{
STATIC_ASSERT(sizeof(Type) == 4);
if (doSwap)
return (Type)B_SWAP_INT32((int32)value);
return value;
}
template<class Type> Type
read_from_buffer_swap32(const void **_buffer, bool doSwap)
{
return swap32<Type>(read_from_buffer<Type>(_buffer), doSwap);
}
static inline ssize_t
size_left(ssize_t size, const void *bufferStart, const void *buffer)
{
return size - static_cast<ssize_t>((const uint8 *)buffer - (const uint8 *)bufferStart);
}
/** Copies the source string into a new buffer with the specified
* maximum size. This always includes a trailing zero byte.
* Returns NULL if the source string is either NULL or empty, or
* if there wasn't enough memory to allocate the buffer.
* The buffer returned is to be freed by the caller using free().
*/
static char *
strndup(const char *source, size_t maxBufferSize)
{
if (source == NULL || source[0] == '\0')
return NULL;
uint32 size = strlen(source) + 1;
if (size > maxBufferSize)
size = maxBufferSize;
char *target = (char *)malloc(size);
if (target == NULL)
return NULL;
memcpy(target, source, size - 1);
target[size - 1] = '\0';
return target;
}
// #pragma mark -
/*************************************************************
* public BParameterWeb
*************************************************************/
BParameterWeb::BParameterWeb()
: mNode(media_node::null) // mNode is set in BControllable::SetParameterWeb()
{
CALLED();
mGroups = new BList();
mOldRefs = new BList();
mNewRefs = new BList();
ASSERT(mGroups != NULL && mOldRefs != NULL && mNewRefs != NULL);
}
BParameterWeb::~BParameterWeb()
{
CALLED();
if (mGroups != NULL) {
for(int32 i = mGroups->CountItems(); i-- > 0;) {
delete static_cast<BParameterGroup *>(mGroups->ItemAt(i));
}
delete mGroups;
}
delete mOldRefs;
delete mNewRefs;
}
media_node
BParameterWeb::Node()
{
return mNode;
}
BParameterGroup *
BParameterWeb::MakeGroup(const char *name)
{
CALLED();
ASSERT(mGroups != NULL);
BParameterGroup *group = new BParameterGroup(this, name);
mGroups->AddItem(group);
return group;
}
int32
BParameterWeb::CountGroups()
{
ASSERT(mGroups != NULL);
return mGroups->CountItems();
}
BParameterGroup *
BParameterWeb::GroupAt(int32 index)
{
ASSERT(mGroups != NULL);
return static_cast<BParameterGroup *>(mGroups->ItemAt(index));
}
int32
BParameterWeb::CountParameters()
{
CALLED();
ASSERT(mGroups != NULL);
// Counts over all groups (and sub-groups) in the web.
// The "groups" list is used as count stack
BList groups(*mGroups);
int32 count = 0;
for (int32 i = 0; i < groups.CountItems(); i++) {
BParameterGroup *group = static_cast<BParameterGroup *>(groups.ItemAt(i));
count += group->CountParameters();
if (group->mGroups != NULL)
groups.AddList(group->mGroups);
}
return count;
}
BParameter *
BParameterWeb::ParameterAt(int32 index)
{
CALLED();
ASSERT(mGroups != NULL);
// Iterates over all groups (and sub-groups) in the web.
// The "groups" list is used as iteration stack (breadth search style)
// Maintains the same order as the Be implementation
BList groups(*mGroups);
for (int32 i = 0; i < groups.CountItems(); i++) {
BParameterGroup *group = static_cast<BParameterGroup *>(groups.ItemAt(i));
int32 count = group->CountParameters();
if (index < count)
return group->ParameterAt(index);
index -= count;
// the index is always relative to the start of the current group
if (group->mGroups != NULL)
groups.AddList(group->mGroups);
}
TRACE("*** could not find parameter at %ld (count = %ld)\n", index, CountParameters());
return NULL;
}
bool
BParameterWeb::IsFixedSize() const
{
return false;
}
type_code
BParameterWeb::TypeCode() const
{
return B_MEDIA_PARAMETER_WEB_TYPE;
}
ssize_t
BParameterWeb::FlattenedSize() const
{
CALLED();
/*
//--------BEGIN-CORE-BPARAMETERWEB-STRUCT-----------
?? 0x01030506: 4 bytes
??: 4 bytes (is always 1)
Group Count: 4 bytes
Node (as media_node): 0x18 bytes (decimal 24 bytes)
//for each Group BEGIN
Flattened Group Size: 4 bytes
Flattened Group: 'Flattened Group Size' bytes
//for each Group END
//for each Group BEGIN
??: 4 bytes (never get written to (holds uninitialized value))
//for each Group END
//---------END-CORE-BPARAMETERWEB-STRUCT--------------
*/
//36 guaranteed bytes, variable after that.
ssize_t size = sizeof(int32) + 2*sizeof(int32) + sizeof(media_node);
for (int32 i = mGroups->CountItems(); i-- > 0;) {
BParameterGroup *group = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
if (group != NULL) {
size += 4 + group->FlattenedSize();
// 4 bytes for the flattened size
}
}
return size;
}
status_t
BParameterWeb::Flatten(void *buffer, ssize_t size) const
{
CALLED();
if (buffer == NULL)
return B_NO_INIT;
ssize_t actualSize = BParameterWeb::FlattenedSize();
if (size < actualSize)
return B_NO_MEMORY;
void *bufferStart = buffer;
write_to_buffer<int32>(&buffer, kParameterWebMagic);
write_to_buffer<int32>(&buffer, kCurrentParameterWebVersion);
// flatten all groups into this buffer
int32 count = mGroups ? mGroups->CountItems() : 0;
write_to_buffer<int32>(&buffer, count);
write_to_buffer<media_node>(&buffer, mNode);
for (int32 i = 0; i < count; i++) {
BParameterGroup *group = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
if (group == NULL) {
ERROR("BParameterWeb::Flatten(): group is NULL\n");
continue;
}
ssize_t groupSize = group->FlattenedSize();
if (groupSize > size_left(size, bufferStart, buffer)) {
ERROR("BParameterWeb::Flatten(): buffer too small\n");
return B_BAD_VALUE;
}
write_to_buffer<ssize_t>(&buffer, groupSize);
// write the flattened sub group
status_t status = group->Flatten(buffer, groupSize);
if (status < B_OK)
return status;
skip_in_buffer(&buffer, groupSize);
}
return B_OK;
}
bool
BParameterWeb::AllowsTypeCode(type_code code) const
{
return code == TypeCode();
}
status_t
BParameterWeb::Unflatten(type_code code, const void *buffer, ssize_t size)
{
CALLED();
if (!AllowsTypeCode(code)) {
ERROR("BParameterWeb::Unflatten(): wrong type code\n");
return B_BAD_TYPE;
}
if (buffer == NULL) {
ERROR("BParameterWeb::Unflatten(): NULL buffer pointer\n");
return B_NO_INIT;
}
// if the buffer is smaller than the size needed to read the
// signature field, the mystery field, the group count, and the Node, then there is a problem
if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(int32) + sizeof(ssize_t) + sizeof(media_node)) )
{
ERROR("BParameterWeb::Unflatten(): size to small\n");
return B_ERROR;
}
const void *bufferStart = buffer;
uint32 magic = read_from_buffer<uint32>(&buffer);
bool isSwapped = false;
if (magic == B_SWAP_INT32(kParameterWebMagic)) {
isSwapped = true;
magic = B_SWAP_INT32(magic);
}
if (magic != kParameterWebMagic)
return B_BAD_DATA;
// Note, it's not completely sure that this field is the version
// information - but it doesn't seem to have another purpose
int32 version = read_from_buffer_swap32<int32>(&buffer, isSwapped);
if (version != kCurrentParameterWebVersion) {
ERROR("BParameterWeb::Unflatten(): wrong version %ld (%lx)?!\n", version, version);
return B_ERROR;
}
#if 0
if (mGroups != NULL) {
for (int32 i = 0; i < mGroups->CountItems(); i++) {
BParameterGroup *CurrentItem = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
if (CurrentItem != NULL) {
delete CurrentItem;
}
}
mGroups->MakeEmpty();
} else {
mGroups = new BList();
}
#endif
int32 count = read_from_buffer_swap32<int32>(&buffer, isSwapped);
mNode = read_from_buffer<media_node>(&buffer);
if (isSwapped)
swap_data(B_INT32_TYPE, &mNode, sizeof(media_node), B_SWAP_ALWAYS);
for (int32 i = 0; i < count; i++) {
ssize_t groupSize = read_from_buffer_swap32<ssize_t>(&buffer, isSwapped);
if (groupSize > size_left(size, bufferStart, buffer)) {
ERROR("BParameterWeb::Unflatten(): buffer too small\n");
return B_BAD_DATA;
}
BParameterGroup *group = new BParameterGroup(this, "unnamed");
status_t status = group->Unflatten(group->TypeCode(), buffer, groupSize);
if (status < B_OK) {
ERROR("BParameterWeb::Unflatten(): unflatten group failed\n");
delete group;
return status;
}
skip_in_buffer(&buffer, groupSize);
mGroups->AddItem(group);
}
// fix all references (ParameterAt() style)
if ((mOldRefs != NULL) && (mNewRefs != NULL)) {
BList groups(*mGroups);
for (int32 i = 0; i < groups.CountItems(); i++) {
BParameterGroup *group = static_cast<BParameterGroup *>(groups.ItemAt(i));
for (int32 index = group->CountParameters(); index-- > 0;) {
BParameter *parameter = static_cast<BParameter *>(group->ParameterAt(index));
parameter->FixRefs(*mOldRefs, *mNewRefs);
}
if (group->mGroups != NULL)
groups.AddList(group->mGroups);
}
mOldRefs->MakeEmpty();
mNewRefs->MakeEmpty();
}
return B_OK;
}
/*************************************************************
* private BParameterWeb
*************************************************************/
/*
unimplemented
BParameterWeb::BParameterWeb(const BParameterWeb &clone)
BParameterWeb &BParameterWeb::operator=(const BParameterWeb &clone)
*/
void
BParameterWeb::AddRefFix(void *oldItem, void *newItem)
{
ASSERT(mOldRefs != NULL);
ASSERT(mNewRefs != NULL);
mOldRefs->AddItem(oldItem);
mNewRefs->AddItem(newItem);
}
// #pragma mark -
/*************************************************************
* private BParameterGroup
*************************************************************/
BParameterGroup::BParameterGroup(BParameterWeb *web, const char *name)
: mWeb(web),
mFlags(0)
{
CALLED();
TRACE("BParameterGroup: web = %p, name = \"%s\"\n", web, name);
mName = strndup(name, 256);
mControls = new BList();
mGroups = new BList();
}
BParameterGroup::~BParameterGroup()
{
CALLED();
if (mControls) {
BParameter **items = reinterpret_cast<BParameter **>(mControls->Items());
for (int i = mControls->CountItems(); i-- > 0;)
delete items[i];
delete mControls;
}
if (mGroups) {
BParameterGroup **items = reinterpret_cast<BParameterGroup **>(mGroups->Items());
for (int i = mGroups->CountItems(); i-- > 0;)
delete items[i];
delete mGroups;
}
free(mName);
}
/*************************************************************
* public BParameterGroup
*************************************************************/
BParameterWeb *
BParameterGroup::Web() const
{
return mWeb;
}
const char *
BParameterGroup::Name() const
{
return mName;
}
void
BParameterGroup::SetFlags(uint32 flags)
{
mFlags = flags;
}
uint32
BParameterGroup::Flags() const
{
return mFlags;
}
BNullParameter *
BParameterGroup::MakeNullParameter(int32 id, media_type mediaType, const char *name,
const char *kind)
{
CALLED();
ASSERT(mControls != NULL);
BNullParameter *parameter = new BNullParameter(id, mediaType, mWeb, name, kind);
parameter->mGroup = this;
mControls->AddItem(parameter);
return parameter;
}
BTextParameter *
BParameterGroup::MakeTextParameter(int32 id, media_type mediaType, const char *name,
const char *kind, size_t max_bytes)
{
CALLED();
ASSERT(mControls != NULL);
BTextParameter *parameter = new BTextParameter(id, mediaType, mWeb, name, kind, max_bytes);
parameter->mGroup = this;
mControls->AddItem(parameter);
return parameter;
}
BContinuousParameter *
BParameterGroup::MakeContinuousParameter(int32 id, media_type mediaType,
const char *name, const char *kind, const char *unit,
float minimum, float maximum, float stepping)
{
CALLED();
ASSERT(mControls != NULL);
BContinuousParameter *parameter = new BContinuousParameter(id, mediaType, mWeb,
name, kind, unit, minimum, maximum, stepping);
parameter->mGroup = this;
mControls->AddItem(parameter);
return parameter;
}
BDiscreteParameter *
BParameterGroup::MakeDiscreteParameter(int32 id, media_type mediaType,
const char *name, const char *kind)
{
CALLED();
ASSERT(mControls != NULL);
BDiscreteParameter *parameter = new BDiscreteParameter(id, mediaType, mWeb, name, kind);
if (parameter == NULL)
return NULL;
parameter->mGroup = this;
mControls->AddItem(parameter);
return parameter;
}
BParameterGroup *
BParameterGroup::MakeGroup(const char *name)
{
CALLED();
ASSERT(mGroups != NULL);
BParameterGroup *group = new BParameterGroup(mWeb, name);
if (group != NULL)
mGroups->AddItem(group);
return group;
}
int32
BParameterGroup::CountParameters()
{
ASSERT(mControls != NULL);
return mControls->CountItems();
}
BParameter *
BParameterGroup::ParameterAt(int32 index)
{
ASSERT(mControls != NULL);
return static_cast<BParameter *>(mControls->ItemAt(index));
}
int32
BParameterGroup::CountGroups()
{
ASSERT(mGroups != NULL);
return mGroups->CountItems();
}
BParameterGroup *
BParameterGroup::GroupAt(int32 index)
{
ASSERT(mGroups != NULL);
return static_cast<BParameterGroup *>(mGroups->ItemAt(index));
}
bool
BParameterGroup::IsFixedSize() const
{
return false;
}
type_code
BParameterGroup::TypeCode() const
{
return B_MEDIA_PARAMETER_GROUP_TYPE;
}
ssize_t
BParameterGroup::FlattenedSize() const
{
CALLED();
ASSERT(mControls != NULL);
ASSERT(mGroups != NULL);
/*
//--------BEGIN-CORE-BPARAMETERGROUP-STRUCT-----------
?? (0x03040507 OR 0x03040509 depending if the flags field is included or not???): 4 bytes
(possible) Flags: 4 bytes
Name String Length: 1 byte (??)
Name String: 'Name String Length' bytes
Param Count: 4 bytes
//for each Param BEGIN
Pointer: 4 bytes
Parameter Type: 4 bytes
Flattened Parameter Size: 4 bytes
Flattened Parameter: 'Flattened Parameter Size' bytes
//for each Param END
Subgroup Count: 4 bytes
//for each SubGroup BEGIN
Pointer: 4 bytes
MEDIA PARAMETER GROUP TYPE('BMCG' (opposite byte order in file)): 4 bytes
Flattened Group Size: 4 bytes
Flattened Group: 'Flattened Group Size' bytes
//for each SubGroup END
//---------END-CORE-BPARAMETERGROUP-STRUCT--------------
*/
//13 guaranteed bytes, variable after that.
ssize_t size = 13;
if (mFlags != 0) {
size += 4;
}
if (mName != NULL) {
size += min_c(strlen(mName),255);
}
int i;
int limit;
limit = mControls->CountItems();
for (i = 0; i < limit; i++) {
BParameter *CurrentParameter = static_cast<BParameter *>(mControls->ItemAt(i));
if (CurrentParameter != NULL) {
//overhead for each parameter flattened
size += 16 + CurrentParameter->FlattenedSize();
}
}
limit = mGroups->CountItems();
for (i = 0; i < limit; i++) {
BParameterGroup *CurrentGroup = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
if (CurrentGroup != NULL) {
//overhead for each group flattened
size += 16 + CurrentGroup->FlattenedSize();
}
}
return size;
}
status_t
BParameterGroup::Flatten(void *buffer, ssize_t size) const
{
CALLED();
if (buffer == NULL) {
ERROR("BParameterGroup::Flatten buffer is NULL\n");
return B_NO_INIT;
}
// NOTICE: It is important that this value is the size returned by
// BParameterGroup::FlattenedSize, not by a descendent's override of this method.
ssize_t actualSize = BParameterGroup::FlattenedSize();
if (size < actualSize) {
ERROR("BParameterGroup::Flatten size to small\n");
return B_NO_MEMORY;
}
if (mFlags != 0) {
write_to_buffer<int32>(&buffer, kBufferGroupMagic);
write_to_buffer<uint32>(&buffer, mFlags);
} else
write_to_buffer<int32>(&buffer, kBufferGroupMagicNoFlags);
write_string_to_buffer(&buffer, mName);
int32 count = mControls ? mControls->CountItems() : 0;
write_to_buffer<int32>(&buffer, count);
for (int32 i = 0; i < count; i++) {
BParameter *parameter = static_cast<BParameter *>(mControls->ItemAt(i));
if (parameter == NULL) {
ERROR("BParameterGroup::Flatten(): NULL parameter\n");
continue;
}
write_to_buffer<BParameter *>(&buffer, parameter);
write_to_buffer<BParameter::media_parameter_type>(&buffer, parameter->Type());
// flatten parameter into this buffer
ssize_t parameterSize = parameter->FlattenedSize();
write_to_buffer<ssize_t>(&buffer, parameterSize);
status_t status = parameter->Flatten(buffer, parameterSize);
// we have only that much bytes left to write in this buffer
if (status < B_OK)
return status;
skip_in_buffer(&buffer, parameterSize);
}
count = mGroups ? mGroups->CountItems() : 0;
write_to_buffer<int32>(&buffer, count);
for (int32 i = 0; i < count; i++) {
BParameterGroup *group = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
if (group == NULL) {
ERROR("BParameterGroup::Flatten(): NULL group\n");
continue;
}
write_to_buffer<BParameterGroup *>(&buffer, group);
write_to_buffer<type_code>(&buffer, group->TypeCode());
// flatten sub group into this buffer
ssize_t groupSize = group->FlattenedSize();
write_to_buffer<ssize_t>(&buffer, groupSize);
status_t status = group->Flatten(buffer, groupSize);
// we have only that much bytes left to write in this buffer
if (status < B_OK)
return status;
skip_in_buffer(&buffer, groupSize);
}
return B_OK;
}
bool
BParameterGroup::AllowsTypeCode(type_code code) const
{
return code == TypeCode();
}
status_t
BParameterGroup::Unflatten(type_code code, const void *buffer, ssize_t size)
{
CALLED();
if (!AllowsTypeCode(code)) {
ERROR("BParameterGroup::Unflatten() wrong type code\n");
return B_BAD_TYPE;
}
if (buffer == NULL) {
ERROR("BParameterGroup::Unflatten() buffer is NULL\n");
return B_NO_INIT;
}
// if the buffer is smaller than the size needed to read the
// signature field, then there is a problem
if (size < static_cast<ssize_t>(sizeof(int32))) {
ERROR("BParameterGroup::Unflatten() size to small\n");
return B_ERROR;
}
const void *bufferStart = buffer;
// used to compute the rest length of the buffer when needed
uint32 magic = read_from_buffer<uint32>(&buffer);
bool isSwapped = false;
if (magic == B_SWAP_INT32(kBufferGroupMagic)
|| magic == B_SWAP_INT32(kBufferGroupMagicNoFlags)) {
isSwapped = true;
magic = B_SWAP_INT32(magic);
}
if (magic == kBufferGroupMagic)
mFlags = read_from_buffer_swap32<int32>(&buffer, isSwapped);
else if (magic == kBufferGroupMagicNoFlags)
mFlags = 0;
else
return B_BAD_TYPE;
if (read_string_from_buffer(&buffer, &mName,
size - static_cast<ssize_t>((uint8 *)buffer - (uint8 *)bufferStart)) < B_OK)
return B_BAD_VALUE;
// Currently disabled since it's not really used -- axeld.
#if 0
//Clear all existing parameters/subgroups
int i;
if (mControls != NULL) {
for(i = 0; i < mControls->CountItems(); i++) {
BParameter *CurrentItem = static_cast<BParameter *>(mControls->ItemAt(i));
if (CurrentItem != NULL) {
delete CurrentItem;
}
}
mControls->MakeEmpty();
} else {
mControls = new BList();
}
if (mGroups != NULL) {
for (i = 0; i < mGroups->CountItems(); i++) {
BParameterGroup *CurrentItem = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
if (CurrentItem != NULL) {
delete CurrentItem;
}
}
mGroups->MakeEmpty();
} else {
mGroups = new BList();
}
#endif
// unflatten parameter list
int32 count = read_from_buffer_swap32<int32>(&buffer, isSwapped);
if (count < 0 || count * kAdditionalParameterSize > size_left(size, bufferStart, buffer))
return B_BAD_VALUE;
for (int32 i = 0; i < count; i++) {
// make sure we can read as many bytes
if (size_left(size, bufferStart, buffer) < 12)
return B_BAD_VALUE;
BParameter *oldPointer = read_from_buffer_swap32<BParameter *>(&buffer, isSwapped);
BParameter::media_parameter_type mediaType =
read_from_buffer_swap32<BParameter::media_parameter_type>(&buffer, isSwapped);
ssize_t parameterSize = read_from_buffer_swap32<ssize_t>(&buffer, isSwapped);
if (parameterSize > size_left(size, bufferStart, buffer))
return B_BAD_VALUE;
BParameter *parameter = MakeControl(mediaType);
if (parameter == NULL) {
ERROR("BParameterGroup::Unflatten(): MakeControl() failed\n");
return B_ERROR;
}
status_t status = parameter->Unflatten(parameter->TypeCode(), buffer, parameterSize);
if (status < B_OK) {
ERROR("BParameterGroup::Unflatten(): parameter->Unflatten() failed\n");
delete parameter;
return status;
}
skip_in_buffer(&buffer, parameterSize);
// add the item to the list
parameter->mGroup = this;
parameter->mWeb = mWeb;
mControls->AddItem(parameter);
// add it's old pointer value to the RefFix list kept by the owner web
if (mWeb != NULL)
mWeb->AddRefFix(oldPointer, parameter);
}
// unflatten sub groups
count = read_from_buffer_swap32<int32>(&buffer, isSwapped);
if (count < 0 || count * kAdditionalParameterGroupSize > size_left(size, bufferStart, buffer))
return B_BAD_VALUE;
for (int32 i = 0; i < count; i++) {
// make sure we can read as many bytes
if (size_left(size, bufferStart, buffer) < 12)
return B_BAD_VALUE;
BParameterGroup *oldPointer = read_from_buffer_swap32<BParameterGroup *>(&buffer, isSwapped);
type_code type = read_from_buffer_swap32<type_code>(&buffer, isSwapped);
ssize_t groupSize = read_from_buffer_swap32<ssize_t>(&buffer, isSwapped);
if (groupSize > size_left(size, bufferStart, buffer))
return B_BAD_VALUE;
BParameterGroup *group = new BParameterGroup(mWeb, "sub-unnamed");
if (group == NULL) {
ERROR("BParameterGroup::Unflatten(): MakeGroup() failed\n");
return B_ERROR;
}
status_t status = group->Unflatten(type, buffer, groupSize);
if (status != B_OK) {
ERROR("BParameterGroup::Unflatten(): group->Unflatten() failed\n");
delete group;
return status;
}
skip_in_buffer(&buffer, groupSize);
mGroups->AddItem(group);
// add it's old pointer value to the RefFix list kept by the owner web
if (mWeb != NULL)
mWeb->AddRefFix(oldPointer, group);
}
return B_OK;
}
/*************************************************************
* private BParameterGroup
*************************************************************/
/*
// unimplemented
BParameterGroup::BParameterGroup()
BParameterGroup::BParameterGroup(const BParameterGroup &clone)
BParameterGroup &BParameterGroup::operator=(const BParameterGroup &clone)
*/
/** Creates an uninitialized parameter of the specified type.
* Unlike the BParameterGroup::MakeXXXParameter() type of methods, this
* method does not add the parameter to this group automatically.
*/
BParameter *
BParameterGroup::MakeControl(int32 type)
{
CALLED();
switch (type) {
case BParameter::B_NULL_PARAMETER:
return new BNullParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL, NULL);
case BParameter::B_DISCRETE_PARAMETER:
return new BDiscreteParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL,
NULL);
case BParameter::B_CONTINUOUS_PARAMETER:
return new BContinuousParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL,
NULL, NULL, 0, 0, 0);
case BParameter::B_TEXT_PARAMETER:
return new BTextParameter(-1, B_MEDIA_NO_TYPE, NULL, NULL, NULL, 0);
default:
ERROR("BParameterGroup::MakeControl unknown type %ld\n", type);
return NULL;
}
}
// #pragma mark -
/*************************************************************
* public BParameter
*************************************************************/
BParameter::media_parameter_type
BParameter::Type() const
{
return mType;
}
BParameterWeb *
BParameter::Web() const
{
return mWeb;
}
BParameterGroup *
BParameter::Group() const
{
return mGroup;
}
const char *
BParameter::Name() const
{
return mName;
}
const char *
BParameter::Kind() const
{
return mKind;
}
const char *
BParameter::Unit() const
{
return mUnit;
}
int32
BParameter::ID() const
{
return mID;
}
void
BParameter::SetFlags(uint32 flags)
{
mFlags = flags;
}
uint32
BParameter::Flags() const
{
return mFlags;
}
status_t
BParameter::GetValue(void *buffer, size_t *_ioSize, bigtime_t *_when)
{
CALLED();
if (buffer == NULL || _ioSize == NULL)
return B_BAD_VALUE;
size_t ioSize = *_ioSize;
if (ioSize <= 0)
return B_NO_MEMORY;
if (mWeb == NULL) {
ERROR("BParameter::GetValue: no parent BParameterWeb\n");
return B_NO_INIT;
}
media_node node = mWeb->Node();
if (IS_INVALID_NODE(node)) {
ERROR("BParameter::GetValue: the parent BParameterWeb is not assigned to a BMediaNode\n");
return B_NO_INIT;
}
controllable_get_parameter_data_request request;
controllable_get_parameter_data_reply reply;
area_id area;
void *data;
if (ioSize > MAX_PARAMETER_DATA) {
// create an area if large data needs to be transfered
area = create_area("get parameter data", &data, B_ANY_ADDRESS, ROUND_UP_TO_PAGE(ioSize),
B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (area < B_OK) {
ERROR("BParameter::GetValue can't create area of %ld bytes\n", ioSize);
return B_NO_MEMORY;
}
} else {
area = -1;
data = reply.rawdata;
}
request.parameter_id = mID;
request.requestsize = ioSize;
request.area = area;
status_t status = QueryPort(node.port, CONTROLLABLE_GET_PARAMETER_DATA, &request,
sizeof(request), &reply, sizeof(reply));
if (status == B_OK) {
// we don't want to copy more than the buffer provides
if (reply.size < ioSize)
ioSize = reply.size;
memcpy(buffer, data, ioSize);
// store reported values
*_ioSize = reply.size;
if (_when != NULL)
*_when = reply.last_change;
} else
ERROR("BParameter::GetValue parameter '%s' querying node %d, "
"port %d failed: %s\n", mName, (int)node.node, (int)node.port,
strerror(status));
if (area >= B_OK)
delete_area(area);
return status;
}
status_t
BParameter::SetValue(const void *buffer, size_t size, bigtime_t when)
{
CALLED();
controllable_set_parameter_data_request request;
controllable_set_parameter_data_reply reply;
media_node node;
area_id area;
status_t rv;
void *data;
if (buffer == 0)
return B_BAD_VALUE;
if (size <= 0)
return B_NO_MEMORY;
if (mWeb == 0) {
ERROR("BParameter::SetValue: no parent BParameterWeb\n");
return B_NO_INIT;
}
node = mWeb->Node();
if (IS_INVALID_NODE(node)) {
ERROR("BParameter::SetValue: the parent BParameterWeb is not assigned to a BMediaNode\n");
return B_NO_INIT;
}
if (size > MAX_PARAMETER_DATA) {
// create an area if large data needs to be transfered
area = create_area("set parameter data", &data, B_ANY_ADDRESS, ROUND_UP_TO_PAGE(size), B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (area < B_OK) {
ERROR("BParameter::SetValue can't create area of %ld bytes\n", size);
return B_NO_MEMORY;
}
} else {
area = -1;
data = request.rawdata;
}
memcpy(data, buffer, size);
request.parameter_id = mID;
request.when = when;
request.area = area;
request.size = size;
rv = QueryPort(node.port, CONTROLLABLE_SET_PARAMETER_DATA, &request, sizeof(request), &reply, sizeof(reply));
if (rv != B_OK)
ERROR("BParameter::SetValue querying node failed\n");
if (area != -1)
delete_area(area);
return rv;
}
int32
BParameter::CountChannels()
{
return mChannels;
}
void
BParameter::SetChannelCount(int32 channel_count)
{
mChannels = channel_count;
}
media_type
BParameter::MediaType()
{
return mMediaType;
}
void
BParameter::SetMediaType(media_type m_type)
{
mMediaType = m_type;
}
int32
BParameter::CountInputs()
{
ASSERT(mInputs != NULL);
return mInputs->CountItems();
}
BParameter *
BParameter::InputAt(int32 index)
{
ASSERT(mInputs != NULL);
return static_cast<BParameter *>(mInputs->ItemAt(index));
}
void
BParameter::AddInput(BParameter *input)
{
CALLED();
// BeBook has this method returning a status value,
// but it should be updated
if (input == NULL)
return;
ASSERT(mInputs != NULL);
if (mInputs->HasItem(input)) {
// if already in input list, don't duplicate.
return;
}
mInputs->AddItem(input);
input->AddOutput(this);
}
int32
BParameter::CountOutputs()
{
ASSERT(mOutputs != NULL);
return mOutputs->CountItems();
}
BParameter *
BParameter::OutputAt(int32 index)
{
ASSERT(mOutputs != NULL);
return static_cast<BParameter *>(mOutputs->ItemAt(index));
}
void
BParameter::AddOutput(BParameter *output)
{
CALLED();
// BeBook has this method returning a status value,
// but it should be updated
if (output == NULL)
return;
ASSERT(mOutputs != NULL);
if (mOutputs->HasItem(output)) {
// if already in output list, don't duplicate.
return;
}
mOutputs->AddItem(output);
output->AddInput(this);
}
bool
BParameter::IsFixedSize() const
{
return false;
}
type_code
BParameter::TypeCode() const
{
return B_MEDIA_PARAMETER_TYPE;
}
ssize_t
BParameter::FlattenedSize() const
{
CALLED();
/*
?? (0x02040607): 4 bytes
BParameter Struct Size (in bytes): 4 bytes
ID: 4 bytes
Name String Length: 1 byte (??)
Name String: 'Name String Length' bytes
Kind String Length: 1 byte (??)
Kind String: 'Kind String Length' bytes
Unit String Length: 1 byte (??)
Unit String: 'Unit String Length' bytes
Inputs Count: 4 bytes
Inputs (pointers): ('Inputs Count')*4 bytes
Outputs Count: 4 bytes
Outputs (pointers): ('Outputs Count')*4 bytes
Media Type: 4 bytes
ChannelCount: 4 bytes
Flags: 4 bytes
*/
//35 bytes are guaranteed, after that, add the variable length parts.
ssize_t size = 35;
if (mName != NULL)
size += strlen(mName);
if (mKind != NULL)
size += strlen(mKind);
if (mUnit != NULL)
size += strlen(mUnit);
if (mInputs != NULL)
size += mInputs->CountItems() * sizeof(BParameter *);
if (mOutputs != NULL)
size += mOutputs->CountItems() * sizeof(BParameter *);
return size;
}
status_t
BParameter::Flatten(void *buffer, ssize_t size) const
{
CALLED();
if (buffer == NULL) {
ERROR("BParameter::Flatten buffer is NULL\n");
return B_NO_INIT;
}
// NOTICE: It is important that this value is the size returned by
// BParameter::FlattenedSize(), not by a descendent's override of this method.
ssize_t actualSize = BParameter::FlattenedSize();
if (size < actualSize) {
ERROR("BParameter::Flatten(): size too small\n");
return B_NO_MEMORY;
}
write_to_buffer<uint32>(&buffer, kParameterMagic);
write_to_buffer<ssize_t>(&buffer, actualSize);
write_to_buffer<int32>(&buffer, mID);
write_string_to_buffer(&buffer, mName);
write_string_to_buffer(&buffer, mKind);
write_string_to_buffer(&buffer, mUnit);
// flatten and write the list of inputs
ssize_t count = mInputs ? mInputs->CountItems() : 0;
write_to_buffer<ssize_t>(&buffer, count);
if (count > 0) {
memcpy(buffer, mInputs->Items(), sizeof(BParameter *) * count);
skip_in_buffer(&buffer, sizeof(BParameter *) * count);
}
// flatten and write the list of outputs
count = mOutputs ? mOutputs->CountItems() : 0;
write_to_buffer<ssize_t>(&buffer, count);
if (count > 0) {
memcpy(buffer, mOutputs->Items(), sizeof(BParameter *) * count);
skip_in_buffer(&buffer, sizeof(BParameter *) * count);
}
write_to_buffer<media_type>(&buffer, mMediaType);
write_to_buffer<int32>(&buffer, mChannels);
write_to_buffer<uint32>(&buffer, mFlags);
return B_OK;
}
bool
BParameter::AllowsTypeCode(type_code code) const
{
return (code == TypeCode());
}
status_t
BParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
{
CALLED();
if (!AllowsTypeCode(code)) {
ERROR("BParameter::Unflatten(): wrong type code\n");
return B_BAD_TYPE;
}
if (buffer == NULL) {
ERROR("BParameter::Unflatten(): buffer is NULL\n");
return B_NO_INIT;
}
// if the buffer is smaller than the size needed to read the
// signature and struct size fields, then there is a problem
if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(ssize_t))) {
ERROR("BParameter::Unflatten() size too small\n");
return B_BAD_VALUE;
}
const void *bufferStart = buffer;
// check magic
uint32 magic = read_from_buffer<uint32>(&buffer);
if (magic == B_SWAP_INT32(kParameterMagic))
mSwapDetected = true;
else if (magic == kParameterMagic)
mSwapDetected = false;
else {
ERROR("BParameter::Unflatten(): bad magic\n");
return B_BAD_TYPE;
}
ssize_t parameterSize = read_from_buffer_swap32<ssize_t>(&buffer, mSwapDetected);
if (parameterSize > size) {
ERROR("BParameter::Unflatten(): buffer too small (%ld > %ld)\n", parameterSize, size);
return B_BAD_VALUE;
}
//if the struct doesn't meet the minimum size for
//a flattened BParameter, then return an error.
//MinFlattenedParamSize =
//ID (4 bytes)
//Name String Length (1 byte)
//Kind String Length (1 byte)
//Unit String Length (1 byte)
//Inputs Count (4 bytes)
//Outputs Count (4 bytes)
//Media Type (4 bytes)
//Channel Count (4 bytes)
//Flags (4 bytes)
//TOTAL: 27 bytes
const ssize_t MinFlattenedParamSize(27);
if (parameterSize < MinFlattenedParamSize) {
ERROR("BParameter::Unflatten out of memory (2)\n");
return B_ERROR;
}
mID = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
if (read_string_from_buffer(&buffer, &mName, size_left(size, bufferStart, buffer)) < B_OK
|| read_string_from_buffer(&buffer, &mKind, size_left(size, bufferStart, buffer)) < B_OK
|| read_string_from_buffer(&buffer, &mUnit, size_left(size, bufferStart, buffer)) < B_OK)
return B_NO_MEMORY;
// read the list of inputs
// it will directly add the pointers in the flattened message to the list;
// these will be fixed to point to the real inputs/outputs later in FixRefs()
int32 count = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
if (mInputs == NULL)
mInputs = new BList();
else
mInputs->MakeEmpty();
for (int32 i = 0; i < count; i++) {
mInputs->AddItem(read_from_buffer_swap32<BParameter * const>(&buffer, mSwapDetected));
}
// read the list of outputs
count = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
if (mOutputs == NULL)
mOutputs = new BList();
else
mOutputs->MakeEmpty();
for (int32 i = 0; i < count; i++) {
mOutputs->AddItem(read_from_buffer_swap32<BParameter * const>(&buffer, mSwapDetected));
}
mMediaType = read_from_buffer_swap32<media_type>(&buffer, mSwapDetected);
mChannels = read_from_buffer_swap32<int32>(&buffer, mSwapDetected);
mFlags = read_from_buffer_swap32<uint32>(&buffer, mSwapDetected);
return B_OK;
}
/*************************************************************
* private BParameter
*************************************************************/
BParameter::BParameter(int32 id, media_type mediaType, media_parameter_type type,
BParameterWeb *web, const char *name, const char *kind, const char *unit)
:
mID(id),
mType(type),
mWeb(web),
mGroup(NULL),
mSwapDetected(true),
mMediaType(mediaType),
mChannels(1),
mFlags(0)
{
CALLED();
mName = strndup(name, 256);
mKind = strndup(kind, 256);
mUnit = strndup(unit, 256);
// create empty input/output lists
mInputs = new BList();
mOutputs = new BList();
}
BParameter::~BParameter()
{
CALLED();
// don't worry about the mWeb/mGroup properties, you don't need
// to remove yourself from a web/group since the only way in which
// a parameter is destroyed is when the owner web/group destroys it
free(mName);
free(mKind);
free(mUnit);
delete mInputs;
delete mOutputs;
mName = NULL; mKind = NULL; mUnit = NULL; mInputs = NULL; mOutputs = NULL;
}
/** Replaces references to items in the old list with the corresponding
* items in the updated list. The references are replaced in the input
* and output lists.
* This is called by BParameterWeb::Unflatten().
*/
void
BParameter::FixRefs(BList &old, BList &updated)
{
CALLED();
ASSERT(mInputs != NULL);
ASSERT(mOutputs != NULL);
// update inputs
void **items = static_cast<void **>(mInputs->Items());
int32 count = mInputs->CountItems();
for (int32 i = 0; i < count; i++) {
int32 index = old.IndexOf(items[i]);
if (index >= 0)
items[i] = updated.ItemAt(index);
else {
ERROR("BParameter::FixRefs(): No mapping found for input");
items[i] = NULL;
}
}
// remove all NULL inputs (those which couldn't be mapped)
for (int32 i = count; i-- > 0;) {
if (items[i] == NULL)
mInputs->RemoveItem(i);
}
// update outputs
items = static_cast<void **>(mOutputs->Items());
count = mOutputs->CountItems();
for (int32 i = 0; i < count; i++) {
int32 index = old.IndexOf(items[i]);
if (index >= 0)
items[i] = updated.ItemAt(index);
else {
ERROR("BParameter::FixRefs(): No mapping found for output");
items[i] = NULL;
}
}
// remove all NULL outputs (those which couldn't be mapped)
for (int32 i = count; i-- > 0;) {
if (items[i] == NULL)
mOutputs->RemoveItem(i);
}
}
// #pragma mark -
/*************************************************************
* public BContinuousParameter
*************************************************************/
type_code
BContinuousParameter::ValueType()
{
return B_FLOAT_TYPE;
}
float
BContinuousParameter::MinValue()
{
return mMinimum;
}
float
BContinuousParameter::MaxValue()
{
return mMaximum;
}
float
BContinuousParameter::ValueStep()
{
return mStepping;
}
void
BContinuousParameter::SetResponse(int resp, float factor, float offset)
{
mResponse = static_cast<response>(resp);
mFactor = factor;
mOffset = offset;
}
void
BContinuousParameter::GetResponse(int *resp, float *factor, float *offset)
{
if (resp != NULL)
*resp = mResponse;
if (factor != NULL)
*factor = mFactor;
if (offset != NULL)
*offset = mOffset;
}
ssize_t
BContinuousParameter::FlattenedSize() const
{
CALLED();
// only adds a fixed amount of bytes
return BParameter::FlattenedSize() + kAdditionalContinuousParameterSize;
}
status_t
BContinuousParameter::Flatten(void *buffer, ssize_t size) const
{
CALLED();
if (buffer == NULL) {
ERROR("BContinuousParameter::Flatten(): buffer is NULL\n");
return B_NO_INIT;
}
ssize_t parameterSize = BParameter::FlattenedSize();
if (size < (parameterSize + kAdditionalContinuousParameterSize)) {
ERROR("BContinuousParameter::Flatten(): size to small\n");
return B_NO_MEMORY;
}
status_t status = BParameter::Flatten(buffer, size);
if (status != B_OK) {
ERROR("BContinuousParameter::Flatten(): BParameter::Flatten() failed\n");
return status;
}
// add our data to the general flattened BParameter
skip_in_buffer(&buffer, parameterSize);
write_to_buffer<float>(&buffer, mMinimum);
write_to_buffer<float>(&buffer, mMaximum);
write_to_buffer<float>(&buffer, mStepping);
write_to_buffer<response>(&buffer, mResponse);
write_to_buffer<float>(&buffer, mFactor);
write_to_buffer<float>(&buffer, mOffset);
return B_OK;
}
status_t
BContinuousParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
{
CALLED();
// we try to check if the buffer size is long enough to hold an object
// as early as possible.
if (!AllowsTypeCode(code)) {
ERROR("BContinuousParameter::Unflatten wrong type code\n");
return B_BAD_TYPE;
}
if (buffer == NULL) {
ERROR("BContinuousParameter::Unflatten buffer is NULL\n");
return B_NO_INIT;
}
// if the buffer is smaller than the size needed to read the
// signature and struct size fields, then there is a problem
if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(ssize_t))) {
ERROR("BContinuousParameter::Unflatten size too small\n");
return B_ERROR;
}
status_t status = BParameter::Unflatten(code, buffer, size);
if (status != B_OK) {
ERROR("BContinuousParameter::Unflatten(): BParameter::Unflatten failed\n");
return status;
}
ssize_t parameterSize = BParameter::FlattenedSize();
skip_in_buffer(&buffer, parameterSize);
if (size < (parameterSize + kAdditionalContinuousParameterSize)) {
ERROR("BContinuousParameter::Unflatten(): buffer too small\n");
return B_BAD_VALUE;
}
mMinimum = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
mMaximum = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
mStepping = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
mResponse = read_from_buffer_swap32<response>(&buffer, SwapOnUnflatten());
mFactor = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
mOffset = read_from_buffer_swap32<float>(&buffer, SwapOnUnflatten());
return B_OK;
}
/*************************************************************
* private BContinuousParameter
*************************************************************/
BContinuousParameter::BContinuousParameter(int32 id, media_type m_type,
BParameterWeb *web, const char *name, const char *kind, const char *unit,
float minimum, float maximum, float stepping)
: BParameter(id, m_type, B_CONTINUOUS_PARAMETER, web, name, kind, unit),
mMinimum(minimum), mMaximum(maximum), mStepping(stepping),
mResponse(B_LINEAR), mFactor(1.0), mOffset(0.0)
{
CALLED();
}
BContinuousParameter::~BContinuousParameter()
{
CALLED();
}
// #pragma mark -
/*************************************************************
* public BDiscreteParameter
*************************************************************/
type_code
BDiscreteParameter::ValueType()
{
return B_INT32_TYPE;
}
int32
BDiscreteParameter::CountItems()
{
ASSERT(mValues != NULL);
return mValues->CountItems();
}
const char *
BDiscreteParameter::ItemNameAt(int32 index)
{
ASSERT(mSelections != NULL);
return reinterpret_cast<const char *>(mSelections->ItemAt(index));
}
int32
BDiscreteParameter::ItemValueAt(int32 index)
{
ASSERT(mValues != NULL);
int32 *item = static_cast<int32 *>(mValues->ItemAt(index));
if (item == NULL)
return 0;
return *item;
}
status_t
BDiscreteParameter::AddItem(int32 value, const char *name)
{
CALLED();
//TRACE("\tthis = %p, value = %ld, name = \"%s\"\n", this, value, name);
ASSERT(mValues != NULL);
ASSERT(mSelections != NULL);
int32 *valueCopy = new int32(value);
char *nameCopy = strndup(name, 256);
if (name != NULL && nameCopy == NULL)
return B_NO_MEMORY;
if (!mValues->AddItem(valueCopy)
|| !mSelections->AddItem(nameCopy))
return B_NO_MEMORY;
return B_OK;
}
status_t
BDiscreteParameter::MakeItemsFromInputs()
{
CALLED();
ASSERT(mValues != NULL);
ASSERT(mSelections != NULL);
ASSERT(mInputs != NULL);
int32 count = mInputs->CountItems();
for(int32 i = 0; i < count; i++) {
BParameter *parameter = static_cast<BParameter *>(mInputs->ItemAt(i));
AddItem(i, parameter->Name());
}
return B_OK;
}
status_t
BDiscreteParameter::MakeItemsFromOutputs()
{
CALLED();
ASSERT(mValues != NULL);
ASSERT(mSelections != NULL);
ASSERT(mOutputs != NULL);
int32 count = mOutputs->CountItems();
for(int32 i = 0; i < count; i++) {
BParameter *parameter = static_cast<BParameter *>(mOutputs->ItemAt(i));
AddItem(i, parameter->Name());
}
return B_OK;
}
void
BDiscreteParameter::MakeEmpty()
{
CALLED();
ASSERT(mValues != NULL);
ASSERT(mSelections != NULL);
for (int32 i = mValues->CountItems(); i-- > 0;) {
delete static_cast<int32 *>(mValues->ItemAt(i));
}
mValues->MakeEmpty();
for(int32 i = mSelections->CountItems(); i-- > 0;) {
free(static_cast<char *>(mSelections->ItemAt(i)));
}
mSelections->MakeEmpty();
}
ssize_t
BDiscreteParameter::FlattenedSize() const
{
CALLED();
ssize_t size = BParameter::FlattenedSize() + kAdditionalDiscreteParameterSize;
int32 count = mValues ? mValues->CountItems() : 0;
for (int32 i = 0; i < count; i++) {
char *selection = static_cast<char *>(mSelections->ItemAt(i));
if (selection != NULL)
size += min_c(strlen(selection), 255);
size += 5;
// string length + value
}
return size;
}
status_t
BDiscreteParameter::Flatten(void *buffer, ssize_t size) const
{
CALLED();
if (buffer == NULL) {
ERROR("BDiscreteParameter::Flatten(): buffer is NULL\n");
return B_NO_INIT;
}
ssize_t parameterSize = BParameter::FlattenedSize();
if (size < FlattenedSize()) {
ERROR("BDiscreteParameter::Flatten(): size too small\n");
return B_NO_MEMORY;
}
status_t status = BParameter::Flatten(buffer, size);
if (status != B_OK) {
ERROR("BDiscreteParameter::Flatten(): BParameter::Flatten failed\n");
return status;
}
skip_in_buffer(&buffer, parameterSize);
int32 count = mValues ? mValues->CountItems() : 0;
write_to_buffer<int32>(&buffer, count);
// write out all value/name pairs
for (int32 i = 0; i < count; i++) {
const char *selection = static_cast<char *>(mSelections->ItemAt(i));
const int32 *value = static_cast<int32 *>(mValues->ItemAt(i));
write_string_to_buffer(&buffer, selection);
write_to_buffer<int32>(&buffer, value ? *value : 0);
}
return B_OK;
}
status_t
BDiscreteParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
{
CALLED();
if (!AllowsTypeCode(code)) {
ERROR("BDiscreteParameter::Unflatten(): bad type code\n");
return B_BAD_TYPE;
}
if (buffer == NULL) {
ERROR("BDiscreteParameter::Unflatten(): buffer is NULL\n");
return B_NO_INIT;
}
// if the buffer is smaller than the size needed to read the
// signature and struct size fields, then there is a problem
if (size < static_cast<ssize_t>(sizeof(int32) + sizeof(ssize_t))) {
ERROR("BDiscreteParameter::Unflatten(): size too small\n");
return B_ERROR;
}
const void *bufferStart = buffer;
status_t status = BParameter::Unflatten(code, buffer, size);
if (status != B_OK) {
ERROR("BDiscreteParameter::Unflatten(): BParameter::Unflatten failed\n");
return status;
}
ssize_t parameterSize = BParameter::FlattenedSize();
skip_in_buffer(&buffer, parameterSize);
if (size < (parameterSize + kAdditionalDiscreteParameterSize)) {
ERROR("BDiscreteParameter::Unflatten(): buffer too small\n");
return B_BAD_VALUE;
}
int32 count = read_from_buffer_swap32<int32>(&buffer, SwapOnUnflatten());
// clear any existing name/value pairs
MakeEmpty();
for (int32 i = 0; i < count; i++) {
char *name;
if (read_string_from_buffer(&buffer, &name, size_left(size, bufferStart, buffer)) < B_OK)
return B_BAD_DATA;
if (size_left(size, bufferStart, buffer) < (int)sizeof(int32))
return B_BAD_DATA;
int32 value = read_from_buffer_swap32<int32>(&buffer, SwapOnUnflatten());
AddItem(value, name);
}
return B_OK;
}
/*************************************************************
* private BDiscreteParameter
*************************************************************/
BDiscreteParameter::BDiscreteParameter(int32 id, media_type mediaType,
BParameterWeb *web, const char *name, const char *kind)
: BParameter(id, mediaType, B_DISCRETE_PARAMETER, web, name, kind, NULL)
{
CALLED();
mSelections = new BList();
mValues = new BList();
}
BDiscreteParameter::~BDiscreteParameter()
{
CALLED();
MakeEmpty();
delete mSelections;
delete mValues;
mSelections = NULL; mValues = NULL;
}
// #pragma mark -
/*************************************************************
* public BNullParameter
*************************************************************/
type_code
BNullParameter::ValueType()
{
// NULL parameters have no value type
return 0;
}
ssize_t
BNullParameter::FlattenedSize() const
{
return BParameter::FlattenedSize();
}
status_t
BNullParameter::Flatten(void *buffer, ssize_t size) const
{
return BParameter::Flatten(buffer, size);
}
status_t
BNullParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
{
return BParameter::Unflatten(code, buffer, size);
}
/*************************************************************
* private BNullParameter
*************************************************************/
BNullParameter::BNullParameter(int32 id, media_type mediaType, BParameterWeb *web,
const char *name, const char *kind)
: BParameter(id, mediaType, B_NULL_PARAMETER, web, name, kind, NULL)
{
}
BNullParameter::~BNullParameter()
{
}
// #pragma mark -
/*************************************************************
* public BTextParameter
*************************************************************/
size_t
BTextParameter::MaxBytes() const
{
// NULL parameters have no value type
return mMaxBytes;
}
type_code
BTextParameter::ValueType()
{
// NULL parameters have no value type
return 0;
}
ssize_t
BTextParameter::FlattenedSize() const
{
return BParameter::FlattenedSize() + sizeof(mMaxBytes);
}
status_t
BTextParameter::Flatten(void *buffer, ssize_t size) const
{
if (buffer == NULL) {
ERROR("BTextParameter::Flatten(): buffer is NULL\n");
return B_NO_INIT;
}
ssize_t parameterSize = BParameter::FlattenedSize();
if (size < static_cast<ssize_t>(parameterSize + sizeof(mMaxBytes))) {
ERROR("BContinuousParameter::Flatten(): size to small\n");
return B_NO_MEMORY;
}
status_t status = BParameter::Flatten(buffer, size);
if (status != B_OK) {
ERROR("BTextParameter::Flatten(): BParameter::Flatten() failed\n");
return status;
}
// add our data to the general flattened BParameter
skip_in_buffer(&buffer, parameterSize);
write_to_buffer<uint32>(&buffer, mMaxBytes);
return B_OK;
}
status_t
BTextParameter::Unflatten(type_code code, const void *buffer, ssize_t size)
{
// we try to check if the buffer size is long enough to hold an object
// as early as possible.
if (!AllowsTypeCode(code)) {
ERROR("BTextParameter::Unflatten wrong type code\n");
return B_BAD_TYPE;
}
if (buffer == NULL) {
ERROR("BTextParameter::Unflatten buffer is NULL\n");
return B_NO_INIT;
}
if (size < static_cast<ssize_t>(sizeof(mMaxBytes))) {
ERROR("BTextParameter::Unflatten size too small\n");
return B_ERROR;
}
status_t status = BParameter::Unflatten(code, buffer, size);
if (status != B_OK) {
ERROR("BTextParameter::Unflatten(): BParameter::Unflatten failed\n");
return status;
}
ssize_t parameterSize = BParameter::FlattenedSize();
skip_in_buffer(&buffer, parameterSize);
if (size < static_cast<ssize_t>(parameterSize + sizeof(mMaxBytes))) {
ERROR("BTextParameter::Unflatten(): buffer too small\n");
return B_BAD_VALUE;
}
mMaxBytes = read_from_buffer_swap32<uint32>(&buffer, SwapOnUnflatten());
return B_OK;
}
/*************************************************************
* private BTextParameter
*************************************************************/
BTextParameter::BTextParameter(int32 id, media_type mediaType, BParameterWeb *web,
const char *name, const char *kind, size_t max_bytes)
: BParameter(id, mediaType, B_NULL_PARAMETER, web, name, kind, NULL)
{
mMaxBytes = max_bytes;
}
BTextParameter::~BTextParameter()
{
}
// #pragma mark -
// reserved functions
status_t BParameterWeb::_Reserved_ControlWeb_0(void *) { return B_ERROR; }
status_t BParameterWeb::_Reserved_ControlWeb_1(void *) { return B_ERROR; }
status_t BParameterWeb::_Reserved_ControlWeb_2(void *) { return B_ERROR; }
status_t BParameterWeb::_Reserved_ControlWeb_3(void *) { return B_ERROR; }
status_t BParameterWeb::_Reserved_ControlWeb_4(void *) { return B_ERROR; }
status_t BParameterWeb::_Reserved_ControlWeb_5(void *) { return B_ERROR; }
status_t BParameterWeb::_Reserved_ControlWeb_6(void *) { return B_ERROR; }
status_t BParameterWeb::_Reserved_ControlWeb_7(void *) { return B_ERROR; }
status_t BParameterGroup::_Reserved_ControlGroup_0(void *) { return B_ERROR; }
status_t BParameterGroup::_Reserved_ControlGroup_1(void *) { return B_ERROR; }
status_t BParameterGroup::_Reserved_ControlGroup_2(void *) { return B_ERROR; }
status_t BParameterGroup::_Reserved_ControlGroup_3(void *) { return B_ERROR; }
status_t BParameterGroup::_Reserved_ControlGroup_4(void *) { return B_ERROR; }
status_t BParameterGroup::_Reserved_ControlGroup_5(void *) { return B_ERROR; }
status_t BParameterGroup::_Reserved_ControlGroup_6(void *) { return B_ERROR; }
status_t BParameterGroup::_Reserved_ControlGroup_7(void *) { return B_ERROR; }
status_t BParameter::_Reserved_Control_0(void *) { return B_ERROR; }
status_t BParameter::_Reserved_Control_1(void *) { return B_ERROR; }
status_t BParameter::_Reserved_Control_2(void *) { return B_ERROR; }
status_t BParameter::_Reserved_Control_3(void *) { return B_ERROR; }
status_t BParameter::_Reserved_Control_4(void *) { return B_ERROR; }
status_t BParameter::_Reserved_Control_5(void *) { return B_ERROR; }
status_t BParameter::_Reserved_Control_6(void *) { return B_ERROR; }
status_t BParameter::_Reserved_Control_7(void *) { return B_ERROR; }
status_t BContinuousParameter::_Reserved_ContinuousParameter_0(void *) { return B_ERROR; }
status_t BContinuousParameter::_Reserved_ContinuousParameter_1(void *) { return B_ERROR; }
status_t BContinuousParameter::_Reserved_ContinuousParameter_2(void *) { return B_ERROR; }
status_t BContinuousParameter::_Reserved_ContinuousParameter_3(void *) { return B_ERROR; }
status_t BContinuousParameter::_Reserved_ContinuousParameter_4(void *) { return B_ERROR; }
status_t BContinuousParameter::_Reserved_ContinuousParameter_5(void *) { return B_ERROR; }
status_t BContinuousParameter::_Reserved_ContinuousParameter_6(void *) { return B_ERROR; }
status_t BContinuousParameter::_Reserved_ContinuousParameter_7(void *) { return B_ERROR; }
status_t BDiscreteParameter::_Reserved_DiscreteParameter_0(void *) { return B_ERROR; }
status_t BDiscreteParameter::_Reserved_DiscreteParameter_1(void *) { return B_ERROR; }
status_t BDiscreteParameter::_Reserved_DiscreteParameter_2(void *) { return B_ERROR; }
status_t BDiscreteParameter::_Reserved_DiscreteParameter_3(void *) { return B_ERROR; }
status_t BDiscreteParameter::_Reserved_DiscreteParameter_4(void *) { return B_ERROR; }
status_t BDiscreteParameter::_Reserved_DiscreteParameter_5(void *) { return B_ERROR; }
status_t BDiscreteParameter::_Reserved_DiscreteParameter_6(void *) { return B_ERROR; }
status_t BDiscreteParameter::_Reserved_DiscreteParameter_7(void *) { return B_ERROR; }
status_t BNullParameter::_Reserved_NullParameter_0(void *) { return B_ERROR; }
status_t BNullParameter::_Reserved_NullParameter_1(void *) { return B_ERROR; }
status_t BNullParameter::_Reserved_NullParameter_2(void *) { return B_ERROR; }
status_t BNullParameter::_Reserved_NullParameter_3(void *) { return B_ERROR; }
status_t BNullParameter::_Reserved_NullParameter_4(void *) { return B_ERROR; }
status_t BNullParameter::_Reserved_NullParameter_5(void *) { return B_ERROR; }
status_t BNullParameter::_Reserved_NullParameter_6(void *) { return B_ERROR; }
status_t BNullParameter::_Reserved_NullParameter_7(void *) { return B_ERROR; }
status_t BTextParameter::_Reserved_TextParameter_0(void *) { return B_ERROR; }
status_t BTextParameter::_Reserved_TextParameter_1(void *) { return B_ERROR; }
status_t BTextParameter::_Reserved_TextParameter_2(void *) { return B_ERROR; }
status_t BTextParameter::_Reserved_TextParameter_3(void *) { return B_ERROR; }
status_t BTextParameter::_Reserved_TextParameter_4(void *) { return B_ERROR; }
status_t BTextParameter::_Reserved_TextParameter_5(void *) { return B_ERROR; }
status_t BTextParameter::_Reserved_TextParameter_6(void *) { return B_ERROR; }
status_t BTextParameter::_Reserved_TextParameter_7(void *) { return B_ERROR; }