"Fossies" - the Fresh Open Source Software Archive

Member "muscle/message/Message.cpp" (28 Nov 2019, 119915 Bytes) of package /linux/privat/muscle7.52.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Message.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 7.41_vs_7.50.

    1 /* This file is Copyright 2000-2013 Meyer Sound Laboratories Inc.  See the included LICENSE.txt file for details. */  
    2 
    3 #include "util/ByteBuffer.h"
    4 #include "util/Queue.h"
    5 #include "message/Message.h"
    6 
    7 namespace muscle {
    8 
    9 using namespace muscle_message_imp;
   10 
   11 static void DoIndents(uint32 num, String & s) {for (uint32 i=0; i<num; i++) s += ' ';}
   12 
   13 static MessageRef::ItemPool _messagePool;
   14 MessageRef::ItemPool * GetMessagePool() {return &_messagePool;}
   15 
   16 static ConstMessageRef _emptyMsgRef(&_messagePool.GetDefaultObject(), false);
   17 const ConstMessageRef & GetEmptyMessageRef() {return _emptyMsgRef;}
   18 
   19 #define DECLARECLONE(X)                             \
   20    AbstractDataArrayRef X :: Clone() const          \
   21    {                                                \
   22       AbstractDataArrayRef ref(NEWFIELD(X));        \
   23       if (ref()) *(static_cast<X*>(ref())) = *this; \
   24       return ref;                                   \
   25    }
   26 
   27 #ifdef MUSCLE_DISABLE_MESSAGE_FIELD_POOLS
   28 # define NEWFIELD(X)  newnothrow X
   29 # define DECLAREFIELDTYPE(X) DECLARECLONE(X)
   30 #else
   31 # define NEWFIELD(X)  _pool##X.ObtainObject()
   32 # define DECLAREFIELDTYPE(X) static ObjectPool<X> _pool##X; DECLARECLONE(X)
   33 #endif
   34 
   35 MessageRef GetMessageFromPool(uint32 what)
   36 {
   37    MessageRef ref(_messagePool.ObtainObject());
   38    if (ref()) ref()->what = what;
   39    return ref;
   40 }
   41 
   42 MessageRef GetMessageFromPool(const Message & copyMe)
   43 {
   44    MessageRef ref(_messagePool.ObtainObject());
   45    if (ref()) *(ref()) = copyMe;
   46    return ref;
   47 }
   48 
   49 MessageRef GetMessageFromPool(const uint8 * flatBytes, uint32 numBytes)
   50 {
   51    MessageRef ref(_messagePool.ObtainObject());
   52    if ((ref())&&(ref()->Unflatten(flatBytes, numBytes) != B_NO_ERROR)) ref.Reset();
   53    return ref;
   54 }
   55 
   56 MessageRef GetMessageFromPool(ObjectPool<Message> & pool, uint32 what)
   57 {
   58    MessageRef ref(pool.ObtainObject());
   59    if (ref()) ref()->what = what;
   60    return ref;
   61 }
   62 
   63 MessageRef GetMessageFromPool(ObjectPool<Message> & pool, const Message & copyMe)
   64 {
   65    MessageRef ref(pool.ObtainObject());
   66    if (ref()) *(ref()) = copyMe;
   67    return ref;
   68 }
   69 
   70 MessageRef GetMessageFromPool(ObjectPool<Message> & pool, const uint8 * flatBytes, uint32 numBytes)
   71 {
   72    MessageRef ref(pool.ObtainObject());
   73    if ((ref())&&(ref()->Unflatten(flatBytes, numBytes) != B_NO_ERROR)) ref.Reset();
   74    return ref;
   75 }
   76 
   77 MessageRef GetLightweightCopyOfMessageFromPool(const Message & copyMe)
   78 {
   79    MessageRef ref(_messagePool.ObtainObject());
   80    if (ref()) ref()->BecomeLightweightCopyOf(copyMe);
   81    return ref;
   82 }
   83 
   84 MessageRef GetLightweightCopyOfMessageFromPool(ObjectPool<Message> & pool, const Message & copyMe)
   85 {
   86    MessageRef ref(pool.ObtainObject());
   87    if (ref()) ref()->BecomeLightweightCopyOf(copyMe);
   88    return ref;
   89 }
   90 
   91 template <class DataType> class FixedSizeDataArray : public AbstractDataArray
   92 {
   93 public:
   94    FixedSizeDataArray() {/* empty */}
   95    virtual ~FixedSizeDataArray() {/* empty */}
   96 
   97    virtual uint32 GetNumItems() const {return _data.GetNumItems();}
   98 
   99    virtual void Clear(bool releaseDataBuffers) {_data.Clear(releaseDataBuffers);}
  100    virtual void Normalize() {_data.Normalize();}
  101 
  102    virtual status_t AddDataItem(const void * item, uint32 size)
  103    {
  104       return (size == sizeof(DataType)) ? (item ? _data.AddTail(*(reinterpret_cast<const DataType *>(item))) : _data.AddTail()) : B_BAD_ARGUMENT;
  105    }
  106 
  107    virtual status_t PrependDataItem(const void * item, uint32 size)
  108    {
  109       return (size == sizeof(DataType)) ? (item ? _data.AddHead(*(reinterpret_cast<const DataType *>(item))) : _data.AddHead()) : B_BAD_ARGUMENT;
  110    }
  111 
  112    virtual uint32 GetItemSize(uint32 /*index*/) const {return sizeof(DataType);}
  113    virtual status_t RemoveDataItem(uint32 index) {return _data.RemoveItemAt(index);}
  114 
  115    virtual status_t FindDataItem(uint32 index, const void ** setDataLoc) const
  116    {
  117       if (index < _data.GetNumItems())
  118       {
  119          *setDataLoc = &_data[index];
  120          return (*setDataLoc) ? B_NO_ERROR : B_DATA_NOT_FOUND;
  121       }
  122       return B_DATA_NOT_FOUND;
  123    }
  124 
  125    virtual status_t ReplaceDataItem(uint32 index, const void * data, uint32 size)
  126    {
  127       return (size == sizeof(DataType)) ? _data.ReplaceItemAt(index, *(static_cast<const DataType *>(data))) : B_BAD_ARGUMENT;
  128    }
  129 
  130    virtual bool ElementsAreFixedSize() const {return true;}
  131 
  132    virtual bool IsFlattenable() const {return true;}
  133 
  134    const DataType & ItemAt(int i) const {return _data[i];}
  135 
  136    FixedSizeDataArray<DataType> & operator=(const FixedSizeDataArray<DataType> & rhs) 
  137    {
  138       if (this != &rhs) _data = rhs._data;
  139       return *this;
  140    }
  141 
  142 protected:
  143    virtual bool AreContentsEqual(const AbstractDataArray * rhs) const
  144    {
  145       const FixedSizeDataArray<DataType> * trhs = dynamic_cast<const FixedSizeDataArray<DataType> *>(rhs);
  146       if (trhs == NULL) return false;
  147 
  148       for (int32 i=GetNumItems()-1; i>=0; i--) if (ItemAt(i) != trhs->ItemAt(i)) return false;
  149       return true;
  150    }
  151 
  152    Queue<DataType> _data;
  153 };
  154 
  155 static void AddItemPreambleToString(uint32 indent, uint32 idx, String & s)
  156 {
  157    DoIndents(indent, s);
  158    char buf[64]; muscleSprintf(buf, "    " UINT32_FORMAT_SPEC ". ", idx);
  159    s += buf;
  160 }
  161 
  162 // An field of ephemeral objects that won't be flattened
  163 class TagDataArray : public FixedSizeDataArray<RefCountableRef>
  164 {
  165 public:
  166    TagDataArray() {/* empty */}
  167    virtual ~TagDataArray() {/* empty */}
  168 
  169    virtual void Flatten(uint8 *) const
  170    {
  171       MCRASH("Message::TagDataArray:Flatten()  This method should never be called!");
  172    }
  173 
  174    // Flattenable interface
  175    virtual uint32 FlattenedSize() const {return 0;}  // tags don't get flattened, so they take up no space
  176 
  177    virtual status_t Unflatten(const uint8 *, uint32)
  178    {
  179       MCRASH("Message::TagDataArray:Unflatten()  This method should never be called!");
  180       return B_NO_ERROR;  // just to keep the compiler happy
  181    }
  182 
  183    virtual uint32 TypeCode() const {return B_TAG_TYPE;}
  184 
  185    virtual AbstractDataArrayRef Clone() const; 
  186 
  187    virtual bool IsFlattenable() const {return false;}
  188 
  189    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  190    {
  191       // This is the best we can do, since we don't know our elements' types
  192       return TypeCode() + GetNumItems();
  193    }
  194 
  195    virtual RefCountableRef GetItemAtAsRefCountableRef(uint32 idx) const {return ItemAt(idx);}
  196 
  197    static void AddItemDescriptionToString(uint32 indent, uint32 idx, const RefCountableRef & tag, String & s)
  198    {
  199       AddItemPreambleToString(indent, idx, s);
  200       char buf[128]; muscleSprintf(buf, "%p\n", tag()); s += buf;
  201    }
  202 
  203 protected:
  204    virtual void AddToString(String & s, uint32, int indent) const
  205    {
  206       const uint32 numItems = GetNumItems();
  207       for (uint32 i=0; i<numItems; i++) AddItemDescriptionToString(indent, i, _data[i], s);
  208    }
  209 };
  210 DECLAREFIELDTYPE(TagDataArray);
  211 
  212 // a field of flattened objects, where all flattened objects are guaranteed to be the same size flattened
  213 template <class DataType, int FlatItemSize, uint32 ItemTypeCode> class FixedSizeFlatObjectArray : public FixedSizeDataArray<DataType>
  214 {
  215 public:
  216    FixedSizeFlatObjectArray() 
  217    {
  218       // empty
  219    }
  220 
  221    virtual ~FixedSizeFlatObjectArray() 
  222    {
  223       // empty
  224    }
  225 
  226    virtual void Flatten(uint8 * buffer) const
  227    {
  228       const uint32 numItems = this->_data.GetNumItems(); 
  229       for (uint32 i=0; i<numItems; i++) 
  230       {
  231          this->_data[i].Flatten(buffer);
  232          buffer += FlatItemSize;
  233       }
  234    }
  235 
  236    // Flattenable interface
  237    virtual uint32 FlattenedSize() const {return this->_data.GetNumItems() * FlatItemSize;}
  238 
  239    virtual status_t Unflatten(const uint8 * buffer, uint32 numBytes)
  240    {
  241       this->_data.Clear();
  242       if (numBytes % FlatItemSize) 
  243       {
  244          LogTime(MUSCLE_LOG_DEBUG, "FixedSizeDataArray %p:  Unexpected numBytes " UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC "\n", this, numBytes, FlatItemSize);
  245          return B_BAD_ARGUMENT;  // length must be an even multiple of item size, or something's wrong!
  246       }
  247 
  248       DataType temp;
  249       const uint32 numItems = numBytes / FlatItemSize;
  250       status_t ret;
  251       if (this->_data.EnsureSize(numItems).IsOK(ret))
  252       {
  253          for (uint32 i=0; i<numItems; i++)
  254          {
  255             if ((temp.Unflatten(buffer, FlatItemSize).IsError(ret))||(this->_data.AddTail(temp).IsError(ret)))
  256             {
  257                LogTime(MUSCLE_LOG_DEBUG, "FixedSizeDataArray %p:  Error unflattened item " UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " [%s]\n", this, i, numItems, ret());
  258                break;
  259             }
  260             buffer += FlatItemSize;
  261          }
  262       }
  263       return ret;
  264    }
  265 
  266    virtual uint32 TypeCode() const {return ItemTypeCode;}
  267 
  268 protected:
  269    virtual void AddToString(String & s, uint32, int indent) const
  270    {
  271       const uint32 numItems = this->GetNumItems();
  272       for (uint32 i=0; i<numItems; i++) 
  273       {
  274          AddItemPreambleToString(indent, i, s);
  275          AddItemToString(s, this->_data[i]);
  276          s += '\n';
  277       }
  278    }
  279 
  280    virtual void AddItemToString(String & s, const DataType & item) const = 0;
  281 };
  282 
  283 /* This class handles storage of all the primitive numeric types for us. */
  284 template <class DataType> class PrimitiveTypeDataArray : public FixedSizeDataArray<DataType> 
  285 {
  286 public:
  287    PrimitiveTypeDataArray() {/* empty */}
  288    virtual ~PrimitiveTypeDataArray() {/* empty */}
  289 
  290    virtual void Flatten(uint8 * buffer) const
  291    {
  292       DataType * dBuf = reinterpret_cast<DataType *>(buffer);
  293       switch(this->_data.GetNumItems())
  294       {
  295          case 0:
  296             // do nothing
  297          break;
  298 
  299          case 1:
  300             ConvertToNetworkByteOrder(dBuf, this->_data.HeadPointer(), 1);
  301          break;
  302 
  303          default:
  304          {
  305             uint32 len0 = 0;
  306             const DataType * field0 = this->_data.GetArrayPointer(0, len0);
  307             if (field0) ConvertToNetworkByteOrder(dBuf, field0, len0);
  308 
  309             uint32 len1;
  310             const DataType * field1 = this->_data.GetArrayPointer(1, len1);
  311             if (field1) ConvertToNetworkByteOrder(&dBuf[len0], field1, len1); 
  312          }
  313          break;
  314       }
  315    }
  316 
  317    virtual status_t Unflatten(const uint8 * buffer, uint32 numBytes)
  318    {
  319       this->_data.Clear();
  320       if (numBytes % sizeof(DataType)) 
  321       {
  322          LogTime(MUSCLE_LOG_DEBUG, "PrimitiveTypeDataArray %p:  Unexpected numBytes " UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC "\n", this, numBytes, (uint32) sizeof(DataType));
  323          return B_BAD_ARGUMENT;  // length must be an even multiple of item size, or something's wrong!
  324       }
  325 
  326       status_t ret;
  327       const uint32 numItems = numBytes / sizeof(DataType);
  328       if (this->_data.EnsureSize(numItems, true).IsOK(ret))
  329       {
  330          // Note that typically you can't rely on the contents of a Queue object to
  331          // be stored in a single, contiguous field like this, but in this case we've
  332          // called Clear() and then EnsureSize(), so we know that the field's headPointer
  333          // is at the front of the field, and we are safe to do this.  --jaf
  334          ConvertFromNetworkByteOrder(this->_data.HeadPointer(), reinterpret_cast<const DataType *>(buffer), numItems);
  335          return B_NO_ERROR;
  336       }
  337       else return ret;
  338    }
  339 
  340    // Flattenable interface
  341    virtual uint32 FlattenedSize() const {return this->_data.GetNumItems() * sizeof(DataType);}
  342 
  343 protected:
  344    virtual void ConvertToNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const = 0;
  345    virtual void ConvertFromNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const = 0;
  346 
  347    virtual const char * GetFormatString() const = 0;
  348 
  349    virtual void AddToString(String & s, uint32, int indent) const
  350    {
  351       const uint32 numItems = this->GetNumItems();
  352       for (uint32 i=0; i<numItems; i++) 
  353       {
  354          AddItemPreambleToString(indent, i, s);
  355          s += '[';
  356          char temp[100]; muscleSprintf(temp, GetFormatString(), this->ItemAt(i)); s += temp;
  357          s += ']';
  358          s += '\n';
  359       }
  360    }
  361 };
  362 
  363 static String PointToString(const Point & p)
  364 {
  365    char buf[128]; muscleSprintf(buf, "Point: x=%f y=%f", p.x(), p.y());
  366    return buf;
  367 }
  368 
  369 class PointDataArray : public FixedSizeFlatObjectArray<Point,sizeof(Point),B_POINT_TYPE>
  370 {
  371 public:
  372    PointDataArray() {/* empty */}
  373    virtual ~PointDataArray() {/* empty */}
  374    virtual AbstractDataArrayRef Clone() const;
  375    virtual void AddItemToString(String & s, const Point & p) const {s += PointToString(p);}
  376 
  377    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  378    {
  379       uint32 ret = TypeCode() + GetNumItems();
  380       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*_data[i].CalculateChecksum());
  381       return ret;
  382    }
  383 };
  384 DECLAREFIELDTYPE(PointDataArray);
  385 
  386 static String RectToString(const Rect & r)
  387 {
  388    char buf[256]; muscleSprintf(buf, "Rect: leftTop=(%f,%f) rightBottom=(%f,%f)", r.left(), r.top(), r.right(), r.bottom());
  389    return buf;
  390 }
  391 
  392 class RectDataArray : public FixedSizeFlatObjectArray<Rect,sizeof(Rect),B_RECT_TYPE>
  393 {
  394 public:
  395    RectDataArray() {/* empty */}
  396    virtual ~RectDataArray() {/* empty */}
  397    virtual AbstractDataArrayRef Clone() const;
  398    virtual void AddItemToString(String & s, const Rect & r) const {s += RectToString(r);}
  399 
  400    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  401    {
  402       uint32 ret = TypeCode() + GetNumItems();
  403       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*_data[i].CalculateChecksum());
  404       return ret;
  405    }
  406 };
  407 DECLAREFIELDTYPE(RectDataArray);
  408 
  409 class Int8DataArray : public PrimitiveTypeDataArray<int8> 
  410 {
  411 public:
  412    Int8DataArray() {/* empty */}
  413    virtual ~Int8DataArray() {/* empty */}
  414 
  415    virtual uint32 TypeCode() const {return B_INT8_TYPE;}
  416 
  417    virtual const char * GetFormatString() const {return "%i";}
  418  
  419    virtual AbstractDataArrayRef Clone() const;
  420 
  421    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  422    {
  423       uint32 ret = TypeCode() + GetNumItems();
  424       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*((uint32)_data[i]));
  425       return ret;
  426    }
  427 
  428 protected:
  429    virtual void ConvertToNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  430    {
  431       memcpy(writeToHere, readFromHere, numItems);  // no translation required, really
  432    }
  433 
  434    virtual void ConvertFromNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  435    {
  436       memcpy(writeToHere, readFromHere, numItems);  // no translation required, really
  437    }
  438 };
  439 DECLAREFIELDTYPE(Int8DataArray);
  440 
  441 class BoolDataArray : public PrimitiveTypeDataArray<bool>
  442 {
  443 public:
  444    BoolDataArray() {/* empty */}
  445    virtual ~BoolDataArray() {/* empty */}
  446 
  447    virtual uint32 TypeCode() const {return B_BOOL_TYPE;}
  448 
  449    virtual const char * GetFormatString() const {return "%i";}
  450 
  451    virtual AbstractDataArrayRef Clone() const;
  452 
  453    virtual void Flatten(uint8 * buffer) const
  454    {
  455       const uint32 numItems = _data.GetNumItems(); 
  456       for (uint32 i=0; i<numItems; i++) buffer[i] = (uint8) (_data[i] ? 1 : 0);
  457    }
  458 
  459    virtual status_t Unflatten(const uint8 * buffer, uint32 numBytes)
  460    {
  461       _data.Clear();
  462 
  463       status_t ret;
  464       if (_data.EnsureSize(numBytes).IsOK(ret))
  465          for (uint32 i=0; i<numBytes; i++) 
  466             if (_data.AddTail((buffer[i] != 0) ? true : false).IsError(ret)) break;
  467 
  468       return ret;
  469    }
  470 
  471    // Flattenable interface
  472    virtual uint32 FlattenedSize() const {return _data.GetNumItems()*sizeof(uint8);}  /* bools are always flattened into 1 byte each */
  473 
  474    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  475    {
  476       uint32 ret = TypeCode() + GetNumItems();
  477       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*(_data[i] ? 1 : 0));
  478       return ret;
  479    }
  480 
  481 protected:
  482    virtual void ConvertToNetworkByteOrder(void *, const void *, uint32) const
  483    {
  484       MCRASH("BoolDataArray::ConvertToNetworkByteOrder should never be called");
  485    }
  486 
  487    virtual void ConvertFromNetworkByteOrder(void *, const void *, uint32) const
  488    {
  489       MCRASH("BoolDataArray::ConvertFromNetworkByteOrder should never be called");
  490    }
  491 };
  492 DECLAREFIELDTYPE(BoolDataArray);
  493 
  494 class Int16DataArray : public PrimitiveTypeDataArray<int16> 
  495 {
  496 public:
  497    Int16DataArray() {/* empty */}
  498    virtual ~Int16DataArray() {/* empty */}
  499 
  500    virtual uint32 TypeCode() const {return B_INT16_TYPE;}
  501 
  502    virtual const char * GetFormatString() const {return "%i";}
  503 
  504    virtual AbstractDataArrayRef Clone() const;
  505 
  506    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  507    {
  508       uint32 ret = TypeCode() + GetNumItems();
  509       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*((uint32)_data[i]));
  510       return ret;
  511    }
  512 
  513 protected:
  514    virtual void ConvertToNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  515    {
  516       int16 * writeToHere16 = static_cast<int16 *>(writeToHere);
  517       const int16 * readFromHere16 = (const int16 *) readFromHere;
  518       for (uint32 i=0; i<numItems; i++) muscleCopyOut(&writeToHere16[i], B_HOST_TO_LENDIAN_INT16(readFromHere16[i]));
  519    }
  520 
  521    virtual void ConvertFromNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  522    {
  523       int16 * writeToHere16 = (int16 *) writeToHere;
  524       const int16 * readFromHere16 = (const int16 *) readFromHere;
  525       for (uint32 i=0; i<numItems; i++) writeToHere16[i] = B_LENDIAN_TO_HOST_INT16(muscleCopyIn<int16>(&readFromHere16[i]));
  526    }
  527 };
  528 DECLAREFIELDTYPE(Int16DataArray);
  529 
  530 class Int32DataArray : public PrimitiveTypeDataArray<int32> 
  531 {
  532 public:
  533    Int32DataArray() {/* empty */}
  534    virtual ~Int32DataArray() {/* empty */}
  535 
  536    virtual uint32 TypeCode() const {return B_INT32_TYPE;}
  537 
  538    virtual const char * GetFormatString() const {return INT32_FORMAT_SPEC;}
  539 
  540    virtual AbstractDataArrayRef Clone() const;
  541 
  542    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  543    {
  544       uint32 ret = TypeCode() + GetNumItems();
  545       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*((uint32)_data[i]));
  546       return ret;
  547    }
  548 
  549 protected:
  550    virtual void ConvertToNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  551    {
  552       int32 * writeToHere32 = (int32 *) writeToHere;
  553       const int32 * readFromHere32 = (const int32 *) readFromHere;
  554       for (uint32 i=0; i<numItems; i++) muscleCopyOut(&writeToHere32[i], B_HOST_TO_LENDIAN_INT32(readFromHere32[i]));
  555    }
  556 
  557    virtual void ConvertFromNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  558    {
  559       int32 * writeToHere32 = (int32 *) writeToHere;
  560       const int32 * readFromHere32 = (const int32 *) readFromHere;
  561       for (uint32 i=0; i<numItems; i++) writeToHere32[i] = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<int32>(&readFromHere32[i]));
  562    }
  563 };
  564 DECLAREFIELDTYPE(Int32DataArray);
  565 
  566 class Int64DataArray : public PrimitiveTypeDataArray<int64> 
  567 {
  568 public:
  569    Int64DataArray() {/* empty */}
  570    virtual ~Int64DataArray() {/* empty */}
  571 
  572    virtual uint32 TypeCode() const {return B_INT64_TYPE;}
  573 
  574    virtual const char * GetFormatString() const {return INT64_FORMAT_SPEC;}
  575 
  576    virtual AbstractDataArrayRef Clone() const;
  577 
  578    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  579    {
  580       uint32 ret = TypeCode() + GetNumItems();
  581       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*CalculateChecksumForUint64(_data[i]));
  582       return ret;
  583    }
  584 
  585 protected:
  586    virtual void ConvertToNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  587    {
  588       int64 * writeToHere64 = (int64 *) writeToHere;
  589       const int64 * readFromHere64 = (const int64 *) readFromHere;
  590       for (uint32 i=0; i<numItems; i++) muscleCopyOut(&writeToHere64[i], B_HOST_TO_LENDIAN_INT64(readFromHere64[i]));
  591    }
  592 
  593    virtual void ConvertFromNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  594    {
  595       int64 * writeToHere64 = (int64 *) writeToHere;
  596       const int64 * readFromHere64 = (const int64 *) readFromHere;
  597       for (uint32 i=0; i<numItems; i++) writeToHere64[i] = B_LENDIAN_TO_HOST_INT64(muscleCopyIn<int64>(&readFromHere64[i]));
  598    }
  599 };
  600 DECLAREFIELDTYPE(Int64DataArray);
  601 
  602 class FloatDataArray : public PrimitiveTypeDataArray<float> 
  603 {
  604 public:
  605    FloatDataArray() {/* empty */}
  606    virtual ~FloatDataArray() {/* empty */}
  607 
  608    virtual uint32 TypeCode() const {return B_FLOAT_TYPE;}
  609 
  610    virtual const char * GetFormatString() const {return "%f";}
  611 
  612    virtual AbstractDataArrayRef Clone() const;
  613 
  614    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  615    {
  616       uint32 ret = TypeCode() + GetNumItems();
  617       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*CalculateChecksumForFloat(_data[i]));
  618       return ret;
  619    }
  620 
  621 protected:
  622    virtual void ConvertToNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  623    {
  624       int32 * writeToHere32 = (int32 *) writeToHere;  // yeah, they're really floats, but no need to worry about that here
  625       const int32 * readFromHere32 = (const int32 *) readFromHere;
  626       for (uint32 i=0; i<numItems; i++) muscleCopyOut(&writeToHere32[i], B_HOST_TO_LENDIAN_INT32(readFromHere32[i]));
  627    }
  628 
  629    virtual void ConvertFromNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  630    {
  631       int32 * writeToHere32 = (int32 *) writeToHere;  // yeah, they're really floats, but no need to worry about that here
  632       const int32 * readFromHere32 = (const int32 *) readFromHere;
  633       for (uint32 i=0; i<numItems; i++) writeToHere32[i] = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<int32>(&readFromHere32[i]));
  634    }
  635 };
  636 DECLAREFIELDTYPE(FloatDataArray);
  637 
  638 class DoubleDataArray : public PrimitiveTypeDataArray<double> 
  639 {
  640 public:
  641    DoubleDataArray() {/* empty */}
  642    virtual ~DoubleDataArray() {/* empty */}
  643 
  644    virtual uint32 TypeCode() const {return B_DOUBLE_TYPE;}
  645 
  646    virtual const char * GetFormatString() const {return "%lf";}
  647 
  648    virtual AbstractDataArrayRef Clone() const;
  649 
  650    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  651    {
  652       uint32 ret = TypeCode() + GetNumItems();
  653       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*CalculateChecksumForDouble(_data[i]));
  654       return ret;
  655    }
  656 
  657 protected:
  658    virtual void ConvertToNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  659    {
  660       int64 * writeToHere64 = (int64 *) writeToHere;  // yeah, they're really doubles, but no need to worry about that here
  661       const int64 * readFromHere64 = (const int64 *) readFromHere;
  662       for (uint32 i=0; i<numItems; i++) muscleCopyOut(&writeToHere64[i], B_HOST_TO_LENDIAN_INT64(readFromHere64[i]));
  663    }
  664 
  665    virtual void ConvertFromNetworkByteOrder(void * writeToHere, const void * readFromHere, uint32 numItems) const
  666    {
  667       int64 * writeToHere64 = (int64 *) writeToHere;  // yeah, they're really doubles, but no need to worry about that here
  668       const int64 * readFromHere64 = (const int64 *) readFromHere;
  669       for (uint32 i=0; i<numItems; i++) writeToHere64[i] = B_LENDIAN_TO_HOST_INT64(muscleCopyIn<int64>(&readFromHere64[i]));
  670    }
  671 };
  672 DECLAREFIELDTYPE(DoubleDataArray);
  673 
  674 class PointerDataArray : public PrimitiveTypeDataArray<void *> 
  675 {
  676 public:
  677    PointerDataArray() {/* empty */}
  678    virtual ~PointerDataArray() {/* empty */}
  679 
  680    virtual uint32 TypeCode() const {return B_POINTER_TYPE;}
  681 
  682    virtual const char * GetFormatString() const {return "%p";}
  683 
  684    virtual bool IsFlattenable() const {return false;}
  685 
  686    virtual AbstractDataArrayRef Clone() const;
  687 
  688    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  689    {
  690       return TypeCode() + GetNumItems();  // Best we can do, since pointer equivalence is not well defined
  691    }
  692 
  693 protected:
  694    virtual void ConvertToNetworkByteOrder(void *, const void *, uint32) const
  695    {
  696       MCRASH("PointerDataArray::ConvertToNetworkByteOrder should never be called");
  697    }
  698 
  699    virtual void ConvertFromNetworkByteOrder(void *, const void *, uint32) const
  700    {
  701       MCRASH("PointerDataArray::ConvertFromNetworkByteOrder should never be called");
  702    }
  703 };
  704 DECLAREFIELDTYPE(PointerDataArray);
  705 
  706 // An abstract field of FlatCountableRefs.
  707 template <class RefType, uint32 ItemTypeCode> class FlatCountableRefDataArray : public FixedSizeDataArray<RefType>
  708 {
  709 public:
  710    FlatCountableRefDataArray() {/* empty */}
  711    virtual ~FlatCountableRefDataArray() {/* empty */}
  712 
  713    virtual uint32 GetItemSize(uint32 index) const 
  714    {
  715       const FlatCountable * msg = this->ItemAt(index)();
  716       return msg ? msg->FlattenedSize() : 0;
  717    }
  718 
  719    virtual uint32 TypeCode() const {return ItemTypeCode;}
  720 
  721    virtual bool ElementsAreFixedSize() const {return false;}
  722 
  723    /** Whether or not we should write the number-of-items element when we flatten this field.
  724      * Older versions of muscle didn't do this for MessageDataArray objects, so we need to
  725      * maintain that behaviour so that we don't break compatibility.  (bleah)
  726      */
  727    virtual bool ShouldWriteNumItems() const {return true;}
  728 
  729    virtual void Flatten(uint8 * buffer) const
  730    {
  731       uint32 writeOffset = 0;
  732       const uint32 numItems = this->_data.GetNumItems(); 
  733 
  734       // Conditional to allow maintaining backwards compatibility with old versions of muscle's MessageDataArrays (sigh)
  735       if (ShouldWriteNumItems()) 
  736       {
  737          const uint32 writeNumElements = B_HOST_TO_LENDIAN_INT32(numItems);
  738          this->WriteData(buffer, &writeOffset, &writeNumElements, sizeof(writeNumElements));
  739       }
  740 
  741       for (uint32 i=0; i<numItems; i++) 
  742       {
  743          const FlatCountable * next = this->ItemAt(i)();
  744          if (next)
  745          {
  746             const uint32 fs = next->FlattenedSize();
  747             const uint32 writeFs = B_HOST_TO_LENDIAN_INT32(fs);
  748             this->WriteData(buffer, &writeOffset, &writeFs, sizeof(writeFs));
  749             next->Flatten(&buffer[writeOffset]);
  750             writeOffset += fs;
  751          }
  752       }
  753    }
  754 
  755    // Flattenable interface
  756    virtual uint32 FlattenedSize() const 
  757    {
  758       const uint32 numItems = this->GetNumItems();
  759       uint32 count = (numItems+(ShouldWriteNumItems()?1:0))*sizeof(uint32);
  760       for (uint32 i=0; i<numItems; i++) count += GetItemSize(i);
  761       return count;
  762    }
  763 
  764    virtual RefCountableRef GetItemAtAsRefCountableRef(uint32 idx) const {return this->ItemAt(idx).GetRefCountableRef();}
  765 };
  766 
  767 static bool AreByteBufferPointersEqual(const ByteBuffer * myBuf, const ByteBuffer * hisBuf)
  768 {
  769    if ((myBuf != NULL) != (hisBuf != NULL)) return false;
  770    return myBuf ? (*myBuf == *hisBuf) : true;
  771 }
  772 
  773 class ByteBufferDataArray : public FlatCountableRefDataArray<FlatCountableRef, B_RAW_TYPE>
  774 {
  775 public:
  776    ByteBufferDataArray()
  777       : _typeCode(B_RAW_TYPE) 
  778    {
  779       // empty
  780    }
  781    virtual ~ByteBufferDataArray() {/* empty */}
  782 
  783    /** Sets our type code.  Typically called after using the default ctor. */
  784    void SetTypeCode(uint32 tc) {_typeCode = tc;}
  785 
  786    virtual uint32 TypeCode() const {return _typeCode;}
  787 
  788    virtual status_t Unflatten(const uint8 * buffer, uint32 numBytes)
  789    {
  790       Clear(false);
  791 
  792       uint32 readOffset = 0;
  793 
  794       status_t ret;
  795 
  796       uint32 numItems;
  797       if (ReadData(buffer, numBytes, &readOffset, &numItems, sizeof(numItems)).IsError(ret))
  798       {
  799          LogTime(MUSCLE_LOG_DEBUG, "ByteBufferDataArray %p:  Error reading numItems (numBytes=" UINT32_FORMAT_SPEC ") [%s]\n", this, numBytes, ret());
  800          return ret;
  801       }
  802       numItems = B_LENDIAN_TO_HOST_INT32(numItems);
  803    
  804       for (uint32 i=0; i<numItems; i++)
  805       {
  806          uint32 readFs;
  807          if (ReadData(buffer, numBytes, &readOffset, &readFs, sizeof(readFs)).IsError(ret))
  808          {
  809             LogTime(MUSCLE_LOG_DEBUG, "ByteBufferDataArray %p:  Error reading item size (i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ", readOffset=" UINT32_FORMAT_SPEC ", numBytes=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, i, numItems, readOffset, numBytes, ret());
  810             return ret;
  811          }
  812 
  813          readFs = B_LENDIAN_TO_HOST_INT32(readFs);
  814          if (readOffset + readFs > numBytes) 
  815          {
  816             LogTime(MUSCLE_LOG_DEBUG, "ByteBufferDataArray %p:  Item size too large (i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ", readOffset=" UINT32_FORMAT_SPEC ", numBytes=" UINT32_FORMAT_SPEC ", readFs=" UINT32_FORMAT_SPEC ")\n", this, i, numItems, readOffset, numBytes, readFs);
  817             return B_BAD_DATA;  // message size too large for our buffer... corruption?
  818          }
  819          FlatCountableRef fcRef(GetByteBufferFromPool(readFs, &buffer[readOffset]).GetRefCountableRef(), true);
  820          if ((fcRef())&&(AddDataItem(&fcRef, sizeof(fcRef)).IsOK(ret))) readOffset += readFs;
  821                                                                    else return ret;
  822       }
  823       return B_NO_ERROR;
  824    }
  825 
  826    static void AddItemDescriptionToString(uint32 indent, uint32 idx, const FlatCountableRef & fcRef, String & s)
  827    {
  828       AddItemPreambleToString(indent, idx, s);
  829 
  830       FlatCountable * fc = fcRef();
  831       ByteBuffer temp;
  832       ByteBuffer * bb = dynamic_cast<ByteBuffer *>(fc);
  833       if ((bb == NULL)&&(fc))
  834       {
  835          temp.SetNumBytes(fc->FlattenedSize(), false);
  836          if (temp())
  837          {
  838             fc->Flatten((uint8*)temp());
  839             bb = &temp;
  840          }
  841       }
  842 
  843       if (bb)
  844       {
  845          char buf[100];
  846          muscleSprintf(buf, "[flattenedSize=" UINT32_FORMAT_SPEC "] ", bb->GetNumBytes()); 
  847          s += buf;
  848          uint32 printBytes = muscleMin(bb->GetNumBytes(), (uint32)10);
  849          if (printBytes > 0)
  850          {
  851             s += '[';
  852             for (uint32 j=0; j<printBytes; j++) 
  853             {
  854                muscleSprintf(buf, "%02x%s", (bb->GetBuffer())[j], (j<printBytes-1)?" ":"");
  855                s += buf;
  856             }
  857             if (printBytes > 10) s += " ...";
  858             s += ']';
  859          }
  860       }
  861       else s += "[NULL]";
  862 
  863       s += '\n';
  864    }
  865 
  866    virtual void AddToString(String & s, uint32, int indent) const
  867    {
  868       const uint32 numItems = GetNumItems();
  869       for (uint32 i=0; i<numItems; i++) AddItemDescriptionToString(indent, i, ItemAt(i), s);
  870    }
  871 
  872    virtual AbstractDataArrayRef Clone() const;
  873 
  874    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
  875    {
  876       uint32 ret = TypeCode() + GetNumItems();
  877       for (int32 i=GetNumItems()-1; i>=0; i--)
  878       {
  879          const ByteBuffer * buf = dynamic_cast<ByteBuffer *>(_data[i]());  // TODO: possibly make this a static cast?
  880          if (buf) ret += ((i+1)*buf->CalculateChecksum());
  881       }
  882       return ret;
  883    }
  884 
  885 protected:
  886    /** Overridden to compare objects instead of merely the pointers to them */
  887    virtual bool AreContentsEqual(const AbstractDataArray * rhs) const
  888    {
  889       const ByteBufferDataArray * brhs = dynamic_cast<const ByteBufferDataArray *>(rhs);
  890       if (brhs == NULL) return false;
  891 
  892       for (int32 i=GetNumItems()-1; i>=0; i--) 
  893       {
  894          const ByteBuffer * myBuf  = static_cast<const ByteBuffer *>(this->ItemAt(i)());
  895          const ByteBuffer * hisBuf = static_cast<const ByteBuffer *>(brhs->ItemAt(i)());
  896          if (AreByteBufferPointersEqual(myBuf, hisBuf) == false) return false;
  897       }
  898       return true;
  899    }
  900 
  901 private:
  902    uint32 _typeCode;
  903 };
  904 DECLAREFIELDTYPE(ByteBufferDataArray);
  905 
  906 static bool AreMessagePointersDeeplyEqual(const Message * myMsg, const Message * hisMsg)
  907 {
  908    if ((myMsg != NULL) != (hisMsg != NULL)) return false;
  909    return myMsg ? (*myMsg == *hisMsg) : true;
  910 }
  911 
  912 class MessageDataArray : public FlatCountableRefDataArray<MessageRef, B_MESSAGE_TYPE>
  913 {
  914 public:
  915    MessageDataArray() {/* empty */}
  916    virtual ~MessageDataArray() {/* empty */}
  917 
  918    /** For backwards compatibility with older muscle streams */
  919    virtual bool ShouldWriteNumItems() const {return false;}
  920 
  921    virtual status_t Unflatten(const uint8 * buffer, uint32 numBytes)
  922    {
  923       Clear(false);
  924 
  925       status_t ret;
  926 
  927       uint32 readOffset = 0;
  928       while(readOffset < numBytes)
  929       {
  930          uint32 readFs;
  931          if (ReadData(buffer, numBytes, &readOffset, &readFs, sizeof(readFs)).IsError(ret))
  932          {
  933             LogTime(MUSCLE_LOG_DEBUG, "MessageDataArray %p:  Read of sub-message size failed (readOffset=" UINT32_FORMAT_SPEC ", numBytes=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, readOffset, numBytes, ret());
  934             return ret;
  935          }
  936 
  937          readFs = B_LENDIAN_TO_HOST_INT32(readFs);
  938          if (readOffset + readFs > numBytes) 
  939          {
  940             LogTime(MUSCLE_LOG_DEBUG, "MessageDataArray %p:  Sub-message size too large (readOffset=" UINT32_FORMAT_SPEC ", numBytes=" UINT32_FORMAT_SPEC ", readFs=" UINT32_FORMAT_SPEC ")\n", this, readOffset, numBytes, readFs);
  941             return B_BAD_DATA;  // message size too large for our buffer... corruption?
  942          }
  943          MessageRef nextMsg = GetMessageFromPool();
  944          if (nextMsg())
  945          {
  946             if (nextMsg()->Unflatten(&buffer[readOffset], readFs).IsError(ret))
  947             {
  948                LogTime(MUSCLE_LOG_DEBUG, "MessageDataArray %p:  Sub-message unflatten failed (readOffset=" UINT32_FORMAT_SPEC ", numBytes=" UINT32_FORMAT_SPEC ", readFs=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, readOffset, numBytes, readFs, ret());
  949                return ret;
  950             }
  951             if (AddDataItem(&nextMsg, sizeof(nextMsg)).IsError(ret)) return ret;
  952             readOffset += readFs;
  953          }
  954          else RETURN_OUT_OF_MEMORY;
  955       }
  956       return B_NO_ERROR;
  957    }
  958 
  959    static void AddItemDescriptionToString(uint32 indent, uint32 i, const MessageRef & msgRef, String & s, uint32 maxRecurseLevel)
  960    {
  961       AddItemPreambleToString(indent, i, s);
  962 
  963       const Message * msg = msgRef();
  964       if (msg)
  965       {
  966          char tcbuf[5]; MakePrettyTypeCodeString(msg->what, tcbuf);
  967          char buf[100]; muscleSprintf(buf, "[what='%s' (" INT32_FORMAT_SPEC "/0x" XINT32_FORMAT_SPEC "), flattenedSize=" UINT32_FORMAT_SPEC ", numFields=" UINT32_FORMAT_SPEC "]\n", tcbuf, msg->what, msg->what, msg->FlattenedSize(), msg->GetNumNames());
  968          s += buf;
  969 
  970          if (maxRecurseLevel > 0) msg->AddToString(s, maxRecurseLevel-1, indent+3);
  971       }
  972       else s += "[NULL]\n";
  973    }
  974 
  975    virtual void AddToString(String & s, uint32 maxRecurseLevel, int indent) const
  976    {
  977       const uint32 numItems = GetNumItems();
  978       for (uint32 i=0; i<numItems; i++) AddItemDescriptionToString(indent, i, ItemAt(i), s, maxRecurseLevel);
  979    }
  980 
  981    virtual AbstractDataArrayRef Clone() const;
  982 
  983    virtual uint32 CalculateChecksum(bool countNonFlattenableFields) const
  984    {
  985       uint32 ret = TypeCode() + GetNumItems();
  986       for (int32 i=GetNumItems()-1; i>=0; i--)
  987       {
  988          const MessageRef & msg = _data[i];
  989          if (msg()) ret += ((i+1)*(msg()->CalculateChecksum(countNonFlattenableFields)));
  990       }
  991       return ret;
  992    }
  993 
  994 protected:
  995    /** Overridden to compare objects instead of merely the pointers to them */
  996    virtual bool AreContentsEqual(const AbstractDataArray * rhs) const
  997    {
  998       const MessageDataArray * trhs = dynamic_cast<const MessageDataArray *>(rhs);
  999       if (trhs == NULL) return false;
 1000 
 1001       for (int32 i=GetNumItems()-1; i>=0; i--) 
 1002       {
 1003          const Message * myMsg  = static_cast<const Message *>(this->ItemAt(i)());
 1004          const Message * hisMsg = static_cast<const Message *>(trhs->ItemAt(i)());
 1005          if (AreMessagePointersDeeplyEqual(myMsg, hisMsg) == false) return false;
 1006       }
 1007       return true;
 1008    }
 1009 };
 1010 DECLAREFIELDTYPE(MessageDataArray);
 1011 
 1012 // An field of Flattenable objects which are *not* guaranteed to all have the same flattened size. 
 1013 template <class DataType> class VariableSizeFlatObjectArray : public FixedSizeDataArray<DataType>
 1014 {
 1015 public:
 1016    VariableSizeFlatObjectArray() {/* empty */}
 1017    virtual ~VariableSizeFlatObjectArray() {/* empty */}
 1018 
 1019    virtual uint32 GetItemSize(uint32 index) const {return this->ItemAt(index).FlattenedSize();}
 1020    virtual bool ElementsAreFixedSize() const {return false;}
 1021 
 1022    virtual void Flatten(uint8 * buffer) const
 1023    {
 1024       // Format:  0. number of entries (4 bytes)
 1025       //          1. entry size in bytes (4 bytes)
 1026       //          2. entry data (n bytes)
 1027       //          (repeat 1. and 2. as necessary)
 1028       const uint32 numElements = this->GetNumItems();
 1029       uint32 networkByteOrder  = B_HOST_TO_LENDIAN_INT32(numElements);
 1030       uint32 writeOffset       = 0;
 1031 
 1032       this->WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
 1033 
 1034       for (uint32 i=0; i<numElements; i++)
 1035       {
 1036          // write element size
 1037          const DataType & s = this->ItemAt(i);
 1038          const uint32 nextElementBytes = s.FlattenedSize();
 1039          networkByteOrder = B_HOST_TO_LENDIAN_INT32(nextElementBytes);
 1040          this->WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
 1041 
 1042          // write element data
 1043          s.Flatten(&buffer[writeOffset]);
 1044          writeOffset += nextElementBytes;
 1045       }
 1046    }
 1047 
 1048    virtual uint32 FlattenedSize() const 
 1049    {
 1050       const uint32 num = this->GetNumItems();
 1051       uint32 sum = (num+1)*sizeof(uint32);  // 1 uint32 for the count, plus 1 per entry for entry-size
 1052       for (uint32 i=0; i<num; i++) sum += this->ItemAt(i).FlattenedSize();
 1053       return sum;
 1054    }
 1055 
 1056    virtual status_t Unflatten(const uint8 * buffer, uint32 inputBufferBytes)
 1057    {
 1058       this->Clear(false);
 1059 
 1060       uint32 networkByteOrder;
 1061       uint32 readOffset = 0;
 1062 
 1063       status_t ret;
 1064 
 1065       if (this->ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)).IsError(ret))
 1066       {
 1067          LogTime(MUSCLE_LOG_DEBUG, "VariableSizeFlatObjectArray %p:  Read of numElements failed (inputBufferBytes=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, inputBufferBytes, ret());
 1068          return ret;
 1069       }
 1070 
 1071       const uint32 numElements = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
 1072       if (this->_data.EnsureSize(numElements).IsError(ret)) return ret;
 1073 
 1074       for (uint32 i=0; i<numElements; i++)
 1075       {
 1076          if (this->ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)).IsError(ret))
 1077          {
 1078             LogTime(MUSCLE_LOG_DEBUG, "VariableSizeFlatObjectArray %p:  Read of element size failed (inputBufferBytes=" UINT32_FORMAT_SPEC ", i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, inputBufferBytes, i, numElements, ret());
 1079             return ret;
 1080          }
 1081 
 1082          const uint32 elementSize = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
 1083          if (elementSize == 0) 
 1084          {
 1085             LogTime(MUSCLE_LOG_DEBUG, "VariableSizeFlatObjectArray %p:  Element size was zero! (inputBufferBytes=" UINT32_FORMAT_SPEC ", i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ")\n", this, inputBufferBytes, i, numElements);
 1086             return B_BAD_DATA;
 1087          }
 1088 
 1089          // read element data
 1090          if (readOffset + elementSize > inputBufferBytes)
 1091          {
 1092             LogTime(MUSCLE_LOG_DEBUG, "VariableSizeFlatObjectArray %p:  Element size was too large! (inputBufferBytes=" UINT32_FORMAT_SPEC ", i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ", readOffset=" UINT32_FORMAT_SPEC ", elementSize=" UINT32_FORMAT_SPEC ")\n", this, inputBufferBytes, i, numElements, readOffset, elementSize);
 1093             return B_BAD_DATA;
 1094          }
 1095 
 1096          // parse element data
 1097          if ((this->_data.AddTail().IsError(ret))||(this->_data.TailPointer()->Unflatten(&buffer[readOffset], elementSize).IsError(ret)))
 1098          {
 1099             LogTime(MUSCLE_LOG_DEBUG, "VariableSizeFlatObjectArray %p:  Error unflattening element! (inputBufferBytes=" UINT32_FORMAT_SPEC ", i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ", readOffset=" UINT32_FORMAT_SPEC ", elementSize=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, inputBufferBytes, i, numElements, readOffset, elementSize, ret());
 1100             return ret;
 1101          }
 1102          readOffset += elementSize;
 1103       }
 1104       return B_NO_ERROR;
 1105    }
 1106 };
 1107 
 1108 class StringDataArray : public VariableSizeFlatObjectArray<String>
 1109 {
 1110 public:
 1111    StringDataArray() {/* empty */}
 1112    virtual ~StringDataArray() {/* empty */}
 1113 
 1114    virtual uint32 TypeCode() const {return B_STRING_TYPE;}
 1115 
 1116    virtual AbstractDataArrayRef Clone() const;
 1117 
 1118    virtual void AddToString(String & s, uint32, int indent) const
 1119    {
 1120       const uint32 numItems = GetNumItems();
 1121       for (uint32 i=0; i<numItems; i++) AddDataItemToString(indent, i, ItemAt(i), s);
 1122    }
 1123 
 1124    static void AddDataItemToString(uint32 indent, uint32 i, const String & nextStr, String & s)
 1125    {
 1126       AddItemPreambleToString(indent, i, s);
 1127       s += '[';
 1128       s += nextStr;
 1129       s += ']';
 1130       s += '\n';
 1131    }
 1132 
 1133    virtual uint32 CalculateChecksum(bool /*countNonFlattenableFields*/) const
 1134    {
 1135       uint32 ret = TypeCode() + GetNumItems();
 1136       for (int32 i=GetNumItems()-1; i>=0; i--) ret += ((i+1)*(_data[i].CalculateChecksum()));
 1137       return ret;
 1138    }
 1139 };
 1140 DECLAREFIELDTYPE(StringDataArray);
 1141 
 1142 void MessageFieldNameIterator :: SkipNonMatchingFieldNames()
 1143 {
 1144    // Gotta move ahead until we find the first matching value!
 1145    while((_iter.HasData())&&(_iter.GetValue().TypeCode() != _typeCode)) _iter++;
 1146 }
 1147 
 1148 Message & Message :: operator=(const Message & rhs) 
 1149 {
 1150    TCHECKPOINT;
 1151 
 1152    if (this != &rhs)
 1153    {
 1154       Clear((rhs._entries.IsEmpty())&&(_entries.GetNumAllocatedItemSlots()>MUSCLE_HASHTABLE_DEFAULT_CAPACITY));  // FogBugz #10274
 1155       what     = rhs.what;
 1156       _entries = rhs._entries;
 1157       for (HashtableIterator<String, MessageField> iter(_entries); iter.HasData(); iter++) iter.GetValue().EnsurePrivate();  // a copied Message shouldn't share data
 1158    }
 1159    return *this;
 1160 }
 1161 
 1162 status_t Message :: GetInfo(const String & fieldName, uint32 * type, uint32 * c, bool * fixedSize) const
 1163 {
 1164    const MessageField * field = GetMessageField(fieldName, B_ANY_TYPE);
 1165    if (field == NULL) return B_DATA_NOT_FOUND;
 1166    if (type)      *type      = field->TypeCode();
 1167    if (c)         *c         = field->GetNumItems();
 1168    if (fixedSize) *fixedSize = field->ElementsAreFixedSize();
 1169    return B_NO_ERROR;
 1170 }
 1171 
 1172 uint32 Message :: GetNumNames(uint32 type) const 
 1173 {
 1174    if (type == B_ANY_TYPE) return _entries.GetNumItems();
 1175 
 1176    // oops, gotta count just the entries of the given type
 1177    uint32 total = 0;
 1178    for (HashtableIterator<String, MessageField> it(_entries, HTIT_FLAG_NOREGISTER); it.HasData(); it++) if (it.GetValue().TypeCode() == type) total++;
 1179    return total;
 1180 }
 1181 
 1182 void Message :: PrintToStream(FILE * optFile, uint32 maxRecurseLevel, int indent) const 
 1183 {
 1184    String s; AddToString(s, maxRecurseLevel, indent);
 1185    fprintf(optFile?optFile:stdout, "%s", s());
 1186 }
 1187 
 1188 String Message :: ToString(uint32 maxRecurseLevel, int indent) const 
 1189 {
 1190    String s;  
 1191    AddToString(s, maxRecurseLevel, indent);
 1192    return s;
 1193 }
 1194 
 1195 void Message :: AddToString(String & s, uint32 maxRecurseLevel, int indent) const 
 1196 {
 1197    TCHECKPOINT;
 1198 
 1199    String ret;
 1200 
 1201    char prettyTypeCodeBuf[5];
 1202    MakePrettyTypeCodeString(what, prettyTypeCodeBuf);
 1203 
 1204    char buf[128];
 1205    DoIndents(indent,s); 
 1206    muscleSprintf(buf, "Message:  what='%s' (" INT32_FORMAT_SPEC "/0x" XINT32_FORMAT_SPEC "), entryCount=" INT32_FORMAT_SPEC ", flatSize=" UINT32_FORMAT_SPEC " checksum=" UINT32_FORMAT_SPEC "\n", prettyTypeCodeBuf, what, what, GetNumNames(B_ANY_TYPE), FlattenedSize(), CalculateChecksum());
 1207    s += buf;
 1208 
 1209    for (HashtableIterator<String, MessageField> iter(_entries, HTIT_FLAG_NOREGISTER); iter.HasData(); iter++)
 1210    {
 1211       const MessageField & mf = iter.GetValue();
 1212       uint32 tc = mf.TypeCode();
 1213       MakePrettyTypeCodeString(tc, prettyTypeCodeBuf);
 1214       DoIndents(indent,s); 
 1215       s += "  Entry: Name=[";
 1216       s += iter.GetKey();
 1217       muscleSprintf(buf, "], GetNumItems()=" INT32_FORMAT_SPEC ", TypeCode()='%s' (" INT32_FORMAT_SPEC ") flatSize=" UINT32_FORMAT_SPEC " checksum=" UINT32_FORMAT_SPEC "\n", mf.GetNumItems(), prettyTypeCodeBuf, tc, mf.FlattenedSize(), mf.CalculateChecksum(false));
 1218       s += buf;
 1219       mf.AddToString(s, maxRecurseLevel, indent);
 1220    }
 1221 }
 1222 
 1223 // Returns an pointer to a held field of the given type, if it exists.  If (tc) is B_ANY_TYPE, then any type field is acceptable.
 1224 MessageField * Message :: GetMessageField(const String & fieldName, uint32 tc)
 1225 {
 1226    MessageField * field;
 1227    return (((field = _entries.Get(fieldName)) != NULL)&&((tc == B_ANY_TYPE)||(tc == field->TypeCode()))) ? field : NULL;
 1228 }
 1229 
 1230 // Returns a read-only pointer to a held field of the given type, if it exists.  If (tc) is B_ANY_TYPE, then any type field is acceptable.
 1231 const MessageField * Message :: GetMessageField(const String & fieldName, uint32 tc) const
 1232 {
 1233    const MessageField * field;
 1234    return (((field = _entries.Get(fieldName)) != NULL)&&((tc == B_ANY_TYPE)||(tc == field->TypeCode()))) ? field : NULL;
 1235 }
 1236 
 1237 // Called by FindFlat(), which (due to its templated nature) can't access this info directly
 1238 const MessageField * Message :: GetMessageFieldAndTypeCode(const String & fieldName, uint32 index, uint32 * retTC) const
 1239 {
 1240    const MessageField * mf = _entries.Get(fieldName);
 1241    if ((mf)&&(index < mf->GetNumItems()))
 1242    {
 1243       *retTC = mf->TypeCode();
 1244       return mf;
 1245    }
 1246    return NULL;
 1247 }
 1248 
 1249 MessageField * Message :: GetOrCreateMessageField(const String & fieldName, uint32 tc)
 1250 {
 1251    MessageField * mf = GetMessageField(fieldName, tc);
 1252    if (mf) return mf;
 1253 
 1254    // Make sure the problem isn't that there already exists a field, but of the wrong type...
 1255    // If that's the case, we can't create a same-named field of a different type, so fail.
 1256    return _entries.PutIfNotAlreadyPresent(fieldName, MessageField(tc));
 1257 }
 1258 
 1259 status_t Message :: Rename(const String & oldFieldName, const String & newFieldName) 
 1260 {
 1261    if (oldFieldName == newFieldName) return B_NO_ERROR;  // nothing needs to be done in this case
 1262 
 1263    MessageField temp;
 1264    return (_entries.Remove(oldFieldName, temp) == B_NO_ERROR) ? _entries.Put(newFieldName, temp) : B_DATA_NOT_FOUND;
 1265 }
 1266 
 1267 uint32 Message :: FlattenedSize() const 
 1268 {
 1269    uint32 sum = 3 * sizeof(uint32);  // For the message header:  4 bytes for the protocol revision #, 4 bytes for the number-of-entries field, 4 bytes for what code
 1270 
 1271    // For each flattenable field: 4 bytes for the name length, name data, 4 bytes for entry type code, 4 bytes for entry data length, entry data
 1272    for (HashtableIterator<String, MessageField> it(_entries, HTIT_FLAG_NOREGISTER); it.HasData(); it++)
 1273    {
 1274       const MessageField & mf = it.GetValue();
 1275       if (mf.IsFlattenable()) sum += sizeof(uint32) + it.GetKey().FlattenedSize() + sizeof(uint32) + sizeof(uint32) + mf.FlattenedSize();
 1276    }
 1277    return sum;
 1278 }
 1279 
 1280 uint32 Message :: CalculateChecksum(bool countNonFlattenableFields) const 
 1281 {
 1282    uint32 ret = what;
 1283 
 1284    // Calculate the number of flattenable entries (may be less than the total number of entries!)
 1285    for (HashtableIterator<String, MessageField> it(_entries, HTIT_FLAG_NOREGISTER); it.HasData(); it++)
 1286    {
 1287       // Note that I'm deliberately NOT considering the ordering of the fields when computing the checksum!
 1288       const MessageField & mf = it.GetValue();
 1289       if ((countNonFlattenableFields)||(mf.IsFlattenable()))
 1290       {
 1291          uint32 fnChk = it.GetKey().CalculateChecksum();
 1292          ret += fnChk;
 1293          if (fnChk == 0) ret++;  // almost-paranoia 
 1294          ret += (fnChk*mf.CalculateChecksum(countNonFlattenableFields));  // multiplying by fnChck helps catch when two fields were swapped
 1295       }
 1296    }
 1297    return ret;
 1298 }
 1299 
 1300 void Message :: Flatten(uint8 * buffer) const 
 1301 {
 1302    TCHECKPOINT;
 1303 
 1304    // Format:  0. Protocol revision number (4 bytes, always set to CURRENT_PROTOCOL_VERSION)
 1305    //          1. 'what' code (4 bytes)
 1306    //          2. Number of entries (4 bytes)
 1307    //          3. Entry name length (4 bytes)
 1308    //          4. Entry name string (flattened String)
 1309    //          5. Entry type code (4 bytes)
 1310    //          6. Entry data length (4 bytes)
 1311    //          7. Entry data (n bytes)
 1312    //          8. loop to 3 as necessary
 1313 
 1314    // Write current protocol version
 1315    uint32 writeOffset = 0;
 1316    uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(CURRENT_PROTOCOL_VERSION);
 1317    WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
 1318 
 1319    // Write 'what' code
 1320    networkByteOrder = B_HOST_TO_LENDIAN_INT32(what);
 1321    WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
 1322 
 1323    // Remember where to write the number-of-entries value (we'll actually write it at the end of this method)
 1324    uint8 * entryCountPtr = &buffer[writeOffset];
 1325    writeOffset += sizeof(uint32);
 1326 
 1327    // Write entries
 1328    uint32 numFlattenedEntries = 0;
 1329    for (HashtableIterator<String, MessageField> it(_entries, HTIT_FLAG_NOREGISTER); it.HasData(); it++)
 1330    {
 1331       const MessageField & mf = it.GetValue();
 1332       if (mf.IsFlattenable())
 1333       {
 1334          numFlattenedEntries++;
 1335 
 1336          // Write entry name length
 1337          const uint32 keyNameSize = it.GetKey().FlattenedSize();
 1338          networkByteOrder = B_HOST_TO_LENDIAN_INT32(keyNameSize);
 1339          WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
 1340 
 1341          // Write entry name
 1342          it.GetKey().Flatten(&buffer[writeOffset]);
 1343          writeOffset += keyNameSize;
 1344 
 1345          // Write entry type code
 1346          networkByteOrder = B_HOST_TO_LENDIAN_INT32(mf.TypeCode());
 1347          WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
 1348 
 1349          // Write entry data length
 1350          const uint32 dataSize = mf.FlattenedSize();
 1351          networkByteOrder = B_HOST_TO_LENDIAN_INT32(dataSize);
 1352          WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
 1353          
 1354          // Write entry data
 1355          mf.Flatten(&buffer[writeOffset]);
 1356          writeOffset += dataSize;
 1357       }
 1358    }
 1359 
 1360    // Write number-of-entries field (now that we know its final value)
 1361    networkByteOrder = B_HOST_TO_LENDIAN_INT32(numFlattenedEntries);
 1362    memcpy(entryCountPtr, &networkByteOrder, sizeof(uint32));
 1363 }
 1364 
 1365 status_t Message :: Unflatten(const uint8 * buffer, uint32 inputBufferBytes) 
 1366 {
 1367    TCHECKPOINT;
 1368 
 1369    Clear(true);
 1370 
 1371    uint32 readOffset = 0;
 1372    
 1373    status_t ret;
 1374 
 1375    // Read and check protocol version number
 1376    uint32 networkByteOrder;
 1377    if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)).IsError(ret))
 1378    {
 1379       LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Couldn't read message protocol version! (inputBufferBytes=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, inputBufferBytes, ret());
 1380       return ret;
 1381    }
 1382 
 1383    const uint32 messageProtocolVersion = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
 1384    if ((messageProtocolVersion < OLDEST_SUPPORTED_PROTOCOL_VERSION)||(messageProtocolVersion > CURRENT_PROTOCOL_VERSION)) 
 1385    {
 1386       LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Unexpected message protocol version " UINT32_FORMAT_SPEC " (inputBufferBytes=" UINT32_FORMAT_SPEC ")\n", this, messageProtocolVersion, inputBufferBytes);
 1387       return B_BAD_DATA;
 1388    }
 1389    
 1390    // Read 'what' code
 1391    if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)).IsError(ret))
 1392    {
 1393       LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Couldn't read what-code! (inputBufferBytes=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, inputBufferBytes, ret());
 1394       return ret;
 1395    }
 1396    what = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
 1397 
 1398    // Read number of entries
 1399    if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)).IsError(ret))
 1400    {
 1401       LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Couldn't read number-of-entries! (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, inputBufferBytes, what, ret());
 1402       return ret;
 1403    }
 1404 
 1405    const uint32 numEntries         = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
 1406    const uint32 minBytesPerEntry   = (sizeof(uint32)*3);  // name-length + typecode-length + payload-length
 1407    const uint32 maxPossibleEntries = inputBufferBytes / minBytesPerEntry;  // how many fields might possibly fit in (inputBufferBytes)
 1408    if (numEntries > maxPossibleEntries) 
 1409    {
 1410       LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Entries-count is larger than the input buffer could possibly represent! (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC " numEntries=" UINT32_FORMAT_SPEC ", maxPossibleEntries=" UINT32_FORMAT_SPEC ")\n", this, inputBufferBytes, what, numEntries, maxPossibleEntries);
 1411       return B_BAD_DATA;
 1412    }
 1413 
 1414    if (_entries.EnsureSize(numEntries, true).IsError(ret)) return ret;
 1415 
 1416    // Read entries
 1417    for (uint32 i=0; i<numEntries; i++)
 1418    {
 1419       // Read entry name length
 1420       if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)).IsError(ret))
 1421       {
 1422          LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Error reading entry name length! (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC " i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, inputBufferBytes, what, i, numEntries, ret());
 1423          return ret;
 1424       }
 1425 
 1426       const uint32 nameLength = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
 1427       if (nameLength > inputBufferBytes-readOffset) 
 1428       {
 1429          LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Entry name length too long! (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC " i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " nameLength=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC ")\n", this, inputBufferBytes, what, i, numEntries, nameLength, (uint32)(inputBufferBytes-readOffset));
 1430          return B_BAD_DATA;
 1431       }
 1432 
 1433       // Read entry name
 1434       String entryName;
 1435       if (entryName.Unflatten(&buffer[readOffset], nameLength).IsError(ret))
 1436       {
 1437          LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Unable to unflatten entry name! (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC " i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " nameLength=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, inputBufferBytes, what, i, numEntries, nameLength, ret());
 1438          return ret;
 1439       }
 1440       readOffset += nameLength;
 1441 
 1442       // Read entry type code
 1443       if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)).IsError(ret))
 1444       {
 1445          LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Unable to read entry type code! (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC " i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " entryName=[%s] ret=[%s])\n", this, inputBufferBytes, what, i, numEntries, entryName(), ret());
 1446          return ret;
 1447       }
 1448       const uint32 tc = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
 1449 
 1450       // Read entry data length
 1451       if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)).IsError(ret))
 1452       {
 1453          LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Unable to read data length! (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC " i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " tc=" UINT32_FORMAT_SPEC " entryName=[%s]) ret=[%s]\n", this, inputBufferBytes, what, i, numEntries, tc, entryName(), ret());
 1454          return ret;
 1455       }
 1456 
 1457       const uint32 eLength = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
 1458       if (eLength > inputBufferBytes-readOffset) 
 1459       {
 1460          LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Data length is too long! (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC " i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " tc=" UINT32_FORMAT_SPEC " eLength=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " entryName=[%s])\n", this, inputBufferBytes, what, i, numEntries, tc, eLength, (uint32)(inputBufferBytes-readOffset), entryName());
 1461          return B_BAD_DATA;
 1462       }
 1463    
 1464       MessageField * nextEntry = GetOrCreateMessageField(entryName, tc);
 1465       if (nextEntry == NULL) 
 1466       {
 1467          LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Unable to create data field object!  (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC " i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " tc=" UINT32_FORMAT_SPEC " entryName=[%s])\n", this, inputBufferBytes, what, i, numEntries, tc, entryName());
 1468          return B_BAD_DATA;
 1469       }
 1470 
 1471       if (nextEntry->Unflatten(&buffer[readOffset], eLength).IsError(ret))
 1472       {
 1473          LogTime(MUSCLE_LOG_DEBUG, "Message %p:  Unable to unflatten data field object!  (inputBufferBytes=" UINT32_FORMAT_SPEC ", what=" UINT32_FORMAT_SPEC " i=" UINT32_FORMAT_SPEC "/" UINT32_FORMAT_SPEC " tc=" UINT32_FORMAT_SPEC " entryName=[%s] eLength=" UINT32_FORMAT_SPEC ") ret=[%s]\n", this, inputBufferBytes, what, i, numEntries, tc, entryName(), eLength, ret());
 1474          Clear();  // fix for occasional crash bug; we were deleting nextEntry here, *and* in the destructor!
 1475          return ret;
 1476       }
 1477       readOffset += eLength;
 1478    }
 1479    return B_NO_ERROR;
 1480 }
 1481 
 1482 status_t Message :: AddFlatAux(const String & fieldName, const FlatCountableRef & ref, uint32 tc, bool prepend)
 1483 {
 1484    MessageField * field = ref() ? GetOrCreateMessageField(fieldName, tc) : NULL;
 1485    return field ? (prepend ? field->PrependDataItem(&ref, sizeof(ref)) : field->AddDataItem(&ref, sizeof(ref))) : B_TYPE_MISMATCH;
 1486 }
 1487 
 1488 status_t Message :: AddString(const String & fieldName, const String & val) 
 1489 {
 1490    MessageField * mf = GetOrCreateMessageField(fieldName, B_STRING_TYPE);
 1491    return mf ? mf->AddDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 1492 }
 1493 
 1494 status_t Message :: AddInt8(const String & fieldName, int8 val) 
 1495 {
 1496    MessageField * mf = GetOrCreateMessageField(fieldName, B_INT8_TYPE);
 1497    return mf ? mf->AddDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 1498 }
 1499 
 1500 status_t Message :: AddInt16(const String & fieldName, int16 val) 
 1501 {
 1502    MessageField * mf = GetOrCreateMessageField(fieldName, B_INT16_TYPE);
 1503    return mf ? mf->AddDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 1504 }
 1505 
 1506 status_t Message :: AddInt32(const String & fieldName, int32 val) 
 1507 {
 1508    MessageField * mf = GetOrCreateMessageField(fieldName, B_INT32_TYPE);
 1509    return mf ? mf->AddDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 1510 }
 1511 
 1512 status_t Message :: AddInt64(const String & fieldName, int64 val) 
 1513 {
 1514    MessageField * mf = GetOrCreateMessageField(fieldName, B_INT64_TYPE);
 1515    return mf ? mf->AddDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 1516 }
 1517 
 1518 status_t Message :: AddBool(const String & fieldName, bool val) 
 1519 {
 1520    MessageField * mf = GetOrCreateMessageField(fieldName, B_BOOL_TYPE);
 1521    status_t ret = mf ? mf->AddDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 1522    return ret;
 1523 }
 1524 
 1525 status_t Message :: AddFloat(const String & fieldName, float val) 
 1526 {
 1527    MessageField * mf = GetOrCreateMessageField(fieldName, B_FLOAT_TYPE);
 1528    return mf ? mf->AddDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 1529 }
 1530 
 1531 status_t Message :: AddDouble(const String & fieldName, double val) 
 1532 {
 1533    MessageField * mf = GetOrCreateMessageField(fieldName, B_DOUBLE_TYPE);
 1534    return mf ? mf->AddDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 1535 }
 1536 
 1537 status_t Message :: AddPointer(const String & fieldName, const void * ptr) 
 1538 {
 1539    MessageField * mf = GetOrCreateMessageField(fieldName, B_POINTER_TYPE);
 1540    return mf ? mf->AddDataItem(&ptr, sizeof(ptr)) : B_TYPE_MISMATCH;
 1541 }
 1542 
 1543 status_t Message :: AddPoint(const String & fieldName, const Point & point) 
 1544 {
 1545    MessageField * mf = GetOrCreateMessageField(fieldName, B_POINT_TYPE);
 1546    return mf ? mf->AddDataItem(&point, sizeof(point)) : B_TYPE_MISMATCH;
 1547 }
 1548 
 1549 status_t Message :: AddRect(const String & fieldName, const Rect & rect) 
 1550 {
 1551    MessageField * mf = GetOrCreateMessageField(fieldName, B_RECT_TYPE);
 1552    return mf ? mf->AddDataItem(&rect, sizeof(rect)) : B_TYPE_MISMATCH;
 1553 }
 1554 
 1555 status_t Message :: AddTag(const String & fieldName, const RefCountableRef & tag)
 1556 {
 1557    if (tag() == NULL) return B_BAD_ARGUMENT;
 1558    MessageField * mf = GetOrCreateMessageField(fieldName, B_TAG_TYPE);
 1559    return mf ? mf->AddDataItem(&tag, sizeof(tag)) : B_TYPE_MISMATCH;
 1560 }
 1561 
 1562 status_t Message :: AddMessage(const String & fieldName, const MessageRef & ref)
 1563 {
 1564    if (ref() == NULL) return B_BAD_ARGUMENT;
 1565    MessageField * mf = GetOrCreateMessageField(fieldName, B_MESSAGE_TYPE);
 1566    return (mf) ? mf->AddDataItem(&ref, sizeof(ref)) : B_TYPE_MISMATCH;
 1567 }
 1568 
 1569 status_t Message :: AddFlat(const String & fieldName, const FlatCountableRef & ref) 
 1570 {
 1571    FlatCountable * fc = ref();
 1572    if (fc)
 1573    {
 1574       const uint32 tc = fc->TypeCode();
 1575       switch(tc)
 1576       {
 1577          case B_STRING_TYPE:  return B_TYPE_MISMATCH;  // sorry, can't do that (Strings aren't FlatCountables)
 1578          case B_POINT_TYPE:   return B_TYPE_MISMATCH;  // sorry, can't do that (Points aren't FlatCountables)
 1579          case B_RECT_TYPE:    return B_TYPE_MISMATCH;  // sorry, can't do that (Rects aren't FlatCountables)
 1580          case B_MESSAGE_TYPE: return AddMessage(fieldName, MessageRef(ref.GetRefCountableRef(), true));
 1581          default:             return AddFlatAux(fieldName, ref, tc, false);
 1582       }
 1583    }
 1584    return B_BAD_ARGUMENT;   
 1585 }
 1586 
 1587 uint32 Message :: GetElementSize(uint32 type)
 1588 {
 1589    switch(type)
 1590    {
 1591       case B_BOOL_TYPE:    return sizeof(bool);
 1592       case B_DOUBLE_TYPE:  return sizeof(double);
 1593       case B_POINTER_TYPE: return sizeof(void *);
 1594       case B_POINT_TYPE:   return sizeof(Point);
 1595       case B_RECT_TYPE:    return sizeof(Rect);
 1596       case B_FLOAT_TYPE:   return sizeof(float);
 1597       case B_INT64_TYPE:   return sizeof(int64);
 1598       case B_INT32_TYPE:   return sizeof(int32);
 1599       case B_INT16_TYPE:   return sizeof(int16);
 1600       case B_INT8_TYPE:    return sizeof(int8);
 1601       case B_MESSAGE_TYPE: return sizeof(MessageRef);
 1602       case B_STRING_TYPE:  return sizeof(String);
 1603       default:             return 0;
 1604    }
 1605 }
 1606 
 1607 status_t Message :: AddDataAux(const String & fieldName, const void * data, uint32 numBytes, uint32 tc, bool prepend)
 1608 {
 1609    if (numBytes == 0) return B_BAD_ARGUMENT;   // can't add 0 bytes, that's silly
 1610    if (tc == B_STRING_TYPE) 
 1611    {
 1612       String temp((const char *)data);  // kept separate to avoid BeOS gcc optimizer bug (otherwise -O3 crashes here)
 1613       return prepend ? PrependString(fieldName, temp) : AddString(fieldName, temp);
 1614    }
 1615 
 1616    // for primitive types, we do this:
 1617    bool isVariableSize = false;
 1618    uint32 elementSize = GetElementSize(tc);
 1619    if (elementSize == 0) 
 1620    {
 1621        // zero indicates a variable-sized data item; we will use a ByteBuffer to hold it.
 1622        isVariableSize = true;
 1623        elementSize    = numBytes;
 1624        if (elementSize == 0) return B_TYPE_MISMATCH;
 1625    }
 1626    if (numBytes % elementSize) return B_BAD_ARGUMENT;  // Can't add half an element, silly!
 1627 
 1628    MessageField * mf = GetOrCreateMessageField(fieldName, tc);
 1629    if (mf == NULL) return B_TYPE_MISMATCH;
 1630 
 1631    status_t ret;
 1632    const uint32 numElements = numBytes/elementSize;
 1633    const uint8 * dataBuf = (const uint8 *) data;
 1634    for (uint32 i=0; i<numElements; i++) 
 1635    {
 1636       FlatCountableRef fcRef;
 1637       const void * dataToAdd = dataBuf ? &dataBuf[i*elementSize] : NULL;
 1638       uint32 addSize = elementSize;
 1639       if (isVariableSize)
 1640       {
 1641          ByteBufferRef bufRef = GetByteBufferFromPool(elementSize, (const uint8 *)dataToAdd);
 1642          if (bufRef() == NULL) RETURN_OUT_OF_MEMORY;
 1643          fcRef.SetFromRefCountableRef(bufRef.GetRefCountableRef());
 1644          dataToAdd = &fcRef;
 1645          addSize = sizeof(fcRef);
 1646       }
 1647       if ((prepend ? mf->PrependDataItem(dataToAdd, addSize) : mf->AddDataItem(dataToAdd, addSize)).IsError(ret)) return ret;
 1648    }
 1649    return B_NO_ERROR;
 1650 }
 1651 
 1652 void * Message :: GetPointerToNormalizedFieldData(const String & fieldName, uint32 * retNumItems, uint32 typeCode) 
 1653 {
 1654    MessageField * e = GetMessageField(fieldName, typeCode);
 1655    if (e)
 1656    {
 1657       e->Normalize();
 1658 
 1659       const void * ptr;
 1660       if (e->FindDataItem(0, &ptr) == B_NO_ERROR)  // must be called AFTER e->Normalize()
 1661       {
 1662          if (retNumItems) *retNumItems = e->GetNumItems();
 1663          return const_cast<void *>(ptr);
 1664       }
 1665    }
 1666    return NULL;
 1667 }
 1668 
 1669 status_t Message :: EnsureFieldIsPrivate(const String & fieldName) 
 1670 {
 1671    MessageField * mf = GetMessageField(fieldName, B_ANY_TYPE);
 1672    return mf ? mf->EnsurePrivate() : B_DATA_NOT_FOUND;
 1673 }
 1674 
 1675 status_t Message :: RemoveData(const String & fieldName, uint32 index) 
 1676 {
 1677    MessageField * mf = GetMessageField(fieldName, B_ANY_TYPE);
 1678    if (mf) 
 1679    {
 1680       const status_t ret = mf->RemoveDataItem(index);
 1681       return mf->IsEmpty() ? RemoveName(fieldName) : ret;
 1682    }
 1683    else return B_DATA_NOT_FOUND;
 1684 }
 1685 
 1686 status_t Message :: FindString(const String & fieldName, uint32 index, const char * & setMe) const
 1687 {
 1688    const MessageField * mf = GetMessageField(fieldName, B_STRING_TYPE);
 1689    if ((mf)&&(index < mf->GetNumItems()))
 1690    {
 1691       setMe = mf->GetItemAtAsString(index)();
 1692       return B_NO_ERROR;
 1693    }
 1694    else return B_DATA_NOT_FOUND;
 1695 }
 1696 
 1697 status_t Message :: FindString(const String & fieldName, uint32 index, const String ** setMe) const 
 1698 {
 1699    const MessageField * mf = GetMessageField(fieldName, B_STRING_TYPE);
 1700    if ((mf)&&(index < mf->GetNumItems()))
 1701    {
 1702       *setMe = &mf->GetItemAtAsString(index);
 1703       return B_NO_ERROR;
 1704    }
 1705    else return B_DATA_NOT_FOUND;
 1706 }
 1707 
 1708 status_t Message :: FindString(const String & fieldName, uint32 index, String & str) const 
 1709 {
 1710    const MessageField * mf = GetMessageField(fieldName, B_STRING_TYPE);
 1711    if ((mf)&&(index < mf->GetNumItems()))
 1712    {
 1713       str = mf->GetItemAtAsString(index);
 1714       return B_NO_ERROR;
 1715    }
 1716    else return B_DATA_NOT_FOUND;
 1717 }
 1718 
 1719 const uint8 * Message :: FindFlatAux(const MessageField * mf, uint32 index, uint32 & retNumBytes, const FlatCountable ** optRetFCPtr) const
 1720 {
 1721    if (optRetFCPtr) *optRetFCPtr = NULL;
 1722    if (index >= mf->GetNumItems()) return NULL;
 1723 
 1724    RefCountableRef rcRef = mf->GetItemAtAsRefCountableRef(index);
 1725    const ByteBuffer * bb = dynamic_cast<const ByteBuffer *>(rcRef());
 1726 
 1727    if (bb)
 1728    {
 1729       retNumBytes = bb->GetNumBytes();
 1730       return bb->GetBuffer();
 1731    }
 1732    else
 1733    {
 1734       FlatCountable * fc = dynamic_cast<FlatCountable *>(rcRef());
 1735       if (fc)
 1736       {
 1737          if (optRetFCPtr) (*optRetFCPtr) = fc;
 1738          return NULL;
 1739       }
 1740    }
 1741 
 1742    const void * data; 
 1743    const status_t ret = mf->FindDataItem(index, &data);
 1744    if (ret == B_NO_ERROR) 
 1745    { 
 1746       retNumBytes = mf->GetItemSize(index); 
 1747       return (const uint8 *)data;
 1748    }
 1749    else return NULL;
 1750 }
 1751 
 1752 status_t Message :: FindFlat(const String & fieldName, uint32 index, FlatCountableRef & ref) const
 1753 {
 1754    TCHECKPOINT;
 1755 
 1756    const MessageField * mf = GetMessageField(fieldName, B_ANY_TYPE);
 1757    if ((mf)&&(index < mf->GetNumItems()))
 1758    {
 1759       RefCountableRef rcRef = mf->GetItemAtAsRefCountableRef(index);
 1760       ref.SetFromRefCountableRef(rcRef);
 1761       return ref() ? B_NO_ERROR : B_TYPE_MISMATCH;
 1762    }
 1763    else return B_DATA_NOT_FOUND;
 1764 }
 1765 
 1766 status_t Message :: FindData(const String & fieldName, uint32 tc, uint32 index, const void ** data, uint32 * setSize) const
 1767 {
 1768    TCHECKPOINT;
 1769 
 1770    const MessageField * field = GetMessageField(fieldName, tc);
 1771    if (field == NULL) return B_DATA_NOT_FOUND;
 1772 
 1773    status_t ret;
 1774    if (field->FindDataItem(index, data).IsOK(ret))
 1775    {
 1776       switch(tc)
 1777       {
 1778          case B_STRING_TYPE:  
 1779          {
 1780             const String * str = (const String *) (*data);
 1781             *data = str->Cstr();  
 1782             if (setSize) *setSize = str->FlattenedSize();
 1783          }
 1784          break;
 1785 
 1786          case B_ANY_TYPE:
 1787             return (field->TypeCode() == B_ANY_TYPE) ? B_BAD_OBJECT : FindData(fieldName, field->TypeCode(), 0, data, setSize);
 1788          break;
 1789 
 1790          default:
 1791          {
 1792             const uint32 es = GetElementSize(tc);
 1793             if (es > 0) 
 1794             {
 1795                if (setSize) *setSize = es;
 1796             }
 1797             else
 1798             {
 1799                // But for user-generated types, we need to get a pointer to the actual data, not just the ref
 1800                const FlatCountableRef * fcRef = (const FlatCountableRef *)(*data);
 1801                const ByteBuffer * buf = dynamic_cast<ByteBuffer *>(fcRef->GetItemPointer());
 1802                if (buf)
 1803                {
 1804                   const void * b = buf->GetBuffer();
 1805                   if (b)
 1806                   {
 1807                      *data = b;
 1808                      if (setSize) *setSize = buf->GetNumBytes();
 1809                      return B_NO_ERROR;
 1810                   }
 1811                }
 1812                return B_TYPE_MISMATCH;
 1813             }
 1814          }
 1815          break;
 1816       }
 1817       return B_NO_ERROR;
 1818    }
 1819    else return ret;
 1820 }
 1821 
 1822 status_t Message :: FindDataItemAux(const String & fieldName, uint32 index, uint32 tc, void * setValue, uint32 valueSize) const
 1823 {
 1824    const MessageField * field = GetMessageField(fieldName, tc);
 1825    if (field == NULL) return B_DATA_NOT_FOUND;
 1826 
 1827    const void * addressOfValue;
 1828    const status_t ret = field->FindDataItem(index, &addressOfValue);
 1829    if (ret != B_NO_ERROR) return ret;
 1830    memcpy(setValue, addressOfValue, valueSize);
 1831    return B_NO_ERROR;
 1832 }
 1833 
 1834 status_t Message :: FindPoint(const String & fieldName, uint32 index, Point & point) const 
 1835 {
 1836    const MessageField * mf = GetMessageField(fieldName, B_POINT_TYPE);
 1837    if ((mf)&&(index < mf->GetNumItems())) 
 1838    {
 1839       point = mf->GetItemAtAsPoint(index);
 1840       return B_NO_ERROR;
 1841    }
 1842    else return B_DATA_NOT_FOUND;
 1843 }
 1844 
 1845 status_t Message :: FindRect(const String & fieldName, uint32 index, Rect & rect) const 
 1846 {
 1847    const MessageField * mf = GetMessageField(fieldName, B_RECT_TYPE);
 1848    if ((mf)&&(index < mf->GetNumItems()))
 1849    {
 1850       rect = mf->GetItemAtAsRect(index);
 1851       return B_NO_ERROR;
 1852    }
 1853    else return B_DATA_NOT_FOUND;
 1854 }
 1855 
 1856 status_t Message :: FindTag(const String & fieldName, uint32 index, RefCountableRef & tag) const 
 1857 {
 1858    const MessageField * mf = GetMessageField(fieldName, B_TAG_TYPE);
 1859    if ((mf)&&(index < mf->GetNumItems()))
 1860    {
 1861       tag = mf->GetItemAtAsRefCountableRef(index);
 1862       return B_NO_ERROR;
 1863    }
 1864    else return B_DATA_NOT_FOUND;
 1865 }
 1866 
 1867 status_t Message :: FindMessage(const String & fieldName, uint32 index, Message & msg) const 
 1868 {
 1869    status_t ret;
 1870    MessageRef msgRef;
 1871    if (FindMessage(fieldName, index, msgRef).IsOK(ret))
 1872    {
 1873       const Message * m = msgRef();
 1874       if (m) 
 1875       {
 1876          msg = *m;
 1877          return B_NO_ERROR;
 1878       }
 1879       else return B_BAD_OBJECT;
 1880    }
 1881    else return ret;
 1882 }
 1883 
 1884 status_t Message :: FindMessage(const String & fieldName, uint32 index, MessageRef & ref) const
 1885 {
 1886    const MessageField * mf = GetMessageField(fieldName, B_MESSAGE_TYPE);
 1887    if ((mf)&&(index < mf->GetNumItems()))
 1888    {
 1889       RefCountableRef rcRef = mf->GetItemAtAsRefCountableRef(index);
 1890       if (rcRef())
 1891       {
 1892          ref.SetFromRefCountableRef(rcRef);
 1893          return ref() ? B_NO_ERROR : B_TYPE_MISMATCH;
 1894       }
 1895       else return B_BAD_OBJECT;
 1896    }
 1897    else return B_DATA_NOT_FOUND;
 1898 }
 1899 
 1900 status_t Message :: FindDataPointer(const String & fieldName, uint32 tc, uint32 index, void ** data, uint32 * setSize) const 
 1901 {
 1902    const void * dataLoc;
 1903    status_t ret;
 1904    if (FindData(fieldName, tc, index, &dataLoc, setSize).IsOK(ret))
 1905    {
 1906       *data = (void *) dataLoc;  // breaks const correctness, but oh well
 1907       return B_NO_ERROR;
 1908    }
 1909    else return ret;
 1910 }
 1911 
 1912 status_t Message :: ReplaceString(bool okayToAdd, const String & fieldName, uint32 index, const String & string) 
 1913 {
 1914    MessageField * field = GetMessageField(fieldName, B_STRING_TYPE);
 1915    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddString(fieldName, string);
 1916    return field ? field->ReplaceDataItem(index, &string, sizeof(string)) : B_DATA_NOT_FOUND;
 1917 }
 1918 
 1919 status_t Message :: ReplaceFlatAux(bool okayToAdd, const String & fieldName, uint32 index, const ByteBufferRef & bufRef, uint32 tc) 
 1920 {
 1921    FlatCountableRef fcRef; fcRef.SetFromRefCountableRefUnchecked(bufRef.GetRefCountableRef());
 1922    return ReplaceDataAux(okayToAdd, fieldName, index, &fcRef, sizeof(fcRef), tc);
 1923 }
 1924 
 1925 status_t Message :: ReplaceDataAux(bool okayToAdd, const String & fieldName, uint32 index, void * dataBuf, uint32 bufSize, uint32 tc)
 1926 {
 1927    MessageField * field = GetMessageField(fieldName, tc);
 1928    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddDataAux(fieldName, dataBuf, bufSize, tc, false);
 1929    return field ? field->ReplaceDataItem(index, dataBuf, bufSize) : B_DATA_NOT_FOUND;
 1930 }
 1931 
 1932 status_t Message :: ReplaceInt8(bool okayToAdd, const String & fieldName, uint32 index, int8 val) 
 1933 {
 1934    MessageField * field = GetMessageField(fieldName, B_INT8_TYPE);
 1935    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddInt8(fieldName, val);
 1936    return field ? field->ReplaceDataItem(index, &val, sizeof(val)) : B_DATA_NOT_FOUND;
 1937 }
 1938 
 1939 status_t Message :: ReplaceInt16(bool okayToAdd, const String & fieldName, uint32 index, int16 val) 
 1940 {
 1941    MessageField * field = GetMessageField(fieldName, B_INT16_TYPE);
 1942    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddInt16(fieldName, val);
 1943    return field ? field->ReplaceDataItem(index, &val, sizeof(val)) : B_DATA_NOT_FOUND;
 1944 }
 1945 
 1946 status_t Message :: ReplaceInt32(bool okayToAdd, const String & fieldName, uint32 index, int32 val) 
 1947 {
 1948    MessageField * field = GetMessageField(fieldName, B_INT32_TYPE);
 1949    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddInt32(fieldName, val);
 1950    return field ? field->ReplaceDataItem(index, &val, sizeof(val)) : B_DATA_NOT_FOUND;
 1951 }
 1952 
 1953 status_t Message :: ReplaceInt64(bool okayToAdd, const String & fieldName, uint32 index, int64 val) 
 1954 {
 1955    MessageField * field = GetMessageField(fieldName, B_INT64_TYPE);
 1956    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddInt64(fieldName, val);
 1957    return field ? field->ReplaceDataItem(index, &val, sizeof(val)) : B_DATA_NOT_FOUND;
 1958 }
 1959 
 1960 status_t Message :: ReplaceBool(bool okayToAdd, const String & fieldName, uint32 index, bool val) 
 1961 {
 1962    MessageField * field = GetMessageField(fieldName, B_BOOL_TYPE);
 1963    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddBool(fieldName, val);
 1964    return field ? field->ReplaceDataItem(index, &val, sizeof(val)) : B_DATA_NOT_FOUND;
 1965 }
 1966 
 1967 status_t Message :: ReplaceFloat(bool okayToAdd, const String & fieldName, uint32 index, float val) 
 1968 {
 1969    MessageField * field = GetMessageField(fieldName, B_FLOAT_TYPE);
 1970    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddFloat(fieldName, val);
 1971    return field ? field->ReplaceDataItem(index, &val, sizeof(val)) : B_DATA_NOT_FOUND;
 1972 }
 1973 
 1974 status_t Message :: ReplaceDouble(bool okayToAdd, const String & fieldName, uint32 index, double val) 
 1975 {
 1976    MessageField * field = GetMessageField(fieldName, B_DOUBLE_TYPE);
 1977    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddDouble(fieldName, val);
 1978    return field ? field->ReplaceDataItem(index, &val, sizeof(val)) : B_DATA_NOT_FOUND;
 1979 }
 1980 
 1981 status_t Message :: ReplacePointer(bool okayToAdd, const String & fieldName, uint32 index, const void * ptr) 
 1982 {
 1983    MessageField * field = GetMessageField(fieldName, B_POINTER_TYPE);
 1984    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddPointer(fieldName, ptr);
 1985    return field ? field->ReplaceDataItem(index, &ptr, sizeof(ptr)) : B_DATA_NOT_FOUND;
 1986 }
 1987 
 1988 status_t Message :: ReplacePoint(bool okayToAdd, const String & fieldName, uint32 index, const Point &point) 
 1989 {
 1990    MessageField * field = GetMessageField(fieldName, B_POINT_TYPE);
 1991    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddPoint(fieldName, point);
 1992    return field ? field->ReplaceDataItem(index, &point, sizeof(point)) : B_DATA_NOT_FOUND;
 1993 }
 1994 
 1995 status_t Message :: ReplaceRect(bool okayToAdd, const String & fieldName, uint32 index, const Rect &rect) 
 1996 {
 1997    MessageField * field = GetMessageField(fieldName, B_RECT_TYPE);
 1998    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddRect(fieldName, rect);
 1999    return field ? field->ReplaceDataItem(index, &rect, sizeof(rect)) : B_DATA_NOT_FOUND;
 2000 }
 2001 
 2002 status_t Message :: ReplaceTag(bool okayToAdd, const String & fieldName, uint32 index, const RefCountableRef & tag) 
 2003 {
 2004    if (tag() == NULL) return B_BAD_ARGUMENT;
 2005    MessageField * field = GetMessageField(fieldName, B_TAG_TYPE);
 2006    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddTag(fieldName, tag);
 2007    return field ? field->ReplaceDataItem(index, &tag, sizeof(tag)) : B_DATA_NOT_FOUND;
 2008 }
 2009 
 2010 status_t Message :: ReplaceMessage(bool okayToAdd, const String & fieldName, uint32 index, const MessageRef & msgRef)
 2011 {
 2012    if (msgRef() == NULL) return B_BAD_ARGUMENT;
 2013    MessageField * field = GetMessageField(fieldName, B_MESSAGE_TYPE);
 2014    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddMessage(fieldName, msgRef);
 2015    if (field) return field->ReplaceDataItem(index, &msgRef, sizeof(msgRef));
 2016    return B_DATA_NOT_FOUND;
 2017 }
 2018 
 2019 status_t Message :: ReplaceFlat(bool okayToAdd, const String & fieldName, uint32 index, const FlatCountableRef & ref) 
 2020 {
 2021    const FlatCountable * fc = ref();
 2022    if (fc)
 2023    {
 2024       const uint32 tc = fc->TypeCode();
 2025       MessageField * field = GetMessageField(fieldName, tc);
 2026       if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddFlat(fieldName, ref);
 2027       if (field)
 2028       { 
 2029          switch(tc)
 2030          {
 2031             case B_MESSAGE_TYPE:  
 2032                return (dynamic_cast<const Message *>(fc)) ? ReplaceMessage(okayToAdd, fieldName, index, MessageRef(ref.GetRefCountableRef(), true)) : B_TYPE_MISMATCH;
 2033 
 2034             default:              
 2035                if (GetElementSize(tc) == 0) return field->ReplaceFlatCountableDataItem(index, ref);
 2036             break;
 2037          }
 2038       }
 2039    }
 2040    return B_BAD_ARGUMENT;
 2041 }
 2042 
 2043 status_t Message :: ReplaceData(bool okayToAdd, const String & fieldName, uint32 type, uint32 index, const void * data, uint32 numBytes) 
 2044 {
 2045    TCHECKPOINT;
 2046 
 2047    if (type == B_STRING_TYPE) 
 2048    {   
 2049       String temp((const char *)data);  // temp to avoid gcc optimizer bug
 2050       return ReplaceString(okayToAdd, fieldName, index, temp);
 2051    }
 2052    MessageField * field = GetMessageField(fieldName, type);
 2053    if ((okayToAdd)&&((field == NULL)||(index >= field->GetNumItems()))) return AddDataAux(fieldName, data, numBytes, type, false);
 2054    if (field == NULL) return B_DATA_NOT_FOUND;
 2055    
 2056    // for primitive types, we do this:
 2057    bool isVariableSize = false;
 2058    uint32 elementSize = GetElementSize(type);
 2059    if (elementSize == 0) 
 2060    {
 2061       // zero indicates a variable-sized data item
 2062       isVariableSize = true;
 2063       elementSize = numBytes;
 2064       if (elementSize == 0) return B_TYPE_MISMATCH;
 2065    }
 2066 
 2067    if (numBytes % elementSize) return B_BAD_ARGUMENT;  // Can't add half an element, silly!
 2068    const uint32 numElements = numBytes / elementSize;
 2069    const uint8 * dataBuf = (const uint8 *) data;
 2070    for (uint32 i=index; i<index+numElements; i++) 
 2071    {
 2072       FlatCountableRef ref;
 2073       const void * dataToAdd = &dataBuf[i*elementSize];
 2074       uint32 addSize = elementSize;
 2075       if (isVariableSize)
 2076       {
 2077          ref.SetFromRefCountableRef(GetByteBufferFromPool(elementSize, (const uint8 *)dataToAdd).GetRefCountableRef());
 2078          if (ref() == NULL) RETURN_OUT_OF_MEMORY;
 2079          dataToAdd = &ref;
 2080          addSize = sizeof(ref);
 2081       }
 2082 
 2083       status_t ret;
 2084       if (field->ReplaceDataItem(i, dataToAdd, addSize).IsError(ret)) return ret;
 2085    }
 2086    return B_NO_ERROR;
 2087 }
 2088 
 2089 uint32 Message :: GetNumValuesInName(const String & fieldName, uint32 type) const
 2090 {
 2091    const MessageField * field = GetMessageField(fieldName, type);
 2092    return field ? field->GetNumItems() : 0;
 2093 }
 2094 
 2095 uint32 Message :: GetFieldTypeForName(const String & fieldName, uint32 defaultTypeCode) const
 2096 {
 2097    const MessageField * field = GetMessageField(fieldName, B_ANY_TYPE);
 2098    return field ? field->TypeCode() : defaultTypeCode;
 2099 }
 2100 
 2101 status_t Message :: CopyName(const String & oldFieldName, Message & copyTo, const String & newFieldName) const
 2102 {
 2103    if ((this == &copyTo)&&(oldFieldName == newFieldName)) return B_NO_ERROR;  // already done!
 2104 
 2105    const MessageField * mf = GetMessageField(oldFieldName, B_ANY_TYPE);
 2106    MessageField * newMF = mf ? copyTo._entries.PutAndGet(newFieldName, *mf) : NULL;
 2107    return newMF ? newMF->EnsurePrivate() : B_DATA_NOT_FOUND;
 2108 }
 2109 
 2110 status_t Message :: ShareName(const String & oldFieldName, Message & shareTo, const String & newFieldName) const
 2111 {
 2112    if ((this == &shareTo)&&(oldFieldName == newFieldName)) return B_NO_ERROR;  // already done!
 2113 
 2114    const MessageField * mf = GetMessageField(oldFieldName, B_ANY_TYPE);
 2115    if (mf == NULL) return B_DATA_NOT_FOUND;
 2116 
 2117    // for non-array fields I'm falling back to copying rather than forcing a const violation
 2118    return mf->HasArray() ? shareTo._entries.Put(newFieldName, *mf) : CopyName(oldFieldName, shareTo, newFieldName);
 2119 }
 2120 
 2121 status_t Message :: MoveName(const String & oldFieldName, Message & moveTo, const String & newFieldName)
 2122 {
 2123    if ((this == &moveTo)&&(oldFieldName == newFieldName)) return B_NO_ERROR;  // already done!
 2124 
 2125    const MessageField * mf = GetMessageField(oldFieldName, B_ANY_TYPE);
 2126    if (mf == NULL) return B_DATA_NOT_FOUND;
 2127 
 2128    status_t ret;
 2129    if (moveTo._entries.Put(newFieldName, *mf).IsOK(ret))
 2130    {
 2131       (void) _entries.Remove(oldFieldName);
 2132       return B_NO_ERROR;
 2133    }
 2134    else return ret;
 2135 }
 2136 
 2137 status_t Message :: PrependString(const String & fieldName, const String & val) 
 2138 {
 2139    MessageField * mf = GetOrCreateMessageField(fieldName, B_STRING_TYPE);
 2140    return mf ? mf->PrependDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 2141 }
 2142 
 2143 status_t Message :: PrependInt8(const String & fieldName, int8 val) 
 2144 {
 2145    MessageField * mf = GetOrCreateMessageField(fieldName, B_INT8_TYPE);
 2146    return mf ? mf->PrependDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 2147 }
 2148 
 2149 status_t Message :: PrependInt16(const String & fieldName, int16 val) 
 2150 {
 2151    MessageField * mf = GetOrCreateMessageField(fieldName, B_INT16_TYPE);
 2152    return mf ? mf->PrependDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 2153 }
 2154 
 2155 status_t Message :: PrependInt32(const String & fieldName, int32 val) 
 2156 {
 2157    MessageField * mf = GetOrCreateMessageField(fieldName, B_INT32_TYPE);
 2158    return mf ? mf->PrependDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 2159 }
 2160 
 2161 status_t Message :: PrependInt64(const String & fieldName, int64 val) 
 2162 {
 2163    MessageField * mf = GetOrCreateMessageField(fieldName, B_INT64_TYPE);
 2164    return mf ? mf->PrependDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 2165 }
 2166 
 2167 status_t Message :: PrependBool(const String & fieldName, bool val) 
 2168 {
 2169    MessageField * mf = GetOrCreateMessageField(fieldName, B_BOOL_TYPE);
 2170    return mf ? mf->PrependDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 2171 }
 2172 
 2173 status_t Message :: PrependFloat(const String & fieldName, float val) 
 2174 {
 2175    MessageField * mf = GetOrCreateMessageField(fieldName, B_FLOAT_TYPE);
 2176    return mf ? mf->PrependDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 2177 }
 2178 
 2179 status_t Message :: PrependDouble(const String & fieldName, double val) 
 2180 {
 2181    MessageField * mf = GetOrCreateMessageField(fieldName, B_DOUBLE_TYPE);
 2182    return mf ? mf->PrependDataItem(&val, sizeof(val)) : B_TYPE_MISMATCH;
 2183 }
 2184 
 2185 status_t Message :: PrependPointer(const String & fieldName, const void * ptr) 
 2186 {
 2187    MessageField * mf = GetOrCreateMessageField(fieldName, B_POINTER_TYPE);
 2188    return mf ? mf->PrependDataItem(&ptr, sizeof(ptr)) : B_TYPE_MISMATCH;
 2189 }
 2190 
 2191 status_t Message :: PrependPoint(const String & fieldName, const Point & point) 
 2192 {
 2193    MessageField * mf = GetOrCreateMessageField(fieldName, B_POINT_TYPE);
 2194    return mf ? mf->PrependDataItem(&point, sizeof(point)) : B_TYPE_MISMATCH;
 2195 }
 2196 
 2197 status_t Message :: PrependRect(const String & fieldName, const Rect & rect) 
 2198 {
 2199    MessageField * mf = GetOrCreateMessageField(fieldName, B_RECT_TYPE);
 2200    return mf ? mf->PrependDataItem(&rect, sizeof(rect)) : B_TYPE_MISMATCH;
 2201 }
 2202 
 2203 status_t Message :: PrependTag(const String & fieldName, const RefCountableRef & tag) 
 2204 {
 2205    if (tag() == NULL) return B_BAD_ARGUMENT;
 2206    MessageField * mf = GetOrCreateMessageField(fieldName, B_TAG_TYPE);
 2207    return mf ? mf->PrependDataItem(&tag, sizeof(tag)) : B_TYPE_MISMATCH;
 2208 }
 2209 
 2210 status_t Message :: PrependMessage(const String & fieldName, const MessageRef & ref)
 2211 {
 2212    if (ref() == NULL) return B_BAD_ARGUMENT;
 2213    MessageField * mf = GetOrCreateMessageField(fieldName, B_MESSAGE_TYPE);
 2214    return mf ? mf->PrependDataItem(&ref, sizeof(ref)) : B_TYPE_MISMATCH;
 2215 }
 2216 
 2217 status_t Message :: PrependFlat(const String & fieldName, const FlatCountableRef & ref)
 2218 {
 2219    FlatCountable * fc = ref();
 2220    if (fc)
 2221    {
 2222       const uint32 tc = fc->TypeCode();
 2223       switch(tc)
 2224       {
 2225          case B_STRING_TYPE:  return B_TYPE_MISMATCH;  // sorry, can't do that (Strings aren't FlatCountables)
 2226          case B_POINT_TYPE:   return B_TYPE_MISMATCH;  // sorry, can't do that (Strings aren't FlatCountables)
 2227          case B_RECT_TYPE:    return B_TYPE_MISMATCH;  // sorry, can't do that (Strings aren't FlatCountables)
 2228          case B_MESSAGE_TYPE: return PrependMessage(fieldName, MessageRef(ref.GetRefCountableRef(), true)); 
 2229          default:             return AddFlatAux(fieldName, ref, tc, true);
 2230       }
 2231    }
 2232    return B_BAD_ARGUMENT;   
 2233 }
 2234 
 2235 status_t Message :: CopyFromImplementation(const Flattenable & copyFrom)
 2236 {
 2237    const Message * cMsg = dynamic_cast<const Message *>(&copyFrom);
 2238    if (cMsg)
 2239    {
 2240       *this = *cMsg;
 2241       return B_NO_ERROR;
 2242    }
 2243    else return FlatCountable::CopyFromImplementation(copyFrom);
 2244 }
 2245 
 2246 bool Message :: operator == (const Message & rhs) const
 2247 {
 2248    return ((this == &rhs)||((what == rhs.what)&&(GetNumNames() == rhs.GetNumNames())&&(FieldsAreSubsetOf(rhs, true))));
 2249 }
 2250 
 2251 bool Message :: FieldsAreSubsetOf(const Message & rhs, bool compareContents) const
 2252 {
 2253    TCHECKPOINT;
 2254 
 2255    // Returns true iff every one of our fields has a like-named, liked-typed, equal-length field in (rhs).
 2256    for (HashtableIterator<String, MessageField> iter(_entries, HTIT_FLAG_NOREGISTER); iter.HasData(); iter++)
 2257    {
 2258       const MessageField * hisNextValue = rhs._entries.Get(iter.GetKey());
 2259       if ((hisNextValue == NULL)||(iter.GetValue().IsEqualTo(*hisNextValue, compareContents) == false)) return false;
 2260    }
 2261    return true;
 2262 }
 2263 
 2264 void Message :: SwapContents(Message & swapWith)
 2265 {
 2266    muscleSwap(what, swapWith.what);
 2267    _entries.SwapContents(swapWith._entries);
 2268 }
 2269 
 2270 #define CONSTRUCT_DATA_TYPE(TheType) {(void) new (_union._data) TheType();}
 2271 #define  DESTRUCT_DATA_TYPE(TheType) {TheType * MUSCLE_MAY_ALIAS p = reinterpret_cast<TheType *>(_union._data); p->~TheType();}
 2272 
 2273 void MessageField :: ChangeType(uint8 newType)
 2274 {
 2275    if (newType != _dataType)
 2276    {
 2277       switch(_dataType)
 2278       {
 2279          case DATA_TYPE_POINT:  DESTRUCT_DATA_TYPE(Point);            break;
 2280          case DATA_TYPE_RECT:   DESTRUCT_DATA_TYPE(Rect);             break;
 2281          case DATA_TYPE_STRING: DESTRUCT_DATA_TYPE(String);           break;
 2282          case DATA_TYPE_REF:    DESTRUCT_DATA_TYPE(RefCountableRef);  break;
 2283          default:               /* empty */                           break;
 2284       }
 2285       _dataType = newType;
 2286       switch(_dataType)
 2287       {
 2288          case DATA_TYPE_POINT:  CONSTRUCT_DATA_TYPE(Point);           break;
 2289          case DATA_TYPE_RECT:   CONSTRUCT_DATA_TYPE(Rect);            break;
 2290          case DATA_TYPE_STRING: CONSTRUCT_DATA_TYPE(String);          break;
 2291          case DATA_TYPE_REF:    CONSTRUCT_DATA_TYPE(RefCountableRef); break;
 2292          default:               /* empty */                           break;
 2293       }
 2294    }
 2295 }
 2296 
 2297 // All methods below this point are assumed to be called only when the MessageField has no AbstractDataArray object instantiated
 2298 
 2299 uint32 MessageField :: SingleFlattenedSize() const
 2300 {
 2301    MASSERT(_state == FIELD_STATE_INLINE, "SingleFlattenedSize() called on empty field");
 2302 
 2303    if (_typeCode == B_BOOL_TYPE) return sizeof(uint8);                                // bools are always flattened to one uint8 each
 2304    else
 2305    {
 2306       const uint32 itemSizeBytes = SingleGetItemSize(0);
 2307            if (_typeCode == B_MESSAGE_TYPE) return sizeof(uint32)+itemSizeBytes;  // special case: Message fields don't write number-of-items, for historical reasons
 2308       else if (_typeCode == B_STRING_TYPE)  return sizeof(uint32)+sizeof(uint32)+GetInlineItemAsString().FlattenedSize();
 2309       else
 2310       {
 2311          const uint32 fixedSize = Message::GetElementSize(_typeCode);
 2312          if (fixedSize > 0) return fixedSize;  // for fixed-size elements with known size, no headers are necessary
 2313 
 2314          // if we got here, then it's the one uint32 for the object-count, one uint32 for the size-of-object, plus the space for the object itself
 2315          const FlatCountable * fc = dynamic_cast<FlatCountable *>(GetInlineItemAsRefCountableRef()());
 2316          return fc ? (sizeof(uint32)+sizeof(uint32)+fc->FlattenedSize()) : 0;
 2317       }
 2318    }
 2319 }
 2320 
 2321 void MessageField :: SingleFlatten(uint8 *buffer) const
 2322 {
 2323    MASSERT(_state == FIELD_STATE_INLINE, "SingleFlatten() called on empty field");
 2324 
 2325    switch(_typeCode)
 2326    {
 2327       case B_BOOL_TYPE:    *buffer = (GetInlineItemAsBool() ? 1 : 0);                                                 break;
 2328       case B_DOUBLE_TYPE:  {uint64 d = B_HOST_TO_LENDIAN_IDOUBLE(GetInlineItemAsDouble()); muscleCopyOut(buffer, d);} break;
 2329       case B_FLOAT_TYPE:   {uint32 f = B_HOST_TO_LENDIAN_IFLOAT(GetInlineItemAsFloat());   muscleCopyOut(buffer, f);} break;
 2330       case B_INT64_TYPE:   {uint64 i = B_HOST_TO_LENDIAN_INT64(GetInlineItemAsInt64());    muscleCopyOut(buffer, i);} break;
 2331       case B_INT32_TYPE:   {uint32 i = B_HOST_TO_LENDIAN_INT32(GetInlineItemAsInt32());    muscleCopyOut(buffer, i);} break;
 2332       case B_INT16_TYPE:   {uint16 i = B_HOST_TO_LENDIAN_INT16(GetInlineItemAsInt16());    muscleCopyOut(buffer, i);} break;
 2333       case B_INT8_TYPE:    *buffer = GetInlineItemAsInt8();                                                           break;
 2334 
 2335       case B_MESSAGE_TYPE:
 2336       {
 2337          const Message * msg = dynamic_cast<Message *>(GetInlineItemAsRefCountableRef()());
 2338          // Note:  No number-of-items field is written, for historical reasons
 2339          const uint32 leMsgSize = B_HOST_TO_LENDIAN_INT32(msg->FlattenedSize());
 2340          muscleCopyOut(buffer, leMsgSize); buffer += sizeof(uint32);
 2341          msg->Flatten(buffer);
 2342       }
 2343       break;
 2344 
 2345       case B_POINTER_TYPE: /* do nothing */ break;
 2346       case B_POINT_TYPE:   GetInlineItemAsPoint().Flatten(buffer); break;
 2347       case B_RECT_TYPE:    GetInlineItemAsRect().Flatten(buffer);  break;
 2348 
 2349       case B_STRING_TYPE:
 2350       {
 2351          const uint32 leItemCount = B_HOST_TO_LENDIAN_INT32(1);  // because we have one string to write
 2352          muscleCopyOut(buffer, leItemCount); buffer += sizeof(uint32);
 2353 
 2354          const String & s = GetInlineItemAsString();
 2355          const uint32 leFlatSize = B_HOST_TO_LENDIAN_INT32(s.FlattenedSize());
 2356          muscleCopyOut(buffer, leFlatSize);  buffer += sizeof(uint32);
 2357          s.Flatten(buffer); 
 2358       }
 2359       break;
 2360 
 2361       case B_TAG_TYPE:     /* do nothing */ break;
 2362 
 2363       default:
 2364       {
 2365          // all other types will follow the variable-sized-objects-field convention
 2366          const uint32 leItemCount = B_HOST_TO_LENDIAN_INT32(1);  // because we have one variable-sized-object to write
 2367          muscleCopyOut(buffer, leItemCount); buffer += sizeof(uint32);
 2368 
 2369          const FlatCountable * fc = dynamic_cast<const FlatCountable *>(GetInlineItemAsRefCountableRef()());
 2370          const uint32 leFlatSize = B_HOST_TO_LENDIAN_INT32(fc ? fc->FlattenedSize() : 0);
 2371          muscleCopyOut(buffer, leFlatSize); buffer += sizeof(uint32);
 2372 
 2373          if (fc) fc->Flatten(buffer);
 2374       }
 2375       break;
 2376    }
 2377 }
 2378 
 2379 // Note:  we assume here that we have enough bytes, at least for the fixed-size types, because we checked for that in MessageField::Unflatten() 
 2380 status_t MessageField :: SingleUnflatten(const uint8 * buffer, uint32 numBytes)
 2381 {
 2382    status_t ret;
 2383    switch(_typeCode)
 2384    {
 2385       case B_BOOL_TYPE:   SetInlineItemAsBool(  buffer[0] != 0);                                          break;
 2386       case B_DOUBLE_TYPE: SetInlineItemAsDouble(B_LENDIAN_TO_HOST_IDOUBLE(muscleCopyIn<uint64>(buffer))); break;
 2387       case B_FLOAT_TYPE:  SetInlineItemAsFloat( B_LENDIAN_TO_HOST_IFLOAT(muscleCopyIn<uint32>(buffer)));  break;
 2388       case B_INT64_TYPE:  SetInlineItemAsInt64( B_LENDIAN_TO_HOST_INT64(muscleCopyIn<uint64>(buffer)));   break;
 2389       case B_INT32_TYPE:  SetInlineItemAsInt32( B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(buffer)));   break;
 2390       case B_INT16_TYPE:  SetInlineItemAsInt16( B_LENDIAN_TO_HOST_INT16(muscleCopyIn<uint16>(buffer)));   break;
 2391       case B_INT8_TYPE:   SetInlineItemAsInt8(  *buffer);                                                 break;
 2392 
 2393       case B_MESSAGE_TYPE:
 2394       {
 2395          if (numBytes < sizeof(uint32)) return B_BAD_DATA;  // huh?
 2396 
 2397          // Note:  Message fields have no number-of-items field, for historical reasons
 2398          const uint32 msgSize = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(buffer));
 2399          buffer += sizeof(uint32); numBytes -= sizeof(uint32);  // this line must be exactly here!
 2400          if (msgSize != numBytes) return B_BAD_DATA;
 2401 
 2402          MessageRef msgRef = GetMessageFromPool(buffer, numBytes);
 2403          if (msgRef() == NULL) return B_OUT_OF_MEMORY;
 2404          SetInlineItemAsRefCountableRef(msgRef.GetRefCountableRef());
 2405       }
 2406       break;
 2407 
 2408       case B_POINTER_TYPE: return B_UNIMPLEMENTED;  // pointers should not be serialized!
 2409       case B_POINT_TYPE:   {Point p; if (p.Unflatten(buffer, numBytes).IsOK(ret)) SetInlineItemAsPoint(p); else return ret;} break;
 2410       case B_RECT_TYPE:    {Rect  r; if (r.Unflatten(buffer, numBytes).IsOK(ret)) SetInlineItemAsRect (r); else return ret;} break;
 2411 
 2412       case B_STRING_TYPE:
 2413       {
 2414          if (numBytes < sizeof(uint32)) return B_BAD_DATA;  // paranoia
 2415 
 2416          // string type follows the variable-sized-objects-field convention
 2417          const uint32 itemCount = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(buffer));
 2418          if (itemCount != 1) return B_LOGIC_ERROR;  // wtf, if we're in this function there should only be one item!
 2419          buffer += sizeof(uint32); numBytes -= sizeof(uint32);
 2420 
 2421          const uint32 itemSize = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(buffer));
 2422          buffer += sizeof(uint32); numBytes -= sizeof(uint32);  // yes, this line MUST be exactly here!
 2423          if (itemSize != numBytes) return B_LOGIC_ERROR;  // our one item should take up the entire buffer, or something is wrong
 2424 
 2425          String s;
 2426          if (s.Unflatten(buffer, numBytes).IsError(ret)) return ret;
 2427          SetInlineItemAsString(s);
 2428       }
 2429       break;
 2430 
 2431       case B_TAG_TYPE:     return B_UNIMPLEMENTED;  // tags should not be serialized!
 2432 
 2433       default:
 2434       {
 2435          if (numBytes < sizeof(uint32)) return B_BAD_DATA;  // paranoia
 2436 
 2437          // all other types will follow the variable-sized-objects-field convention
 2438          const uint32 itemCount = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(buffer));
 2439          if (itemCount != 1) return B_LOGIC_ERROR;  // wtf, if we're in this function there should only be one item!
 2440          buffer += sizeof(uint32); numBytes -= sizeof(uint32);
 2441 
 2442          const uint32 itemSize = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(buffer));
 2443          buffer += sizeof(uint32); numBytes -= sizeof(uint32);  // yes, this line MUST be exactly here!
 2444          if (itemSize != numBytes) return B_LOGIC_ERROR;  // our one item should take up the entire buffer, or something is wrong
 2445 
 2446          ByteBufferRef bbRef = GetByteBufferFromPool(numBytes, buffer);
 2447          if (bbRef() == NULL) return B_OUT_OF_MEMORY;
 2448 
 2449          SetInlineItemAsRefCountableRef(bbRef.GetRefCountableRef());
 2450       }
 2451       break;
 2452    }
 2453 
 2454    _state = FIELD_STATE_INLINE;
 2455    return B_NO_ERROR;
 2456 }
 2457 
 2458 void MessageField :: SingleSetValue(const void * data, uint32 /*size*/)
 2459 {
 2460    _state = FIELD_STATE_INLINE;
 2461    switch(_typeCode)
 2462    {
 2463       case B_BOOL_TYPE:    SetInlineItemAsBool(   *static_cast<const bool          *>(data)); break;
 2464       case B_DOUBLE_TYPE:  SetInlineItemAsDouble( *static_cast<const double        *>(data)); break;
 2465       case B_FLOAT_TYPE:   SetInlineItemAsFloat(  *static_cast<const float         *>(data)); break;
 2466       case B_INT64_TYPE:   SetInlineItemAsInt64(  *static_cast<const int64         *>(data)); break;
 2467       case B_INT32_TYPE:   SetInlineItemAsInt32(  *static_cast<const int32         *>(data)); break;
 2468       case B_INT16_TYPE:   SetInlineItemAsInt16(  *static_cast<const int16         *>(data)); break;
 2469       case B_INT8_TYPE:    SetInlineItemAsInt8(   *static_cast<const int8          *>(data)); break;
 2470       case B_POINTER_TYPE: SetInlineItemAsPointer(*static_cast<const MFVoidPointer *>(data)); break;
 2471       case B_POINT_TYPE:   SetInlineItemAsPoint(  *static_cast<const Point         *>(data)); break;
 2472       case B_RECT_TYPE:    SetInlineItemAsRect(   *static_cast<const Rect          *>(data)); break;
 2473       case B_STRING_TYPE:  SetInlineItemAsString( *static_cast<const String        *>(data)); break;
 2474 
 2475       case B_MESSAGE_TYPE: case B_TAG_TYPE: default:
 2476          SetInlineItemAsRefCountableRef(*static_cast<const RefCountableRef *>(data));
 2477       break;
 2478    }
 2479 }
 2480 
 2481 status_t MessageField :: SingleAddDataItem(const void * data, uint32 size)
 2482 {
 2483    if (_state == FIELD_STATE_EMPTY)
 2484    {
 2485       _state = FIELD_STATE_INLINE;
 2486       SingleSetValue(data, size);
 2487       return B_NO_ERROR; 
 2488    }
 2489    else
 2490    {
 2491       // Oops, we need to allocate an array now!
 2492       AbstractDataArrayRef adaRef = CreateDataArray(_typeCode);
 2493       if ((adaRef())&&(adaRef()->AddDataItem(_union._data, size) == B_NO_ERROR))  // add our existing single-item to the array
 2494       {
 2495          if (adaRef()->AddDataItem(data, size) == B_NO_ERROR)
 2496          {
 2497             _state = FIELD_STATE_ARRAY;
 2498             SetInlineItemAsRefCountableRef(adaRef.GetRefCountableRef());
 2499             return B_NO_ERROR;
 2500          } 
 2501       }
 2502       return B_OUT_OF_MEMORY;
 2503    }
 2504 }
 2505 
 2506 status_t MessageField :: SingleRemoveDataItem(uint32 index)
 2507 {
 2508    if ((index > 0)||(_state != FIELD_STATE_INLINE)) return B_BAD_ARGUMENT;
 2509 
 2510    SetInlineItemToNull();
 2511    _state = FIELD_STATE_EMPTY;
 2512    return B_NO_ERROR;
 2513 }
 2514 
 2515 status_t MessageField :: SinglePrependDataItem(const void * data, uint32 size)
 2516 {
 2517    if (_state == FIELD_STATE_EMPTY)
 2518    {
 2519       _state = FIELD_STATE_INLINE;
 2520       SingleSetValue(data, size);
 2521       return B_NO_ERROR; 
 2522    }
 2523    else
 2524    {
 2525       // Oops, we need to allocate an array now!
 2526       AbstractDataArrayRef adaRef = CreateDataArray(_typeCode);
 2527       if ((adaRef())&&(adaRef()->AddDataItem(_union._data, size) == B_NO_ERROR))  // add our existing single-item to the array
 2528       {
 2529          if (adaRef()->PrependDataItem(data, size) == B_NO_ERROR)
 2530          {
 2531             _state = FIELD_STATE_ARRAY;
 2532             SetInlineItemAsRefCountableRef(adaRef.GetRefCountableRef());
 2533             return B_NO_ERROR;
 2534          } 
 2535       }
 2536       return B_OUT_OF_MEMORY;
 2537    }
 2538 }
 2539 
 2540 status_t MessageField :: SingleFindDataItem(uint32 index, const void ** setDataLoc) const
 2541 {
 2542    if ((_state != FIELD_STATE_INLINE)||(index > 0)) return B_BAD_ARGUMENT;
 2543 
 2544    *setDataLoc = _union._data;
 2545    return B_NO_ERROR;
 2546 }
 2547 
 2548 status_t MessageField :: SingleReplaceDataItem(uint32 index, const void * data, uint32 size)
 2549 {
 2550    if ((_state != FIELD_STATE_INLINE)||(index > 0)) return B_BAD_ARGUMENT;
 2551    
 2552    SingleSetValue(data, size);
 2553    return B_NO_ERROR;
 2554 }
 2555 
 2556 // For a given absolutely-fixed-size-type, returns the number of bytes that this type will flatten to.
 2557 // For any other types, returns 0.
 2558 static uint32 GetFlattenedSizeForFixedSizeType(uint32 typeCode)
 2559 {
 2560    switch(typeCode)
 2561    {
 2562       case B_BOOL_TYPE:    return 1;  // note:  NOT sizeof(bool)!
 2563       case B_DOUBLE_TYPE:  return sizeof(double);
 2564       case B_POINTER_TYPE: return sizeof(void *);   // pointer-fields are not flattened anyway, but for completeness
 2565       case B_POINT_TYPE:   return 2*sizeof(float);
 2566       case B_RECT_TYPE:    return 4*sizeof(float);
 2567       case B_FLOAT_TYPE:   return sizeof(float);
 2568       case B_INT64_TYPE:   return sizeof(int64);
 2569       case B_INT32_TYPE:   return sizeof(int32);
 2570       case B_INT16_TYPE:   return sizeof(int16);
 2571       case B_INT8_TYPE:    return sizeof(int8);
 2572       default:             return 0;
 2573    }
 2574 }
 2575 
 2576 uint32 MessageField :: SingleGetItemSize(uint32 index) const
 2577 {
 2578    if ((_state == FIELD_STATE_EMPTY)||(index > 0)) return 0;  // no valid items to get the size of!
 2579 
 2580    switch(_typeCode)
 2581    {
 2582       case B_BOOL_TYPE:    return sizeof(bool);  // note: may be larger than 1, depending on the compiler!
 2583       case B_DOUBLE_TYPE:  return sizeof(double);
 2584       case B_POINTER_TYPE: return sizeof(void *);
 2585       case B_POINT_TYPE:   return sizeof(Point);
 2586       case B_RECT_TYPE:    return sizeof(Rect);
 2587       case B_FLOAT_TYPE:   return sizeof(float);
 2588       case B_INT64_TYPE:   return sizeof(int64);
 2589       case B_INT32_TYPE:   return sizeof(int32);
 2590       case B_INT16_TYPE:   return sizeof(int16);
 2591       case B_INT8_TYPE:    return sizeof(int8);
 2592       case B_STRING_TYPE:  return GetInlineItemAsString().FlattenedSize();
 2593 
 2594       default:
 2595       {
 2596          const FlatCountable * fc = dynamic_cast<FlatCountable *>(GetInlineItemAsRefCountableRef()());
 2597          return fc ? fc->FlattenedSize() : 0; 
 2598       }
 2599    }
 2600 }
 2601 
 2602 uint32 MessageField :: SingleCalculateChecksum(bool countNonFlattenableFields) const
 2603 {
 2604    MASSERT(_state == FIELD_STATE_INLINE, "SingleCalculateChecksum() called on empty field");
 2605 
 2606    uint32 ret = _typeCode + 1;  // +1 is for the one item we have
 2607    switch(_typeCode)
 2608    {
 2609       case B_BOOL_TYPE:    ret += (uint32) (GetInlineItemAsBool() ? 1 : 0);            break;
 2610       case B_DOUBLE_TYPE:  ret += CalculateChecksumForDouble(GetInlineItemAsDouble()); break;
 2611       case B_FLOAT_TYPE:   ret += CalculateChecksumForFloat(GetInlineItemAsFloat());   break;
 2612       case B_INT64_TYPE:   ret += CalculateChecksumForUint64(GetInlineItemAsInt64());  break;
 2613       case B_INT32_TYPE:   ret += (uint32) GetInlineItemAsInt32();                     break;
 2614       case B_INT16_TYPE:   ret += (uint32) GetInlineItemAsInt16();                     break;
 2615       case B_INT8_TYPE:    ret += (uint32) GetInlineItemAsInt8();                      break;
 2616       case B_MESSAGE_TYPE: ret += static_cast<const Message *>(GetInlineItemAsRefCountableRef()())->CalculateChecksum(countNonFlattenableFields); break;
 2617       case B_POINTER_TYPE: /* do nothing */;                                           break;
 2618       case B_POINT_TYPE:   ret += GetInlineItemAsPoint().CalculateChecksum();          break;
 2619       case B_RECT_TYPE:    ret += GetInlineItemAsRect().CalculateChecksum();           break;
 2620       case B_STRING_TYPE:  ret += GetInlineItemAsString().CalculateChecksum();         break;
 2621       case B_TAG_TYPE:     /* do nothing */ break;
 2622 
 2623       default:
 2624       {
 2625          const ByteBuffer * bb = dynamic_cast<const ByteBuffer *>(GetInlineItemAsRefCountableRef()());
 2626          if (bb) ret += bb->CalculateChecksum();
 2627       }
 2628       break;
 2629    }
 2630 
 2631    return ret;
 2632 }
 2633 
 2634 bool MessageField :: SingleElementsAreFixedSize() const
 2635 {
 2636    switch(_typeCode)
 2637    {
 2638       case B_BOOL_TYPE:
 2639       case B_DOUBLE_TYPE:
 2640       case B_POINTER_TYPE:
 2641       case B_POINT_TYPE:
 2642       case B_RECT_TYPE:
 2643       case B_FLOAT_TYPE:
 2644       case B_INT64_TYPE:
 2645       case B_INT32_TYPE:
 2646       case B_INT16_TYPE:
 2647       case B_INT8_TYPE:
 2648          return true;
 2649 
 2650       default:
 2651          return false;
 2652    }
 2653 }
 2654 
 2655 bool MessageField :: SingleIsFlattenable() const
 2656 {
 2657    return ((_typeCode != B_TAG_TYPE)&&(_typeCode != B_POINTER_TYPE));
 2658 }
 2659 
 2660 static void AddSingleItemToString(uint32 indent, const String & itemStr, String & s)
 2661 {
 2662    AddItemPreambleToString(indent, 0, s);
 2663    s += itemStr;
 2664    s += '\n'; 
 2665 }
 2666 
 2667 template <typename T> void AddFormattedSingleItemToString(uint32 indent, const char * fmt, T val, String & s)
 2668 {
 2669    char buf[64]; muscleSprintf(buf, fmt, val);
 2670    AddSingleItemToString(indent, buf, s); 
 2671 }
 2672 
 2673 void MessageField :: AddToString(String & s, uint32 maxRecurseLevel, int indent) const 
 2674 {
 2675    if (HasArray()) GetArray()->AddToString(s, maxRecurseLevel, indent); 
 2676               else SingleAddToString(s, maxRecurseLevel, indent);
 2677 }
 2678 
 2679 void MessageField :: SingleAddToString(String & s, uint32 maxRecurseLevel, int indent) const
 2680 {
 2681    if (_state == FIELD_STATE_INLINE)  // paranoia
 2682    {
 2683       switch(_typeCode)
 2684       {
 2685          case B_BOOL_TYPE:    AddFormattedSingleItemToString(indent, "[%i]", GetInlineItemAsBool(),                     s); break;
 2686          case B_DOUBLE_TYPE:  AddFormattedSingleItemToString(indent, "[%f]", GetInlineItemAsDouble(),                   s); break;
 2687          case B_FLOAT_TYPE:   AddFormattedSingleItemToString(indent, "[%f]", GetInlineItemAsFloat(),                    s); break;
 2688          case B_INT64_TYPE:   AddFormattedSingleItemToString(indent, "[" INT64_FORMAT_SPEC "]", GetInlineItemAsInt64(), s); break;
 2689          case B_INT32_TYPE:   AddFormattedSingleItemToString(indent, "[" INT32_FORMAT_SPEC "]", GetInlineItemAsInt32(), s); break;
 2690          case B_INT16_TYPE:   AddFormattedSingleItemToString(indent, "[%i]", GetInlineItemAsInt16(),                    s); break;
 2691          case B_INT8_TYPE:    AddFormattedSingleItemToString(indent, "[%i]", GetInlineItemAsInt8(),                     s); break;
 2692 
 2693          case B_MESSAGE_TYPE: 
 2694             MessageDataArray::AddItemDescriptionToString(indent, 0, MessageRef(GetInlineItemAsRefCountableRef(), false), s, maxRecurseLevel);
 2695          break;
 2696 
 2697          case B_POINTER_TYPE: AddFormattedSingleItemToString(indent, "[%p]", GetInlineItemAsPointer(), s);        break;
 2698          case B_POINT_TYPE:   AddSingleItemToString(indent, PointToString(GetInlineItemAsPoint()), s);            break;
 2699          case B_RECT_TYPE:    AddSingleItemToString(indent, RectToString(GetInlineItemAsRect()), s);              break;
 2700          case B_STRING_TYPE:  AddSingleItemToString(indent, GetInlineItemAsString().Prepend("[").Append("]"), s); break;
 2701 
 2702          default:
 2703          {
 2704             const ByteBuffer * bb = dynamic_cast<const ByteBuffer *>(GetInlineItemAsRefCountableRef()());
 2705             if (bb) ByteBufferDataArray::AddItemDescriptionToString(indent, 0, FlatCountableRef(GetInlineItemAsRefCountableRef(), true), s);
 2706                else AddFormattedSingleItemToString(indent, "%p", GetInlineItemAsRefCountableRef()(), s);
 2707          }
 2708          break;
 2709       }
 2710    }
 2711 }
 2712 
 2713 // If they are byte-buffers, we'll compare the contents, otherwise we can only compare the pointers
 2714 static bool CompareRefCountableRefs(const RefCountableRef & myRCR, const RefCountableRef & hisRCR)
 2715 {
 2716    const ByteBuffer * myBB  = dynamic_cast<const ByteBuffer *>(myRCR());
 2717    const ByteBuffer * hisBB = dynamic_cast<const ByteBuffer *>(hisRCR());
 2718    return ((myBB)&&(hisBB)) ? ((*myBB) == (*hisBB)) : (myRCR == hisRCR);
 2719 }
 2720 
 2721 bool MessageField :: IsEqualTo(const MessageField & rhs, bool compareContents) const
 2722 {
 2723    if (_typeCode != rhs._typeCode) return false;
 2724 
 2725    const uint32 mySize  = GetNumItems();
 2726    const uint32 hisSize = rhs.GetNumItems();  // FogBugz #10980
 2727    if (mySize != hisSize) return false;  // can't be equal if we don't have the same sizes
 2728    if (mySize == 0)       return true;   // no more to compare, if we're both empty
 2729    if (compareContents == false) return true;  // if we're not comparing contents, then that's all we need to check
 2730 
 2731    switch(_state)
 2732    {
 2733       case FIELD_STATE_INLINE:
 2734          switch(rhs._state)
 2735          {
 2736             case FIELD_STATE_INLINE:
 2737                // Case:  I'm inline, he's inline
 2738                switch(_typeCode)
 2739                {
 2740                   case B_BOOL_TYPE:    return (GetInlineItemAsBool()   == rhs.GetInlineItemAsBool());
 2741                   case B_DOUBLE_TYPE:  return (GetInlineItemAsDouble() == rhs.GetInlineItemAsDouble());
 2742                   case B_FLOAT_TYPE:   return (GetInlineItemAsFloat()  == rhs.GetInlineItemAsFloat());
 2743                   case B_INT64_TYPE:   return (GetInlineItemAsInt64()  == rhs.GetInlineItemAsInt64());
 2744                   case B_INT32_TYPE:   return (GetInlineItemAsInt32()  == rhs.GetInlineItemAsInt32());
 2745                   case B_INT16_TYPE:   return (GetInlineItemAsInt16()  == rhs.GetInlineItemAsInt16());
 2746                   case B_INT8_TYPE:    return (GetInlineItemAsInt8()   == rhs.GetInlineItemAsInt8());
 2747  
 2748                   case B_MESSAGE_TYPE:
 2749                   {
 2750                      const Message * myMsg  = dynamic_cast<Message *>(GetInlineItemAsRefCountableRef()());
 2751                      const Message * hisMsg = dynamic_cast<Message *>(rhs.GetInlineItemAsRefCountableRef()());
 2752                      return AreMessagePointersDeeplyEqual(myMsg, hisMsg);
 2753                   }
 2754 
 2755                   case B_POINTER_TYPE: return (GetInlineItemAsPointer() == rhs.GetInlineItemAsPointer());
 2756                   case B_POINT_TYPE:   return (GetInlineItemAsPoint()   == rhs.GetInlineItemAsPoint());
 2757                   case B_RECT_TYPE:    return (GetInlineItemAsRect()    == rhs.GetInlineItemAsRect());
 2758                   case B_STRING_TYPE:  return (GetInlineItemAsString()  == rhs.GetInlineItemAsString());
 2759                   case B_TAG_TYPE:     // fall through!
 2760                   default:             return CompareRefCountableRefs(GetInlineItemAsRefCountableRef(), rhs.GetInlineItemAsRefCountableRef());
 2761                }
 2762             break;
 2763 
 2764             case FIELD_STATE_ARRAY:
 2765             {
 2766                // Case:  I'm inline, he's array
 2767                const void * hisData;
 2768                if (rhs.GetArray()->FindDataItem(0, &hisData) != B_NO_ERROR) return false;  // semi-paranoia: this call should never fail
 2769 
 2770                switch(_typeCode)
 2771                {
 2772                   case B_BOOL_TYPE:    return (GetInlineItemAsBool()   == *(static_cast<const bool   *>(hisData)));
 2773                   case B_DOUBLE_TYPE:  return (GetInlineItemAsDouble() == *(static_cast<const double *>(hisData)));
 2774                   case B_FLOAT_TYPE:   return (GetInlineItemAsFloat()  == *(static_cast<const float  *>(hisData)));
 2775                   case B_INT64_TYPE:   return (GetInlineItemAsInt64()  == *(static_cast<const int64  *>(hisData)));
 2776                   case B_INT32_TYPE:   return (GetInlineItemAsInt32()  == *(static_cast<const int32  *>(hisData)));
 2777                   case B_INT16_TYPE:   return (GetInlineItemAsInt16()  == *(static_cast<const int16  *>(hisData)));
 2778                   case B_INT8_TYPE:    return (GetInlineItemAsInt8()   == *(static_cast<const int8   *>(hisData)));
 2779  
 2780                   case B_MESSAGE_TYPE:
 2781                   {
 2782                      const Message * myMsg  = dynamic_cast<Message *>(GetInlineItemAsRefCountableRef()());
 2783                      const Message * hisMsg = dynamic_cast<Message *>((*(static_cast<const RefCountableRef *>(hisData)))());
 2784                      return AreMessagePointersDeeplyEqual(myMsg, hisMsg);
 2785                   }
 2786                   // no break necessary since we never get here
 2787 
 2788                   case B_POINTER_TYPE: return (GetInlineItemAsPointer() == *(static_cast<const MFVoidPointer *>(hisData)));
 2789                   case B_POINT_TYPE:   return (GetInlineItemAsPoint()   == *(static_cast<const Point  *>(hisData)));
 2790                   case B_RECT_TYPE:    return (GetInlineItemAsRect()    == *(static_cast<const Rect   *>(hisData)));
 2791                   case B_STRING_TYPE:  return (GetInlineItemAsString()  == *(static_cast<const String *>(hisData)));
 2792                   case B_TAG_TYPE:     // fall through!
 2793                   default:             return CompareRefCountableRefs(GetInlineItemAsRefCountableRef(), *(static_cast<const RefCountableRef *>(hisData)));
 2794                }
 2795             }
 2796             break;
 2797 
 2798             default:
 2799                MCRASH("MessageField::IsEqualTo():  Bad _state B!");
 2800             break;
 2801          }
 2802       break;
 2803 
 2804       case FIELD_STATE_ARRAY:
 2805               if (rhs.HasArray())                   return GetArray()->IsEqualTo(rhs.GetArray(), compareContents);
 2806          else if (rhs._state == FIELD_STATE_INLINE) return rhs.IsEqualTo(*this, compareContents);  // no sense duplicating code
 2807          // fall through
 2808       default:
 2809          MCRASH("MessageField::IsEqualTo():  Bad _state C!");
 2810       break;
 2811    }
 2812 
 2813    return false;  // we should never get here anyway, but having this avoids a compiler warning
 2814 }
 2815 
 2816 MessageField & MessageField :: operator = (const MessageField & rhs)
 2817 {
 2818    // First, get rid of any existing state we are holding
 2819    SetInlineItemToNull();
 2820    _state = FIELD_STATE_EMPTY;
 2821    
 2822    _typeCode = rhs._typeCode;
 2823    switch(rhs._state)
 2824    {
 2825       case FIELD_STATE_EMPTY:  /* do nothing */                                                      break;
 2826       case FIELD_STATE_INLINE: SingleSetValue(rhs._union._data, Message::GetElementSize(_typeCode)); break;
 2827       case FIELD_STATE_ARRAY:  
 2828          _state = FIELD_STATE_ARRAY;
 2829          SetInlineItemAsRefCountableRef(rhs.GetInlineItemAsRefCountableRef());   // note array is ref-shared at this point!
 2830       break;
 2831    }
 2832    return *this;
 2833 }
 2834 
 2835 AbstractDataArrayRef MessageField :: CreateDataArray(uint32 typeCode) const
 2836 {
 2837    AbstractDataArrayRef ada;
 2838    switch(typeCode)
 2839    {
 2840       case B_BOOL_TYPE:    ada.SetRef(NEWFIELD(BoolDataArray));    break;
 2841       case B_DOUBLE_TYPE:  ada.SetRef(NEWFIELD(DoubleDataArray));  break;
 2842       case B_POINTER_TYPE: ada.SetRef(NEWFIELD(PointerDataArray)); break;
 2843       case B_POINT_TYPE:   ada.SetRef(NEWFIELD(PointDataArray));   break;
 2844       case B_RECT_TYPE:    ada.SetRef(NEWFIELD(RectDataArray));    break;
 2845       case B_FLOAT_TYPE:   ada.SetRef(NEWFIELD(FloatDataArray));   break;
 2846       case B_INT64_TYPE:   ada.SetRef(NEWFIELD(Int64DataArray));   break;
 2847       case B_INT32_TYPE:   ada.SetRef(NEWFIELD(Int32DataArray));   break;
 2848       case B_INT16_TYPE:   ada.SetRef(NEWFIELD(Int16DataArray));   break;
 2849       case B_INT8_TYPE:    ada.SetRef(NEWFIELD(Int8DataArray));    break;
 2850       case B_MESSAGE_TYPE: ada.SetRef(NEWFIELD(MessageDataArray)); break;
 2851       case B_STRING_TYPE:  ada.SetRef(NEWFIELD(StringDataArray));  break;
 2852       case B_TAG_TYPE:     ada.SetRef(NEWFIELD(TagDataArray));     break;
 2853       default:
 2854          ada.SetRef(NEWFIELD(ByteBufferDataArray));
 2855          if (ada()) (static_cast<ByteBufferDataArray*>(ada()))->SetTypeCode(typeCode);
 2856          break;
 2857    }
 2858    return ada;
 2859 }
 2860 
 2861 status_t MessageField :: EnsurePrivate()
 2862 {
 2863    switch(_state)
 2864    {
 2865       case FIELD_STATE_ARRAY:
 2866          if (GetArrayRef().IsRefPrivate() == false)
 2867          {
 2868             AbstractDataArrayRef newArrayCopy = GetArray()->Clone();
 2869             if (newArrayCopy() == NULL) return B_OUT_OF_MEMORY;
 2870             SetInlineItemAsRefCountableRef(newArrayCopy.GetRefCountableRef());
 2871          }
 2872       break;
 2873 
 2874       case FIELD_STATE_INLINE:
 2875          if (_dataType == DATA_TYPE_REF)
 2876          {
 2877             const RefCountableRef & rcRef = GetInlineItemAsRefCountableRef();
 2878             if ((rcRef())&&(GetArrayRef().IsRefPrivate() == false))
 2879             {
 2880                const Message * msg = dynamic_cast<const Message *>(rcRef());
 2881                if (msg)
 2882                {
 2883                   MessageRef newMsg = GetMessageFromPool(*msg);
 2884                   if (newMsg() == NULL) return B_OUT_OF_MEMORY;
 2885                   SetInlineItemAsRefCountableRef(newMsg.GetRefCountableRef());
 2886                }
 2887                else
 2888                {
 2889                   const FlatCountable * fc = dynamic_cast<const FlatCountable *>(rcRef());
 2890                   if (fc)
 2891                   {
 2892                      ByteBufferRef newBuf = fc->FlattenToByteBuffer();
 2893                      if (newBuf() == NULL) return B_BAD_OBJECT;
 2894                      SetInlineItemAsRefCountableRef(newBuf.GetRefCountableRef());
 2895                   }
 2896                }
 2897             }
 2898          }         
 2899       break;
 2900 
 2901       default:
 2902          // do nothing
 2903       break;
 2904    }
 2905 
 2906    return B_NO_ERROR;
 2907 }
 2908 
 2909 status_t MessageField :: ReplaceFlatCountableDataItem(uint32 index, muscle::Ref<muscle::FlatCountable> const & fcRef)
 2910 {
 2911    switch(_state)
 2912    {
 2913       case FIELD_STATE_INLINE:
 2914          SetInlineItemAsRefCountableRef(fcRef.GetRefCountableRef());
 2915       return B_NO_ERROR;
 2916 
 2917       case FIELD_STATE_ARRAY:
 2918       {
 2919          // Note that I don't check for MessageDataArray here since it's already been handled in the calling method
 2920          ByteBufferDataArray * bbda = dynamic_cast<ByteBufferDataArray *>(GetArray());
 2921          if (bbda) 
 2922          {
 2923             ByteBufferRef bbRef(fcRef.GetRefCountableRef(), true);
 2924             return bbRef() ? bbda->ReplaceDataItem(index, &bbRef, sizeof(bbRef)) : B_TYPE_MISMATCH;
 2925          }
 2926 
 2927          TagDataArray * tda = dynamic_cast<TagDataArray *>(GetArray());
 2928          if (tda) 
 2929          {
 2930             RefCountableRef rcRef = fcRef.GetRefCountableRef();
 2931             return tda->ReplaceDataItem(index, &rcRef, sizeof(rcRef));
 2932          }
 2933 
 2934          return B_BAD_OBJECT;
 2935       }
 2936       break;
 2937 
 2938       case FIELD_STATE_EMPTY: return B_DATA_NOT_FOUND;
 2939       default:                return B_LOGIC_ERROR;
 2940    }
 2941 }
 2942 
 2943 uint32 MessageField :: GetNumItemsInFlattenedBuffer(const uint8 * bytes, uint32 numBytes) const
 2944 {
 2945    const uint32 fsItemSize = GetFlattenedSizeForFixedSizeType(_typeCode);
 2946 
 2947         if (fsItemSize > 0) return numBytes/fsItemSize;
 2948    else if (_typeCode == B_MESSAGE_TYPE)
 2949    {
 2950       // special case for the Message type since it doesn't have a number-of-items-count, annoyingly enough
 2951       if (numBytes < sizeof(uint32)) return 0;  // huh?
 2952       const uint32 firstMsgSize = B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(bytes));
 2953 
 2954       numBytes -= sizeof(uint32);                 // this must be done exactly here!
 2955       if (firstMsgSize > numBytes) return 0;      // malformed buffer size?
 2956       return (firstMsgSize == numBytes) ? 1 : 2;  // we don't need to count the actual number of Messages for now
 2957    }
 2958    else
 2959    {
 2960       // For all other types, the first four bytes in the buffer is the number-of-items-count
 2961       if (numBytes < sizeof(uint32)) return 0;  // huh?
 2962       return B_LENDIAN_TO_HOST_INT32(muscleCopyIn<uint32>(bytes));
 2963    }
 2964 }
 2965 
 2966 status_t MessageField :: Unflatten(const uint8 * bytes, uint32 numBytes)
 2967 {
 2968    _state = FIELD_STATE_EMPTY;  // semi-paranoia
 2969    SetInlineItemToNull();       // ditto
 2970 
 2971    const uint32 numItemsInBuffer = GetNumItemsInFlattenedBuffer(bytes, numBytes);
 2972    if (numItemsInBuffer == 1) return SingleUnflatten(bytes, numBytes);
 2973    else
 2974    {
 2975       AbstractDataArrayRef adaRef = CreateDataArray(_typeCode);
 2976       if (adaRef() == NULL) return B_OUT_OF_MEMORY;
 2977 
 2978       status_t ret;
 2979       if (adaRef()->Unflatten(bytes, numBytes).IsOK(ret))  // add our existing single-item to the array
 2980       {
 2981          _state = FIELD_STATE_ARRAY;
 2982          SetInlineItemAsRefCountableRef(adaRef.GetRefCountableRef());
 2983          return B_NO_ERROR;
 2984       }
 2985       else return ret;
 2986    }
 2987 }
 2988 
 2989 const Rect & MessageField :: GetItemAtAsRect(uint32 index) const
 2990 {
 2991    switch(_state)
 2992    {
 2993       case FIELD_STATE_ARRAY:
 2994       {
 2995          const RectDataArray * rda = dynamic_cast<const RectDataArray *>(GetArray());
 2996          if (rda) return rda->ItemAt(index);
 2997       }
 2998       break;
 2999 
 3000       case FIELD_STATE_INLINE: return GetInlineItemAsRect();
 3001       default:                 /* do nothing */ break;
 3002    }
 3003    return GetDefaultObjectForType<Rect>();
 3004 }
 3005 
 3006 const Point & MessageField :: GetItemAtAsPoint(uint32 index) const
 3007 {
 3008    switch(_state)
 3009    {
 3010       case FIELD_STATE_ARRAY:
 3011       {
 3012          const PointDataArray * pda = dynamic_cast<const PointDataArray *>(GetArray());
 3013          if (pda) return pda->ItemAt(index);
 3014       }
 3015       break;
 3016 
 3017       case FIELD_STATE_INLINE: return GetInlineItemAsPoint();
 3018       default:                 /* do nothing */ break;
 3019    }
 3020    return GetDefaultObjectForType<Point>();
 3021 }
 3022 
 3023 const String & MessageField :: GetItemAtAsString(uint32 index) const
 3024 {
 3025    switch(_state)
 3026    {
 3027       case FIELD_STATE_ARRAY:
 3028       {
 3029          const StringDataArray * sda = dynamic_cast<const StringDataArray *>(GetArray());
 3030          if (sda) return sda->ItemAt(index);
 3031       }
 3032       break;
 3033 
 3034       case FIELD_STATE_INLINE: return GetInlineItemAsString();
 3035       default:                 /* do nothing */ break;
 3036    }
 3037    return GetDefaultObjectForType<String>();
 3038 }
 3039 
 3040 RefCountableRef MessageField :: GetItemAtAsRefCountableRef(uint32 index) const
 3041 {
 3042    switch(_state)
 3043    {
 3044       case FIELD_STATE_ARRAY:  return GetArray()->GetItemAtAsRefCountableRef(index);
 3045       case FIELD_STATE_INLINE: return GetInlineItemAsRefCountableRef();
 3046       default:                 /* do nothing */ break;
 3047    }
 3048    return GetDefaultObjectForType<RefCountableRef>();
 3049 }
 3050 
 3051 void MessageField :: Clear() 
 3052 {
 3053    SetInlineItemToNull();
 3054    _state = FIELD_STATE_EMPTY;
 3055 }
 3056 
 3057 } // end namespace muscle