mirror of
https://github.com/OpenFOAM/ThirdParty-6.git
synced 2025-12-08 06:57:43 +00:00
3039 lines
95 KiB
C++
3039 lines
95 KiB
C++
/*=========================================================================
|
|
|
|
Program: ParaView
|
|
Module: vtkClientServerStream.cxx
|
|
|
|
Copyright (c) Kitware, Inc.
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
#include "vtkClientServerStream.h"
|
|
|
|
#include "vtkAbstractArray.h"
|
|
#include "vtkArrayIterator.h"
|
|
#include "vtkArrayIteratorIncludes.h"
|
|
#include "vtkByteSwap.h"
|
|
#include "vtkSmartPointer.h"
|
|
#include "vtkType.h"
|
|
#include "vtkTypeTraits.h"
|
|
#include <typeinfo>
|
|
#include "vtkVariantExtract.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <sstream>
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Portability of typename keyword.
|
|
#if defined(__sgi) && !defined(_COMPILER_VERSION) && !defined(__GNUC__)
|
|
# define VTK_CSS_TYPENAME
|
|
#elif defined(_MSC_VER) && (_MSC_VER < 1310)
|
|
# define VTK_CSS_TYPENAME
|
|
#else
|
|
# define VTK_CSS_TYPENAME typename
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Macro to dispatch templated functions based on type in a switch.
|
|
#define VTK_CSS_TEMPLATE_MACRO(kind, call) \
|
|
case int8_##kind: { vtkTypeInt8* T = 0; call; } break; \
|
|
case int16_##kind: { vtkTypeInt16* T = 0; call; } break; \
|
|
case int32_##kind: { vtkTypeInt32* T = 0; call; } break; \
|
|
case int64_##kind: { vtkTypeInt64* T = 0; call; } break; \
|
|
case uint8_##kind: { vtkTypeUInt8* T = 0; call; } break; \
|
|
case uint16_##kind: { vtkTypeUInt16* T = 0; call; } break; \
|
|
case uint32_##kind: { vtkTypeUInt32* T = 0; call; } break; \
|
|
case uint64_##kind: { vtkTypeUInt64* T = 0; call; } break; \
|
|
case float32_##kind: { vtkTypeFloat32* T = 0; call; } break; \
|
|
case float64_##kind: { vtkTypeFloat64* T = 0; call; } break
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Define some traits for vtkType types.
|
|
template <class T> struct vtkClientServerTypeTraits;
|
|
#define VTK_CLIENT_SERVER_TYPE_TRAIT(in, out) \
|
|
template<> \
|
|
struct vtkClientServerTypeTraits< in > \
|
|
{ \
|
|
/* Type identifier for value of this type. */ \
|
|
static vtkClientServerStream::Types Value() \
|
|
{ return vtkClientServerStream::out##_value; } \
|
|
/* Type identifier for array of this type. */ \
|
|
static vtkClientServerStream::Types Array() \
|
|
{ return vtkClientServerStream::out##_array; } \
|
|
}
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeInt8, int8);
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeInt16, int16);
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeInt32, int32);
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeInt64, int64);
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeUInt8, uint8);
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeUInt16, uint16);
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeUInt32, uint32);
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeUInt64, uint64);
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeFloat32, float32);
|
|
VTK_CLIENT_SERVER_TYPE_TRAIT(vtkTypeFloat64, float64);
|
|
#undef VTK_CLIENT_SERVER_TYPE_TRAIT
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Internal implementation data.
|
|
class vtkClientServerStreamInternals
|
|
{
|
|
public:
|
|
vtkClientServerStreamInternals(vtkObjectBase* owner): Objects(owner) {}
|
|
vtkClientServerStreamInternals(const vtkClientServerStreamInternals& r,
|
|
vtkObjectBase* owner):
|
|
Data(r.Data), ValueOffsets(r.ValueOffsets),
|
|
MessageIndexes(r.MessageIndexes), Objects(r.Objects, owner),
|
|
StartIndex(r.StartIndex), Invalid(r.Invalid), String(r.String) {}
|
|
|
|
// Actual binary data in the stream.
|
|
typedef std::vector<unsigned char> DataType;
|
|
DataType Data;
|
|
|
|
// Offset to each value stored in the stream.
|
|
typedef std::vector<DataType::difference_type> ValueOffsetsType;
|
|
ValueOffsetsType ValueOffsets;
|
|
|
|
// Index into ValueOffsets of the first value corresponding to each
|
|
// message.
|
|
typedef std::vector<ValueOffsetsType::size_type> MessageIndexesType;
|
|
MessageIndexesType MessageIndexes;
|
|
|
|
// Hold references to vtkObjectBase instances stored in the stream.
|
|
// The object that owns this stream is passed as the argument to
|
|
// Register/UnRegister for objects stored in the stream because the
|
|
// owner of this stream effectively owns those objects. If no owner
|
|
// is given, then the objects are not referenced.
|
|
struct ObjectsType: std::vector<vtkObjectBase*>
|
|
{
|
|
typedef std::vector<vtkObjectBase*> Superclass;
|
|
ObjectsType(vtkObjectBase* owner): Owner(owner) {}
|
|
ObjectsType(const ObjectsType& r, vtkObjectBase* owner): Superclass(r),
|
|
Owner(owner)
|
|
{
|
|
if(this->Owner)
|
|
{
|
|
for(Superclass::iterator i = this->begin(); i != this->end(); ++i)
|
|
{
|
|
(*i)->Register(this->Owner);
|
|
}
|
|
}
|
|
}
|
|
~ObjectsType() { this->Clear(); }
|
|
ObjectsType& operator=(const ObjectsType& that)
|
|
{
|
|
Superclass::operator=(that);
|
|
if(this->Owner)
|
|
{
|
|
for(Superclass::iterator i = this->begin(); i != this->end(); ++i)
|
|
{
|
|
(*i)->Register(this->Owner);
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
vtkObjectBase* Owner;
|
|
|
|
void Insert(vtkObjectBase* obj)
|
|
{
|
|
if(obj)
|
|
{
|
|
if(this->Owner)
|
|
{
|
|
obj->Register(this->Owner);
|
|
}
|
|
this->push_back(obj);
|
|
}
|
|
}
|
|
|
|
void Clear()
|
|
{
|
|
for(Superclass::iterator i = this->begin(); i != this->end(); ++i)
|
|
{
|
|
if(this->Owner)
|
|
{
|
|
(*i)->UnRegister(this->Owner);
|
|
}
|
|
}
|
|
this->erase(this->begin(), this->end());
|
|
}
|
|
};
|
|
ObjectsType Objects;
|
|
|
|
// Index into ValueOffsets where the last Command started. Used to
|
|
// detect valid message completion.
|
|
static const ValueOffsetsType::size_type InvalidStartIndex;
|
|
ValueOffsetsType::size_type StartIndex;
|
|
|
|
// Whether the stream has been constructed improperly.
|
|
int Invalid;
|
|
|
|
// Buffer for return value from StreamToString.
|
|
std::string String;
|
|
|
|
// Access to protected members of vtkClientServerStream.
|
|
static vtkClientServerStream& Write(vtkClientServerStream& css,
|
|
const void* data, size_t length)
|
|
{ return css.Write(data, length); }
|
|
static const unsigned char* GetValue(const vtkClientServerStream& css,
|
|
int message, int value)
|
|
{ return css.GetValue(message, value); }
|
|
};
|
|
|
|
const vtkClientServerStreamInternals::ValueOffsetsType::size_type
|
|
vtkClientServerStreamInternals::InvalidStartIndex =
|
|
static_cast<vtkClientServerStreamInternals::ValueOffsetsType::size_type>(-1);
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::vtkClientServerStream(vtkObjectBase* owner)
|
|
{
|
|
// Initialize the internal representation of the stream.
|
|
this->Internal = new vtkClientServerStreamInternals(owner);
|
|
this->Reserve(1024);
|
|
this->Reset();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::~vtkClientServerStream()
|
|
{
|
|
delete this->Internal;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::vtkClientServerStream(const vtkClientServerStream& r,
|
|
vtkObjectBase* owner)
|
|
{
|
|
// Allocate and copy the internal representation of the stream.
|
|
this->Internal = new vtkClientServerStreamInternals(*r.Internal, owner);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator=(const vtkClientServerStream& that)
|
|
{
|
|
*this->Internal = *that.Internal;
|
|
return *this;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::Copy(const vtkClientServerStream* source)
|
|
{
|
|
*this = *source;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::Write(const void* data, size_t length)
|
|
{
|
|
// Make sure we have data.
|
|
if(length == 0)
|
|
{
|
|
return *this;
|
|
}
|
|
else if(!data)
|
|
{
|
|
vtkGenericWarningMacro(
|
|
"vtkClientServerStream::Write given NULL pointer and non-zero length.");
|
|
return *this;
|
|
}
|
|
|
|
// Copy the value into the data.
|
|
this->Internal->Data.resize(this->Internal->Data.size() + length);
|
|
memcpy(&*(this->Internal->Data.end() - length), data, length);
|
|
return *this;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::Reserve(size_t size)
|
|
{
|
|
this->Internal->Data.reserve(size);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::Reset()
|
|
{
|
|
// Empty the entire stream.
|
|
vtkClientServerStreamInternals::DataType().swap(this->Internal->Data);
|
|
|
|
this->Internal->ValueOffsets.erase(this->Internal->ValueOffsets.begin(),
|
|
this->Internal->ValueOffsets.end());
|
|
this->Internal->MessageIndexes.erase(this->Internal->MessageIndexes.begin(),
|
|
this->Internal->MessageIndexes.end());
|
|
this->Internal->Objects.Clear();
|
|
|
|
// No message has yet been started.
|
|
this->Internal->Invalid = 0;
|
|
this->Internal->StartIndex =
|
|
vtkClientServerStreamInternals::InvalidStartIndex;
|
|
|
|
// Store the byte order of data to come.
|
|
#ifdef VTK_WORDS_BIGENDIAN
|
|
this->Internal->Data.push_back(vtkClientServerStream::BigEndian);
|
|
#else
|
|
this->Internal->Data.push_back(vtkClientServerStream::LittleEndian);
|
|
#endif
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator << (vtkClientServerStream::Commands t)
|
|
{
|
|
// Make sure we do not start another command without ending the
|
|
// previous one.
|
|
if(this->Internal->StartIndex !=
|
|
vtkClientServerStreamInternals::InvalidStartIndex)
|
|
{
|
|
// Got two Commands without an End between them. This is an
|
|
// invalid stream.
|
|
this->Internal->Invalid = 1;
|
|
return *this;
|
|
}
|
|
|
|
// Save where this message starts.
|
|
this->Internal->StartIndex = this->Internal->ValueOffsets.size();
|
|
|
|
// The command counts as the first value in the message.
|
|
this->Internal->ValueOffsets.push_back(
|
|
this->Internal->Data.end()-this->Internal->Data.begin());
|
|
|
|
// Store the command in the stream.
|
|
vtkTypeUInt32 data = static_cast<vtkTypeUInt32>(t);
|
|
return this->Write(&data, sizeof(data));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator << (vtkClientServerStream::Types t)
|
|
{
|
|
// If this is the end of a message, record the message start
|
|
// position.
|
|
if(t == vtkClientServerStream::End)
|
|
{
|
|
// Make sure the command we are ending actually started.
|
|
if(this->Internal->StartIndex ==
|
|
vtkClientServerStreamInternals::InvalidStartIndex)
|
|
{
|
|
// This is an invalid stream.
|
|
this->Internal->Invalid = 1;
|
|
return *this;
|
|
}
|
|
|
|
// Store the value index where this command started.
|
|
this->Internal->MessageIndexes.push_back(this->Internal->StartIndex);
|
|
|
|
// No current Command is being constructed.
|
|
this->Internal->StartIndex =
|
|
vtkClientServerStreamInternals::InvalidStartIndex;
|
|
}
|
|
|
|
// All values write their type first. Mark the start of this type
|
|
// and optional value.
|
|
this->Internal->ValueOffsets.push_back(
|
|
this->Internal->Data.end()-this->Internal->Data.begin());
|
|
|
|
// Store the type in the stream.
|
|
vtkTypeUInt32 data = static_cast<vtkTypeUInt32>(t);
|
|
return this->Write(&data, sizeof(data));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator << (vtkClientServerStream::Argument a)
|
|
{
|
|
if(a.Data && a.Size)
|
|
{
|
|
// Mark the start of this type and optional value.
|
|
this->Internal->ValueOffsets.push_back(
|
|
this->Internal->Data.end()-this->Internal->Data.begin());
|
|
|
|
// If the argument is a vtk_object_pointer, we need to store a
|
|
// reference to the object.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, a.Data, sizeof(tp));
|
|
if(tp == vtkClientServerStream::vtk_object_pointer)
|
|
{
|
|
vtkObjectBase* obj;
|
|
memcpy(&obj, a.Data+sizeof(tp), sizeof(obj));
|
|
this->Internal->Objects.Insert(obj);
|
|
}
|
|
|
|
// Write the data to the stream.
|
|
return this->Write(a.Data, a.Size);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator << (vtkClientServerStream::Array a)
|
|
{
|
|
// Store the array type, then length, then data.
|
|
*this << a.Type;
|
|
this->Write(&a.Length, sizeof(a.Length));
|
|
this->Write(a.Data, a.Size);
|
|
|
|
// Special case for InsertString. We need to add the null terminator.
|
|
if(a.Type == vtkClientServerStream::string_value)
|
|
{
|
|
char n = 0;
|
|
this->Write(&n, 1);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator << (const vtkClientServerStream& css)
|
|
{
|
|
const unsigned char* data;
|
|
size_t length;
|
|
// Do not allow object pointers to be passed in binary form.
|
|
if(this != &css && css.Internal->Objects.empty() &&
|
|
css.GetData(&data, &length))
|
|
{
|
|
// Store the stream_value type, then length, then data.
|
|
*this << vtkClientServerStream::stream_value;
|
|
vtkTypeUInt32 size = static_cast<vtkTypeUInt32>(length);
|
|
this->Write(&size, sizeof(size));
|
|
return this->Write(data, size);
|
|
}
|
|
else
|
|
{
|
|
// This is an invalid stream.
|
|
this->Internal->Invalid = 1;
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator << (vtkClientServerID id)
|
|
{
|
|
// Store the id_value type and then the id value itself.
|
|
*this << vtkClientServerStream::id_value;
|
|
return this->Write(&id.ID, sizeof(id.ID));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator << (vtkObjectBase* obj)
|
|
{
|
|
// The stream will now hold a reference to the object.
|
|
this->Internal->Objects.Insert(obj);
|
|
|
|
// Store the vtk_object_pointer type and then the pointer value itself.
|
|
*this << vtkClientServerStream::vtk_object_pointer;
|
|
return this->Write(&obj, sizeof(obj));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator << (const vtkStdString& val)
|
|
{
|
|
(*this) << val.c_str();
|
|
return *this;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template<typename iterT>
|
|
void vtkClientServerPutArrayVariant(vtkClientServerStream& css, iterT* it)
|
|
{
|
|
vtkIdType numVals = it->GetNumberOfValues();
|
|
for (vtkIdType i = 0; i < numVals; ++i)
|
|
{
|
|
css << it->GetValue(i);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream&
|
|
vtkClientServerStream::operator << (const vtkVariant& val)
|
|
{
|
|
vtkTypeUInt8 variantValid = val.IsValid();
|
|
if (variantValid && val.IsVTKObject() && !val.IsArray())
|
|
{ // If val is a VTK object that is not an array, fail by encoding an invalid vtkVariant value.
|
|
variantValid = 0;
|
|
}
|
|
(*this) << variantValid;
|
|
|
|
if (variantValid)
|
|
{
|
|
vtkTypeUInt8 variantType = static_cast<vtkTypeUInt8>(val.GetType());
|
|
(*this) << variantType;
|
|
|
|
bool validDummy;
|
|
switch (variantType)
|
|
{
|
|
vtkExtendedTemplateMacro(
|
|
(*this) << vtkVariantExtract<VTK_TT>(val, validDummy));
|
|
case VTK_OBJECT:
|
|
{ // The object must be an array; encode it.
|
|
vtkAbstractArray* array = val.ToArray();
|
|
vtkTypeInt32 arrayType = array->GetDataType();
|
|
vtkTypeInt32 numComponents = array->GetNumberOfComponents();
|
|
vtkTypeInt64 numTuples = array->GetNumberOfTuples();
|
|
(*this) << arrayType << numComponents << numTuples;
|
|
vtkArrayIterator* iter = array->NewIterator();
|
|
switch(array->GetDataType())
|
|
{
|
|
vtkExtendedArrayIteratorTemplateMacro(
|
|
vtkClientServerPutArrayVariant<VTK_TT>(*this,static_cast<VTK_TT*>(iter)));
|
|
}
|
|
iter->Delete();
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream& vtkClientServerStream::operator << (bool x)
|
|
{
|
|
// Store the type first, then the value.
|
|
// Boolean values in the stream are represented by vtkTypeUInt8.
|
|
*this << vtkClientServerStream::bool_value;
|
|
vtkTypeUInt8 b = x?1:0;
|
|
return this->Write(&b, sizeof(b));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Template and macro to implement all insertion operators in the same way.
|
|
template <class T>
|
|
vtkClientServerStream&
|
|
vtkClientServerStreamOperatorSL(vtkClientServerStream* self, T x)
|
|
{
|
|
// Store the type first, then the value.
|
|
typedef VTK_CSS_TYPENAME vtkTypeTraits<T>::SizedType Type;
|
|
*self << vtkClientServerTypeTraits<Type>::Value();
|
|
return vtkClientServerStreamInternals::Write(*self, &x, sizeof(x));
|
|
}
|
|
|
|
#define VTK_CLIENT_SERVER_OPERATOR(type) \
|
|
vtkClientServerStream& vtkClientServerStream::operator << (type x) \
|
|
{ \
|
|
return vtkClientServerStreamOperatorSL(this, x); \
|
|
}
|
|
VTK_CLIENT_SERVER_OPERATOR(char)
|
|
VTK_CLIENT_SERVER_OPERATOR(int)
|
|
VTK_CLIENT_SERVER_OPERATOR(short)
|
|
VTK_CLIENT_SERVER_OPERATOR(long)
|
|
VTK_CLIENT_SERVER_OPERATOR(signed char)
|
|
VTK_CLIENT_SERVER_OPERATOR(unsigned char)
|
|
VTK_CLIENT_SERVER_OPERATOR(unsigned int)
|
|
VTK_CLIENT_SERVER_OPERATOR(unsigned short)
|
|
VTK_CLIENT_SERVER_OPERATOR(unsigned long)
|
|
#if defined(VTK_TYPE_USE_LONG_LONG)
|
|
VTK_CLIENT_SERVER_OPERATOR(long long)
|
|
VTK_CLIENT_SERVER_OPERATOR(unsigned long long)
|
|
#endif
|
|
#if defined(VTK_TYPE_USE___INT64)
|
|
VTK_CLIENT_SERVER_OPERATOR(__int64)
|
|
VTK_CLIENT_SERVER_OPERATOR(unsigned __int64)
|
|
#endif
|
|
VTK_CLIENT_SERVER_OPERATOR(float)
|
|
VTK_CLIENT_SERVER_OPERATOR(double)
|
|
#undef VTK_CLIENT_SERVER_OPERATOR
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream& vtkClientServerStream::operator << (const char* x)
|
|
{
|
|
// String length will include null terminator. NULL string will be
|
|
// length 0.
|
|
vtkTypeUInt32 length = static_cast<vtkTypeUInt32>(x?(strlen(x)+1):0);
|
|
*this << vtkClientServerStream::string_value;
|
|
this->Write(&length, sizeof(length));
|
|
return this->Write(x, static_cast<size_t>(length));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::Array
|
|
vtkClientServerStream::InsertString(const char* begin, const char* end)
|
|
{
|
|
// Make sure the string does not end early.
|
|
const char* c = begin;
|
|
while(c < end && *c)
|
|
{
|
|
++c;
|
|
}
|
|
end = c;
|
|
|
|
// Construct a fake array with a string type. This will be handled
|
|
// by the insertion operator with a special case for InsertString to
|
|
// add the null terminator.
|
|
vtkClientServerStream::Array a =
|
|
{
|
|
vtkClientServerStream::string_value,
|
|
static_cast<vtkTypeUInt32>(end-begin+1),
|
|
static_cast<vtkTypeUInt32>(end-begin),
|
|
begin
|
|
};
|
|
return a;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Template and macro to implement all InsertArray methods in the same way.
|
|
template <class T>
|
|
vtkClientServerStream::Array
|
|
vtkClientServerStreamInsertArray(const T* data, int length)
|
|
{
|
|
// Construct and return the array information structure.
|
|
typedef VTK_CSS_TYPENAME vtkTypeTraits<T>::SizedType Type;
|
|
vtkClientServerStream::Array a =
|
|
{
|
|
vtkClientServerTypeTraits<Type>::Array(),
|
|
static_cast<vtkTypeUInt32>(length),
|
|
static_cast<vtkTypeUInt32>(sizeof(Type)*length),
|
|
data
|
|
};
|
|
return a;
|
|
}
|
|
|
|
#define VTK_CLIENT_SERVER_INSERT_ARRAY(type) \
|
|
vtkClientServerStream::Array \
|
|
vtkClientServerStream::InsertArray(const type* data, int length) \
|
|
{ \
|
|
return vtkClientServerStreamInsertArray(data, length); \
|
|
}
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(char)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(short)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(int)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(long)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(signed char)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(unsigned char)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(unsigned short)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(unsigned int)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(unsigned long)
|
|
#if defined(VTK_TYPE_USE_LONG_LONG)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(long long)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(unsigned long long)
|
|
#endif
|
|
#if defined(VTK_TYPE_USE___INT64)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(__int64)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(unsigned __int64)
|
|
#endif
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(float)
|
|
VTK_CLIENT_SERVER_INSERT_ARRAY(double)
|
|
#undef VTK_CLIENT_SERVER_INSERT_ARRAY
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Template to implement each type conversion in the lookup tables below.
|
|
// The "long, long, long" arguments are used to convince VS6 to select
|
|
// the proper overload when more than one of these functions otherwise
|
|
// looks the same after template instantiation. This works around the
|
|
// lack of partial ordering of templates in VS6.
|
|
template <class SourceType, class T>
|
|
void vtkClientServerStreamGetArgumentCase(SourceType*,
|
|
const unsigned char* src, T* dest,
|
|
long, long, long)
|
|
{
|
|
// Copy the value out of the stream and convert it.
|
|
SourceType value;
|
|
memcpy(&value, src, sizeof(value));
|
|
*dest = static_cast<T>(value);
|
|
}
|
|
template <class SourceType>
|
|
void vtkClientServerStreamGetArgumentCase(SourceType*,
|
|
const unsigned char* src,
|
|
bool* dest, long, long, int)
|
|
{
|
|
// Copy the value out of the stream and convert it.
|
|
SourceType value;
|
|
memcpy(&value, src, sizeof(value));
|
|
*dest = value? true:false;
|
|
}
|
|
template <class T>
|
|
void vtkClientServerStreamGetArgumentCase(bool*,
|
|
const unsigned char* src,
|
|
T* dest, long, int, int)
|
|
{
|
|
// Boolean values in the stream are represented by vtkTypeUInt8.
|
|
vtkTypeUInt8 value;
|
|
memcpy(&value, src, sizeof(value));
|
|
*dest = static_cast<T>(value);
|
|
}
|
|
void vtkClientServerStreamGetArgumentCase(bool*,
|
|
const unsigned char* src,
|
|
bool* dest, int, int, int)
|
|
{
|
|
// Boolean values in the stream are represented by vtkTypeUInt8.
|
|
vtkTypeUInt8 value;
|
|
memcpy(&value, src, sizeof(value));
|
|
*dest = value? true:false;
|
|
}
|
|
|
|
#define VTK_CSS_GET_ARGUMENT_CASE(TypeId, SourceType) \
|
|
case vtkClientServerStream::TypeId: \
|
|
{ \
|
|
SourceType* T = 0; \
|
|
vtkClientServerStreamGetArgumentCase(T, src, dest, 1, 1, 1); \
|
|
} break
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeInt8* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeInt8.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(bool_value, bool);
|
|
|
|
// Unsafe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeInt16* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeInt16.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(bool_value, bool);
|
|
|
|
// Unsafe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeInt32* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeInt32.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int32_value, vtkTypeInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(bool_value, bool);
|
|
|
|
// Unsafe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int64_value, vtkTypeInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint64_value, vtkTypeUInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeInt64* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeInt64.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int32_value, vtkTypeInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int64_value, vtkTypeInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(bool_value, bool);
|
|
|
|
// Unsafe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint64_value, vtkTypeUInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float64_value, vtkTypeFloat64);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeUInt8* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeUInt8.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(bool_value, bool);
|
|
|
|
// Unsafe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int32_value, vtkTypeInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeUInt16* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeUInt16.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(bool_value, bool);
|
|
|
|
// Unsafe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int32_value, vtkTypeInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeUInt32* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeUInt32.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(bool_value, bool);
|
|
|
|
// Unsafe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int32_value, vtkTypeInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int64_value, vtkTypeInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint64_value, vtkTypeUInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeUInt64* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeUInt64.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint64_value, vtkTypeUInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(bool_value, bool);
|
|
|
|
// Unsafe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int32_value, vtkTypeInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int64_value, vtkTypeInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float64_value, vtkTypeFloat64);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeFloat32* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeFloat32.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
|
|
// Unsafe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int32_value, vtkTypeInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float64_value, vtkTypeFloat64);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
vtkTypeFloat64* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a vtkTypeFloat64.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int32_value, vtkTypeInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float64_value, vtkTypeFloat64);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
int vtkClientServerStreamGetArgument(vtkClientServerStream::Types type,
|
|
const unsigned char* src,
|
|
bool* dest)
|
|
{
|
|
// Lookup what types can be converted safely to a bool.
|
|
switch(type)
|
|
{
|
|
// Safe conversions:
|
|
VTK_CSS_GET_ARGUMENT_CASE(bool_value, bool);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint8_value, vtkTypeUInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint16_value, vtkTypeUInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint32_value, vtkTypeUInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(uint64_value, vtkTypeUInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int8_value, vtkTypeInt8);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int16_value, vtkTypeInt16);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int32_value, vtkTypeInt32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(int64_value, vtkTypeInt64);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float32_value, vtkTypeFloat32);
|
|
VTK_CSS_GET_ARGUMENT_CASE(float64_value, vtkTypeFloat64);
|
|
default: return 0;
|
|
};
|
|
return 1;
|
|
}
|
|
|
|
#undef VTK_CSS_GET_ARGUMENT_CASE
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Template and macro to implement value GetArgument methods in the same way.
|
|
template <class T>
|
|
int
|
|
vtkClientServerStreamGetArgumentValue(const vtkClientServerStream* self,
|
|
int midx, int argument, T* value,
|
|
long)
|
|
{
|
|
typedef VTK_CSS_TYPENAME vtkTypeTraits<T>::SizedType Type;
|
|
if(const unsigned char* data =
|
|
vtkClientServerStreamInternals::GetValue(*self, midx, 1+argument))
|
|
{
|
|
// Get the type of the value in the stream.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, data, sizeof(tp));
|
|
data += sizeof(tp);
|
|
|
|
// Call the type conversion function for this type.
|
|
return vtkClientServerStreamGetArgument(
|
|
static_cast<vtkClientServerStream::Types>(tp), data,
|
|
reinterpret_cast<Type*>(value));
|
|
}
|
|
return 0;
|
|
}
|
|
int
|
|
vtkClientServerStreamGetArgumentValue(const vtkClientServerStream* self,
|
|
int midx, int argument, bool* value,
|
|
int)
|
|
{
|
|
if(const unsigned char* data =
|
|
vtkClientServerStreamInternals::GetValue(*self, midx, 1+argument))
|
|
{
|
|
// Get the type of the value in the stream.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, data, sizeof(tp));
|
|
data += sizeof(tp);
|
|
|
|
// Call the type conversion function for this type.
|
|
return vtkClientServerStreamGetArgument(
|
|
static_cast<vtkClientServerStream::Types>(tp), data, value);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define VTK_CSS_GET_ARGUMENT(type) \
|
|
int vtkClientServerStream::GetArgument(int message, int argument, \
|
|
type* value) const \
|
|
{ \
|
|
return vtkClientServerStreamGetArgumentValue(this, message, \
|
|
argument, value, 1); \
|
|
}
|
|
VTK_CSS_GET_ARGUMENT(bool)
|
|
VTK_CSS_GET_ARGUMENT(signed char)
|
|
VTK_CSS_GET_ARGUMENT(char)
|
|
VTK_CSS_GET_ARGUMENT(int)
|
|
VTK_CSS_GET_ARGUMENT(short)
|
|
VTK_CSS_GET_ARGUMENT(long)
|
|
VTK_CSS_GET_ARGUMENT(unsigned char)
|
|
VTK_CSS_GET_ARGUMENT(unsigned int)
|
|
VTK_CSS_GET_ARGUMENT(unsigned short)
|
|
VTK_CSS_GET_ARGUMENT(unsigned long)
|
|
VTK_CSS_GET_ARGUMENT(float)
|
|
VTK_CSS_GET_ARGUMENT(double)
|
|
#if defined(VTK_TYPE_USE_LONG_LONG)
|
|
VTK_CSS_GET_ARGUMENT(long long)
|
|
VTK_CSS_GET_ARGUMENT(unsigned long long)
|
|
#endif
|
|
#if defined(VTK_TYPE_USE___INT64)
|
|
VTK_CSS_GET_ARGUMENT(__int64)
|
|
VTK_CSS_GET_ARGUMENT(unsigned __int64)
|
|
#endif
|
|
#undef VTK_CSS_GET_ARGUMENT
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Template and macro to implement array GetArgument methods in the same way.
|
|
template <class T>
|
|
int
|
|
vtkClientServerStreamGetArgumentArray(const vtkClientServerStream* self,
|
|
int midx, int argument, T* value,
|
|
vtkTypeUInt32 length)
|
|
{
|
|
typedef VTK_CSS_TYPENAME vtkTypeTraits<T>::SizedType Type;
|
|
if(const unsigned char* data =
|
|
vtkClientServerStreamInternals::GetValue(*self, midx, 1+argument))
|
|
{
|
|
// Get the type of the value in the stream.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, data, sizeof(tp));
|
|
data += sizeof(tp);
|
|
|
|
// If the type and length of the array match, use it.
|
|
if(static_cast<vtkClientServerStream::Types>(tp) ==
|
|
vtkClientServerTypeTraits<Type>::Array())
|
|
{
|
|
// Get the length of the value in the stream.
|
|
vtkTypeUInt32 len;
|
|
memcpy(&len, data, sizeof(len));
|
|
data += sizeof(len);
|
|
|
|
if(len == length)
|
|
{
|
|
// Copy the value out of the stream.
|
|
memcpy(value, data, len*sizeof(Type));
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#define VTK_CSS_GET_ARGUMENT_ARRAY(type) \
|
|
int vtkClientServerStream::GetArgument(int message, int argument, \
|
|
type* value, \
|
|
vtkTypeUInt32 length) const \
|
|
{ \
|
|
return vtkClientServerStreamGetArgumentArray(this, message, argument, \
|
|
value, length); \
|
|
}
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(signed char)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(char)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(int)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(short)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(long)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(unsigned char)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(unsigned int)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(unsigned short)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(unsigned long)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(float)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(double)
|
|
#if defined(VTK_TYPE_USE_LONG_LONG)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(long long)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(unsigned long long)
|
|
#endif
|
|
#if defined(VTK_TYPE_USE___INT64)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(__int64)
|
|
VTK_CSS_GET_ARGUMENT_ARRAY(unsigned __int64)
|
|
#endif
|
|
#undef VTK_CSS_GET_ARGUMENT_ARRAY
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetArgument(int message, int argument,
|
|
const char** value) const
|
|
{
|
|
// Get a pointer to the type/value pair in the stream.
|
|
if(const unsigned char* data = this->GetValue(message, 1+argument))
|
|
{
|
|
// Get the type of the value in the stream.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, data, sizeof(tp));
|
|
data += sizeof(tp);
|
|
|
|
// Make sure the type is a string.
|
|
if(static_cast<vtkClientServerStream::Types>(tp) ==
|
|
vtkClientServerStream::string_value)
|
|
{
|
|
// Get the length of the string.
|
|
vtkTypeUInt32 len;
|
|
memcpy(&len, data, sizeof(len));
|
|
data += sizeof(len);
|
|
|
|
if(len > 0)
|
|
{
|
|
// Give back a pointer directly to the string in the stream.
|
|
*value = reinterpret_cast<const char*>(data);
|
|
}
|
|
else
|
|
{
|
|
// String pointer value was NULL.
|
|
*value = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetArgument(int message, int argument,
|
|
char** value) const
|
|
{
|
|
const char* tmp;
|
|
if(this->GetArgument(message, argument, &tmp))
|
|
{
|
|
*value = const_cast<char*>(tmp);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetArgument(int message, int argument, vtkStdString* value) const
|
|
{
|
|
return this->GetArgument(message, argument, static_cast<std::string*>(value));
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetArgument(int message, int argument, std::string *value) const
|
|
{
|
|
char* tmp = NULL;
|
|
if (this->GetArgument(message, argument, &tmp) && tmp)
|
|
{
|
|
*value = tmp;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetArgument(int message, int argument,
|
|
vtkClientServerStream* value) const
|
|
{
|
|
// Get a pointer to the type/value pair in the stream.
|
|
if(const unsigned char* data = this->GetValue(message, 1+argument))
|
|
{
|
|
// Get the type of the value in the stream.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, data, sizeof(tp));
|
|
data += sizeof(tp);
|
|
|
|
// Make sure the type is a stream_value.
|
|
if(static_cast<vtkClientServerStream::Types>(tp) ==
|
|
vtkClientServerStream::stream_value)
|
|
{
|
|
// Get the length of the stream data.
|
|
vtkTypeUInt32 len;
|
|
memcpy(&len, data, sizeof(len));
|
|
data += sizeof(len);
|
|
|
|
// Set the data in the given stream.
|
|
size_t length = static_cast<size_t>(len);
|
|
return value->SetData(data, length);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetArgument(int message, int argument,
|
|
vtkClientServerID* value) const
|
|
{
|
|
// Get a pointer to the type/value pair in the stream.
|
|
if(const unsigned char* data = this->GetValue(message, 1+argument))
|
|
{
|
|
// Get the type of the value in the stream.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, data, sizeof(tp));
|
|
data += sizeof(tp);
|
|
|
|
// Make sure the type is an id_value.
|
|
if(static_cast<vtkClientServerStream::Types>(tp) ==
|
|
vtkClientServerStream::id_value)
|
|
{
|
|
// Copy the value out of the stream.
|
|
memcpy(&value->ID, data, sizeof(value->ID));
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Template to implement GetArgument zero-to-null-pointer conversions.
|
|
template <class SourceType>
|
|
int vtkClientServerStreamGetArgumentPointer(SourceType*,
|
|
const unsigned char* src,
|
|
vtkObjectBase** dest)
|
|
{
|
|
// Copy the value out of the stream.
|
|
SourceType value;
|
|
memcpy(&value, src, sizeof(value));
|
|
|
|
// Values of 0 can be converted to a NULL pointer.
|
|
if(value == static_cast<SourceType>(0))
|
|
{
|
|
*dest = 0;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int vtkClientServerStream::GetArgument(int message, int argument,
|
|
vtkObjectBase** value) const
|
|
{
|
|
// Get a pointer to the type/value pair in the stream.
|
|
int result = 0;
|
|
if(const unsigned char* data = this->GetValue(message, 1+argument))
|
|
{
|
|
// Get the type of the value in the stream.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, data, sizeof(tp));
|
|
data += sizeof(tp);
|
|
|
|
// Make sure the type is a vtk_object_pointer or is 0.
|
|
switch(static_cast<vtkClientServerStream::Types>(tp))
|
|
{
|
|
VTK_CSS_TEMPLATE_MACRO(value, result =
|
|
vtkClientServerStreamGetArgumentPointer
|
|
(T, data, value));
|
|
case vtkClientServerStream::vtk_object_pointer:
|
|
{
|
|
// Copy the value out of the stream.
|
|
memcpy(value, data, sizeof(*value));
|
|
result = 1;
|
|
} break;
|
|
case vtkClientServerStream::id_value:
|
|
{
|
|
// Copy the value out of the stream.
|
|
vtkClientServerID id;
|
|
memcpy(&id.ID, data, sizeof(id.ID));
|
|
// ID value 0 can be converted to a NULL pointer.
|
|
if(id.ID == 0)
|
|
{
|
|
*value = 0;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
template<typename T>
|
|
int vtkClientServerGetVariant(const vtkClientServerStream* self, int message, int& argument, vtkVariant& out)
|
|
{
|
|
T raw;
|
|
int result = self->GetArgument(message, argument++, &raw);
|
|
if (!result) return result;
|
|
out = raw;
|
|
return result; // result != 0 by definition
|
|
}
|
|
|
|
// Specialize for vtkVariant as \a argument is handled differently.
|
|
template<>
|
|
int vtkClientServerGetVariant<vtkVariant>(const vtkClientServerStream* self, int message, int& argument, vtkVariant& out)
|
|
{
|
|
int result = self->GetArgument(message, argument, &out);
|
|
if (!result) return result;
|
|
return result; // result != 0 by definition
|
|
}
|
|
|
|
template<typename T>
|
|
int vtkClientServerGetArrayVariant(const vtkClientServerStream* self, int message, int& argument, vtkAbstractArray* array)
|
|
{
|
|
vtkVariant value;
|
|
vtkIdType maxId = array->GetMaxId();
|
|
int result = 1;
|
|
for (vtkIdType i = 0; i <= maxId; ++i)
|
|
{
|
|
result = vtkClientServerGetVariant<T>(self, message, argument, value);
|
|
if (!result) return result;
|
|
array->SetVariantValue(i, value);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int vtkClientServerStream::GetArgument(int message, int& argument, vtkVariant* value) const
|
|
{
|
|
int result;
|
|
|
|
vtkTypeUInt8 variantValid;
|
|
result = this->GetArgument(message, argument++, &variantValid);
|
|
if (!result) return result;
|
|
|
|
if (variantValid)
|
|
{
|
|
vtkTypeUInt8 variantType;
|
|
result = this->GetArgument(message, argument++, &variantType);
|
|
if (!result) return result;
|
|
|
|
switch (variantType)
|
|
{
|
|
vtkExtendedTemplateMacro(
|
|
vtkClientServerGetVariant<VTK_TT>(this, message, argument, *value));
|
|
case VTK_OBJECT:
|
|
{
|
|
// Only vtkAbstractArray subclasses are supported, and only their raw values are encoded (no vtkInformation keys)
|
|
// Packed values include: the array type, the # components(nc), # tuples(nt), nc*nt raw values.
|
|
vtkTypeInt32 arrayType;
|
|
vtkTypeInt32 numComponents;
|
|
vtkTypeInt64 numTuples;
|
|
result = this->GetArgument(message, argument++, &arrayType);
|
|
if (!result) return result;
|
|
result = this->GetArgument(message, argument++, &numComponents);
|
|
if (!result) return result;
|
|
result = this->GetArgument(message, argument++, &numTuples);
|
|
if (!result) return result;
|
|
vtkSmartPointer<vtkAbstractArray> array;
|
|
array.TakeReference(vtkAbstractArray::CreateArray(arrayType));
|
|
if (!array) return 1;
|
|
array->SetNumberOfComponents(numComponents);
|
|
array->SetNumberOfTuples(numTuples);
|
|
switch (arrayType)
|
|
{
|
|
vtkExtraExtendedTemplateMacro(
|
|
vtkClientServerGetArrayVariant<VTK_TT>(this, message, argument, array));
|
|
}
|
|
*value = array.GetPointer();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*value = vtkVariant();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetArgumentLength(int message, int argument,
|
|
vtkTypeUInt32* length) const
|
|
{
|
|
// Get a pointer to the type/value pair in the stream.
|
|
if(const unsigned char* data = this->GetValue(message, 1+argument))
|
|
{
|
|
// Get the type of the value in the stream.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, data, sizeof(tp));
|
|
data += sizeof(tp);
|
|
|
|
// Make sure the type is an array type.
|
|
switch(static_cast<vtkClientServerStream::Types>(tp))
|
|
{
|
|
case vtkClientServerStream::int8_array:
|
|
case vtkClientServerStream::uint8_array:
|
|
case vtkClientServerStream::int16_array:
|
|
case vtkClientServerStream::uint16_array:
|
|
case vtkClientServerStream::int32_array:
|
|
case vtkClientServerStream::uint32_array:
|
|
case vtkClientServerStream::float32_array:
|
|
case vtkClientServerStream::int64_array:
|
|
case vtkClientServerStream::uint64_array:
|
|
case vtkClientServerStream::float64_array:
|
|
{
|
|
// Get the length of the array.
|
|
memcpy(length, data, sizeof(*length));
|
|
} return 1;
|
|
default: break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetArgumentObject(int message, int argument,
|
|
vtkObjectBase** value,
|
|
const char* type) const
|
|
{
|
|
// Get the argument object and check its type.
|
|
vtkObjectBase* obj;
|
|
if(this->GetArgument(message, argument, &obj))
|
|
{
|
|
// if the pointer is valid then check the type
|
|
if(obj && !obj->IsA(type))
|
|
{
|
|
return 0;
|
|
}
|
|
*value = obj;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetData(const unsigned char** data,
|
|
size_t* length) const
|
|
{
|
|
// Do not return data unless stream is valid.
|
|
if(!this->Internal->Invalid)
|
|
{
|
|
if(data)
|
|
{
|
|
*data = &*this->Internal->Data.begin();
|
|
}
|
|
|
|
if(length)
|
|
{
|
|
*length = this->Internal->Data.size();
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if(data)
|
|
{
|
|
*data = 0;
|
|
}
|
|
|
|
if(length)
|
|
{
|
|
*length = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::SetData(const unsigned char* data, size_t length)
|
|
{
|
|
// Reset and remove the byte order entry from the stream.
|
|
this->Reset();
|
|
this->Internal->Data.erase(this->Internal->Data.begin(),
|
|
this->Internal->Data.end());
|
|
|
|
// Store the given data in the stream.
|
|
if(data)
|
|
{
|
|
this->Internal->Data.insert(this->Internal->Data.begin(), data, data+length);
|
|
}
|
|
|
|
// Parse the stream to fill in ValueOffsets and MessageIndexes and
|
|
// to perform byte-swapping if necessary.
|
|
if(this->ParseData())
|
|
{
|
|
// Data have been byte-swapped to the native representation.
|
|
#ifdef VTK_WORDS_BIGENDIAN
|
|
this->Internal->Data[0] = vtkClientServerStream::BigEndian;
|
|
#else
|
|
this->Internal->Data[0] = vtkClientServerStream::LittleEndian;
|
|
#endif
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
// Data are invalid. Reset the stream and report failure.
|
|
this->Reset();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::ParseData()
|
|
{
|
|
// Make sure we have at least one byte.
|
|
if(this->Internal->Data.empty())
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
// We are not modifying the vector size. It is safe to use pointers
|
|
// into it.
|
|
unsigned char* begin = &*this->Internal->Data.begin();
|
|
unsigned char* end = begin + this->Internal->Data.size();
|
|
|
|
// Save the byte order.
|
|
int order = *begin;
|
|
|
|
// Traverse the data until no more commands are found.
|
|
unsigned char* data = begin+1;
|
|
while(data && data < end)
|
|
{
|
|
// Parse the command.
|
|
data = this->ParseCommand(order, data, begin, end);
|
|
|
|
// Parse the arguments until End is reached.
|
|
int foundEnd = 0;
|
|
while(!foundEnd && data && data < end)
|
|
{
|
|
// Parse the type identifier.
|
|
vtkClientServerStream::Types type;
|
|
data = this->ParseType(order, data, begin, end, &type);
|
|
if(!data)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Process the rest of the value based on its type.
|
|
switch(type)
|
|
{
|
|
case vtkClientServerStream::int8_value:
|
|
case vtkClientServerStream::uint8_value:
|
|
case vtkClientServerStream::bool_value:
|
|
data = this->ParseValue(order, data, end, 1); break;
|
|
case vtkClientServerStream::int8_array:
|
|
case vtkClientServerStream::uint8_array:
|
|
data = this->ParseArray(order, data, end, 1); break;
|
|
case vtkClientServerStream::int16_value:
|
|
case vtkClientServerStream::uint16_value:
|
|
data = this->ParseValue(order, data, end, 2); break;
|
|
case vtkClientServerStream::int16_array:
|
|
case vtkClientServerStream::uint16_array:
|
|
data = this->ParseArray(order, data, end, 2); break;
|
|
case vtkClientServerStream::id_value:
|
|
case vtkClientServerStream::int32_value:
|
|
case vtkClientServerStream::uint32_value:
|
|
case vtkClientServerStream::float32_value:
|
|
data = this->ParseValue(order, data, end, 4); break;
|
|
case vtkClientServerStream::int32_array:
|
|
case vtkClientServerStream::uint32_array:
|
|
case vtkClientServerStream::float32_array:
|
|
data = this->ParseArray(order, data, end, 4); break;
|
|
case vtkClientServerStream::int64_value:
|
|
case vtkClientServerStream::uint64_value:
|
|
case vtkClientServerStream::float64_value:
|
|
data = this->ParseValue(order, data, end, 8); break;
|
|
case vtkClientServerStream::int64_array:
|
|
case vtkClientServerStream::uint64_array:
|
|
case vtkClientServerStream::float64_array:
|
|
data = this->ParseArray(order, data, end, 8); break;
|
|
case vtkClientServerStream::string_value:
|
|
data = this->ParseString(order, data, end); break;
|
|
case vtkClientServerStream::stream_value:
|
|
data = this->ParseStream(order, data, end); break;
|
|
case vtkClientServerStream::LastResult:
|
|
// There are no data for this type. Do nothing.
|
|
break;
|
|
case vtkClientServerStream::End:
|
|
this->ParseEnd(); foundEnd = 1; break;
|
|
|
|
// An object pointer cannot be safely transferred in a buffer.
|
|
case vtkClientServerStream::vtk_object_pointer:
|
|
default: /* ERROR */
|
|
data = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return whether parsing finished.
|
|
return (data == end)? 1:0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned char* vtkClientServerStream::ParseCommand(int order,
|
|
unsigned char* data,
|
|
unsigned char* begin,
|
|
unsigned char* end)
|
|
{
|
|
// Byte-swap this command's identifier.
|
|
if(data > end-sizeof(vtkTypeUInt32))
|
|
{
|
|
/* ERROR */
|
|
return 0;
|
|
}
|
|
this->PerformByteSwap(order, data, 1, sizeof(vtkTypeUInt32));
|
|
|
|
// Mark the start of the command.
|
|
this->Internal->StartIndex =
|
|
this->Internal->ValueOffsets.end()-this->Internal->ValueOffsets.begin();
|
|
this->Internal->ValueOffsets.push_back(data - begin);
|
|
|
|
// Return the position after the command identifier.
|
|
return data + sizeof(vtkTypeUInt32);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::ParseEnd()
|
|
{
|
|
// Record completed message.
|
|
this->Internal->MessageIndexes.push_back(this->Internal->StartIndex);
|
|
this->Internal->StartIndex =
|
|
vtkClientServerStreamInternals::InvalidStartIndex;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned char*
|
|
vtkClientServerStream::ParseType(int order, unsigned char* data,
|
|
unsigned char* begin, unsigned char* end,
|
|
vtkClientServerStream::Types* type)
|
|
{
|
|
// Read this type identifier.
|
|
vtkTypeUInt32 tp;
|
|
if(data > end-sizeof(tp))
|
|
{
|
|
/* ERROR */
|
|
return 0;
|
|
}
|
|
this->PerformByteSwap(order, data, 1, sizeof(tp));
|
|
memcpy(&tp, data, sizeof(tp));
|
|
*type = static_cast<vtkClientServerStream::Types>(tp);
|
|
|
|
// Record the start of this type and optional value.
|
|
this->Internal->ValueOffsets.push_back(data - begin);
|
|
|
|
// Return the position after the type identifier.
|
|
return data + sizeof(vtkTypeUInt32);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned char* vtkClientServerStream::ParseValue(int order,
|
|
unsigned char* data,
|
|
unsigned char* end,
|
|
unsigned int wordSize)
|
|
{
|
|
// Byte-swap the value.
|
|
if(data > end-wordSize)
|
|
{
|
|
/* ERROR */
|
|
return 0;
|
|
}
|
|
this->PerformByteSwap(order, data, 1, wordSize);
|
|
|
|
// Return the position after the value.
|
|
return data+wordSize;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned char* vtkClientServerStream::ParseArray(int order,
|
|
unsigned char* data,
|
|
unsigned char* end,
|
|
unsigned int wordSize)
|
|
{
|
|
// Read the array length.
|
|
vtkTypeUInt32 length;
|
|
if(data > end-sizeof(length))
|
|
{
|
|
/* ERROR */
|
|
return 0;
|
|
}
|
|
this->PerformByteSwap(order, data, 1, sizeof(length));
|
|
memcpy(&length, data, sizeof(length));
|
|
data += sizeof(length);
|
|
|
|
// Calculate the size of the array data.
|
|
vtkTypeUInt32 size = length*wordSize;
|
|
|
|
// Byte-swap the array data.
|
|
if(data > end-size)
|
|
{
|
|
/* ERROR */
|
|
return 0;
|
|
}
|
|
this->PerformByteSwap(order, data, length, wordSize);
|
|
|
|
// Return the position after the array.
|
|
return data+size;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned char* vtkClientServerStream::ParseString(int order,
|
|
unsigned char* data,
|
|
unsigned char* end)
|
|
{
|
|
// Read the string length.
|
|
vtkTypeUInt32 length;
|
|
if(data > end-sizeof(length))
|
|
{
|
|
/* ERROR */
|
|
return 0;
|
|
}
|
|
this->PerformByteSwap(order, data, 1, sizeof(length));
|
|
memcpy(&length, data, sizeof(length));
|
|
data += sizeof(length);
|
|
|
|
// Skip the string data. It does not need swapping.
|
|
if(data > end-length)
|
|
{
|
|
/* ERROR */
|
|
return 0;
|
|
}
|
|
|
|
// Return the position after the string.
|
|
return data+length;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
unsigned char* vtkClientServerStream::ParseStream(int order,
|
|
unsigned char* data,
|
|
unsigned char* end)
|
|
{
|
|
// Stream data are represented as an array of bytes.
|
|
return this->ParseArray(order, data, end, 1);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::PerformByteSwap(int dataByteOrder,
|
|
unsigned char* data,
|
|
unsigned int numWords,
|
|
unsigned int wordSize)
|
|
{
|
|
char* ptr = reinterpret_cast<char*>(data);
|
|
if(dataByteOrder == vtkClientServerStream::BigEndian)
|
|
{
|
|
switch (wordSize)
|
|
{
|
|
case 1: break;
|
|
case 2: vtkByteSwap::Swap2BERange(ptr, numWords); break;
|
|
case 4: vtkByteSwap::Swap4BERange(ptr, numWords); break;
|
|
case 8: vtkByteSwap::Swap8BERange(ptr, numWords); break;
|
|
default: break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (wordSize)
|
|
{
|
|
case 1: break;
|
|
case 2: vtkByteSwap::Swap2LERange(ptr, numWords); break;
|
|
case 4: vtkByteSwap::Swap4LERange(ptr, numWords); break;
|
|
case 8: vtkByteSwap::Swap8LERange(ptr, numWords); break;
|
|
default: break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetNumberOfMessages() const
|
|
{
|
|
return static_cast<int>(this->Internal->MessageIndexes.size());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetNumberOfValues(int message) const
|
|
{
|
|
if(!this->Internal->Invalid &&
|
|
message >= 0 && message < this->GetNumberOfMessages())
|
|
{
|
|
if(message+1 < this->GetNumberOfMessages())
|
|
{
|
|
// Requested message is not the last message. Use the beginning
|
|
// of the next message to find its length.
|
|
return static_cast<int>
|
|
(this->Internal->MessageIndexes[message+1] -
|
|
this->Internal->MessageIndexes[message]);
|
|
}
|
|
else if(this->Internal->StartIndex !=
|
|
vtkClientServerStreamInternals::InvalidStartIndex)
|
|
{
|
|
// Requested message is the last completed message, but there is
|
|
// a partial message in progress. Use the beginning of the next
|
|
// partial message to find this message's length.
|
|
return static_cast<int>
|
|
(this->Internal->StartIndex -
|
|
this->Internal->MessageIndexes[message]);
|
|
}
|
|
else
|
|
{
|
|
// Requested message is the last message. Use the length of the
|
|
// value indices array to find the message's length.
|
|
return static_cast<int>(this->Internal->ValueOffsets.size() -
|
|
this->Internal->MessageIndexes[message]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const unsigned char*
|
|
vtkClientServerStream::GetValue(int message, int value) const
|
|
{
|
|
if(value >= 0 && value < this->GetNumberOfValues(message))
|
|
{
|
|
// Get the index to the beginning of the requested message.
|
|
vtkClientServerStreamInternals::ValueOffsetsType::size_type index =
|
|
this->Internal->MessageIndexes[message];
|
|
|
|
// Return a pointer to the value-th value in the message.
|
|
const unsigned char* data = &*this->Internal->Data.begin();
|
|
return data + this->Internal->ValueOffsets[index + value];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Templates to find argument size within a stream.
|
|
template <class T> size_t vtkClientServerStreamValueSize(T*){return sizeof(T);}
|
|
template <class T>
|
|
size_t vtkClientServerStreamArraySize(const unsigned char* data, T*)
|
|
{
|
|
// Get the length of the value in the stream.
|
|
vtkTypeUInt32 len;
|
|
memcpy(&len, data, sizeof(len));
|
|
return sizeof(len) + len*sizeof(T);
|
|
}
|
|
|
|
vtkClientServerStream::Argument
|
|
vtkClientServerStream::GetArgument(int message, int argument) const
|
|
{
|
|
// Prepare a return value.
|
|
vtkClientServerStream::Argument result = {0, 0};
|
|
|
|
// Get a pointer to the type/value pair in the stream.
|
|
if(const unsigned char* data = this->GetValue(message, 1+argument))
|
|
{
|
|
// Store the starting location of the value.
|
|
result.Data = data;
|
|
|
|
// Get the type of the value in the stream.
|
|
vtkTypeUInt32 tp;
|
|
memcpy(&tp, data, sizeof(tp));
|
|
data += sizeof(tp);
|
|
|
|
// Find the length of the argument's data based on its type.
|
|
switch(tp)
|
|
{
|
|
VTK_CSS_TEMPLATE_MACRO(value, result.Size = sizeof(tp) +
|
|
vtkClientServerStreamValueSize(T));
|
|
VTK_CSS_TEMPLATE_MACRO(array, result.Size = sizeof(tp) +
|
|
vtkClientServerStreamArraySize(data, T));
|
|
case vtkClientServerStream::id_value:
|
|
{
|
|
result.Size = sizeof(tp) + sizeof(vtkClientServerID().ID);
|
|
} break;
|
|
case vtkClientServerStream::string_value:
|
|
{
|
|
// A string is represented as an array of 1 byte values.
|
|
vtkTypeUInt8* T = 0;
|
|
result.Size = sizeof(tp) + vtkClientServerStreamArraySize(data, T);
|
|
} break;
|
|
case vtkClientServerStream::vtk_object_pointer:
|
|
{
|
|
result.Size = sizeof(tp) + sizeof(vtkObjectBase*);
|
|
} break;
|
|
case vtkClientServerStream::stream_value:
|
|
{
|
|
// A stream is represented as an array of 1 byte values.
|
|
vtkTypeUInt8* T = 0;
|
|
result.Size = sizeof(tp) + vtkClientServerStreamArraySize(data, T);
|
|
} break;
|
|
case vtkClientServerStream::LastResult:
|
|
{
|
|
result.Size = sizeof(tp);
|
|
} break;
|
|
case vtkClientServerStream::End:
|
|
default:
|
|
result.Data = 0;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::Commands
|
|
vtkClientServerStream::GetCommand(int message) const
|
|
{
|
|
// The first value in a message is always the command.
|
|
if(const unsigned char* data = this->GetValue(message, 0))
|
|
{
|
|
// Retrieve the command value and convert it to the proper type.
|
|
vtkTypeUInt32 cmd;
|
|
memcpy(&cmd, data, sizeof(cmd));
|
|
if(cmd < vtkClientServerStream::EndOfCommands)
|
|
{
|
|
return static_cast<vtkClientServerStream::Commands>(cmd);
|
|
}
|
|
}
|
|
return vtkClientServerStream::EndOfCommands;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::GetNumberOfArguments(int message) const
|
|
{
|
|
// Arguments do not include the Command or End markers.
|
|
if(int numValues = this->GetNumberOfValues(message))
|
|
{
|
|
return numValues - 2;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::Types
|
|
vtkClientServerStream::GetArgumentType(int message, int argument) const
|
|
{
|
|
// Get a pointer to the type/value pair in the stream.
|
|
if(const unsigned char* data = this->GetValue(message, 1+argument))
|
|
{
|
|
// Get the type of the value in the stream and convert it.
|
|
vtkTypeUInt32 type;
|
|
memcpy(&type, data, sizeof(type));
|
|
if(type < vtkClientServerStream::End)
|
|
{
|
|
return static_cast<vtkClientServerStream::Types>(type);
|
|
}
|
|
}
|
|
return vtkClientServerStream::End;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Map from the vtkClientServerStream::Types enumeration to strings.
|
|
// This must be kept in-sync with the enumeration.
|
|
static const char* const vtkClientServerStreamTypeNames[][4] =
|
|
{
|
|
{"int8_value","int8","i8",0}, {"int8_array","int8a","i8a",0},
|
|
{"int16_value","int16","i16",0}, {"int16_array","int16a","i16a",0},
|
|
{"int32_value","int32","i32",0}, {"int32_array","int32a","i32a",0},
|
|
{"int64_value","int64","i64",0}, {"int64_array","int64a","i64a",0},
|
|
{"uint8_value","uint8","u8",0}, {"uint8_array","uint8a","u8a",0},
|
|
{"uint16_value","uint16","u16",0}, {"uint16_array","uint16a","u16a",0},
|
|
{"uint32_value","uint32","u32",0}, {"uint32_array","uint32a","u32a",0},
|
|
{"uint64_value","uint64","u64",0}, {"uint64_array","uint64a","u64a",0},
|
|
{"float32_value","float32","f32",0}, {"float32_array","float32a","f32a",0},
|
|
{"float64_value","float64","f64",0}, {"float64_array","float64a","f64a",0},
|
|
{"bool_value", "bool", "bool", 0},
|
|
{"string_value","string","str",0},
|
|
{"id_value","id",0,0},
|
|
{"vtk_object_pointer","obj",0,0},
|
|
{"stream_value","stream",0,0},
|
|
{"LastResult","result",0,0},
|
|
{"End",0,0,0},
|
|
{0,0,0,0}
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char*
|
|
vtkClientServerStream
|
|
::GetStringFromType(vtkClientServerStream::Types type)
|
|
{
|
|
return vtkClientServerStream::GetStringFromType(type, 0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char*
|
|
vtkClientServerStream
|
|
::GetStringFromType(vtkClientServerStream::Types type, int index)
|
|
{
|
|
// Lookup the type if it is in range.
|
|
if(type >= vtkClientServerStream::int8_value &&
|
|
type <= vtkClientServerStream::End)
|
|
{
|
|
if(index <= 0)
|
|
{
|
|
return vtkClientServerStreamTypeNames[type][0];
|
|
}
|
|
const char* const* names = vtkClientServerStreamTypeNames[type];
|
|
int i=1;
|
|
while(i < index && names[i])
|
|
{
|
|
++i;
|
|
}
|
|
if(names[i])
|
|
{
|
|
return names[i];
|
|
}
|
|
else
|
|
{
|
|
return names[i-1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::Types
|
|
vtkClientServerStream::GetTypeFromString(const char* name)
|
|
{
|
|
return vtkClientServerStream::GetTypeFromString(name, 0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::Types
|
|
vtkClientServerStream::GetTypeFromString(const char* begin, const char* end)
|
|
{
|
|
// Setup the ending position.
|
|
if(begin && (!end || end < begin))
|
|
{
|
|
end = begin+strlen(begin);
|
|
}
|
|
|
|
// Find a string matching the given name.
|
|
for(int t = vtkClientServerStream::int8_value;
|
|
begin && t < vtkClientServerStream::End; ++t)
|
|
{
|
|
for(const char* const* n = vtkClientServerStreamTypeNames[t]; *n; ++n)
|
|
{
|
|
if(strncmp(*n, begin, end-begin) == 0)
|
|
{
|
|
return static_cast<vtkClientServerStream::Types>(t);
|
|
}
|
|
}
|
|
}
|
|
return vtkClientServerStream::End;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Map from the vtkClientServerStream::Commands enumeration to strings.
|
|
// This must be kept in-sync with the enumeration.
|
|
static const char* const vtkClientServerStreamCommandNames[] =
|
|
{
|
|
"New", "Invoke", "Delete", "Assign",
|
|
"Reply", "Error", "EndOfCommands",
|
|
0
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char*
|
|
vtkClientServerStream
|
|
::GetStringFromCommand(vtkClientServerStream::Commands cmd)
|
|
{
|
|
// Lookup the command if it is in range.
|
|
if(cmd >= vtkClientServerStream::New &&
|
|
cmd <= vtkClientServerStream::EndOfCommands)
|
|
{
|
|
return vtkClientServerStreamCommandNames[cmd];
|
|
}
|
|
else
|
|
{
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::Commands
|
|
vtkClientServerStream::GetCommandFromString(const char* name)
|
|
{
|
|
return vtkClientServerStream::GetCommandFromString(name, 0);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkClientServerStream::Commands
|
|
vtkClientServerStream::GetCommandFromString(const char* begin,
|
|
const char* end)
|
|
{
|
|
// Setup the ending position.
|
|
if(begin && (!end || end < begin))
|
|
{
|
|
end = begin+strlen(begin);
|
|
}
|
|
|
|
// Find a string matching the given name.
|
|
for(int c = vtkClientServerStream::New;
|
|
begin && c < vtkClientServerStream::EndOfCommands; ++c)
|
|
{
|
|
if(strncmp(vtkClientServerStreamCommandNames[c], begin, end-begin) == 0)
|
|
{
|
|
return static_cast<vtkClientServerStream::Commands>(c);
|
|
}
|
|
}
|
|
return vtkClientServerStream::EndOfCommands;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::Print(ostream& os) const
|
|
{
|
|
vtkIndent indent;
|
|
this->Print(os, indent);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::Print(ostream& os, vtkIndent indent) const
|
|
{
|
|
for(int m=0; m < this->GetNumberOfMessages(); ++m)
|
|
{
|
|
this->PrintMessage(os, m, indent);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::PrintMessage(ostream& os, int message) const
|
|
{
|
|
vtkIndent indent;
|
|
this->PrintMessage(os, message, indent);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::PrintMessage(ostream& os, int message,
|
|
vtkIndent indent) const
|
|
{
|
|
os << indent << "Message " << message << " = ";
|
|
os << this->GetStringFromCommand(this->GetCommand(message)) << "\n";
|
|
for(int a=0; a < this->GetNumberOfArguments(message); ++a)
|
|
{
|
|
this->PrintArgument(os, message, a, indent.GetNextIndent());
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::PrintArgument(ostream& os, int message,
|
|
int argument) const
|
|
{
|
|
vtkIndent indent;
|
|
this->PrintArgument(os, message, argument, indent);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::PrintArgument(ostream& os, int message,
|
|
int argument, vtkIndent indent) const
|
|
{
|
|
this->PrintArgumentInternal(os, message, argument, 1, indent);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::PrintArgumentValue(ostream& os, int message,
|
|
int argument) const
|
|
{
|
|
vtkIndent indent;
|
|
this->PrintArgumentInternal(os, message, argument, 0, indent);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function to convert a value to a string.
|
|
template <class T>
|
|
void vtkClientServerStreamValueToString(const vtkClientServerStream* self,
|
|
ostream& os, int m, int a, T*)
|
|
{
|
|
typedef VTK_CSS_TYPENAME vtkTypeTraits<T>::PrintType PrintType;
|
|
T arg;
|
|
self->GetArgument(m, a, &arg);
|
|
os << static_cast<PrintType>(arg);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function to convert an array to a string.
|
|
template <class T>
|
|
void vtkClientServerStreamArrayToString(const vtkClientServerStream* self,
|
|
ostream& os, int m, int a, T*)
|
|
{
|
|
typedef VTK_CSS_TYPENAME vtkTypeTraits<T>::PrintType PrintType;
|
|
vtkTypeUInt32 length;
|
|
T arglocal[6];
|
|
T* arg = arglocal;
|
|
self->GetArgumentLength(m, a, &length);
|
|
if(length > 6)
|
|
{
|
|
arg = new T[length];
|
|
}
|
|
self->GetArgument(m, a, arg, length);
|
|
const char* comma = "";
|
|
for(vtkTypeUInt32 i=0; i < length; ++i)
|
|
{
|
|
os << comma << static_cast<PrintType>(arg[i]);
|
|
comma = ", ";
|
|
}
|
|
if(arg != arglocal)
|
|
{
|
|
delete [] arg;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function to print a value argument.
|
|
template <class T>
|
|
void vtkClientServerStreamPrintValue(const vtkClientServerStream* self,
|
|
ostream& os, vtkIndent indent,
|
|
int m, int a, int t, T* tt)
|
|
{
|
|
if(t)
|
|
{
|
|
vtkClientServerStream::Types type = self->GetArgumentType(m, a);
|
|
os << indent << "Argument " << a << " = " << self->GetStringFromType(type)
|
|
<< " {";
|
|
}
|
|
vtkClientServerStreamValueToString(self, os, m, a, tt);
|
|
if(t)
|
|
{
|
|
os << "}\n";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Function to print an array argument.
|
|
template <class T>
|
|
void vtkClientServerStreamPrintArray(const vtkClientServerStream* self,
|
|
ostream& os, vtkIndent indent,
|
|
int m, int a, int t, T* tt)
|
|
{
|
|
if(t)
|
|
{
|
|
vtkClientServerStream::Types type = self->GetArgumentType(m, a);
|
|
os << indent << "Argument " << a << " = "
|
|
<< self->GetStringFromType(type) << " {";
|
|
}
|
|
vtkClientServerStreamArrayToString(self, os, m, a, tt);
|
|
if(t)
|
|
{
|
|
os << "}\n";
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::PrintArgumentInternal(ostream& os, int message,
|
|
int argument, int annotate,
|
|
vtkIndent indent) const
|
|
{
|
|
switch(this->GetArgumentType(message, argument))
|
|
{
|
|
VTK_CSS_TEMPLATE_MACRO(value, vtkClientServerStreamPrintValue
|
|
(this, os, indent, message, argument, annotate, T));
|
|
VTK_CSS_TEMPLATE_MACRO(array, vtkClientServerStreamPrintArray
|
|
(this, os, indent, message, argument, annotate, T));
|
|
case vtkClientServerStream::bool_value:
|
|
{
|
|
bool arg;
|
|
int result = this->GetArgument(message, argument, &arg);
|
|
if(annotate)
|
|
{
|
|
os << indent << "Argument " << argument << " = bool_value ";
|
|
os << "{" << (arg? "true" : "false") << "}\n";
|
|
}
|
|
else if(result)
|
|
{
|
|
os << (arg? "true" : "false");
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::string_value:
|
|
{
|
|
const char* arg = NULL;
|
|
this->GetArgument(message, argument, &arg);
|
|
if(annotate)
|
|
{
|
|
os << indent << "Argument " << argument << " = string_value ";
|
|
if(arg)
|
|
{
|
|
os << "{" << arg << "}\n";
|
|
}
|
|
else
|
|
{
|
|
os << "(null)\n";
|
|
}
|
|
}
|
|
else if(arg)
|
|
{
|
|
os << arg;
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::stream_value:
|
|
{
|
|
vtkClientServerStream arg;
|
|
int result = this->GetArgument(message, argument, &arg);
|
|
if(annotate)
|
|
{
|
|
os << indent << "Argument " << argument << " = stream_value ";
|
|
if(result)
|
|
{
|
|
vtkIndent nextIndent = indent.GetNextIndent();
|
|
os << "{\n";
|
|
arg.Print(os, nextIndent);
|
|
os << nextIndent << "}\n";
|
|
}
|
|
else
|
|
{
|
|
os << "invalid\n";
|
|
}
|
|
}
|
|
else if(result)
|
|
{
|
|
arg.Print(os);
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::id_value:
|
|
{
|
|
vtkClientServerID arg;
|
|
this->GetArgument(message, argument, &arg);
|
|
if(annotate)
|
|
{
|
|
os << indent << "Argument " << argument
|
|
<< " = id_value {" << arg.ID << "}\n";
|
|
}
|
|
else
|
|
{
|
|
os << arg.ID;
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::vtk_object_pointer:
|
|
{
|
|
vtkObjectBase* arg;
|
|
this->GetArgument(message, argument, &arg);
|
|
if(annotate)
|
|
{
|
|
os << indent << "Argument " << argument << " = vtk_object_pointer ";
|
|
if(arg)
|
|
{
|
|
os << "{" << arg->GetClassName() << " (" << arg << ")}\n";
|
|
}
|
|
else
|
|
{
|
|
os << "(null)\n";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
os << arg;
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::LastResult:
|
|
{
|
|
if(annotate)
|
|
{
|
|
os << indent << "Argument " << argument << " = LastResult\n";
|
|
}
|
|
} break;
|
|
default:
|
|
{
|
|
if(annotate)
|
|
{
|
|
os << indent << "Argument " << argument << " = invalid\n";
|
|
}
|
|
} break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
const char* vtkClientServerStream::StreamToString() const
|
|
{
|
|
std::ostringstream ostr;
|
|
this->StreamToString(ostr);
|
|
this->Internal->String = ostr.str();
|
|
return this->Internal->String.c_str();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::StreamToString(ostream& os) const
|
|
{
|
|
vtkIndent indent;
|
|
this->StreamToString(os, indent);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::StreamToString(ostream& os,
|
|
vtkIndent indent) const
|
|
{
|
|
for(int m=0; m < this->GetNumberOfMessages(); ++m)
|
|
{
|
|
os << indent;
|
|
this->MessageToString(os, m, indent);
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::MessageToString(ostream& os, int m) const
|
|
{
|
|
vtkIndent indent;
|
|
this->MessageToString(os, m, indent);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::MessageToString(ostream& os, int m,
|
|
vtkIndent indent) const
|
|
{
|
|
os << this->GetStringFromCommand(this->GetCommand(m));
|
|
for(int a=0; a < this->GetNumberOfArguments(m); ++a)
|
|
{
|
|
os << " ";
|
|
this->ArgumentToString(os, m, a, indent);
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::ArgumentToString(ostream& os, int m, int a) const
|
|
{
|
|
vtkIndent indent;
|
|
this->ArgumentToString(os, m, a, indent);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::ArgumentToString(ostream& os, int m, int a,
|
|
vtkIndent indent) const
|
|
{
|
|
vtkClientServerStream::Types type = this->GetArgumentType(m, a);
|
|
|
|
// Special case for strings: string0 == null, string() == ""
|
|
if(type == vtkClientServerStream::string_value)
|
|
{
|
|
const char* arg = NULL;
|
|
this->GetArgument(m, a, &arg);
|
|
if(!arg)
|
|
{
|
|
os << "string0";
|
|
return;
|
|
}
|
|
int needType = (*arg == 0)?1:0;
|
|
for(const char* c = arg; *c; ++c)
|
|
{
|
|
if(*c == '(' || *c == ')')
|
|
{
|
|
needType = 1;
|
|
break;
|
|
}
|
|
}
|
|
if(!needType)
|
|
{
|
|
this->ArgumentValueToString(os, m, a, indent);
|
|
return;
|
|
}
|
|
}
|
|
|
|
os << this->GetStringFromType(type, 1) << "(";
|
|
this->ArgumentValueToString(os, m, a, indent);
|
|
os << ")";
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkClientServerStream::ArgumentValueToString(ostream& os,
|
|
int m, int a,
|
|
vtkIndent indent) const
|
|
{
|
|
switch(this->GetArgumentType(m, a))
|
|
{
|
|
VTK_CSS_TEMPLATE_MACRO(value, vtkClientServerStreamValueToString
|
|
(this, os, m, a, T));
|
|
VTK_CSS_TEMPLATE_MACRO(array, vtkClientServerStreamArrayToString
|
|
(this, os, m, a, T));
|
|
case vtkClientServerStream::bool_value:
|
|
{
|
|
bool arg;
|
|
this->GetArgument(m, a, &arg);
|
|
os << (arg? "true" : "false");
|
|
} break;
|
|
case vtkClientServerStream::string_value:
|
|
{
|
|
const char* arg = NULL;
|
|
this->GetArgument(m, a, &arg);
|
|
if(arg)
|
|
{
|
|
for(const char* c = arg; *c; ++c)
|
|
{
|
|
switch(*c)
|
|
{
|
|
case '\\': os << "\\\\"; break;
|
|
case '(': os << "\\("; break;
|
|
case ')': os << "\\)"; break;
|
|
default: os << *c; break;
|
|
}
|
|
}
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::stream_value:
|
|
{
|
|
vtkClientServerStream arg;
|
|
int result = this->GetArgument(m, a, &arg);
|
|
if(result)
|
|
{
|
|
os << "\n";
|
|
arg.StreamToString(os, indent.GetNextIndent());
|
|
os << indent;
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::id_value:
|
|
{
|
|
vtkClientServerID arg;
|
|
this->GetArgument(m, a, &arg);
|
|
os << arg.ID;
|
|
} break;
|
|
case vtkClientServerStream::vtk_object_pointer:
|
|
{
|
|
vtkObjectBase* arg;
|
|
this->GetArgument(m, a, &arg);
|
|
if(arg)
|
|
{
|
|
os << arg;
|
|
}
|
|
else
|
|
{
|
|
os << "0";
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::LastResult: break;
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::StreamFromString(const char* str)
|
|
{
|
|
this->Reset();
|
|
if(this->StreamFromStringInternal(str, str+strlen(str)))
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
this->Reset();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::StreamFromStringInternal(const char* begin,
|
|
const char* end)
|
|
{
|
|
const char* position = begin;
|
|
while(1)
|
|
{
|
|
// Skip whitespace and newlines.
|
|
while(position < end && (*position == ' ' || *position == '\t' ||
|
|
*position == '\r' || *position == '\n'))
|
|
{
|
|
++position;
|
|
}
|
|
if(position == end)
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Add this message.
|
|
if(!this->AddMessageFromString(position, end, &position))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::AddMessageFromString(const char* begin,
|
|
const char* end,
|
|
const char** next)
|
|
{
|
|
// Find the end of the command name.
|
|
const char* commandBegin = begin;
|
|
const char* commandEnd = commandBegin;
|
|
while(commandEnd < end && !(*commandEnd == ' ' || *commandEnd == '\t' ||
|
|
*commandEnd == '\r' || *commandEnd == '\n'))
|
|
{
|
|
++commandEnd;
|
|
}
|
|
vtkClientServerStream::Commands cmd =
|
|
this->GetCommandFromString(commandBegin, commandEnd);
|
|
if(cmd == vtkClientServerStream::EndOfCommands)
|
|
{
|
|
// The command is missing, try to guess it based on the first
|
|
// argument.
|
|
if((commandEnd-commandBegin > 3 && strncmp(commandBegin, "id(", 3) == 0) ||
|
|
(commandEnd-commandBegin == 8 &&
|
|
strncmp(commandBegin, "result()", 8) == 0) ||
|
|
(commandEnd-commandBegin == 12 &&
|
|
strncmp(commandBegin, "LastResult()", 12) == 0))
|
|
{
|
|
// First argument is an id. Assume this is an Invoke command.
|
|
cmd = vtkClientServerStream::Invoke;
|
|
}
|
|
else if(commandEnd-commandBegin > 3 &&
|
|
strncmp(commandBegin, "vtk", 3) == 0)
|
|
{
|
|
// First argument looks like the name of a VTK class. Assume
|
|
// this is a New command.
|
|
cmd = vtkClientServerStream::New;
|
|
}
|
|
else
|
|
{
|
|
// We did not find a message.
|
|
return 0;
|
|
}
|
|
|
|
// We guessed the command, so the first argument starts at
|
|
// commandBegin.
|
|
commandEnd = commandBegin;
|
|
}
|
|
|
|
// Insert the command into the stream.
|
|
*this << cmd;
|
|
|
|
// Scan for arguments until the end of a line occurs outside an
|
|
// argument.
|
|
const char* position = commandEnd;
|
|
while(1)
|
|
{
|
|
// Skip whitespace.
|
|
while(position < end && (*position == ' ' || *position == '\t'))
|
|
{
|
|
++position;
|
|
}
|
|
|
|
// Check for end-of-line.
|
|
if(position == end || *position == '\r' || *position == '\n')
|
|
{
|
|
break;
|
|
}
|
|
|
|
// Add the next argument.
|
|
if(!this->AddArgumentFromString(position, end, &position))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Insert the message ending token into the stream.
|
|
*this << vtkClientServerStream::End;
|
|
|
|
// Report where to continue scanning.
|
|
*next = position;
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStreamPointerFromString(const char* begin, const char* end,
|
|
vtkObjectBase** value)
|
|
{
|
|
// Copy the value to a null-terminated buffer.
|
|
char buffer[60];
|
|
char* ptr = buffer;
|
|
if(end-begin+1 > 60)
|
|
{
|
|
ptr = new char[end-begin+1];
|
|
}
|
|
strncpy(ptr, begin, end-begin);
|
|
ptr[end-begin] = 0;
|
|
|
|
// Try to convert the value.
|
|
int result = sscanf(ptr, "%p", value)? 1:0;
|
|
|
|
// Free the buffer.
|
|
if(ptr != buffer)
|
|
{
|
|
delete [] ptr;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template <class T>
|
|
int vtkClientServerStreamValueFromString(const char* begin, const char* end,
|
|
T* value)
|
|
{
|
|
// Copy the value to a null-terminated buffer.
|
|
char buffer[60];
|
|
char* ptr = buffer;
|
|
if(end-begin+1 > 60)
|
|
{
|
|
ptr = new char[end-begin+1];
|
|
}
|
|
strncpy(ptr, begin, end-begin);
|
|
ptr[end-begin] = 0;
|
|
|
|
// Try to convert the value.
|
|
VTK_CSS_TYPENAME vtkTypeTraits<T>::PrintType pvalue;
|
|
int result = sscanf(ptr, vtkTypeTraits<T>::ParseFormat(), &pvalue)?1:0;
|
|
if(result)
|
|
{
|
|
*value = static_cast<T>(pvalue);
|
|
}
|
|
|
|
// Free the buffer.
|
|
if(ptr != buffer)
|
|
{
|
|
delete [] ptr;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStreamBoolFromString(const char* begin, const char* end,
|
|
bool* value)
|
|
{
|
|
// Scan for the beginning of the value.
|
|
const char* valueBegin = begin;
|
|
while(valueBegin < end && (*valueBegin == ' ' || *valueBegin == '\t' ||
|
|
*valueBegin == '\r' || *valueBegin == '\n'))
|
|
{
|
|
++valueBegin;
|
|
}
|
|
|
|
// Scan for the end of the value.
|
|
const char* valueEnd = valueBegin;
|
|
while(valueEnd < end && (*valueEnd != ' ' && *valueEnd != '\t' &&
|
|
*valueEnd != '\r' && *valueEnd != '\n'))
|
|
{
|
|
++valueEnd;
|
|
}
|
|
|
|
// Make sure this was the only value.
|
|
while(valueEnd < end)
|
|
{
|
|
if(*valueEnd != ' ' && *valueEnd != '\t' &&
|
|
*valueEnd != '\r' && *valueEnd != '\n')
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// Check the value.
|
|
if(valueEnd-valueBegin == 4 && (valueBegin[0] == 't' &&
|
|
valueBegin[1] == 'r' &&
|
|
valueBegin[2] == 'u' &&
|
|
valueBegin[3] == 'e'))
|
|
{
|
|
*value = true;
|
|
return 1;
|
|
}
|
|
else if(valueEnd-valueBegin == 5 && (valueBegin[0] == 'f' &&
|
|
valueBegin[1] == 'a' &&
|
|
valueBegin[2] == 'l' &&
|
|
valueBegin[3] == 's' &&
|
|
valueBegin[4] == 'e'))
|
|
{
|
|
*value = false;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template <class T>
|
|
int vtkClientServerStreamValueFromString(vtkClientServerStream* self,
|
|
const char* begin, const char* end,
|
|
T*)
|
|
{
|
|
T value;
|
|
if(vtkClientServerStreamValueFromString(begin, end, &value))
|
|
{
|
|
*self << value;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template <class T>
|
|
int vtkClientServerStreamArrayFromString(vtkClientServerStream* self,
|
|
const char* begin, const char* end,
|
|
T*)
|
|
{
|
|
// Count how many values will be read.
|
|
int length = 0;
|
|
int text = 0;
|
|
int comma = 0;
|
|
for(const char* c = begin; c < end; ++c)
|
|
{
|
|
switch(*c)
|
|
{
|
|
case ' ': break;
|
|
case '\t': break;
|
|
case '\r': break;
|
|
case '\n': break;
|
|
case ',': comma = 1; break;
|
|
default: text = 1; break;
|
|
}
|
|
if(comma)
|
|
{
|
|
if(text)
|
|
{
|
|
++length;
|
|
}
|
|
text = 0;
|
|
comma = 0;
|
|
}
|
|
}
|
|
if(text)
|
|
{
|
|
++length;
|
|
}
|
|
|
|
// Allocate the array.
|
|
T arraylocal[6];
|
|
T* ptr = arraylocal;
|
|
if(length > 6)
|
|
{
|
|
ptr = new T[length];
|
|
}
|
|
|
|
// Parse each value.
|
|
int result = 1;
|
|
int index = 0;
|
|
const char* valueBegin = begin;
|
|
while(result && valueBegin < end && index < length)
|
|
{
|
|
// Scan for the beginning of the value.
|
|
while(valueBegin < end && (*valueBegin == ' ' || *valueBegin == '\t' ||
|
|
*valueBegin == '\r' || *valueBegin == '\n'))
|
|
{
|
|
++valueBegin;
|
|
}
|
|
|
|
// Scan for the end of the value.
|
|
const char* valueEnd = valueBegin;
|
|
while(valueEnd < end && *valueEnd != ',' && *valueEnd != ' ' &&
|
|
*valueEnd != '\t' && *valueEnd != '\r' && *valueEnd != '\n')
|
|
{
|
|
++valueEnd;
|
|
}
|
|
|
|
// Parse this value.
|
|
if(!vtkClientServerStreamValueFromString(valueBegin, valueEnd,
|
|
ptr+index))
|
|
{
|
|
result = 0;
|
|
}
|
|
++index;
|
|
|
|
// Scan past the comma.
|
|
valueBegin = valueEnd;
|
|
while(valueBegin < end && *valueBegin != ',')
|
|
{
|
|
++valueBegin;
|
|
}
|
|
if(valueBegin < end && *valueBegin == ',')
|
|
{
|
|
++valueBegin;
|
|
}
|
|
}
|
|
|
|
// Make sure we got all the values.
|
|
if(index < length)
|
|
{
|
|
result = 0;
|
|
}
|
|
|
|
// Insert the array.
|
|
if(result)
|
|
{
|
|
*self << vtkClientServerStream::InsertArray(ptr, length);
|
|
}
|
|
|
|
// Free the array.
|
|
if(ptr != arraylocal)
|
|
{
|
|
delete [] ptr;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkClientServerStream::AddArgumentFromString(const char* begin,
|
|
const char* end,
|
|
const char** next)
|
|
{
|
|
// Find the end of the argument type.
|
|
const char* typeBegin = begin;
|
|
const char* typeEnd = typeBegin;
|
|
int done = 0;
|
|
while(!done && typeEnd < end)
|
|
{
|
|
switch(*typeEnd)
|
|
{
|
|
case '(': done = 1; break;
|
|
case ' ': done = 1; break;
|
|
case '\t': done = 1; break;
|
|
case '\r': done = 1; break;
|
|
case '\n': done = 1; break;
|
|
default: ++typeEnd; break;
|
|
}
|
|
}
|
|
|
|
// If we did not find a paren, just assume it is a string argument.
|
|
if(*typeEnd != '(')
|
|
{
|
|
// Report where to continue scanning.
|
|
*next = typeEnd;
|
|
|
|
// Special case for strings: string0 == null
|
|
if((strncmp(typeBegin, "string0", typeEnd-typeBegin) == 0) ||
|
|
(strncmp(typeBegin, "str0", typeEnd-typeBegin) == 0))
|
|
{
|
|
// Insert the null string.
|
|
*this << static_cast<char*>(0);
|
|
return 1;
|
|
}
|
|
|
|
// Insert the string argument.
|
|
*this << vtkClientServerStream::InsertString(typeBegin, typeEnd);
|
|
return 1;
|
|
}
|
|
|
|
// Get the argument type.
|
|
vtkClientServerStream::Types type =
|
|
vtkClientServerStream::GetTypeFromString(typeBegin, typeEnd);
|
|
if(type == vtkClientServerStream::End)
|
|
{
|
|
// Unknown type!
|
|
return 0;
|
|
}
|
|
|
|
// Find the argument value boundaries.
|
|
const char* valueBegin = typeEnd+1;
|
|
const char* valueEnd = valueBegin;
|
|
int nesting = 1;
|
|
int hasComma = 0;
|
|
done = 0;
|
|
while(!done && valueEnd < end)
|
|
{
|
|
switch(*valueEnd)
|
|
{
|
|
case '\\': if(++valueEnd < end) { ++valueEnd; } break;
|
|
case '(': ++nesting; ++valueEnd; break;
|
|
case ')': if(--nesting == 0) { done = 1; } else { ++valueEnd; } break;
|
|
case ',': ++valueEnd; hasComma = 1; break;
|
|
default: ++valueEnd; break;
|
|
}
|
|
}
|
|
|
|
if(valueEnd == end)
|
|
{
|
|
// Unterminated argument value!
|
|
return 0;
|
|
}
|
|
|
|
// If the type is a scalar type and the value has a comma, convert
|
|
// the type to an array type.
|
|
switch(type)
|
|
{
|
|
case int8_value: if(hasComma) { type = int8_array; } break;
|
|
case int16_value: if(hasComma) { type = int16_array; } break;
|
|
case int32_value: if(hasComma) { type = int32_array; } break;
|
|
case int64_value: if(hasComma) { type = int64_array; } break;
|
|
case uint8_value: if(hasComma) { type = uint8_array; } break;
|
|
case uint16_value: if(hasComma) { type = uint16_array; } break;
|
|
case uint32_value: if(hasComma) { type = uint32_array; } break;
|
|
case uint64_value: if(hasComma) { type = uint64_array; } break;
|
|
case float32_value: if(hasComma) { type = float32_array; } break;
|
|
case float64_value: if(hasComma) { type = float64_array; } break;
|
|
default: break;
|
|
}
|
|
|
|
// Convert the value from a string to the proper type.
|
|
int result = 0;
|
|
switch(type)
|
|
{
|
|
VTK_CSS_TEMPLATE_MACRO(value,
|
|
result = vtkClientServerStreamValueFromString
|
|
(this, valueBegin, valueEnd, T));
|
|
VTK_CSS_TEMPLATE_MACRO(array,
|
|
result = vtkClientServerStreamArrayFromString
|
|
(this, valueBegin, valueEnd, T));
|
|
case vtkClientServerStream::bool_value:
|
|
{
|
|
// Convert the bool value from a string.
|
|
bool arg;
|
|
result = vtkClientServerStreamBoolFromString(valueBegin, valueEnd,
|
|
&arg);
|
|
if(result)
|
|
{
|
|
*this << arg;
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::string_value:
|
|
{
|
|
// Allocate a buffer for the string.
|
|
char buffer[128];
|
|
char* ptr = buffer;
|
|
if(valueEnd-valueBegin+1 > 128)
|
|
{
|
|
ptr = new char[valueEnd-valueEnd+1];
|
|
}
|
|
|
|
// Copy the string to the buffer removing escapes.
|
|
char* out = ptr;
|
|
for(const char* c = valueBegin; c < valueEnd; ++c)
|
|
{
|
|
switch(*c)
|
|
{
|
|
case '\\': if(++c < valueEnd) { *out++ = *c; }
|
|
default: *out++ = *c; break;
|
|
}
|
|
}
|
|
*out++ = 0;
|
|
|
|
// Insert the string argument.
|
|
*this << out;
|
|
|
|
// Free the buffer.
|
|
if(ptr != buffer)
|
|
{
|
|
delete [] ptr;
|
|
}
|
|
|
|
result = 1;
|
|
} break;
|
|
case vtkClientServerStream::stream_value:
|
|
{
|
|
vtkClientServerStream arg;
|
|
result = arg.StreamFromStringInternal(valueBegin, valueEnd);
|
|
if(result)
|
|
{
|
|
*this << arg;
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::id_value:
|
|
{
|
|
// Convert the ID value from a string.
|
|
vtkClientServerID arg;
|
|
result = vtkClientServerStreamValueFromString(valueBegin, valueEnd,
|
|
&arg.ID);
|
|
if(result)
|
|
{
|
|
*this << arg;
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::vtk_object_pointer:
|
|
{
|
|
vtkObjectBase* arg;
|
|
result = vtkClientServerStreamPointerFromString(valueBegin, valueEnd,
|
|
&arg);
|
|
if(result)
|
|
{
|
|
*this << arg;
|
|
}
|
|
} break;
|
|
case vtkClientServerStream::LastResult:
|
|
{
|
|
*this << vtkClientServerStream::LastResult;
|
|
result = 1;
|
|
} break;
|
|
default: break;
|
|
}
|
|
|
|
// Report where to continue scanning.
|
|
if(result)
|
|
{
|
|
*next = valueEnd+1;
|
|
}
|
|
|
|
return result;
|
|
}
|