git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1233 a95241bf-73f2-0310-859d-f6bbb57e9c96
3154 lines
77 KiB
C++
3154 lines
77 KiB
C++
/***********************************************************************
|
|
* AUTHOR: Zousar Shaker
|
|
* FILE: ParameterWeb.cpp
|
|
* DESCR: BParameterWeb, BParameterGroup, BParameter, BNullParameter,
|
|
* BContinuousParameter, BDiscreteParameter
|
|
***********************************************************************/
|
|
#include <ParameterWeb.h>
|
|
#include <Debug.h>
|
|
#include "debug.h"
|
|
|
|
//--------BEGIN-ADDED-BY-ZS----------------------------------
|
|
|
|
//Comment keywords:
|
|
// FIXME: Something that should be fixed
|
|
// QUESTION: Something that needs clarification
|
|
// NOTICE: Explanation of what's going on
|
|
|
|
typedef unsigned char byte;
|
|
|
|
/* by Marcus Overhagen: Sorry Zousar, but I really want the program
|
|
* to be stopped when something is wrong!
|
|
*/
|
|
#if 1 /* always use these */
|
|
|
|
#define ASSERT_WRETURN_VALUE(CheckExpr,RetVal) \
|
|
ASSERT(CheckExpr)
|
|
|
|
#define ASSERT_RETURN(CheckExpr) \
|
|
ASSERT(CheckExpr)
|
|
|
|
#else /* and disable the other macros */
|
|
|
|
/*************************************************************
|
|
* Used to check assertions, and if the assertions fail, a
|
|
* value is returned. It is used only to check
|
|
* potentially erronious conditions INTERNAL to the code (ie:
|
|
* if I have forgotten to change a variable from NULL to some
|
|
* usable value) it is NOT used to check erronious input from
|
|
* the outside world (ie: if the user of a class passes NULL for
|
|
* some parameter). (ZS)
|
|
*************************************************************/
|
|
#define ASSERT_WRETURN_VALUE(CheckExpr,RetVal)\
|
|
if(!(CheckExpr))\
|
|
{\
|
|
return (RetVal);\
|
|
}
|
|
/*************************************************************
|
|
* Used to check assertions, and if the assertions fail, the
|
|
* method returns (no return value). It is used only to check
|
|
* potentially erronious conditions INTERNAL to the code (ie:
|
|
* if I have forgotten to change a variable from NULL to some
|
|
* usable value) it is NOT used to check erronious input from
|
|
* the outside world (ie: if the user of a class passes NULL for
|
|
* some parameter). (ZS)
|
|
*************************************************************/
|
|
#define ASSERT_RETURN(CheckExpr)\
|
|
if(!(CheckExpr))\
|
|
{\
|
|
return;\
|
|
}
|
|
|
|
#endif /* end of disabled macros */
|
|
|
|
/*
|
|
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--------------
|
|
|
|
*/
|
|
|
|
//--------END-ADDED-BY-ZS-------------------------------------
|
|
|
|
|
|
|
|
/*************************************************************
|
|
*
|
|
*************************************************************/
|
|
|
|
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";
|
|
|
|
/*************************************************************
|
|
* public BParameterWeb
|
|
*************************************************************/
|
|
|
|
BParameterWeb::BParameterWeb():mNode(media_node::null)
|
|
{
|
|
mGroups = new BList();
|
|
|
|
mOldRefs = new BList();
|
|
mNewRefs = new BList();
|
|
}
|
|
|
|
|
|
BParameterWeb::~BParameterWeb()
|
|
{
|
|
int i;
|
|
|
|
if(mGroups != NULL)
|
|
{
|
|
for(i = 0;i < mGroups->CountItems(); i++)
|
|
{
|
|
BParameterGroup *CurrentGroup = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
|
|
|
|
if(CurrentGroup != NULL)
|
|
{
|
|
delete CurrentGroup;
|
|
}
|
|
}
|
|
mGroups->MakeEmpty();
|
|
delete mGroups;
|
|
mGroups = NULL;
|
|
}
|
|
|
|
if(mOldRefs != NULL)
|
|
{
|
|
mOldRefs->MakeEmpty();
|
|
delete mOldRefs;
|
|
}
|
|
|
|
if(mNewRefs != NULL)
|
|
{
|
|
mNewRefs->MakeEmpty();
|
|
delete mNewRefs;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
media_node
|
|
BParameterWeb::Node()
|
|
{
|
|
return mNode;
|
|
}
|
|
|
|
|
|
BParameterGroup *
|
|
BParameterWeb::MakeGroup(const char *name)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mGroups != NULL,NULL);
|
|
|
|
BParameterGroup *NewGroup = new BParameterGroup(this,name);
|
|
|
|
mGroups->AddItem(NewGroup);
|
|
|
|
return NewGroup;
|
|
}
|
|
|
|
|
|
int32
|
|
BParameterWeb::CountGroups()
|
|
{
|
|
ASSERT_WRETURN_VALUE(mGroups != NULL,0);
|
|
|
|
return mGroups->CountItems();
|
|
}
|
|
|
|
|
|
BParameterGroup *
|
|
BParameterWeb::GroupAt(int32 index)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mGroups != NULL,NULL);
|
|
|
|
return static_cast<BParameterGroup *>(mGroups->ItemAt(index));
|
|
}
|
|
|
|
|
|
int32
|
|
BParameterWeb::CountParameters()
|
|
{
|
|
//iterative traversal of the parameter web
|
|
//NOTE: This most definately should be tested and debugged.
|
|
|
|
ASSERT_WRETURN_VALUE(mGroups != NULL,0);
|
|
|
|
int32 RetVal = 0;
|
|
|
|
int i;
|
|
int Limit = mGroups->CountItems();
|
|
for(i = 0; i < Limit; i++)
|
|
{
|
|
BList *GroupStack = new BList();
|
|
BList *IterStack = new BList();
|
|
BParameterGroup *CurrentGroup = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
|
|
int *CurrentIter = new int(0);
|
|
|
|
while(1)
|
|
{
|
|
if(CurrentGroup != NULL)
|
|
{
|
|
if((*CurrentIter) == 0)
|
|
//if this is the first time you're encountering this node, add the parameters within it.
|
|
{
|
|
RetVal += CurrentGroup->CountParameters();
|
|
}
|
|
|
|
if((*CurrentIter) < CurrentGroup->CountGroups())
|
|
//if we've still got sub-groups within the current group to account for
|
|
{
|
|
IterStack->AddItem(CurrentIter);
|
|
GroupStack->AddItem(CurrentGroup);
|
|
|
|
//update the current group
|
|
CurrentGroup = CurrentGroup->GroupAt(*CurrentIter);
|
|
//increment the current iter
|
|
(*CurrentIter)++;
|
|
|
|
//create a new iter for the group you're descending into
|
|
CurrentIter = new int(0);
|
|
}
|
|
else if(GroupStack->CountItems())
|
|
//we've taken care of all the subgroups of the current group, and there's still something on the stack, clean up, and pop it
|
|
{
|
|
//toss out the iter associated with this group
|
|
if(CurrentIter != NULL)
|
|
delete CurrentIter;
|
|
|
|
CurrentGroup = static_cast<BParameterGroup *>(GroupStack->RemoveItem(GroupStack->CountItems()-1));
|
|
CurrentIter = static_cast<int *>(IterStack->RemoveItem(IterStack->CountItems()-1));
|
|
}
|
|
else
|
|
//we've taken care of all the subgroups of the current group, and there's nothing on the stack, we're done.
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if(GroupStack->CountItems())
|
|
{
|
|
if(CurrentIter != NULL)
|
|
delete CurrentIter;
|
|
|
|
CurrentGroup = static_cast<BParameterGroup *>(GroupStack->RemoveItem(GroupStack->CountItems()-1));
|
|
CurrentIter = static_cast<int *>(IterStack->RemoveItem(IterStack->CountItems()-1));
|
|
}
|
|
else
|
|
{
|
|
//NULL current group, and nothing on the stack, it's time to exit
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(CurrentIter != NULL)
|
|
delete CurrentIter;
|
|
|
|
delete IterStack;
|
|
delete GroupStack;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
BParameter *
|
|
BParameterWeb::ParameterAt(int32 index)
|
|
{
|
|
//iterative traversal of the parameter web
|
|
//NOTE: This most definately should be tested and debugged.
|
|
|
|
ASSERT_WRETURN_VALUE(mGroups != NULL,0);
|
|
|
|
|
|
int i;
|
|
int Limit = mGroups->CountItems();
|
|
for(i = 0; i < Limit; i++)
|
|
{
|
|
BList *GroupStack = new BList();
|
|
BList *IterStack = new BList();
|
|
BParameterGroup *CurrentGroup = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
|
|
int *CurrentIter = new int(0);
|
|
|
|
while(1)
|
|
{
|
|
if(CurrentGroup != NULL)
|
|
{
|
|
|
|
if((*CurrentIter) == 0)
|
|
//if this is the first time you're encountering this node, add the parameters within it.
|
|
{
|
|
if(index < CurrentGroup->CountParameters())
|
|
{
|
|
//delete the current iter (it is not on the stack)
|
|
if(CurrentIter != NULL)
|
|
delete CurrentIter;
|
|
|
|
//delete items in the IterStack
|
|
for(int j = 0; j < IterStack->CountItems(); j++)
|
|
{
|
|
int *Temp = static_cast<int *>(IterStack->ItemAt(j));
|
|
if(Temp != NULL)
|
|
delete CurrentIter;
|
|
}
|
|
IterStack->MakeEmpty();
|
|
delete IterStack;
|
|
|
|
GroupStack->MakeEmpty();
|
|
delete GroupStack;
|
|
|
|
return CurrentGroup->ParameterAt(index);
|
|
}
|
|
else
|
|
{
|
|
index -= CurrentGroup->CountParameters();
|
|
}
|
|
}
|
|
|
|
if((*CurrentIter) < CurrentGroup->CountGroups())
|
|
//if we've still got sub-groups within the current group to account for
|
|
{
|
|
IterStack->AddItem(CurrentIter);
|
|
GroupStack->AddItem(CurrentGroup);
|
|
|
|
//update the current group
|
|
CurrentGroup = CurrentGroup->GroupAt(*CurrentIter);
|
|
//increment the current iter
|
|
(*CurrentIter)++;
|
|
|
|
//create a new iter for the group you're descending into
|
|
CurrentIter = new int(0);
|
|
}
|
|
else if(GroupStack->CountItems())
|
|
//we've taken care of all the subgroups of the current group, and there's still something on the stack, clean up, and pop it
|
|
{
|
|
//toss out the iter associated with this group
|
|
if(CurrentIter != NULL)
|
|
delete CurrentIter;
|
|
|
|
CurrentGroup = static_cast<BParameterGroup *>(GroupStack->RemoveItem(GroupStack->CountItems()-1));
|
|
CurrentIter = static_cast<int *>(IterStack->RemoveItem(IterStack->CountItems()-1));
|
|
}
|
|
else
|
|
//we've taken care of all the subgroups of the current group, and there's nothing on the stack, we're done.
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if(GroupStack->CountItems())
|
|
{
|
|
if(CurrentIter != NULL)
|
|
delete CurrentIter;
|
|
|
|
CurrentGroup = static_cast<BParameterGroup *>(GroupStack->RemoveItem(GroupStack->CountItems()-1));
|
|
CurrentIter = static_cast<int *>(IterStack->RemoveItem(IterStack->CountItems()-1));
|
|
}
|
|
else
|
|
{
|
|
//NULL current group, and nothing on the stack, it's time to exit
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(CurrentIter != NULL)
|
|
delete CurrentIter;
|
|
|
|
delete IterStack;
|
|
delete GroupStack;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
bool
|
|
BParameterWeb::IsFixedSize() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
type_code
|
|
BParameterWeb::TypeCode() const
|
|
{
|
|
return B_MEDIA_PARAMETER_WEB_TYPE;
|
|
}
|
|
|
|
|
|
ssize_t
|
|
BParameterWeb::FlattenedSize() const
|
|
{
|
|
/*
|
|
//--------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 RetVal = sizeof(int32) + 2*sizeof(int32) + sizeof(media_node);
|
|
|
|
int i;
|
|
int limit;
|
|
|
|
limit = mGroups->CountItems();
|
|
for(i = 0; i < limit; i++)
|
|
{
|
|
BParameterGroup *CurrentGroup = static_cast<BParameterGroup *>(mGroups->ItemAt(i));
|
|
if(CurrentGroup != NULL)
|
|
{
|
|
//overhead for each parameter flattened
|
|
RetVal += 8; //4 bytes for the flattened size, and 4 in the 'mystery parameter'...
|
|
RetVal += CurrentGroup->FlattenedSize();
|
|
}
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
status_t
|
|
BParameterWeb::Flatten(void *buffer,
|
|
ssize_t size) const
|
|
{
|
|
if(buffer == NULL)
|
|
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 ActualFSize = BParameterWeb::FlattenedSize();
|
|
|
|
if(size < ActualFSize)
|
|
return B_NO_MEMORY;
|
|
|
|
byte *CurrentPos = reinterpret_cast<byte *>(buffer);
|
|
|
|
//QUESTION: I have no idea where this magic number came from, and i'm not sure that it's
|
|
//being written in the correct byte order.
|
|
*(reinterpret_cast<int32 *>(CurrentPos)) = 0x01030506;
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//QUESTION: Another unknown constant. This one is different in style than the others though.
|
|
*(reinterpret_cast<int32 *>(CurrentPos)) = 1;
|
|
CurrentPos += sizeof(int32);
|
|
|
|
|
|
int i;
|
|
int NumItems;
|
|
void **Items;
|
|
|
|
|
|
ssize_t *TotalWrittenSubGroupsCount = reinterpret_cast<ssize_t *>(CurrentPos);
|
|
(*TotalWrittenSubGroupsCount) = 0;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
if(mGroups != NULL)
|
|
{
|
|
NumItems = mGroups->CountItems();
|
|
Items = static_cast<void **>(mGroups->Items());
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
BParameterGroup *CurrentSubGroup = static_cast<BParameterGroup *>(Items[i]);
|
|
if(CurrentSubGroup != NULL)
|
|
{
|
|
ssize_t FlattenedSubGroupSize = CurrentSubGroup->FlattenedSize();
|
|
|
|
//write the flattened size value
|
|
*(reinterpret_cast<ssize_t *>(CurrentPos)) = FlattenedSubGroupSize;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//write the flattened sub group
|
|
status_t SubGroupFlattenStatus = CurrentSubGroup->Flatten(CurrentPos,FlattenedSubGroupSize);
|
|
|
|
if(SubGroupFlattenStatus != B_OK)
|
|
{
|
|
return SubGroupFlattenStatus;
|
|
}
|
|
|
|
CurrentPos += FlattenedSubGroupSize;
|
|
|
|
(*TotalWrittenSubGroupsCount)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
bool
|
|
BParameterWeb::AllowsTypeCode(type_code code) const
|
|
{
|
|
return (code == this->TypeCode());
|
|
}
|
|
|
|
|
|
status_t
|
|
BParameterWeb::Unflatten(type_code c,
|
|
const void *buf,
|
|
ssize_t size)
|
|
{
|
|
if(!this->AllowsTypeCode(c))
|
|
return B_BAD_TYPE;
|
|
|
|
if(buf == NULL)
|
|
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)) )
|
|
{
|
|
return B_ERROR;
|
|
}
|
|
|
|
const byte *CurrentPos = static_cast<const byte *>(buf);
|
|
|
|
//QUESTION: I have no idea where this magic number came from, and i'm not sure that it's
|
|
//being read in the correct byte order.
|
|
if( *(reinterpret_cast<const int32 *>(CurrentPos)) != 0x010300506)
|
|
{
|
|
return B_BAD_TYPE;
|
|
}
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//QUESTION: I have no idea where this magic number came from, and i'm not sure that it's
|
|
//being read in the correct byte order. THIS SURELY HAS SOME MEANING I'M NOT AWARE OF.
|
|
if( *(reinterpret_cast<const int32 *>(CurrentPos)) != 1)
|
|
{
|
|
return B_ERROR;
|
|
}
|
|
CurrentPos += sizeof(int32);
|
|
|
|
|
|
//this variable is used to cap lengths/sizes read from the flattened buffer
|
|
//to maximum reasonable sizes to ensure that we don't run off the buffer.
|
|
int MaxByteLength;
|
|
int i;
|
|
|
|
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();
|
|
}
|
|
|
|
|
|
|
|
//read NumGroups
|
|
int NumItems = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//MaxByteLength = size - ((offset into struct) + (minimum bytes REQUIRED AFTER name string))
|
|
//In this case, the fields REQUIRED after the group list are:
|
|
//(none)
|
|
//TOTAL: 0 bytes
|
|
MaxByteLength = size - (((CurrentPos + sizeof(media_node)) - static_cast<const byte *>(buf)) + 0);
|
|
|
|
ssize_t MinFlattenedItemSize = 8;
|
|
|
|
//each item occupies a minimum of 8 bytes, so make sure that there is enough
|
|
//space remaining in the buffer for the specified NumItems (assuming each is minimum size)
|
|
NumItems = min_c(NumItems,MaxByteLength/MinFlattenedItemSize);
|
|
|
|
|
|
|
|
//read Node
|
|
mNode = *(reinterpret_cast<const media_node *>(CurrentPos));
|
|
CurrentPos += sizeof(media_node);
|
|
|
|
|
|
status_t RetVal = B_OK;
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
//read the flattened size of this item
|
|
ssize_t SubGroupSize = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string))
|
|
//In this case, the fields REQUIRED after the group list are:
|
|
//NumGroups*(4 bytes)
|
|
//TOTAL: NumGroups*(4 bytes) bytes
|
|
MaxByteLength = size - ((CurrentPos - static_cast<const byte *>(buf)) + (NumItems*4));
|
|
|
|
//make sure that the SubGroupSize cannot overflow the buffer we are reading out of
|
|
SubGroupSize = min_c(SubGroupSize,MaxByteLength);
|
|
|
|
|
|
BParameterGroup *NewSubGroup = new BParameterGroup(this,"New_UnNamed_SubGroup");
|
|
|
|
RetVal = NewSubGroup->Unflatten(NewSubGroup->TypeCode(),CurrentPos,SubGroupSize);
|
|
|
|
if(RetVal != B_OK)
|
|
{
|
|
delete NewSubGroup;
|
|
//don't return, because we should still fix references...
|
|
break;
|
|
}
|
|
|
|
CurrentPos += SubGroupSize;
|
|
|
|
//add the item to the list
|
|
mGroups->AddItem(NewSubGroup);
|
|
|
|
}
|
|
|
|
|
|
//fix all references
|
|
if((mOldRefs != NULL) && (mNewRefs != NULL))
|
|
{
|
|
int limit = this->CountParameters();
|
|
for(i = 0; i < limit; i++)
|
|
{
|
|
BParameter *CurrentParam = this->ParameterAt(i);
|
|
if(CurrentParam != NULL)
|
|
{
|
|
CurrentParam->FixRefs(*mOldRefs,*mNewRefs);
|
|
}
|
|
}
|
|
|
|
this->mOldRefs->MakeEmpty();
|
|
this->mNewRefs->MakeEmpty();
|
|
}
|
|
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/*************************************************************
|
|
* private BParameterWeb
|
|
*************************************************************/
|
|
|
|
/*
|
|
unimplemented
|
|
BParameterWeb::BParameterWeb(const BParameterWeb &clone)
|
|
BParameterWeb &BParameterWeb::operator=(const BParameterWeb &clone)
|
|
*/
|
|
|
|
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; }
|
|
|
|
void
|
|
BParameterWeb::AddRefFix(void *oldItem,
|
|
void *newItem)
|
|
{
|
|
ASSERT_RETURN(mOldRefs != NULL);
|
|
ASSERT_RETURN(mNewRefs != NULL);
|
|
|
|
mOldRefs->AddItem(oldItem);
|
|
mNewRefs->AddItem(newItem);
|
|
}
|
|
|
|
/*************************************************************
|
|
* private BParameterGroup
|
|
*************************************************************/
|
|
|
|
BParameterGroup::BParameterGroup(BParameterWeb *web,
|
|
const char *name):mWeb(web)
|
|
{
|
|
mControls = new BList();
|
|
mGroups = new BList();
|
|
|
|
int NameLength = 0;
|
|
if(name != NULL)
|
|
{
|
|
NameLength = strlen(name);
|
|
}
|
|
mName = new char[NameLength + 1];
|
|
memcpy(mName,name,NameLength);
|
|
mName[NameLength] = 0;
|
|
|
|
mFlags = 0;
|
|
}
|
|
|
|
|
|
BParameterGroup::~BParameterGroup()
|
|
{
|
|
int i;
|
|
|
|
int NumItems;
|
|
void **Items;
|
|
|
|
if(mControls != NULL)
|
|
{
|
|
NumItems = mControls->CountItems();
|
|
Items = static_cast<void **>(mControls->Items());
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
if(Items[i] != NULL)
|
|
{
|
|
delete Items[i];
|
|
Items[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(mGroups != NULL)
|
|
{
|
|
NumItems = mGroups->CountItems();
|
|
Items = static_cast<void **>(mControls->Items());
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
if(Items[i] != NULL)
|
|
{
|
|
delete Items[i];
|
|
Items[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(mName != NULL)
|
|
{
|
|
delete[] mName;
|
|
mName = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
/*************************************************************
|
|
* 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 m_type,
|
|
const char *name,
|
|
const char *kind)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mControls != NULL,NULL);
|
|
|
|
BNullParameter *NewParam = new BNullParameter(id,m_type,mWeb,name,kind);
|
|
|
|
NewParam->mGroup = this;
|
|
|
|
mControls->AddItem(NewParam);
|
|
|
|
return NewParam;
|
|
}
|
|
|
|
|
|
BContinuousParameter *
|
|
BParameterGroup::MakeContinuousParameter(int32 id,
|
|
media_type m_type,
|
|
const char *name,
|
|
const char *kind,
|
|
const char *unit,
|
|
float minimum,
|
|
float maximum,
|
|
float stepping)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mControls != NULL,NULL);
|
|
|
|
BContinuousParameter *NewParam = new BContinuousParameter(id,m_type,mWeb,name,kind,unit,minimum,maximum,stepping);
|
|
|
|
NewParam->mGroup = this;
|
|
|
|
mControls->AddItem(NewParam);
|
|
|
|
return NewParam;
|
|
}
|
|
|
|
|
|
BDiscreteParameter *
|
|
BParameterGroup::MakeDiscreteParameter(int32 id,
|
|
media_type m_type,
|
|
const char *name,
|
|
const char *kind)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mControls != NULL,NULL);
|
|
|
|
BDiscreteParameter *NewParam = new BDiscreteParameter(id,m_type,mWeb,name,kind);
|
|
|
|
NewParam->mGroup = this;
|
|
|
|
mControls->AddItem(NewParam);
|
|
|
|
return NewParam;
|
|
}
|
|
|
|
|
|
BParameterGroup *
|
|
BParameterGroup::MakeGroup(const char *name)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mGroups != NULL,NULL);
|
|
|
|
BParameterGroup *NewGroup = new BParameterGroup(mWeb,name);
|
|
|
|
mGroups->AddItem(NewGroup);
|
|
|
|
return NewGroup;
|
|
}
|
|
|
|
|
|
int32
|
|
BParameterGroup::CountParameters()
|
|
{
|
|
ASSERT_WRETURN_VALUE(mControls != NULL,0);
|
|
|
|
return mControls->CountItems();
|
|
}
|
|
|
|
|
|
BParameter *
|
|
BParameterGroup::ParameterAt(int32 index)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mControls != NULL,NULL);
|
|
|
|
return static_cast<BParameter *>(mControls->ItemAt(index));
|
|
}
|
|
|
|
|
|
int32
|
|
BParameterGroup::CountGroups()
|
|
{
|
|
ASSERT_WRETURN_VALUE(mGroups != NULL,0);
|
|
|
|
return mGroups->CountItems();
|
|
}
|
|
|
|
|
|
BParameterGroup *
|
|
BParameterGroup::GroupAt(int32 index)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mGroups != NULL,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
|
|
{
|
|
ASSERT_WRETURN_VALUE(mControls != NULL,0);
|
|
ASSERT_WRETURN_VALUE(mGroups != NULL,0);
|
|
/*
|
|
//--------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 RetVal = 13;
|
|
|
|
if(mFlags != 0)
|
|
{
|
|
RetVal += 4;
|
|
}
|
|
|
|
if(mName != NULL)
|
|
{
|
|
RetVal += 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
|
|
RetVal += 16;
|
|
RetVal += 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
|
|
RetVal += 16;
|
|
RetVal += CurrentGroup->FlattenedSize();
|
|
}
|
|
}
|
|
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
status_t
|
|
BParameterGroup::Flatten(void *buffer,
|
|
ssize_t size) const
|
|
{
|
|
if(buffer == NULL)
|
|
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 ActualFSize = BParameterGroup::FlattenedSize();
|
|
|
|
if(size < ActualFSize)
|
|
return B_NO_MEMORY;
|
|
|
|
byte *CurrentPos = reinterpret_cast<byte *>(buffer);
|
|
|
|
//QUESTION: I have no idea where this magic number came from, and i'm not sure that it's
|
|
//being written in the correct byte order.
|
|
if(mFlags == 0)
|
|
{
|
|
*(reinterpret_cast<int32 *>(CurrentPos)) = 0x03040507;
|
|
CurrentPos += sizeof(int32);
|
|
}
|
|
else
|
|
{
|
|
*(reinterpret_cast<int32 *>(CurrentPos)) = 0x03040509;
|
|
CurrentPos += sizeof(int32);
|
|
|
|
*(reinterpret_cast<uint32 *>(CurrentPos)) = mFlags;
|
|
CurrentPos += sizeof(uint32);
|
|
}
|
|
|
|
//flatten and write the name string
|
|
byte NameStringLength = 0;
|
|
if(mName != NULL)
|
|
{
|
|
NameStringLength = min_c(strlen(mName),255);
|
|
}
|
|
*(reinterpret_cast<byte *>(CurrentPos)) = NameStringLength;
|
|
CurrentPos += sizeof(byte);
|
|
|
|
memcpy(CurrentPos,mName,NameStringLength);
|
|
CurrentPos += NameStringLength;
|
|
|
|
|
|
int i;
|
|
int NumItems;
|
|
void **Items;
|
|
|
|
ssize_t *TotalWrittenParamsCount = reinterpret_cast<ssize_t *>(CurrentPos);
|
|
(*TotalWrittenParamsCount) = 0;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
if(mControls != NULL)
|
|
{
|
|
NumItems = mControls->CountItems();
|
|
Items = static_cast<void **>(mControls->Items());
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
BParameter *CurrentParam = static_cast<BParameter *>(Items[i]);
|
|
if(CurrentParam != NULL)
|
|
{
|
|
//write the pointer value
|
|
*(reinterpret_cast<BParameter **>(CurrentPos)) = CurrentParam;
|
|
CurrentPos += sizeof(BParameter *);
|
|
|
|
//write the type value
|
|
*(reinterpret_cast<BParameter::media_parameter_type *>(CurrentPos)) = CurrentParam->Type();
|
|
CurrentPos += sizeof(BParameter::media_parameter_type);
|
|
|
|
ssize_t FlattenedParamSize = CurrentParam->FlattenedSize();
|
|
|
|
//write the flattened size value
|
|
*(reinterpret_cast<ssize_t *>(CurrentPos)) = FlattenedParamSize;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//write the flattened parameter
|
|
status_t ParamFlattenStatus = CurrentParam->Flatten(CurrentPos,FlattenedParamSize);
|
|
|
|
if(ParamFlattenStatus != B_OK)
|
|
{
|
|
return ParamFlattenStatus;
|
|
}
|
|
|
|
CurrentPos += FlattenedParamSize;
|
|
|
|
(*TotalWrittenParamsCount)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
ssize_t *TotalWrittenSubGroupsCount = reinterpret_cast<ssize_t *>(CurrentPos);
|
|
(*TotalWrittenSubGroupsCount) = 0;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
if(mGroups != NULL)
|
|
{
|
|
NumItems = mGroups->CountItems();
|
|
Items = static_cast<void **>(mGroups->Items());
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
BParameterGroup *CurrentSubGroup = static_cast<BParameterGroup *>(Items[i]);
|
|
if(CurrentSubGroup != NULL)
|
|
{
|
|
//write the pointer value
|
|
*(reinterpret_cast<BParameterGroup **>(CurrentPos)) = CurrentSubGroup;
|
|
CurrentPos += sizeof(BParameterGroup *);
|
|
|
|
//write the type code value
|
|
*(reinterpret_cast<type_code *>(CurrentPos)) = CurrentSubGroup->TypeCode();
|
|
CurrentPos += sizeof(type_code);
|
|
|
|
ssize_t FlattenedSubGroupSize = CurrentSubGroup->FlattenedSize();
|
|
|
|
//write the flattened size value
|
|
*(reinterpret_cast<ssize_t *>(CurrentPos)) = FlattenedSubGroupSize;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//write the flattened sub group
|
|
status_t SubGroupFlattenStatus = CurrentSubGroup->Flatten(CurrentPos,FlattenedSubGroupSize);
|
|
|
|
if(SubGroupFlattenStatus != B_OK)
|
|
{
|
|
return SubGroupFlattenStatus;
|
|
}
|
|
|
|
CurrentPos += FlattenedSubGroupSize;
|
|
|
|
(*TotalWrittenSubGroupsCount)++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
bool
|
|
BParameterGroup::AllowsTypeCode(type_code code) const
|
|
{
|
|
return (code == this->TypeCode());
|
|
}
|
|
|
|
|
|
status_t
|
|
BParameterGroup::Unflatten(type_code c,
|
|
const void *buf,
|
|
ssize_t size)
|
|
{
|
|
if(!this->AllowsTypeCode(c))
|
|
return B_BAD_TYPE;
|
|
|
|
if(buf == NULL)
|
|
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)) )
|
|
{
|
|
return B_ERROR;
|
|
}
|
|
|
|
const byte *CurrentPos = static_cast<const byte *>(buf);
|
|
|
|
uint32 Flags = 0;
|
|
|
|
//QUESTION: I have no idea where this magic number came from, and i'm not sure that it's
|
|
//being read in the correct byte order.
|
|
if( *(reinterpret_cast<const int32 *>(CurrentPos)) == 0x03040507)
|
|
{
|
|
CurrentPos += sizeof(int32);
|
|
}
|
|
else if( *(reinterpret_cast<const int32 *>(CurrentPos)) == 0x03040509)
|
|
{
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//check to make sure we've got room to read the flags field
|
|
if(size < static_cast<ssize_t>(sizeof(int32) + sizeof(uint32)))
|
|
{
|
|
return B_ERROR;
|
|
}
|
|
|
|
Flags = *(reinterpret_cast<const uint32 *>(CurrentPos));
|
|
CurrentPos += sizeof(uint32);
|
|
}
|
|
else
|
|
{
|
|
return B_BAD_TYPE;
|
|
}
|
|
|
|
this->mFlags = Flags;
|
|
|
|
|
|
|
|
|
|
//this variable is used to cap lengths/sizes read from the flattened buffer
|
|
//to maximum reasonable sizes to ensure that we don't run off the buffer.
|
|
int32 MaxByteLength;
|
|
|
|
//read the name string
|
|
byte NameStringLength = *(reinterpret_cast<const byte *>(CurrentPos));
|
|
CurrentPos += sizeof(byte);
|
|
|
|
//MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string))
|
|
//In this case, the fields REQUIRED after the name string are:
|
|
//Param Count (4 bytes)
|
|
//Subgroup Count (4 bytes)
|
|
//TOTAL: 8 bytes
|
|
MaxByteLength = size - ((CurrentPos - static_cast<const byte *>(buf)) + 8);
|
|
|
|
NameStringLength = min_c(NameStringLength,MaxByteLength);
|
|
|
|
if(mName != NULL)
|
|
{
|
|
delete[] mName;
|
|
mName = NULL;
|
|
}
|
|
mName = new char[NameStringLength + 1];
|
|
memcpy(mName,CurrentPos,NameStringLength);
|
|
mName[NameStringLength] = 0;
|
|
CurrentPos += NameStringLength;
|
|
|
|
|
|
|
|
|
|
//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();
|
|
}
|
|
|
|
|
|
|
|
//read NumParameters
|
|
ssize_t NumItems = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string))
|
|
//In this case, the fields REQUIRED after the name string are:
|
|
//Subgroup Count (4 bytes)
|
|
//TOTAL: 4 bytes
|
|
MaxByteLength = size - ((CurrentPos - static_cast<const byte *>(buf)) + 4);
|
|
|
|
ssize_t MinFlattenedItemSize(12);
|
|
|
|
//each item occupies a minimum of 12 bytes, so make sure that there is enough
|
|
//space remaining in the buffer for the specified NumItems (assuming each is minimum size)
|
|
NumItems = min_c(NumItems,MaxByteLength/MinFlattenedItemSize);
|
|
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
//read the old pointer value of this item
|
|
BParameter *OldPointerVal = *(reinterpret_cast<BParameter *const*>(CurrentPos));
|
|
CurrentPos += sizeof(BParameter *);
|
|
|
|
//read the media_parameter_type of this item
|
|
BParameter::media_parameter_type ParamType = *(reinterpret_cast<const BParameter::media_parameter_type *>(CurrentPos));
|
|
CurrentPos += sizeof(BParameter::media_parameter_type);
|
|
|
|
//read the flattened size of this item
|
|
ssize_t ParamSize = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string))
|
|
//In this case, the fields REQUIRED after the name string are:
|
|
//Subgroup Count (4 bytes)
|
|
//TOTAL: 4 bytes
|
|
MaxByteLength = size - ((CurrentPos - static_cast<const byte *>(buf)) + 4);
|
|
|
|
//make sure that the ParamSize cannot overflow the buffer we are reading out of
|
|
ParamSize = min_c(ParamSize,MaxByteLength);
|
|
|
|
BParameter *NewParam = this->MakeControl(ParamType);
|
|
|
|
//need to be careful because ParamType could be invalid
|
|
if(NewParam == NULL)
|
|
{
|
|
return B_ERROR;
|
|
}
|
|
|
|
status_t RetVal = NewParam->Unflatten(NewParam->TypeCode(),CurrentPos,ParamSize);
|
|
|
|
if(RetVal != B_OK)
|
|
{
|
|
delete NewParam;
|
|
return RetVal;
|
|
}
|
|
|
|
CurrentPos += ParamSize;
|
|
|
|
//add the item to the list
|
|
mControls->AddItem(NewParam);
|
|
|
|
//add it's old pointer value to the RefFix list kept by the owner web
|
|
if(mWeb != NULL)
|
|
{
|
|
mWeb->AddRefFix(OldPointerVal,NewParam);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//read NumSubGroups
|
|
NumItems = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string))
|
|
//In this case, the fields REQUIRED after the name string are:
|
|
//(none)
|
|
//TOTAL: 0 bytes
|
|
MaxByteLength = size - ((CurrentPos - static_cast<const byte *>(buf)) + 0);
|
|
|
|
MinFlattenedItemSize = 12;
|
|
|
|
//each item occupies a minimum of 12 bytes, so make sure that there is enough
|
|
//space remaining in the buffer for the specified NumItems (assuming each is minimum size)
|
|
NumItems = min_c(NumItems,MaxByteLength/MinFlattenedItemSize);
|
|
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
//read the old pointer value of this item
|
|
BParameter *OldPointerVal = *(reinterpret_cast<BParameter *const*>(CurrentPos));
|
|
CurrentPos += sizeof(BParameter *);
|
|
|
|
//read the type_code of this item
|
|
type_code BufTypeCode = *(reinterpret_cast<const type_code *>(CurrentPos));
|
|
CurrentPos += sizeof(type_code);
|
|
|
|
//read the flattened size of this item
|
|
ssize_t SubGroupSize = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//MaxByteLength = size - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string))
|
|
//In this case, the fields REQUIRED after the name string are:
|
|
//(none)
|
|
//TOTAL: 0 bytes
|
|
MaxByteLength = size - ((CurrentPos - static_cast<const byte *>(buf)) + 0);
|
|
|
|
//make sure that the SubGroupSize cannot overflow the buffer we are reading out of
|
|
SubGroupSize = min_c(SubGroupSize,MaxByteLength);
|
|
|
|
|
|
BParameterGroup *NewSubGroup = new BParameterGroup(mWeb,"New_UnNamed_SubGroup");
|
|
|
|
status_t RetVal = NewSubGroup->Unflatten(BufTypeCode,CurrentPos,SubGroupSize);
|
|
|
|
if(RetVal != B_OK)
|
|
{
|
|
delete NewSubGroup;
|
|
return RetVal;
|
|
}
|
|
|
|
CurrentPos += SubGroupSize;
|
|
|
|
//add the item to the list
|
|
mGroups->AddItem(NewSubGroup);
|
|
|
|
//add it's old pointer value to the RefFix list kept by the owner web
|
|
if(mWeb != NULL)
|
|
{
|
|
mWeb->AddRefFix(OldPointerVal,NewSubGroup);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
/*************************************************************
|
|
* private BParameterGroup
|
|
*************************************************************/
|
|
|
|
/*
|
|
// unimplemented
|
|
BParameterGroup::BParameterGroup()
|
|
BParameterGroup::BParameterGroup(const BParameterGroup &clone)
|
|
BParameterGroup &BParameterGroup::operator=(const BParameterGroup &clone)
|
|
*/
|
|
|
|
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; }
|
|
|
|
|
|
BParameter *
|
|
BParameterGroup::MakeControl(int32 type)
|
|
{
|
|
/*NOTE:
|
|
Creates a new parameter for addition within this with a type defined by the passed 'type' parameter,
|
|
BUT DOES NOT ADD THE CREATED PARAMETER TO THE INTERNAL LIST OF PARAMETERS
|
|
*/
|
|
switch(type)
|
|
{
|
|
case(BParameter::B_NULL_PARAMETER):
|
|
{
|
|
return new BNullParameter(-1,B_MEDIA_UNKNOWN_TYPE,mWeb,"New_UnNamed_NullParameter",B_GENERIC);
|
|
}
|
|
break;
|
|
case(BParameter::B_DISCRETE_PARAMETER):
|
|
{
|
|
return new BDiscreteParameter(-1,B_MEDIA_UNKNOWN_TYPE,mWeb,"New_UnNamed_DiscreteParameter",B_GENERIC);
|
|
}
|
|
break;
|
|
case(BParameter::B_CONTINUOUS_PARAMETER):
|
|
{
|
|
return new BContinuousParameter(-1,B_MEDIA_UNKNOWN_TYPE,mWeb,"New_UnNamed_ContinuousParameter",B_GENERIC,"",0,100,1);
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
return NULL;
|
|
}
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*************************************************************
|
|
* 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)
|
|
{
|
|
UNIMPLEMENTED();
|
|
/*
|
|
* XXX FIXME! call BControllable::GetControlValue() here.
|
|
*/
|
|
return B_BAD_VALUE;
|
|
}
|
|
|
|
|
|
status_t
|
|
BParameter::SetValue(const void *buffer,
|
|
size_t size,
|
|
bigtime_t when)
|
|
{
|
|
UNIMPLEMENTED();
|
|
/*
|
|
* XXX FIXME! call BControllable::SetControlValue() here.
|
|
*/
|
|
return B_BAD_VALUE;
|
|
}
|
|
|
|
|
|
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_WRETURN_VALUE(mInputs != NULL,0);
|
|
|
|
return mInputs->CountItems();
|
|
}
|
|
|
|
|
|
BParameter *
|
|
BParameter::InputAt(int32 index)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mInputs != NULL,NULL);
|
|
|
|
return static_cast<BParameter *>(mInputs->ItemAt(index));
|
|
}
|
|
|
|
|
|
void
|
|
BParameter::AddInput(BParameter *input)
|
|
{
|
|
// BeBook has this method returning a status value,
|
|
// but it should be updated
|
|
if(input == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ASSERT_RETURN(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_WRETURN_VALUE(mOutputs != NULL,0);
|
|
|
|
return mOutputs->CountItems();
|
|
}
|
|
|
|
|
|
BParameter *
|
|
BParameter::OutputAt(int32 index)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mOutputs != NULL,NULL);
|
|
|
|
return static_cast<BParameter *>(mOutputs->ItemAt(index));
|
|
}
|
|
|
|
|
|
void
|
|
BParameter::AddOutput(BParameter *output)
|
|
{
|
|
// BeBook has this method returning a status value,
|
|
// but it should be updated
|
|
if(output == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ASSERT_RETURN(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
|
|
{
|
|
/*
|
|
?? (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 RetVal = 35;
|
|
|
|
if(mName != NULL) RetVal += strlen(mName);
|
|
|
|
if(mKind != NULL) RetVal += strlen(mKind);
|
|
|
|
if(mUnit != NULL) RetVal += strlen(mUnit);
|
|
|
|
if(mInputs != NULL) RetVal += mInputs->CountItems()*sizeof(BParameter *);
|
|
|
|
if(mOutputs != NULL) RetVal += mOutputs->CountItems()*sizeof(BParameter *);
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
status_t
|
|
BParameter::Flatten(void *buffer,
|
|
ssize_t size) const
|
|
{
|
|
if(buffer == NULL)
|
|
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 ActualFSize = BParameter::FlattenedSize();
|
|
|
|
if(size < ActualFSize)
|
|
return B_NO_MEMORY;
|
|
|
|
byte *CurrentPos = reinterpret_cast<byte *>(buffer);
|
|
|
|
//QUESTION: I have no idea where this magic number came from, and i'm not sure that it's
|
|
//being written in the correct byte order.
|
|
*(reinterpret_cast<int32 *>(CurrentPos)) = 0x02040607;
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//flatten and write the struct size
|
|
*(reinterpret_cast<ssize_t *>(CurrentPos)) = ActualFSize;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//flatten and write the ID
|
|
*(reinterpret_cast<int32 *>(CurrentPos)) = mID;
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//flatten and write the name string
|
|
byte NameStringLength = 0;
|
|
if(mName != NULL)
|
|
{
|
|
NameStringLength = min_c(strlen(mName),255);
|
|
}
|
|
*(reinterpret_cast<byte *>(CurrentPos)) = NameStringLength;
|
|
CurrentPos += sizeof(byte);
|
|
|
|
memcpy(CurrentPos,mName,NameStringLength);
|
|
CurrentPos += NameStringLength;
|
|
|
|
//flatten and write the kind string
|
|
byte KindStringLength = 0;
|
|
if(mKind != NULL)
|
|
{
|
|
KindStringLength = min_c(strlen(mKind),255);
|
|
}
|
|
*(reinterpret_cast<byte *>(CurrentPos)) = KindStringLength;
|
|
CurrentPos += sizeof(byte);
|
|
|
|
memcpy(CurrentPos,mKind,KindStringLength);
|
|
CurrentPos += KindStringLength;
|
|
|
|
//flatten and write the unit string
|
|
byte UnitStringLength = 0;
|
|
if(mUnit != NULL)
|
|
{
|
|
UnitStringLength = min_c(strlen(mUnit),255);
|
|
}
|
|
*(reinterpret_cast<byte *>(CurrentPos)) = UnitStringLength;
|
|
CurrentPos += sizeof(byte);
|
|
|
|
memcpy(CurrentPos,mUnit,UnitStringLength);
|
|
CurrentPos += UnitStringLength;
|
|
|
|
|
|
//flatten and write the list of inputs
|
|
ssize_t NumInputs = 0;
|
|
if(mInputs != NULL)
|
|
{
|
|
NumInputs = mInputs->CountItems();
|
|
}
|
|
*(reinterpret_cast<ssize_t *>(CurrentPos)) = NumInputs;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
memcpy(CurrentPos,mInputs->Items(),sizeof(BParameter *)*NumInputs);
|
|
|
|
|
|
//flatten and write the list of outputs
|
|
ssize_t NumOutputs = 0;
|
|
if(mOutputs != NULL)
|
|
{
|
|
NumOutputs = mOutputs->CountItems();
|
|
}
|
|
*(reinterpret_cast<ssize_t *>(CurrentPos)) = NumOutputs;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
memcpy(CurrentPos,mOutputs->Items(),sizeof(BParameter *)*NumOutputs);
|
|
|
|
|
|
//flatten and write the media type
|
|
*(reinterpret_cast<media_type *>(CurrentPos)) = mMediaType;
|
|
CurrentPos += sizeof(media_type);
|
|
|
|
//flatten and write the channel count
|
|
*(reinterpret_cast<int32 *>(CurrentPos)) = mChannels;
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//flatten and write the flags
|
|
*(reinterpret_cast<uint32 *>(CurrentPos)) = mFlags;
|
|
CurrentPos += sizeof(uint32);
|
|
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
bool
|
|
BParameter::AllowsTypeCode(type_code code) const
|
|
{
|
|
return (code == this->TypeCode());
|
|
}
|
|
|
|
|
|
status_t
|
|
BParameter::Unflatten(type_code c,
|
|
const void *buf,
|
|
ssize_t size)
|
|
{
|
|
|
|
if(!this->AllowsTypeCode(c))
|
|
return B_BAD_TYPE;
|
|
|
|
if(buf == NULL)
|
|
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)))
|
|
{
|
|
return B_ERROR;
|
|
}
|
|
|
|
const byte *CurrentPos = static_cast<const byte *>(buf);
|
|
|
|
|
|
//QUESTION: I have no idea where this magic number came from, and i'm not sure that it's
|
|
//being read in the correct byte order.
|
|
if( *(reinterpret_cast<const int32 *>(CurrentPos)) != 0x02040607)
|
|
{
|
|
return B_BAD_TYPE;
|
|
}
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//read the struct size
|
|
ssize_t ParamStructSize = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
if(ParamStructSize > size)
|
|
{
|
|
//if the struct size is larger than the size of the buffer we were given,
|
|
//there's a problem
|
|
return B_MISMATCHED_VALUES;
|
|
}
|
|
|
|
//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(ParamStructSize < MinFlattenedParamSize)
|
|
{
|
|
return B_ERROR;
|
|
}
|
|
|
|
//read the ID
|
|
this->mID = *(reinterpret_cast<const int32 *>(CurrentPos));
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//this variable is used to cap lengths/sizes read from the flattened buffer
|
|
//to maximum reasonable sizes to ensure that we don't run off the buffer.
|
|
int32 MaxByteLength;
|
|
|
|
//read the name string
|
|
byte NameStringLength = *(reinterpret_cast<const byte *>(CurrentPos));
|
|
CurrentPos += sizeof(byte);
|
|
|
|
//MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER name string))
|
|
//In this case, the fields REQUIRED after the name string are:
|
|
//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: 22 bytes
|
|
MaxByteLength = ParamStructSize - ((CurrentPos - static_cast<const byte *>(buf)) + 22);
|
|
|
|
NameStringLength = min_c(NameStringLength,MaxByteLength);
|
|
|
|
if(mName != NULL)
|
|
{
|
|
delete[] mName;
|
|
mName = NULL;
|
|
}
|
|
mName = new char[NameStringLength + 1];
|
|
memcpy(mName,CurrentPos,NameStringLength);
|
|
mName[NameStringLength] = 0;
|
|
CurrentPos += NameStringLength;
|
|
|
|
//read the kind string
|
|
byte KindStringLength = *(reinterpret_cast<const byte *>(CurrentPos));
|
|
CurrentPos += sizeof(byte);
|
|
|
|
//MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER kind string))
|
|
//In this case, the fields REQUIRED after the kind string are:
|
|
//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: 21 bytes
|
|
MaxByteLength = ParamStructSize - ((CurrentPos - static_cast<const byte *>(buf)) + 21);
|
|
|
|
KindStringLength = min_c(KindStringLength,MaxByteLength);
|
|
|
|
if(mKind != NULL)
|
|
{
|
|
delete[] mKind;
|
|
mKind = NULL;
|
|
}
|
|
mKind = new char[KindStringLength + 1];
|
|
memcpy(mKind,CurrentPos,KindStringLength);
|
|
mKind[KindStringLength] = 0;
|
|
CurrentPos += KindStringLength;
|
|
|
|
//read the unit string
|
|
byte UnitStringLength = *(reinterpret_cast<const byte *>(CurrentPos));
|
|
CurrentPos += sizeof(byte);
|
|
|
|
//MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER unit string))
|
|
//In this case, the fields REQUIRED after the unit string are:
|
|
//Inputs Count (4 bytes)
|
|
//Outputs Count (4 bytes)
|
|
//Media Type (4 bytes)
|
|
//Channel Count (4 bytes)
|
|
//Flags (4 bytes)
|
|
//TOTAL: 20 bytes
|
|
MaxByteLength = ParamStructSize - ((CurrentPos - static_cast<const byte *>(buf)) + 20);
|
|
|
|
UnitStringLength = min_c(UnitStringLength,MaxByteLength);
|
|
|
|
if(mUnit != NULL)
|
|
{
|
|
delete[] mUnit;
|
|
mUnit = NULL;
|
|
}
|
|
mUnit = new char[UnitStringLength + 1];
|
|
memcpy(mUnit,CurrentPos,UnitStringLength);
|
|
mUnit[UnitStringLength] = 0;
|
|
CurrentPos += UnitStringLength;
|
|
|
|
//Set this flag to false to indicate that the pointer values in this parameter, have
|
|
//not been swapped.
|
|
mSwapDetected = false;
|
|
|
|
//read the list of inputs
|
|
int i,j;
|
|
|
|
ssize_t NumInputs = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
|
|
//MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER inputs list))
|
|
//In this case, the fields REQUIRED after the inputs list are:
|
|
//Outputs Count (4 bytes)
|
|
//Media Type (4 bytes)
|
|
//Channel Count (4 bytes)
|
|
//Flags (4 bytes)
|
|
//TOTAL: 16 bytes
|
|
MaxByteLength = ParamStructSize - ((CurrentPos - static_cast<const byte *>(buf)) + 16);
|
|
|
|
NumInputs = min_c(NumInputs,static_cast<ssize_t>(MaxByteLength/sizeof(BParameter *)));
|
|
|
|
|
|
if(this->mInputs == NULL)
|
|
{
|
|
this->mInputs = new BList();
|
|
}
|
|
else
|
|
{
|
|
//if this object has an existing list of (valid) inputs, go to each one, removing this object
|
|
//as an output for each of the objects in the input list, then clear the list
|
|
if(mSwapDetected)
|
|
{
|
|
ssize_t OldInputCount = mInputs->CountItems();
|
|
for(i = 0; i < OldInputCount; i++)
|
|
{
|
|
BParameter *CurrentParam = static_cast<BParameter *>(this->mInputs->ItemAt(i));
|
|
if((CurrentParam != NULL) && (CurrentParam->mOutputs != NULL))
|
|
{
|
|
//Remove ALL instances of this parameter from the other parameter's
|
|
//output list
|
|
j = 0;
|
|
ssize_t CurrentParamsOutputCount = CurrentParam->mOutputs->CountItems();
|
|
while(j < CurrentParamsOutputCount)
|
|
{
|
|
if(CurrentParam->mOutputs->ItemAt(j) == this)
|
|
{
|
|
//remove this item, update the CurrentParamsOutputCount,
|
|
//and DON'T increment j
|
|
CurrentParam->mOutputs->RemoveItem(j);
|
|
CurrentParamsOutputCount--;
|
|
}
|
|
else
|
|
{
|
|
//move on to the next one
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this->mInputs->MakeEmpty();
|
|
}
|
|
|
|
for(i = 0; i < NumInputs; i++)
|
|
{
|
|
this->AddInput(*(reinterpret_cast<BParameter * const *>(CurrentPos)));
|
|
CurrentPos += sizeof(BParameter *);
|
|
}
|
|
|
|
|
|
//read the list of outputs
|
|
ssize_t NumOutputs = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
|
|
//MaxByteLength = ParamStructSize - ((current offset into struct) + (minimum bytes REQUIRED AFTER outputs list))
|
|
//In this case, the fields REQUIRED after the outputs list are:
|
|
//Media Type (4 bytes)
|
|
//Channel Count (4 bytes)
|
|
//Flags (4 bytes)
|
|
//TOTAL: 12 bytes
|
|
MaxByteLength = ParamStructSize - ((CurrentPos - static_cast<const byte *>(buf)) + 12);
|
|
|
|
NumOutputs = min_c(NumOutputs,static_cast<ssize_t>(MaxByteLength/sizeof(BParameter *)));
|
|
|
|
|
|
if(this->mOutputs == NULL)
|
|
{
|
|
this->mOutputs = new BList();
|
|
}
|
|
else
|
|
{
|
|
//if this object has an existing list of (valid) outputs, go to each one, removing this object
|
|
//as an input for each of the objects in the output list, then clear the list
|
|
if(mSwapDetected)
|
|
{
|
|
ssize_t OldOutputCount = mOutputs->CountItems();
|
|
for(i = 0; i < OldOutputCount; i++)
|
|
{
|
|
BParameter *CurrentParam = static_cast<BParameter *>(this->mOutputs->ItemAt(i));
|
|
if((CurrentParam != NULL) && (CurrentParam->mInputs != NULL))
|
|
{
|
|
//Remove ALL instances of this parameter from the other parameter's
|
|
//input list
|
|
j = 0;
|
|
ssize_t CurrentParamsInputCount = CurrentParam->mInputs->CountItems();
|
|
while(j < CurrentParamsInputCount)
|
|
{
|
|
if(CurrentParam->mInputs->ItemAt(j) == this)
|
|
{
|
|
//remove this item, update the CurrentParamsInputCount,
|
|
//and DON'T increment j
|
|
CurrentParam->mInputs->RemoveItem(j);
|
|
CurrentParamsInputCount--;
|
|
}
|
|
else
|
|
{
|
|
//move on to the next one
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this->mOutputs->MakeEmpty();
|
|
}
|
|
|
|
for(i = 0; i < NumOutputs; i++)
|
|
{
|
|
this->AddOutput(*(reinterpret_cast<BParameter * const *>(CurrentPos)));
|
|
CurrentPos += sizeof(BParameter *);
|
|
}
|
|
|
|
//read the media type
|
|
this->mMediaType = *(reinterpret_cast<const media_type *>(CurrentPos));
|
|
CurrentPos += sizeof(media_type);
|
|
|
|
//read the channel count
|
|
this->mChannels = *(reinterpret_cast<const int32 *>(CurrentPos));
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//read the flags
|
|
this->mFlags = *(reinterpret_cast<const uint32 *>(CurrentPos));
|
|
CurrentPos += sizeof(uint32);
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
/*************************************************************
|
|
* private BParameter
|
|
*************************************************************/
|
|
|
|
|
|
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; }
|
|
|
|
|
|
BParameter::BParameter(int32 id,
|
|
media_type m_type,
|
|
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(m_type),mChannels(1),mFlags(0)
|
|
{
|
|
mGroup = NULL;
|
|
|
|
//copy the name string
|
|
if(name == NULL)
|
|
{
|
|
mName = new char[1];
|
|
mName[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
ssize_t NewNameLength = strlen(name);
|
|
mName = new char[NewNameLength + 1];
|
|
mName[NewNameLength] = 0;
|
|
}
|
|
//copy the kind string
|
|
if(kind == NULL)
|
|
{
|
|
mKind = new char[1];
|
|
mKind[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
ssize_t NewKindLength = strlen(kind);
|
|
mKind = new char[NewKindLength + 1];
|
|
mKind[NewKindLength] = 0;
|
|
}
|
|
//copy the unit string
|
|
if(unit == NULL)
|
|
{
|
|
mUnit = new char[1];
|
|
mUnit[0] = 0;
|
|
}
|
|
else
|
|
{
|
|
ssize_t NewUnitLength = strlen(unit);
|
|
mUnit = new char[NewUnitLength + 1];
|
|
mUnit[NewUnitLength] = 0;
|
|
}
|
|
|
|
//create an empty input list
|
|
mInputs = new BList();
|
|
|
|
//create an empty output list
|
|
mOutputs = new BList();
|
|
|
|
}
|
|
|
|
|
|
BParameter::~BParameter()
|
|
{
|
|
//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
|
|
|
|
if(mName != NULL)
|
|
{
|
|
delete[] mName;
|
|
mName = NULL;
|
|
}
|
|
if(mKind != NULL)
|
|
{
|
|
delete[] mKind;
|
|
mKind = NULL;
|
|
}
|
|
if(mUnit != NULL)
|
|
{
|
|
delete[] mUnit;
|
|
mUnit = NULL;
|
|
}
|
|
|
|
int i,j;
|
|
|
|
//clean up the inputs list
|
|
if(this->mInputs != NULL)
|
|
{
|
|
//if this object has an existing list of (valid)inputs, go to each one, removing this object
|
|
//as an output for each of the objects in the input list, then destroy the list
|
|
if(mSwapDetected)
|
|
{
|
|
ssize_t OldInputCount = mInputs->CountItems();
|
|
for(i = 0; i < OldInputCount; i++)
|
|
{
|
|
BParameter *CurrentParam = static_cast<BParameter *>(this->mInputs->ItemAt(i));
|
|
if((CurrentParam != NULL) && (CurrentParam->mOutputs != NULL))
|
|
{
|
|
//Remove ALL instances of this parameter from the other parameter's
|
|
//output list
|
|
j = 0;
|
|
ssize_t CurrentParamsOutputCount = CurrentParam->mOutputs->CountItems();
|
|
while(j < CurrentParamsOutputCount)
|
|
{
|
|
if(CurrentParam->mOutputs->ItemAt(j) == this)
|
|
{
|
|
//remove this item, update the CurrentParamsOutputCount,
|
|
//and DON'T increment j
|
|
CurrentParam->mOutputs->RemoveItem(j);
|
|
CurrentParamsOutputCount--;
|
|
}
|
|
else
|
|
{
|
|
//move on to the next one
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this->mInputs->MakeEmpty();
|
|
delete mInputs;
|
|
mInputs = NULL;
|
|
}
|
|
|
|
//clean up the outputs list
|
|
if(this->mOutputs != NULL)
|
|
{
|
|
//if this object has an existing list of (valid) outputs, go to each one, removing this object
|
|
//as an input for each of the objects in the output list, then clear the list
|
|
if(mSwapDetected)
|
|
{
|
|
ssize_t OldOutputCount = mOutputs->CountItems();
|
|
for(i = 0; i < OldOutputCount; i++)
|
|
{
|
|
BParameter *CurrentParam = static_cast<BParameter *>(this->mOutputs->ItemAt(i));
|
|
if((CurrentParam != NULL) && (CurrentParam->mInputs != NULL))
|
|
{
|
|
//Remove ALL instances of this parameter from the other parameter's
|
|
//input list
|
|
j = 0;
|
|
ssize_t CurrentParamsInputCount = CurrentParam->mInputs->CountItems();
|
|
while(j < CurrentParamsInputCount)
|
|
{
|
|
if(CurrentParam->mInputs->ItemAt(j) == this)
|
|
{
|
|
//remove this item, update the CurrentParamsInputCount,
|
|
//and DON'T increment j
|
|
CurrentParam->mInputs->RemoveItem(j);
|
|
CurrentParamsInputCount--;
|
|
}
|
|
else
|
|
{
|
|
//move on to the next one
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this->mOutputs->MakeEmpty();
|
|
delete mOutputs;
|
|
mOutputs = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void
|
|
BParameter::FixRefs(BList &old,
|
|
BList &updated)
|
|
{
|
|
//Replaces references to (ie: pointers) items in the old list, with the
|
|
//coresponding items in the updated list.
|
|
//References are replaced in the mInputs and mOutputs lists.
|
|
|
|
if(!mSwapDetected)
|
|
{
|
|
ASSERT_RETURN(mInputs);
|
|
ASSERT_RETURN(mOutputs);
|
|
|
|
int i;
|
|
void **Items = static_cast<void **>(mInputs->Items());
|
|
int NumItems = mInputs->CountItems();
|
|
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
void *CurrentItem = Items[i];
|
|
|
|
int32 Index = old.IndexOf(CurrentItem);
|
|
|
|
if(Index >= 0)
|
|
{
|
|
Items[i] = updated.ItemAt(Index);
|
|
}
|
|
}
|
|
|
|
Items = static_cast<void **>(mOutputs->Items());
|
|
NumItems = mOutputs->CountItems();
|
|
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
void *CurrentItem = Items[i];
|
|
|
|
int32 Index = old.IndexOf(CurrentItem);
|
|
|
|
if(Index >= 0)
|
|
{
|
|
Items[i] = updated.ItemAt(Index);
|
|
}
|
|
}
|
|
|
|
mSwapDetected = true;
|
|
}
|
|
|
|
}
|
|
|
|
/*************************************************************
|
|
* 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
|
|
{
|
|
ssize_t RetVal = BParameter::FlattenedSize();
|
|
|
|
/*
|
|
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)
|
|
*/
|
|
|
|
RetVal += 24;
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
status_t
|
|
BContinuousParameter::Flatten(void *buffer,
|
|
ssize_t size) const
|
|
{
|
|
if(buffer == NULL)
|
|
return B_NO_INIT;
|
|
|
|
ssize_t TotalBParameterFlatSize = BParameter::FlattenedSize();
|
|
//see BContinuousParameter::FlattenedSize() for a description of this value
|
|
const ssize_t AdditionalBContParamFlatSize = 24;
|
|
|
|
if(size < (TotalBParameterFlatSize + AdditionalBContParamFlatSize))
|
|
{
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
status_t RetVal = BParameter::Flatten(buffer,size);
|
|
|
|
if(RetVal != B_OK)
|
|
{
|
|
return RetVal;
|
|
}
|
|
|
|
byte *CurrentPos = reinterpret_cast<byte *>(buffer);
|
|
CurrentPos += TotalBParameterFlatSize;
|
|
|
|
//write out the mMinimum property
|
|
*(reinterpret_cast<float *>(CurrentPos)) = mMinimum;
|
|
CurrentPos += sizeof(float);
|
|
//write out the mMaximum property
|
|
*(reinterpret_cast<float *>(CurrentPos)) = mMaximum;
|
|
CurrentPos += sizeof(float);
|
|
//write out the mStepping property
|
|
*(reinterpret_cast<float *>(CurrentPos)) = mStepping;
|
|
CurrentPos += sizeof(float);
|
|
//write out the mResponse property
|
|
*(reinterpret_cast<response *>(CurrentPos)) = mResponse;
|
|
CurrentPos += sizeof(response);
|
|
//write out the mFactor property
|
|
*(reinterpret_cast<float *>(CurrentPos)) = mFactor;
|
|
CurrentPos += sizeof(float);
|
|
//write out the mOffset property
|
|
*(reinterpret_cast<float *>(CurrentPos)) = mOffset;
|
|
CurrentPos += sizeof(float);
|
|
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BContinuousParameter::Unflatten(type_code c,
|
|
const void *buf,
|
|
ssize_t size)
|
|
{
|
|
|
|
/*
|
|
* NOTICE: This method tries to avoid corrupting an existing parameter
|
|
* by only reading values out of the buffer after it has verified
|
|
* that the size of the buffer is sufficient to read all needed
|
|
* fields. In this way, we avoid having to exit this method after
|
|
* the 'this' object has been modified by reading a part of the buffer.
|
|
*/
|
|
|
|
if(!this->AllowsTypeCode(c))
|
|
return B_BAD_TYPE;
|
|
|
|
if(buf == NULL)
|
|
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)))
|
|
{
|
|
return B_ERROR;
|
|
}
|
|
|
|
const byte *CurrentPos = static_cast<const byte *>(buf);
|
|
|
|
|
|
//QUESTION: I have no idea where this magic number came from, and i'm not sure that it's
|
|
//being read in the correct byte order.
|
|
if( *(reinterpret_cast<const int32 *>(CurrentPos)) != 0x02040607)
|
|
{
|
|
return B_BAD_TYPE;
|
|
}
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//read the struct size
|
|
ssize_t ParamStructSize = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//see BContinuousParameter::FlattenedSize() for a description of this value
|
|
const ssize_t AdditionalBContParamFlatSize = 24;
|
|
|
|
if((ParamStructSize + AdditionalBContParamFlatSize) > size)
|
|
{
|
|
//if the struct size is larger than the size of the buffer we were given,
|
|
//there's a problem
|
|
return B_ERROR;
|
|
}
|
|
|
|
//read the base BParameter
|
|
status_t RetVal = BParameter::Unflatten(c,buf,size);
|
|
|
|
if(RetVal != B_OK)
|
|
{
|
|
return RetVal;
|
|
}
|
|
|
|
CurrentPos = static_cast<const byte *>(buf);
|
|
CurrentPos += ParamStructSize;
|
|
|
|
|
|
//read the mMinimum property
|
|
mMinimum = *(reinterpret_cast<const float *>(CurrentPos));
|
|
CurrentPos += sizeof(float);
|
|
//read the mMaximum property
|
|
mMaximum = *(reinterpret_cast<const float *>(CurrentPos));
|
|
CurrentPos += sizeof(float);
|
|
//read the mStepping property
|
|
mStepping = *(reinterpret_cast<const float *>(CurrentPos));
|
|
CurrentPos += sizeof(float);
|
|
//read the mResponse property
|
|
mResponse = *(reinterpret_cast<const response *>(CurrentPos));
|
|
CurrentPos += sizeof(response);
|
|
//read the mFactor property
|
|
mFactor = *(reinterpret_cast<const float *>(CurrentPos));
|
|
CurrentPos += sizeof(float);
|
|
//read the mOffset property
|
|
mOffset = *(reinterpret_cast<const float *>(CurrentPos));
|
|
CurrentPos += sizeof(float);
|
|
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
/*************************************************************
|
|
* private BContinuousParameter
|
|
*************************************************************/
|
|
|
|
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; }
|
|
|
|
|
|
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)
|
|
{
|
|
}
|
|
|
|
|
|
BContinuousParameter::~BContinuousParameter()
|
|
{
|
|
}
|
|
|
|
/*************************************************************
|
|
* public BDiscreteParameter
|
|
*************************************************************/
|
|
|
|
type_code
|
|
BDiscreteParameter::ValueType()
|
|
{
|
|
return B_INT32_TYPE;
|
|
}
|
|
|
|
|
|
int32
|
|
BDiscreteParameter::CountItems()
|
|
{
|
|
ASSERT_WRETURN_VALUE(mValues != NULL,0);
|
|
|
|
return mValues->CountItems();
|
|
}
|
|
|
|
|
|
const char *
|
|
BDiscreteParameter::ItemNameAt(int32 index)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mSelections != NULL,NULL);
|
|
|
|
return reinterpret_cast<const char *>(mSelections->ItemAt(index));
|
|
}
|
|
|
|
|
|
int32
|
|
BDiscreteParameter::ItemValueAt(int32 index)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mValues != NULL,0);
|
|
|
|
//check for out of range
|
|
if((index < 0) || (index >= mValues->CountItems()))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int32 *Item = static_cast<int32 *>(mValues->ItemAt(index));
|
|
if(Item == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
return *Item;
|
|
}
|
|
|
|
|
|
status_t
|
|
BDiscreteParameter::AddItem(int32 value,
|
|
const char *name)
|
|
{
|
|
ASSERT_WRETURN_VALUE(mValues != NULL,B_ERROR);
|
|
ASSERT_WRETURN_VALUE(mSelections != NULL,B_ERROR);
|
|
|
|
int32 *NewVal = new int32(value);
|
|
char *NewSel = NULL;
|
|
if(name != NULL)
|
|
{
|
|
ssize_t NameLength = strlen(name);
|
|
NewSel = new char[NameLength + 1];
|
|
memcpy(NewSel,name,NameLength);
|
|
NewSel[NameLength] = 0;
|
|
}
|
|
|
|
//QUESTION: How do we watch for the B_NO_MEMORY case (Be Book refers to this)?
|
|
mValues->AddItem(NewVal);
|
|
mSelections->AddItem(NewSel);
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BDiscreteParameter::MakeItemsFromInputs()
|
|
{
|
|
ASSERT_WRETURN_VALUE(mValues != NULL,B_ERROR);
|
|
ASSERT_WRETURN_VALUE(mSelections != NULL,B_ERROR);
|
|
ASSERT_WRETURN_VALUE(mInputs != NULL,B_ERROR);
|
|
|
|
int32 i;
|
|
ssize_t NumInputs = mInputs->CountItems();
|
|
for(i = 0; i < NumInputs; i++)
|
|
{
|
|
BParameter *CurrentParam = static_cast<BParameter *>(mInputs->ItemAt(i));
|
|
this->AddItem(i,CurrentParam->Name());
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BDiscreteParameter::MakeItemsFromOutputs()
|
|
{
|
|
ASSERT_WRETURN_VALUE(mValues != NULL,B_ERROR);
|
|
ASSERT_WRETURN_VALUE(mSelections != NULL,B_ERROR);
|
|
ASSERT_WRETURN_VALUE(mOutputs != NULL,B_ERROR);
|
|
|
|
int32 i;
|
|
ssize_t NumOutputs = mOutputs->CountItems();
|
|
for(i = 0; i < NumOutputs; i++)
|
|
{
|
|
BParameter *CurrentParam = static_cast<BParameter *>(mOutputs->ItemAt(i));
|
|
this->AddItem(i,CurrentParam->Name());
|
|
}
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
void
|
|
BDiscreteParameter::MakeEmpty()
|
|
{
|
|
ASSERT_RETURN(mValues != NULL);
|
|
ASSERT_RETURN(mSelections != NULL);
|
|
|
|
int32 i;
|
|
ssize_t ListSize = mValues->CountItems();
|
|
for(i = 0; i < ListSize; i++)
|
|
{
|
|
int32 *CurrentValue = static_cast<int32 *>(mValues->ItemAt(i));
|
|
if(CurrentValue != NULL)
|
|
{
|
|
delete CurrentValue;
|
|
}
|
|
}
|
|
mValues->MakeEmpty();
|
|
|
|
ListSize = mSelections->CountItems();
|
|
for(i = 0; i < ListSize; i++)
|
|
{
|
|
char *CurrentSelection = static_cast<char *>(mSelections->ItemAt(i));
|
|
if(CurrentSelection != NULL)
|
|
{
|
|
delete[] CurrentSelection;
|
|
}
|
|
}
|
|
mSelections->MakeEmpty();
|
|
|
|
}
|
|
|
|
|
|
ssize_t
|
|
BDiscreteParameter::FlattenedSize() const
|
|
{
|
|
ssize_t RetVal = BParameter::FlattenedSize();
|
|
/*
|
|
//--------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-------------------
|
|
*/
|
|
RetVal += sizeof(ssize_t);
|
|
|
|
ssize_t NumItems = mValues->CountItems();
|
|
int32 i;
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
char *CurrentSel = static_cast<char *>(mSelections->ItemAt(i));
|
|
|
|
if(CurrentSel != NULL)
|
|
{
|
|
RetVal += min_c(strlen(CurrentSel),255);
|
|
}
|
|
|
|
//regardless of string size, there is a cost of 5 bytes for each item (string length + value)
|
|
RetVal += 5;
|
|
}
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
|
|
status_t
|
|
BDiscreteParameter::Flatten(void *buffer,
|
|
ssize_t size) const
|
|
{
|
|
if(buffer == NULL)
|
|
return B_NO_INIT;
|
|
|
|
ssize_t TotalBParameterFlatSize = BParameter::FlattenedSize();
|
|
|
|
//see BDiscreteParameter::FlattenedSize() for a description of this value
|
|
ssize_t AdditionalBDiscParamFlatSize = sizeof(ssize_t);
|
|
|
|
ssize_t NumItems = mValues->CountItems();
|
|
int32 i;
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
char *CurrentSel = static_cast<char *>(mSelections->ItemAt(i));
|
|
|
|
if(CurrentSel != NULL)
|
|
{
|
|
AdditionalBDiscParamFlatSize += min_c(strlen(CurrentSel),255);
|
|
}
|
|
|
|
//regardless of string size, there is a cost of 5 bytes for each item (string length + value)
|
|
AdditionalBDiscParamFlatSize += 5;
|
|
}
|
|
|
|
|
|
if(size < (TotalBParameterFlatSize + AdditionalBDiscParamFlatSize))
|
|
{
|
|
return B_NO_MEMORY;
|
|
}
|
|
|
|
status_t RetVal = BParameter::Flatten(buffer,size);
|
|
|
|
if(RetVal != B_OK)
|
|
{
|
|
return RetVal;
|
|
}
|
|
|
|
byte *CurrentPos = reinterpret_cast<byte *>(buffer);
|
|
CurrentPos += TotalBParameterFlatSize;
|
|
|
|
//write out the number of value/name pairs
|
|
*(reinterpret_cast<ssize_t *>(CurrentPos)) = NumItems;
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//write out all value/name pairs themselves
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
const char *CurrentSel = static_cast<char *>(mSelections->ItemAt(i));
|
|
const int32 *CurrentVal = static_cast<int32 *>(mValues->ItemAt(i));
|
|
|
|
if(CurrentSel != NULL)
|
|
{
|
|
byte NameLength = min_c(strlen(CurrentSel),255);
|
|
|
|
//write out the name length
|
|
*(reinterpret_cast<byte *>(CurrentPos)) = NameLength;
|
|
CurrentPos += sizeof(byte);
|
|
|
|
memcpy(CurrentPos,CurrentSel,NameLength);
|
|
CurrentPos += NameLength;
|
|
}
|
|
else
|
|
{
|
|
//write out a zero name length
|
|
*(reinterpret_cast<byte *>(CurrentPos)) = 0;
|
|
CurrentPos += sizeof(byte);
|
|
}
|
|
|
|
if(CurrentVal != NULL)
|
|
{
|
|
//write out the value
|
|
*(reinterpret_cast<int32 *>(CurrentPos)) = *CurrentVal;
|
|
CurrentPos += sizeof(int32);
|
|
}
|
|
else
|
|
{
|
|
//write out a zero value
|
|
*(reinterpret_cast<int32 *>(CurrentPos)) = 0;
|
|
CurrentPos += sizeof(int32);
|
|
}
|
|
}
|
|
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
|
|
status_t
|
|
BDiscreteParameter::Unflatten(type_code c,
|
|
const void *buf,
|
|
ssize_t size)
|
|
{
|
|
/*
|
|
* NOTICE: This method tries to avoid corrupting an existing parameter
|
|
* by only reading values out of the buffer after it has verified
|
|
* that the size of the buffer is sufficient to read all needed
|
|
* fields. In this way, we avoid having to exit this method after
|
|
* the 'this' object has been modified by reading a part of the buffer.
|
|
*/
|
|
|
|
if(!this->AllowsTypeCode(c))
|
|
return B_BAD_TYPE;
|
|
|
|
if(buf == NULL)
|
|
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)))
|
|
{
|
|
return B_ERROR;
|
|
}
|
|
|
|
const byte *CurrentPos = static_cast<const byte *>(buf);
|
|
|
|
|
|
//QUESTION: I have no idea where this magic number came from, and i'm not sure that it's
|
|
//being read in the correct byte order.
|
|
if( *(reinterpret_cast<const int32 *>(CurrentPos)) != 0x02040607)
|
|
{
|
|
return B_BAD_TYPE;
|
|
}
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//read the struct size
|
|
ssize_t ParamStructSize = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
//this is the minimum REQUIRED additional space for a BDiscreteParameter in a flattened buffer
|
|
const ssize_t AdditionalBDiscParamFlatSize = 1;
|
|
|
|
if((ParamStructSize + AdditionalBDiscParamFlatSize) > size)
|
|
{
|
|
//if the struct size is larger than the size of the buffer we were given,
|
|
//there's a problem
|
|
return B_ERROR;
|
|
}
|
|
|
|
//read the base BParameter
|
|
status_t RetVal = BParameter::Unflatten(c,buf,size);
|
|
|
|
if(RetVal != B_OK)
|
|
{
|
|
return RetVal;
|
|
}
|
|
|
|
CurrentPos = static_cast<const byte *>(buf);
|
|
CurrentPos += ParamStructSize;
|
|
|
|
//read NumItems
|
|
ssize_t NumItems = *(reinterpret_cast<const ssize_t *>(CurrentPos));
|
|
CurrentPos += sizeof(ssize_t);
|
|
|
|
ssize_t MaxByteLength = size - (CurrentPos - static_cast<const byte *>(buf));
|
|
|
|
const ssize_t MinFlattenedItemSize(5);
|
|
|
|
//each item occupies a minimum of 5 bytes, so make sure that there is enough
|
|
//space remaining in the buffer for the specified NumItems (assuming each is minimum size)
|
|
NumItems = min_c(NumItems,MaxByteLength/MinFlattenedItemSize);
|
|
|
|
//clear any existing name/value pairs
|
|
this->MakeEmpty();
|
|
|
|
int i;
|
|
for(i = 0; i < NumItems; i++)
|
|
{
|
|
//read the string length for the name associated with this item
|
|
byte NameStringLength = *(reinterpret_cast<const byte *>(CurrentPos));
|
|
CurrentPos += sizeof(byte);
|
|
|
|
//ensure that we don't read so much that we don't have enough buffer left for the minimum remainder
|
|
//of this item (4 byte int32 value), or for the minimum size of the remaining items (5bytes*(num remaining items))
|
|
MaxByteLength = size - ((CurrentPos - static_cast<const byte *>(buf)) + (NumItems - (i+1))*MinFlattenedItemSize + sizeof(int32));
|
|
|
|
NameStringLength = min_c(NameStringLength,MaxByteLength);
|
|
|
|
//read the name string
|
|
char *ItemName = new char[NameStringLength + 1];
|
|
memcpy(ItemName,CurrentPos,NameStringLength);
|
|
ItemName[NameStringLength] = 0;
|
|
CurrentPos += NameStringLength;
|
|
|
|
|
|
//read the value of this item
|
|
int32 ItemValue = *(reinterpret_cast<const int32 *>(CurrentPos));
|
|
CurrentPos += sizeof(int32);
|
|
|
|
//add the item and name to the list
|
|
this->AddItem(ItemValue,ItemName);
|
|
}
|
|
|
|
|
|
return B_OK;
|
|
}
|
|
|
|
/*************************************************************
|
|
* private BDiscreteParameter
|
|
*************************************************************/
|
|
|
|
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; }
|
|
|
|
|
|
BDiscreteParameter::BDiscreteParameter(int32 id,
|
|
media_type m_type,
|
|
BParameterWeb *web,
|
|
const char *name,
|
|
const char *kind)
|
|
: BParameter(id,m_type,B_DISCRETE_PARAMETER,web,name,kind,"")
|
|
{
|
|
this->mSelections = new BList();
|
|
this->mValues = new BList();
|
|
}
|
|
|
|
|
|
BDiscreteParameter::~BDiscreteParameter()
|
|
{
|
|
this->MakeEmpty();
|
|
|
|
if(this->mSelections != NULL)
|
|
{
|
|
delete this->mSelections;
|
|
}
|
|
if(this->mValues != NULL)
|
|
{
|
|
delete this->mValues;
|
|
}
|
|
}
|
|
|
|
/*************************************************************
|
|
* 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 c,
|
|
const void *buf,
|
|
ssize_t size)
|
|
{
|
|
return BParameter::Unflatten(c,buf,size);
|
|
}
|
|
|
|
/*************************************************************
|
|
* private BNullParameter
|
|
*************************************************************/
|
|
|
|
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; }
|
|
|
|
|
|
BNullParameter::BNullParameter(int32 id,
|
|
media_type m_type,
|
|
BParameterWeb *web,
|
|
const char *name,
|
|
const char *kind)
|
|
: BParameter(id,m_type,B_NULL_PARAMETER,web,name,kind,"")
|
|
{
|
|
}
|
|
|
|
|
|
BNullParameter::~BNullParameter()
|
|
{
|
|
}
|
|
|
|
|