[NeoStats-Devel] [Commits] r2809 - trunk/src
[email protected] Mon, 12 Sep 2005 23:55:23 +1000
| Newsgroups | gmane.comp.neostats.devel |
|---|---|
| Message-ID | <[email protected]> |
Author: Fish
Date: Mon Sep 12 21:55:15 2005
New Revision: 2809
Added:
trunk/src/MiniMessage.c (contents, props changed)
trunk/src/MiniMessageGateway.c (contents, props changed)
Log:
Commit the MiniMessage files
Added: trunk/src/MiniMessage.c
==============================================================================
--- (empty file)
+++ trunk/src/MiniMessage.c Mon Sep 12 21:55:15 2005
@@ -0,0 +1,1373 @@
+/* NeoStats - IRC Statistical Services
+** Copyright (c) 1999-2005 Adam Rutter, Justin Hammond, Mark Hetherington
+** http://www.neostats.net/
+**
+** Portions Copyright (c) 2000 - 2001 ^Enigma^
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+** USA
+**
+** NeoStats CVS Identification
+** $Id$
+*/
+
+/** @file MiniMessage.c
+ * @brief module functions
+ */
+
+
+#include "neostats.h"
+#include "MiniMessage.h"
+
+#ifdef cplusplus
+extern "C" {
+#endif
+
+static uint32 _allocedBytes = 0; /* for memory-leak debugging */
+
+uint32 MGetNumBytesAllocated() {return _allocedBytes;}
+
+#ifdef MUSCLE_ENABLE_MEMORY_TRACKING
+
+void * MMalloc(uint32 numBytes)
+{
+ uint32 * ret = (uint32 *) malloc(numBytes+sizeof(uint32));
+ if (ret)
+ {
+ *ret = numBytes;
+ _allocedBytes += numBytes;
+/*printf("++%lu -> %lu\n", *ret, _allocedBytes);*/
+ return ret+1;
+ }
+ return NULL;
+}
+
+void * MFree(void * ptr)
+{
+ if (ptr)
+ {
+ uint32 * ret = ((uint32 *)ptr)-1;
+ _allocedBytes -= *ret;
+/*printf("--%lu -> %lu\n", *ret, _allocedBytes);*/
+ free(ret);
+ }
+}
+
+void * MRealloc(void * oldBuf, uint32 newSize)
+{
+ uint32 oldSize = oldBuf ? (*(((uint32*)oldBuf)-1)) : 0;
+
+ if (newSize == oldSize) return oldBuf;
+ else
+ {
+ void * newBuf = (newSize > 0) ? MMalloc(newSize) : NULL;
+ if ((newSize > 0)&&(newBuf == NULL)) return NULL; // out-of-memory error! Avoid side effects
+
+ if ((newBuf)&&(oldBuf)) memcpy(newBuf, oldBuf, (newSize<oldSize)?newSize:oldSize);
+ if (oldBuf) MFree(oldBuf);
+ return newBuf;
+ }
+}
+
+#endif
+
+static status_t ReadData(const uint8 * inBuf, uint32 inputBufferBytes, uint32 * readOffset, void * copyTo, uint32 blockSize)
+{
+ if ((*readOffset + blockSize) > inputBufferBytes) return B_ERROR;
+ memcpy(copyTo, &inBuf[*readOffset], blockSize);
+ *readOffset += blockSize;
+ return B_NO_ERROR;
+};
+
+static void WriteData(uint8 * outBuf, uint32 * writeOffset, const void * copyFrom, uint32 blockSize)
+{
+ memcpy(&outBuf[*writeOffset], copyFrom, blockSize);
+ *writeOffset += blockSize;
+};
+
+#define OLDEST_SUPPORTED_PROTOCOL_VERSION 1347235888 /* 'PM00' */
+#define CURRENT_PROTOCOL_VERSION 1347235888 /* 'PM00' */
+
+struct _MMessageField; /* forward declaration */
+struct _MMessageField {
+ struct _MMessageField * prevField; /* used by our linked list */
+ struct _MMessageField * nextField; /* used by our linked list */
+ uint32 allocSize; /* Our allocation size, for convenience */
+ const char * name; /* pointer to our field name, for convenience */
+ uint32 nameBytes; /* number of bytes in field name (including NUL) */
+ uint32 typeCode;
+ void * data; /* Pointer to our data bytes, for convenience */
+ uint32 itemSize; /* item size, for convenience */
+ uint32 numItems; /* number of item-slots in this field */
+ MBool isFixedSize; /* If MFalse, data is an array of MByteBuffers */
+ MBool isFlattenable; /* If MFalse, data shouldn't be Flattened */
+ /* ... data bytes here ... */
+ /* name bytes start here, after the last data byte */
+ /* Note that name bytes must be last, or MMRenameField() breaks */
+};
+typedef struct _MMessageField MMessageField;
+
+/* Our internal implementation of the MMessage object... known only to the */
+/* code inside this file! All external code shouldn't need to know about this. */
+struct _MMessage {
+ uint32 what;
+ uint32 numFields;
+ MMessageField * firstField;
+ MMessageField * lastField;
+
+ struct _MMessage * scratch; /* scratch variable, used in Unflatten */
+};
+
+MByteBuffer * MBAllocByteBuffer(uint32 numBytes, MBool clearBytes)
+{
+ MByteBuffer * mbb = (MByteBuffer *) MMalloc((sizeof(MByteBuffer)+numBytes)-1); /* -1 since at least 1 data byte is in the struct */
+ if (mbb)
+ {
+ mbb->numBytes = numBytes;
+ if (clearBytes) memset(&mbb->bytes, 0, numBytes);
+ }
+ return mbb;
+}
+
+MByteBuffer * MBStrdupByteBuffer(const char * sourceString)
+{
+ int slen = strlen(sourceString)+1;
+ MByteBuffer * mbb = MBAllocByteBuffer(slen, MFalse);
+ if (mbb) memcpy(&mbb->bytes, sourceString, slen);
+ return mbb;
+}
+
+MByteBuffer * MBCloneByteBuffer(const MByteBuffer * cloneMe)
+{
+ MByteBuffer * mbb = MBAllocByteBuffer(cloneMe->numBytes, MFalse);
+ if (mbb) memcpy(&mbb->bytes, &cloneMe->bytes, mbb->numBytes);
+ return mbb;
+}
+
+MBool MBAreByteBuffersEqual(const MByteBuffer * buf1, const MByteBuffer * buf2)
+{
+ return ((buf1 == buf2)||((buf1->numBytes == buf2->numBytes)&&(memcmp(&buf1->bytes, &buf2->bytes, buf1->numBytes) == 0)));
+}
+
+void MBFreeByteBuffer(MByteBuffer * msg)
+{
+ /* yup, it's that easy... but you should still always call this function */
+ /* instead of calling MFree() directly, in case the implementation changes later */
+ if (msg) MFree(msg);
+}
+
+/* Note that numNameBytes includes the NUL byte! */
+static MMessageField * AllocMMessageField(const char * fieldName, uint32 numNameBytes, uint32 typeCode, uint32 numItems, uint32 itemSize)
+{
+ if (numItems > 0)
+ {
+ const uint32 dataSize = numItems*itemSize;
+ const uint32 allocSize = sizeof(MMessageField)+dataSize+numNameBytes;
+ MMessageField * ret = (MMessageField *) MMalloc(allocSize);
+ if (ret)
+ {
+ ret->prevField = ret->nextField = NULL;
+ ret->allocSize = allocSize;
+ ret->nameBytes = numNameBytes;
+ ret->typeCode = typeCode;
+ ret->itemSize = itemSize;
+ ret->numItems = numItems;
+ ret->data = ((char *)ret) + sizeof(MMessageField); /* data bytes start immediately after the struct */
+ ret->name = ((char *)ret->data)+dataSize; /* name starts right after the data */
+ ret->isFixedSize = ret->isFlattenable = MTrue;
+ memset(ret->data, 0, dataSize);
+ memcpy((void *)ret->name, fieldName, numNameBytes);
+ ((char *)ret->name)[ret->nameBytes-1] = '\0'; /* paranoia: guarantee that the field name is terminated */
+ }
+ return ret;
+ }
+ else return NULL; /* we don't allow zero-item fields! */
+}
+
+static MMessageField * CloneMMessageField(const MMessageField * cloneMe)
+{
+ MMessageField * clone = (MMessageField *) MMalloc(cloneMe->allocSize);
+ if (clone)
+ {
+ memcpy(clone, cloneMe, cloneMe->isFixedSize ? cloneMe->allocSize : sizeof(MMessageField));
+ clone->prevField = clone->nextField = NULL;
+ clone->data = ((char *)clone) + (((char *)cloneMe->data)-((char *)cloneMe));
+ clone->name = ((const char *)clone) + (cloneMe->name-((const char *)cloneMe));
+ if (clone->isFixedSize == MFalse)
+ {
+ /* Oops, this field has alloced-pointer semantics, so we have to clone all the items too */
+ if (clone->typeCode == B_MESSAGE_TYPE)
+ {
+ MMessage ** dstArray = (MMessage **) clone->data;
+ const MMessage ** srcArray = (const MMessage **) cloneMe->data;
+ int32 i;
+ for (i=cloneMe->numItems-1; i>=0; i--)
+ {
+ if (srcArray[i])
+ {
+ if ((dstArray[i] = MMCloneMessage(srcArray[i])) == NULL)
+ {
+ /* Allocation failure! Roll back previous allocs and fail cleanly */
+ int32 j;
+ for (j=clone->numItems-1; j>i; j++) MMFreeMessage(dstArray[j]);
+ MFree(clone);
+ return NULL;
+ }
+ }
+ else dstArray[i] = NULL;
+ }
+ }
+ else
+ {
+ MByteBuffer ** dstArray = (MByteBuffer **) clone->data;
+ const MByteBuffer ** srcArray = (const MByteBuffer **) cloneMe->data;
+ int32 i;
+ for (i=cloneMe->numItems-1; i>=0; i--)
+ {
+ if (srcArray[i])
+ {
+ if ((dstArray[i] = MBCloneByteBuffer(srcArray[i])) == NULL)
+ {
+ /* Allocation failure! Roll back previous allocs and fail cleanly */
+ int32 j;
+ for (j=clone->numItems-1; j>i; j++) MBFreeByteBuffer(dstArray[j]);
+ MFree(clone);
+ return NULL;
+ }
+ }
+ else dstArray[i] = NULL;
+ }
+ }
+
+ /* copy the name too, since we didn't do it above */
+ memcpy((char *)clone->name, cloneMe->name, clone->nameBytes);
+ }
+ }
+ return clone;
+}
+
+static void FreeMMessageField(MMessageField * field)
+{
+ if (field)
+ {
+ if (field->isFixedSize == MFalse)
+ {
+ /* Oops, this field has alloced-pointer semantics, so we have to free all the items too */
+ if (field->typeCode == B_MESSAGE_TYPE)
+ {
+ MMessage ** array = (MMessage **) field->data;
+ int32 i;
+ for (i=field->numItems-1; i>=0; i--) MMFreeMessage(array[i]);
+ }
+ else
+ {
+ MByteBuffer ** array = (MByteBuffer **) field->data;
+ int32 i;
+ for (i=field->numItems-1; i>=0; i--) MBFreeByteBuffer(array[i]);
+ }
+ }
+ MFree(field);
+ }
+}
+
+MMessage * MMAllocMessage(uint32 what)
+{
+ MMessage * ret = (MMessage *) MMalloc(sizeof(MMessage));
+ if (ret)
+ {
+ ret->what = what;
+ ret->numFields = 0;
+ ret->firstField = ret->lastField = NULL;
+ }
+ return ret;
+}
+
+MMessage * MMCloneMessage(const MMessage * cloneMe)
+{
+ MMessage * clone = MMAllocMessage(cloneMe->what);
+ if (clone)
+ {
+ const MMessageField * nextField = cloneMe->firstField;
+ while(nextField)
+ {
+ MMessageField * cloneField = CloneMMessageField(nextField);
+ if (cloneField)
+ {
+ if (clone->lastField)
+ {
+ clone->lastField->nextField = cloneField;
+ cloneField->prevField = clone->lastField;
+ clone->lastField = cloneField;
+ }
+ else clone->firstField = clone->lastField = cloneField;
+
+ clone->numFields++;
+ }
+ else
+ {
+ MMFreeMessage(clone);
+ return NULL;
+ }
+ nextField = nextField->nextField;
+ }
+ }
+ return clone;
+}
+
+void MMFreeMessage(MMessage * msg)
+{
+ if (msg)
+ {
+ MMClearMessage(msg);
+ MFree(msg);
+ }
+}
+
+uint32 MMGetWhat(const MMessage * msg)
+{
+ return msg->what;
+}
+
+void MMSetWhat(MMessage * msg, uint32 newWhat)
+{
+ msg->what = newWhat;
+}
+
+void MMClearMessage(MMessage * msg)
+{
+ MMessageField * field = msg->firstField;
+ while(field)
+ {
+ MMessageField * nextField = field->nextField;
+ FreeMMessageField(field);
+ field = nextField;
+ }
+ msg->firstField = msg->lastField = NULL;
+ msg->numFields = 0;
+}
+
+/** This function adds the given field into msg's linked list of fields. */
+static void AddMMessageField(MMessage * msg, MMessageField * field)
+{
+ field->prevField = msg->lastField;
+ if (msg->lastField) msg->lastField->nextField = field;
+ else msg->firstField = field;
+ msg->lastField = field;
+ msg->numFields++;
+}
+
+static MBool IsTypeCodeVariableSize(uint32 typeCode)
+{
+ /* Don't allow the user to put data blobs under any of the non-data-blob type codes, */
+ /* because that would mess up our internal logic which assumes that fields of those */
+ /* types have the appropriate data for their type */
+ switch(typeCode)
+ {
+ case B_BOOL_TYPE: case B_DOUBLE_TYPE: case B_FLOAT_TYPE: case B_INT64_TYPE:
+ case B_INT32_TYPE: case B_INT16_TYPE: case B_INT8_TYPE:
+ case B_POINTER_TYPE: case B_POINT_TYPE: case B_RECT_TYPE:
+ return MFalse;
+
+ default:
+ return MTrue;
+ }
+}
+
+static MMessageField * LookupMMessageField(const MMessage * msg, const char * fieldName, uint32 typeCode)
+{
+ MMessageField * f = msg->lastField; /* assuming we're more likely to look up what we added most recently (?) */
+ while(f)
+ {
+ if (strcmp(f->name, fieldName) == 0) return ((typeCode == B_ANY_TYPE)||(typeCode == f->typeCode)) ? f : NULL;
+ f = f->prevField;
+ }
+ return NULL; /* field not found */
+}
+
+static void DetachMMessageField(MMessage * msg, MMessageField * field)
+{
+ if (field->prevField) field->prevField->nextField = field->nextField;
+ if (field->nextField) field->nextField->prevField = field->prevField;
+ if (field == msg->lastField) msg->lastField = field->prevField;
+ if (field == msg->firstField) msg->firstField = field->nextField;
+ field->prevField = field->nextField = NULL;
+ msg->numFields--;
+}
+
+/** This function handles placing a new variable-sized-data-blob field into a Message */
+static MByteBuffer ** PutMMVariableFieldAux(MMessage * msg, MBool retainOldData, uint32 typeCode, const char * fieldName, uint32 numItems)
+{
+ MMessageField * newField = AllocMMessageField(fieldName, strlen(fieldName)+1, typeCode, numItems, sizeof(MByteBuffer *));
+ if (newField)
+ {
+ MMessageField * oldField = LookupMMessageField(msg, fieldName, B_ANY_TYPE);
+ newField->isFixedSize = MFalse;
+ if (oldField)
+ {
+ if ((retainOldData)&&(oldField->typeCode == typeCode))
+ {
+ uint32 commonItems = (numItems < oldField->numItems) ? numItems : oldField->numItems;
+ uint32 i;
+ MByteBuffer ** fromArray = (MByteBuffer **) oldField->data;
+ MByteBuffer ** toArray = (MByteBuffer **) newField->data;
+ for (i=0; i<commonItems; i++)
+ {
+ toArray[i] = fromArray[i];
+ fromArray[i] = NULL;
+ }
+ }
+ DetachMMessageField(msg, oldField);
+ FreeMMessageField(oldField);
+ }
+ AddMMessageField(msg, newField);
+ }
+ return newField ? (MByteBuffer **)newField->data : NULL;
+}
+
+static void * GetFieldDataAux(const MMessage * msg, const char * fieldName, uint32 typeCode, uint32 * optRetNumItems)
+{
+ MMessageField * f = LookupMMessageField(msg, fieldName, typeCode);
+ if ((f)&&(f->numItems > 0))
+ {
+ if (optRetNumItems) *optRetNumItems = f->numItems;
+ return f->data;
+ }
+ return NULL;
+}
+
+static void * PutMMFixedFieldAux(MMessage * msg, MBool retainOldData, uint32 typeCode, const char * fieldName, uint32 numItems, uint32 itemSize)
+{
+ MMessageField * newField = AllocMMessageField(fieldName, strlen(fieldName)+1, typeCode, numItems, itemSize);
+ if (newField)
+ {
+ MMessageField * oldField = LookupMMessageField(msg, fieldName, B_ANY_TYPE);
+ if (oldField)
+ {
+ if ((retainOldData)&&(oldField->typeCode == typeCode)) memcpy(newField->data, oldField->data, ((numItems < oldField->numItems) ? numItems : oldField->numItems)*itemSize);
+ DetachMMessageField(msg, oldField);
+ FreeMMessageField(oldField);
+ }
+ AddMMessageField(msg, newField);
+ }
+ return newField ? newField->data : NULL;
+}
+
+status_t MMRemoveField(MMessage * msg, const char * fieldName)
+{
+ MMessageField * field = LookupMMessageField(msg, fieldName, B_ANY_TYPE);
+ if (field)
+ {
+ DetachMMessageField(msg, field);
+ FreeMMessageField(field);
+ return B_NO_ERROR;
+ }
+ return B_ERROR;
+}
+
+MByteBuffer ** MMPutStringField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return PutMMVariableFieldAux(msg, retainOldData, B_STRING_TYPE, fieldName, numItems);
+}
+
+MBool * MMPutBoolField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return (MBool *) PutMMFixedFieldAux(msg, retainOldData, B_BOOL_TYPE, fieldName, numItems, sizeof(MBool));
+}
+
+int8 * MMPutInt8Field(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return (int8 *) PutMMFixedFieldAux(msg, retainOldData, B_INT8_TYPE, fieldName, numItems, sizeof(int8));
+}
+
+int16 * MMPutInt16Field(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return (int16 *) PutMMFixedFieldAux(msg, retainOldData, B_INT16_TYPE, fieldName, numItems, sizeof(int16));
+}
+
+int32 * MMPutInt32Field(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return (int32 *) PutMMFixedFieldAux(msg, retainOldData, B_INT32_TYPE, fieldName, numItems, sizeof(int32));
+}
+
+int64 * MMPutInt64Field(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return (int64 *) PutMMFixedFieldAux(msg, retainOldData, B_INT64_TYPE, fieldName, numItems, sizeof(int64));
+}
+
+float * MMPutFloatField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return (float *) PutMMFixedFieldAux(msg, retainOldData, B_FLOAT_TYPE, fieldName, numItems, sizeof(float));
+}
+
+double * MMPutDoubleField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return (double *) PutMMFixedFieldAux(msg, retainOldData, B_DOUBLE_TYPE, fieldName, numItems, sizeof(double));
+}
+
+MMessage ** MMPutMessageField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ MMessageField * newField = AllocMMessageField(fieldName, strlen(fieldName)+1, B_MESSAGE_TYPE, numItems, sizeof(MMessage *));
+ if (newField)
+ {
+ MMessageField * oldField = LookupMMessageField(msg, fieldName, B_ANY_TYPE);
+ newField->isFixedSize = MFalse;
+ if (oldField)
+ {
+ if ((retainOldData)&&(oldField->typeCode == B_MESSAGE_TYPE))
+ {
+ uint32 commonItems = (numItems < oldField->numItems) ? numItems : oldField->numItems;
+ uint32 i;
+ MMessage ** fromArray = (MMessage **) oldField->data;
+ MMessage ** toArray = (MMessage **) newField->data;
+ for (i=0; i<commonItems; i++)
+ {
+ toArray[i] = fromArray[i];
+ fromArray[i] = NULL;
+ }
+ }
+ DetachMMessageField(msg, oldField);
+ FreeMMessageField(oldField);
+ }
+ AddMMessageField(msg, newField);
+ }
+ return newField ? (MMessage **)newField->data : NULL;
+}
+
+void ** MMPutPointerField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ void ** ret = (void **) PutMMFixedFieldAux(msg, retainOldData, B_POINTER_TYPE, fieldName, numItems, sizeof(void *));
+ if (ret)
+ {
+ MMessageField * f = LookupMMessageField(msg, fieldName, B_POINTER_TYPE);
+ if (f) f->isFlattenable = MFalse;
+ }
+ return ret;
+}
+
+MPoint * MMPutPointField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return (MPoint *) PutMMFixedFieldAux(msg, retainOldData, B_POINT_TYPE, fieldName, numItems, sizeof(MPoint));
+}
+
+MRect * MMPutRectField(MMessage * msg, MBool retainOldData, const char * fieldName, uint32 numItems)
+{
+ return (MRect *) PutMMFixedFieldAux(msg, retainOldData, B_RECT_TYPE, fieldName, numItems, sizeof(MRect));
+}
+
+MByteBuffer ** MMPutDataField(MMessage * msg, MBool retainOldData, uint32 typeCode, const char * fieldName, uint32 numItems)
+{
+ return ((typeCode != B_MESSAGE_TYPE)&&(IsTypeCodeVariableSize(typeCode))) ? PutMMVariableFieldAux(msg, retainOldData, typeCode, fieldName, numItems) : NULL;
+}
+
+static uint32 GetMMessageFieldFlattenedSize(const MMessageField * f, MBool includeHeaders)
+{
+ uint32 sum = includeHeaders ? (sizeof(uint32) + f->nameBytes + sizeof(uint32) + sizeof(uint32)) : 0; /* Entry name length, entry name, string, type code, entry data length */
+ if (IsTypeCodeVariableSize(f->typeCode))
+ {
+ uint32 numItems = f->numItems;
+ uint32 i;
+
+ sum += (numItems*sizeof(uint32)); /* because each sub-item is preceded by its byte-count */
+ if (f->typeCode == B_MESSAGE_TYPE)
+ {
+ /* Note that NULL entries will be flattened as empty Messages, since the protocol doesn't support them directly. */
+ const MMessage ** msgs = (const MMessage **) f->data;
+ for (i=0; i<numItems; i++) sum += msgs[i] ? MMGetFlattenedSize(msgs[i]) : (3*sizeof(uint32));
+ }
+ else
+ {
+ const MByteBuffer ** bufs = (const MByteBuffer **) f->data;
+ sum += sizeof(uint32); /* num-items-in-array field */
+ for (i=0; i<numItems; i++) sum += bufs[i] ? bufs[i]->numBytes : 0;
+ }
+ }
+ else sum += f->numItems*f->itemSize; /* Entry data length and data items */
+
+ return sum;
+}
+
+/* Copies (numItems) items from (in) to (out), swapping the byte gender of each item as it goes. */
+static void SwapCopy(void * out, const void * in, uint32 numItems, uint32 itemSize)
+{
+ if (itemSize > 1)
+ {
+ const int numBytes = numItems * itemSize;
+ int whichByte;
+ for (whichByte=itemSize-1; whichByte>=0; whichByte--)
+ {
+ int i;
+ uint8 * out8 = ((uint8 *)out)+whichByte;
+ const uint8 * in8 = ((const uint8 *)in)+itemSize-(whichByte+1);
+ for(i=0; i<numBytes; i+=itemSize) out8[i] = in8[i];
+ }
+ }
+ else memcpy(out, in, numItems);
+}
+
+static uint32 FlattenMMessageField(const MMessageField * f, void * outBuf)
+{
+ /* 3. Entry name length (4 bytes) */
+ /* 4. Entry name string (flattened String) */
+ /* 5. Entry type code (4 bytes) */
+ /* 6. Entry data length (4 bytes) */
+ /* 7. Entry data (n bytes) */
+
+ /* Write entry name length */
+ uint32 writeOffset = 0;
+ uint8 * buffer = (uint8 *) outBuf;
+ {
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(f->nameBytes);
+ WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+ }
+
+ /* Write entry name */
+ memcpy(&buffer[writeOffset], f->name, f->nameBytes); writeOffset += f->nameBytes;
+
+ /* Write entry type code */
+ {
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(f->typeCode);
+ WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+ }
+
+ /* Write entry data length */
+ {
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(GetMMessageFieldFlattenedSize(f, MFalse));
+ WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+ }
+
+ /* Write entry data */
+ if (IsTypeCodeVariableSize(f->typeCode))
+ {
+ uint32 numItems = f->numItems;
+ uint32 i;
+
+ if (f->typeCode == B_MESSAGE_TYPE)
+ {
+ /* Note that NULL entries will be flattened as empty Messages, since the protocol doesn't support them directly. */
+ /* Note also that for this type the number-of-items-in-array field is NOT written into the buffer (sigh) */
+ const MMessage ** msgs = (const MMessage **) f->data;
+ for (i=0; i<numItems; i++)
+ {
+ const MMessage * subMsg = msgs[i];
+ uint32 msgSize = subMsg ? MMGetFlattenedSize(subMsg) : (3*sizeof(uint32));
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(msgSize);
+ WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+ if (subMsg)
+ {
+ MMFlattenMessage(subMsg, &buffer[writeOffset]); writeOffset += msgSize;
+ }
+ else
+ {
+ /* No MMessage present? Then we're going to have to fake one */
+ /* Format: 0. Protocol revision number (4 bytes, always set to CURRENT_PROTOCOL_VERSION) */
+ /* 1. 'what' code (4 bytes) */
+ /* 2. Number of entries (4 bytes) */
+
+ /* Write current protocol version */
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(CURRENT_PROTOCOL_VERSION);
+ WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+
+ /* Write 'what' code (zero) */
+ networkByteOrder = B_HOST_TO_LENDIAN_INT32(0);
+ WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+
+ /* Write number of entries (zero) */
+ networkByteOrder = B_HOST_TO_LENDIAN_INT32(0);
+ WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+ }
+ }
+ }
+ else
+ {
+ const MByteBuffer ** bufs = (const MByteBuffer **) f->data;
+ int i;
+
+ /* Write the number of items in the array */
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(numItems);
+ WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+
+ for (i=0; i<numItems; i++)
+ {
+ uint32 bufSize = bufs[i] ? bufs[i]->numBytes : 0;
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(bufSize);
+ WriteData(buffer, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+ memcpy(&buffer[writeOffset], &bufs[i]->bytes, bufSize); writeOffset += bufSize;
+ }
+ }
+ }
+ else
+ {
+ uint32 dataSize = f->numItems*f->itemSize;
+ MBool doMemcpy = MTrue;
+ if (BYTE_ORDER != LITTLE_ENDIAN)
+ {
+ doMemcpy = MFalse;
+ switch(f->typeCode)
+ {
+ case B_BOOL_TYPE: case B_INT8_TYPE: doMemcpy = MTrue; break;
+ case B_POINT_TYPE: SwapCopy(&buffer[writeOffset], f->data, f->numItems*2, sizeof(float)); break;
+ case B_RECT_TYPE: SwapCopy(&buffer[writeOffset], f->data, f->numItems*4, sizeof(float)); break;
+ default: SwapCopy(&buffer[writeOffset], f->data, f->numItems, f->itemSize); break;
+ }
+ }
+ if (doMemcpy) memcpy(&buffer[writeOffset], f->data, dataSize);
+ writeOffset += dataSize;
+ }
+
+ return writeOffset;
+}
+
+uint32 MMGetFlattenedSize(const MMessage * msg)
+{
+ /* For the message header: 4 bytes for the protocol revision #, 4 bytes for the number-of-entries field, 4 bytes for what code */
+ uint32 sum = 3 * sizeof(uint32);
+
+ const MMessageField * f = msg->firstField;
+ while(f)
+ {
+ if (f->isFlattenable) sum += GetMMessageFieldFlattenedSize(f, MTrue);
+ f = f->nextField;
+ }
+ return sum;
+}
+
+void MMFlattenMessage(const MMessage * msg, void * outBuf)
+{
+ /* Format: 0. Protocol revision number (4 bytes, always set to CURRENT_PROTOCOL_VERSION) */
+ /* 1. 'what' code (4 bytes) */
+ /* 2. Number of entries (4 bytes) */
+ /* 3. Entry name length (4 bytes) */
+ /* 4. Entry name string (flattened String) */
+ /* 5. Entry type code (4 bytes) */
+ /* 6. Entry data length (4 bytes) */
+ /* 7. Entry data (n bytes) */
+ /* 8. loop to 3 as necessary */
+
+ /* Write current protocol version */
+ uint32 writeOffset = 0;
+ {
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(CURRENT_PROTOCOL_VERSION);
+ WriteData(outBuf, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+ }
+
+ /* Write 'what' code */
+ {
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(msg->what);
+ WriteData(outBuf, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+ }
+
+ /* Calculate the number of flattenable entries (may be less than the total number of entries!) */
+ {
+ uint32 numFlattenableEntries = 0;
+ {
+ const MMessageField * f = msg->firstField;
+ while(f)
+ {
+ if (f->isFlattenable) numFlattenableEntries++;
+ f = f->nextField;
+ }
+ }
+
+ /* Write number of entries */
+ {
+ uint32 networkByteOrder = B_HOST_TO_LENDIAN_INT32(numFlattenableEntries);
+ WriteData(outBuf, &writeOffset, &networkByteOrder, sizeof(networkByteOrder));
+ }
+
+ /* Write entries */
+ {
+ const MMessageField * f = msg->firstField;
+ while(f)
+ {
+ if (f->isFlattenable) writeOffset += FlattenMMessageField(f, &((char *)outBuf)[writeOffset]);
+ f = f->nextField;
+ }
+ }
+ }
+/*printf("%s %lu/%lu\n", (writeOffset != MMGetFlattenedSize(msg))?"ERROR":"ok", writeOffset, MMGetFlattenedSize(msg)); DEBUG */
+}
+
+static MMessageField * ImportMMessageField(const char * fieldName, uint32 nameLength, uint32 tc, uint32 eLength, const void * dataPtr, uint32 itemSize, uint32 swapSize)
+{
+ uint32 numItems = eLength/itemSize;
+ MMessageField * field = AllocMMessageField(fieldName, nameLength, tc, numItems, itemSize);
+ if (field)
+ {
+ if (BYTE_ORDER != LITTLE_ENDIAN) SwapCopy(field->data, dataPtr, numItems*(itemSize/swapSize), swapSize);
+ else memcpy(field->data, dataPtr, numItems*itemSize);
+ return field;
+ }
+ return NULL;
+}
+
+status_t MMUnflattenMessage(MMessage * msg, const void * inBuf, uint32 inputBufferBytes)
+{
+ uint32 i, readOffset = 0;
+ const uint8 * buffer = (const uint8 *) inBuf;
+ const uint8 * dataPtr;
+
+ /* Read and check protocol version number */
+ uint32 networkByteOrder, numEntries;
+ {
+ uint32 messageProtocolVersion;
+ if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)) != B_NO_ERROR) return B_ERROR;
+
+ messageProtocolVersion = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
+ if ((messageProtocolVersion < OLDEST_SUPPORTED_PROTOCOL_VERSION)||(messageProtocolVersion > CURRENT_PROTOCOL_VERSION)) return B_ERROR;
+
+ /* Read 'what' code */
+ if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)) != B_NO_ERROR) return B_ERROR;
+ msg->what = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
+
+ /* Read number of entries */
+ if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)) != B_NO_ERROR) return B_ERROR;
+ numEntries = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
+ }
+
+ MMClearMessage(msg);
+
+ /* Read entries */
+ for (i=0; i<numEntries; i++)
+ {
+ const char * fieldName;
+ uint32 nameLength, tc, eLength;
+ MMessageField * newField = NULL;
+ MBool doAddField = MTrue;
+
+ /* Read entry name length */
+ if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)) != B_NO_ERROR) return B_ERROR;
+
+ nameLength = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
+ if (nameLength > inputBufferBytes-readOffset) return B_ERROR;
+
+ /* Read entry name */
+ fieldName = (const char *) &buffer[readOffset];
+ readOffset += nameLength;
+
+ /* Read entry type code */
+ if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)) != B_NO_ERROR) return B_ERROR;
+ tc = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
+
+ /* Read entry data length */
+ if (ReadData(buffer, inputBufferBytes, &readOffset, &networkByteOrder, sizeof(networkByteOrder)) != B_NO_ERROR) return B_ERROR;
+ eLength = B_LENDIAN_TO_HOST_INT32(networkByteOrder);
+ if (eLength > inputBufferBytes-readOffset) return B_ERROR;
+
+ dataPtr = &buffer[readOffset];
+ switch(tc)
+ {
+ case B_BOOL_TYPE: newField = ImportMMessageField(fieldName, nameLength, tc, eLength, dataPtr, sizeof(MBool), sizeof(MBool)); break;
+ case B_DOUBLE_TYPE: newField = ImportMMessageField(fieldName, nameLength, tc, eLength, dataPtr, sizeof(double), sizeof(double)); break;
+ case B_FLOAT_TYPE: newField = ImportMMessageField(fieldName, nameLength, tc, eLength, dataPtr, sizeof(float), sizeof(float)); break;
+ case B_INT64_TYPE: newField = ImportMMessageField(fieldName, nameLength, tc, eLength, dataPtr, sizeof(int64), sizeof(int64)); break;
+ case B_INT32_TYPE: newField = ImportMMessageField(fieldName, nameLength, tc, eLength, dataPtr, sizeof(int32), sizeof(int32)); break;
+ case B_INT16_TYPE: newField = ImportMMessageField(fieldName, nameLength, tc, eLength, dataPtr, sizeof(int16), sizeof(int16)); break;
+ case B_INT8_TYPE: newField = ImportMMessageField(fieldName, nameLength, tc, eLength, dataPtr, sizeof(int8), sizeof(int8)); break;
+
+ case B_MESSAGE_TYPE:
+ {
+ /* Annoying special case, since this type doesn't contain a number-of-items field, */
+ /* we have to read them in to a temporary linked list and find out how many there are that way */
+ MMessage * head = NULL, * tail = NULL;
+ uint32 eUsed = 0;
+ uint32 eOffset = readOffset;
+ uint32 listLength = 0;
+ status_t ret = B_NO_ERROR;
+ while((eUsed < eLength)&&(ret == B_NO_ERROR))
+ {
+ uint32 entryLen;
+ ret = B_ERROR; /* go pessimistic for a bit */
+ if (ReadData(buffer, inputBufferBytes, &eOffset, &entryLen, sizeof(entryLen)) == B_NO_ERROR)
+ {
+ entryLen = B_LENDIAN_TO_HOST_INT32(entryLen);
+ if (eOffset + entryLen <= inputBufferBytes)
+ {
+ MMessage * newMsg = MMAllocMessage(0);
+ if (newMsg)
+ {
+ if (MMUnflattenMessage(newMsg, &buffer[eOffset], entryLen) == B_NO_ERROR)
+ {
+ ret = B_NO_ERROR;
+ eOffset += entryLen;
+ eUsed += (sizeof(uint32) + entryLen);
+ if (tail)
+ {
+ tail->scratch = newMsg;
+ tail = newMsg;
+ }
+ else head = tail = newMsg;
+
+ listLength++;
+ }
+ else MMFreeMessage(newMsg);
+ }
+ }
+ }
+ }
+ if (ret == B_NO_ERROR)
+ {
+ MMessage ** newMsgField = MMPutMessageField(msg, MFalse, fieldName, listLength);
+ if (newMsgField)
+ {
+ uint32 i;
+ for (i=0; i<listLength; i++)
+ {
+ newMsgField[i] = head;
+ head = head->scratch;
+ }
+ doAddField = MFalse;
+ }
+ else ret = B_ERROR;
+ }
+ if (ret != B_NO_ERROR)
+ {
+ /* Clean up on error */
+ while(head)
+ {
+ MMessage * next = head->scratch;
+ MMFreeMessage(head);
+ head = next;
+ }
+ MMRemoveField(msg, fieldName);
+ return B_ERROR;
+ }
+ }
+ break;
+
+ /** Note that this should never really happen since we don't put pointers in flattened messages anymore, but it's here for backwards compatibility
+ * with older code that did do that.
+ */
+ case B_POINTER_TYPE: newField = ImportMMessageField(fieldName, nameLength, B_INT32_TYPE, eLength, dataPtr, sizeof(int32), sizeof(int32)); break;
+ case B_POINT_TYPE: newField = ImportMMessageField(fieldName, nameLength, tc, eLength, dataPtr, sizeof(float)*2, sizeof(float)); break;
+ case B_RECT_TYPE: newField = ImportMMessageField(fieldName, nameLength, tc, eLength, dataPtr, sizeof(float)*4, sizeof(float)); break;
+
+ default:
+ {
+ /* All other types get loaded as variable-sized byte buffers */
+ uint32 numItems;
+ uint32 eOffset = readOffset;
+ if (ReadData(buffer, inputBufferBytes, &eOffset, &numItems, sizeof(numItems)) == B_NO_ERROR)
+ {
+ MByteBuffer ** bufs;
+ numItems = B_LENDIAN_TO_HOST_INT32(numItems);
+ bufs = PutMMVariableFieldAux(msg, MFalse, tc, fieldName, numItems);
+ if (bufs)
+ {
+ uint32 eLeft = eLength;
+ uint32 i;
+
+ doAddField = MFalse;
+ for (i=0; i<numItems; i++)
+ {
+ uint32 itemSize;
+ MBool ok = MFalse;
+ if (ReadData(buffer, inputBufferBytes, &eOffset, &itemSize, sizeof(itemSize)) == B_NO_ERROR)
+ {
+ itemSize = B_LENDIAN_TO_HOST_INT32(itemSize);
+ if ((itemSize+sizeof(uint32) <= eLeft)&&((bufs[i] = MBAllocByteBuffer(itemSize, MFalse)) != NULL))
+ {
+ eLeft -= (itemSize + sizeof(uint32));
+ memcpy(&bufs[i]->bytes, &buffer[eOffset], itemSize);
+ eOffset += itemSize;
+ ok = true;
+ }
+ }
+ if (ok == MFalse)
+ {
+ MMRemoveField(msg, fieldName);
+ return B_ERROR;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ if (doAddField)
+ {
+ if (newField) AddMMessageField(msg, newField);
+ else return B_ERROR;
+ }
+
+ readOffset += eLength;
+ }
+ return B_NO_ERROR;
+}
+
+status_t MMMoveField(MMessage * sourceMsg, const char * fieldName, MMessage * destMsg)
+{
+ if (sourceMsg == destMsg) return B_NO_ERROR; /* easy to move it to itself, it's already there! */
+ else
+ {
+ MMessageField * moveMe = LookupMMessageField(sourceMsg, fieldName, B_ANY_TYPE);
+ if (moveMe)
+ {
+ DetachMMessageField(sourceMsg, moveMe);
+ if (destMsg)
+ {
+ MMessageField * killMe = LookupMMessageField(destMsg, fieldName, B_ANY_TYPE);
+ if (killMe)
+ {
+ DetachMMessageField(destMsg, killMe);
+ FreeMMessageField(moveMe);
+ }
+ AddMMessageField(destMsg, moveMe);
+ }
+ else FreeMMessageField(moveMe); /* move to NULL == kill it */
+
+ return B_NO_ERROR;
+ }
+ return B_ERROR;
+ }
+}
+
+status_t MMCopyField(const MMessage * sourceMsg, const char * fieldName, MMessage * destMsg)
+{
+ if (sourceMsg == destMsg) return B_NO_ERROR; /* easy to move it to itself, it's already there! */
+ else
+ {
+ MMessageField * copyMe = LookupMMessageField(sourceMsg, fieldName, B_ANY_TYPE);
+ if (copyMe)
+ {
+ if (destMsg)
+ {
+ MMessageField * clone = CloneMMessageField(copyMe);
+ if (clone)
+ {
+ MMessageField * killMe = LookupMMessageField(destMsg, fieldName, B_ANY_TYPE);
+ if (killMe)
+ {
+ DetachMMessageField(destMsg, killMe);
+ FreeMMessageField(copyMe);
+ }
+ AddMMessageField(destMsg, copyMe);
+ }
+ else return B_ERROR;
+ }
+ return B_NO_ERROR;
+ }
+ return B_ERROR;
+ }
+}
+
+status_t MMRenameField(MMessage * msg, const char * oldFieldName, const char * newFieldName)
+{
+ if (strcmp(oldFieldName, newFieldName) == 0) return B_NO_ERROR;
+ else
+ {
+ MMessageField * f = LookupMMessageField(msg, oldFieldName, B_ANY_TYPE);
+ if (f)
+ {
+ MMessageField * overwriteThis = LookupMMessageField(msg, newFieldName, B_ANY_TYPE); /* do this lookup before any mods! */
+ int slen = strlen(newFieldName)+1;
+ int diff = (slen - f->nameBytes);
+ if (diff != 0)
+ {
+ uint32 newSize = f->allocSize+diff;
+ MMessageField * g = (MMessageField *) MRealloc(f, newSize);
+ if (g == NULL) return B_ERROR;
+
+ g->allocSize = newSize;
+ g->nameBytes = slen;
+ if (g != f)
+ {
+ /* Oops, gotta update all the pointers to point to the new field */
+ g->data = ((char *)g) + sizeof(MMessageField); /* data bytes start immediately after the struct */
+ g->name = ((const char *)g->data)+(g->numItems*g->itemSize); /* name starts right after the data */
+ if (g->prevField) g->prevField->nextField = g;
+ if (g->nextField) g->nextField->prevField = g;
+ if (msg->firstField == f) msg->firstField = g;
+ if (msg->lastField == f) msg->lastField = g;
+ f = g;
+ }
+ }
+ memcpy((char *)f->name, newFieldName, slen);
+
+ /* If our field now occupies the same name as another, delete the other, to maintain fieldname uniqueness */
+ if (overwriteThis)
+ {
+ DetachMMessageField(msg, overwriteThis);
+ FreeMMessageField(overwriteThis);
+ }
+
+ return B_NO_ERROR;
+ }
+ }
+ return B_ERROR;
+}
+
+MByteBuffer ** MMGetStringField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (MByteBuffer **) GetFieldDataAux(msg, fieldName, B_STRING_TYPE, optRetNumItems);
+}
+
+MBool * MMGetBoolField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (MBool *) GetFieldDataAux(msg, fieldName, B_BOOL_TYPE, optRetNumItems);
+}
+
+int8 * MMGetInt8Field(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (int8 *) GetFieldDataAux(msg, fieldName, B_INT8_TYPE, optRetNumItems);
+}
+
+int16 * MMGetInt16Field(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (int16 *) GetFieldDataAux(msg, fieldName, B_INT16_TYPE, optRetNumItems);
+}
+
+int32 * MMGetInt32Field(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (int32 *) GetFieldDataAux(msg, fieldName, B_INT32_TYPE, optRetNumItems);
+}
+
+int64 * MMGetInt64Field(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (int64 *) GetFieldDataAux(msg, fieldName, B_INT64_TYPE, optRetNumItems);
+}
+
+float * MMGetFloatField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (float *) GetFieldDataAux(msg, fieldName, B_FLOAT_TYPE, optRetNumItems);
+}
+
+double * MMGetDoubleField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (double *) GetFieldDataAux(msg, fieldName, B_DOUBLE_TYPE, optRetNumItems);
+}
+
+MMessage ** MMGetMessageField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (MMessage **) GetFieldDataAux(msg, fieldName, B_MESSAGE_TYPE, optRetNumItems);
+}
+
+void ** MMGetPointerField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (void **) GetFieldDataAux(msg, fieldName, B_POINTER_TYPE, optRetNumItems);
+}
+
+MPoint * MMGetPointField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (MPoint *) GetFieldDataAux(msg, fieldName, B_POINT_TYPE, optRetNumItems);
+}
+
+MRect * MMGetRectField(const MMessage * msg, const char * fieldName, uint32 * optRetNumItems)
+{
+ return (MRect *) GetFieldDataAux(msg, fieldName, B_RECT_TYPE, optRetNumItems);
+}
+
+MByteBuffer ** MMGetDataField(const MMessage * msg, uint32 typeCode, const char * fieldName, uint32 * optRetNumItems)
+{
+ return ((typeCode != B_MESSAGE_TYPE)&&(IsTypeCodeVariableSize(typeCode))) ? (MByteBuffer **) GetFieldDataAux(msg, fieldName, typeCode, optRetNumItems) : NULL;
+}
+
+status_t MMGetFieldInfo(const MMessage * msg, const char * fieldName, uint32 typeCode, uint32 * optRetNumItems, uint32 * optRetTypeCode)
+{
+ MMessageField * f = LookupMMessageField(msg, fieldName, typeCode);
+ if (f)
+ {
+ if (optRetNumItems) *optRetNumItems = f->numItems;
+ if (optRetTypeCode) *optRetTypeCode = f->typeCode;
+ return B_NO_ERROR;
+ }
+ return B_ERROR;
+}
+
+MMessageIterator MMGetFieldNameIterator(const MMessage * msg, uint32 typeCode)
+{
+ MMessageIterator ret;
+ ret.message = msg;
+ ret.iterState = msg->firstField;
+ ret.typeCode = typeCode;
+ return ret;
+}
+
+const char * MMGetNextFieldName(MMessageIterator * iter, uint32 * optRetTypeCode)
+{
+ while(iter->iterState)
+ {
+ MMessageField * f = (MMessageField *) iter->iterState;
+ if ((iter->typeCode == B_ANY_TYPE)||(iter->typeCode == f->typeCode))
+ {
+ const char * ret = f->name;
+ if (optRetTypeCode) *optRetTypeCode = f->typeCode;
+ iter->iterState = f->nextField;
+ return ret;
+ }
+ else iter->iterState = f->nextField;
+ }
+ return NULL;
+}
+
+static void DoIndent(int numSpaces)
+{
+ int i=0;
+ for (i=0; i<numSpaces; i++) putchar(' ');
+}
+
+static void PrintMMessageToStreamAux(const MMessage * msg, int indent); /* forward declaration */
+
+static void PrintMMessageFieldToStream(const MMessageField * field, int indent)
+{
+ char pbuf[5];
+ const void * data = field->data;
+
+ int i = 0;
+ int ni = field->numItems;
+ if (ni > 10) ni = 10; /* truncate to avoid too much spam */
+
+ MakePrettyTypeCodeString(field->typeCode, pbuf);
+ DoIndent(indent); printf("Entry: Name=[%s] GetNumItems()=%lu, TypeCode=%s (%li) flatSize=%lu\n", field->name, field->numItems, pbuf, field->typeCode, GetMMessageFieldFlattenedSize(field, MFalse));
+ for (i=0; i<ni; i++)
+ {
+ DoIndent(indent); printf(" %i. ", i);
+ switch(field->typeCode)
+ {
+ case B_BOOL_TYPE: printf("%i\n", (((const MBool *)data)[i])); break;
+ case B_DOUBLE_TYPE: printf("%f\n", ((const double *)data)[i]); break;
+ case B_FLOAT_TYPE: printf("%f\n", ((const float *)data)[i]); break;
+ case B_INT64_TYPE: printf("%lli\n", ((const int64 *)data)[i]); break;
+ case B_INT32_TYPE: printf("%li\n", ((const int32 *)data)[i]); break;
+ case B_POINTER_TYPE: printf("%p\n", ((const void **)data)[i]); break;
+ case B_INT16_TYPE: printf("%i\n", ((const int16 *)data)[i]); break;
+ case B_INT8_TYPE: printf("%i\n", ((const int8 *)data)[i]); break;
+
+ case B_POINT_TYPE:
+ {
+ const MPoint * pt = &((const MPoint *)data)[i];
+ printf("x=%f y=%f\n", pt->x, pt->y);
+ }
+ break;
+
+ case B_RECT_TYPE:
+ {
+ const MRect * rc = &((const MRect *)data)[i];
+ printf("l=%f t=%f r=%f b=%f\n", rc->left, rc->top, rc->right, rc->bottom);
+ }
+ break;
+
+ case B_MESSAGE_TYPE:
+ {
+ MMessage * subMsg = ((MMessage **)field->data)[i];
+ if (subMsg) PrintMMessageToStreamAux(subMsg, indent+3);
+ else printf("(NULL Message)\n");
+ }
+ break;
+
+ case B_STRING_TYPE:
+ {
+ MByteBuffer * subBuf = ((MByteBuffer **)field->data)[i];
+ if (subBuf) printf("[%s]\n", (const char *) (&subBuf->bytes));
+ else printf("(NULL String)\n");
+ }
+ break;
+
+ default:
+ {
+ MByteBuffer * subBuf = ((MByteBuffer **)field->data)[i];
+ if (subBuf)
+ {
+ int numBytes = subBuf->numBytes;
+ if (numBytes > 0)
+ {
+ const uint8 * b = &subBuf->bytes;
+ int nb = subBuf->numBytes;
+ int j;
+
+ if (nb > 10)
+ {
+ printf("(%i bytes, starting with", nb);
+ nb = 10;
+ }
+ else printf("(%i bytes, equal to",nb);
+
+ for (j=0; j<nb; j++) printf(" %02x", b[j]);
+ if (nb < subBuf->numBytes) printf("...)\n");
+ else printf(")\n");
+ }
+ else printf("(zero-length buffer)\n");
+ }
+ else printf("(NULL Buffer)\n");
+ }
+ break;
+ }
+ }
+}
+
+static void PrintMMessageToStreamAux(const MMessage * msg, int indent)
+{
+ /* Make a pretty type code string */
+ char buf[5];
+ MakePrettyTypeCodeString(msg->what, buf);
+
+ printf("MMessage: msg=%p, what='%s' (%li/0x%lx), entryCount=%li, flatSize=%lu\n", msg, buf, msg->what, msg->what, msg->numFields, MMGetFlattenedSize(msg));
+
+ indent += 2;
+ {
+ MMessageField * f = msg->firstField;
+ while(f)
+ {
+ PrintMMessageFieldToStream(f, indent);
+ f = f->nextField;
+ }
+ }
+}
+
+void MMPrintToStream(const MMessage * msg)
+{
+ PrintMMessageToStreamAux(msg, 0);
+}
+
+MBool MMAreMessagesEqual(const MMessage * msg1, const MMessage * msg2)
+{
+ if (msg1 == msg2) return MTrue;
+ if ((msg1->what != msg2->what)||(msg1->numFields != msg2->numFields)) return MFalse;
+ else
+ {
+ const MMessageField * f1 = msg1->firstField;
+ while(f1)
+ {
+ uint32 numItems = f1->numItems;
+ const MMessageField * f2 = LookupMMessageField(msg2, f1->name, f1->typeCode);
+ if ((f2 == NULL)||(f2->numItems != numItems)||(f2->typeCode != f1->typeCode)) return MFalse;
+
+ if (IsTypeCodeVariableSize(f1->typeCode))
+ {
+ uint32 i;
+ if (f1->typeCode == B_MESSAGE_TYPE)
+ {
+ const MMessage ** msgs1 = (const MMessage **) f1->data;
+ const MMessage ** msgs2 = (const MMessage **) f2->data;
+ for (i=0; i<numItems; i++) if (((msgs1[i] != NULL) != (msgs2[i] != NULL))||((msgs1[i])&&(MMAreMessagesEqual(msgs1[i], msgs2[i]) == MFalse))) return MFalse;
+ }
+ else
+ {
+ const MByteBuffer ** bufs1 = (const MByteBuffer **) f1->data;
+ const MByteBuffer ** bufs2 = (const MByteBuffer **) f2->data;
+ for (i=0; i<numItems; i++) if (((bufs1[i] != NULL) != (bufs2[i] != NULL))||((bufs1[i])&&(MBAreByteBuffersEqual(bufs1[i], bufs2[i]) == MFalse))) return MFalse;
+ }
+ }
+ else if (memcmp(f1->data, f2->data, numItems*f1->itemSize) != 0) return MFalse;
+
+ f1 = f1->nextField;
+ }
+ }
+ return MTrue;
+}
+
+#ifdef cplusplus
+};
+#endif
Added: trunk/src/MiniMessageGateway.c
==============================================================================
--- (empty file)
+++ trunk/src/MiniMessageGateway.c Mon Sep 12 21:55:15 2005
@@ -0,0 +1,242 @@
+/* NeoStats - IRC Statistical Services
+** Copyright (c) 1999-2005 Adam Rutter, Justin Hammond, Mark Hetherington
+** http://www.neostats.net/
+**
+** Portions Copyright (c) 2000 - 2001 ^Enigma^
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+** USA
+**
+** NeoStats CVS Identification
+** $Id$
+*/
+
+/** @file MiniMessageGateway.c
+ * @brief module functions
+ */
+
+#include "neostats.h"
+#include "MiniMessageGateway.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _MMessageGateway {
+ MByteBuffer * _curInput; /* We receive data into this buffer */
+ MByteBuffer * _curOutput; /* The head of our output-buffers linked list */
+ MByteBuffer * _outputTail; /* The tail of our output-buffers linked list */
+ uint32 _curInputPos; /* Index of next byte to receive in _curInput */
+ uint32 _maxInputPos; /* Index of last byte to receive in _curInput */
+ uint32 _curOutputPos; /* Index of next byte to send in _curOutput */
+};
+
+static inline MByteBuffer * GetNextPointer(const MByteBuffer * buf)
+{
+ return *((MByteBuffer **)(&buf->bytes));
+}
+
+static inline void SetNextPointer(MByteBuffer * buf, const MByteBuffer * next)
+{
+ *((const MByteBuffer **)(&buf->bytes)) = next;
+}
+
+MMessageGateway * MGAllocMessageGateway()
+{
+ MMessageGateway * ret = MMalloc(sizeof(MMessageGateway));
+ if (ret)
+ {
+ ret->_outputTail = NULL;
+ ret->_curInputPos = 0; /* input buffer doesn't have a next pointer */
+ ret->_curOutputPos = sizeof(MByteBuffer *); /* start sending after the next pointer */
+ ret->_maxInputPos = (2*sizeof(uint32)); /* start by reading the fixed-size header fields */
+ ret->_curOutput = NULL;
+ ret->_curInput = MBAllocByteBuffer(ret->_maxInputPos, false);
+ if (ret->_curInput == NULL)
+ {
+ MFree(ret);
+ ret = NULL;
+ }
+ }
+ return ret;
+}
+
+void MGFreeMessageGateway(MMessageGateway * gw)
+{
+ if (gw)
+ {
+ MBFreeByteBuffer(gw->_curInput);
+ while(gw->_curOutput)
+ {
+ MByteBuffer * next = GetNextPointer(gw->_curOutput);
+ MBFreeByteBuffer(gw->_curOutput);
+ gw->_curOutput = next;
+ }
+ MFree(gw);
+ }
+}
+
+static const uint32 _MUSCLE_MESSAGE_ENCODING_DEFAULT = 1164862256; /* 'Enc0' -- vanilla encoding */
+
+status_t MGAddOutgoingMessage(MMessageGateway * gw, const MMessage * msg)
+{
+ uint32 flatSize = MMGetFlattenedSize(msg);
+ MByteBuffer * buf = MBAllocByteBuffer(sizeof(MMessage *) + (2*sizeof(uint32)) + flatSize, false);
+ if (buf)
+ {
+ uint32 * h = (uint32 *)(((MMessage **)(&buf->bytes))+1);
+
+ SetNextPointer(buf, NULL);
+ h[0] = B_HOST_TO_LENDIAN_INT32(flatSize);
+ h[1] = B_HOST_TO_LENDIAN_INT32(_MUSCLE_MESSAGE_ENCODING_DEFAULT);
+ MMFlattenMessage(msg, (uint8 *) &h[2]);
+
+ if (gw->_outputTail)
+ {
+ SetNextPointer(gw->_outputTail, buf);
+ gw->_outputTail = buf;
+ }
+ else gw->_curOutput = gw->_outputTail = buf;
+
+ return B_NO_ERROR;
+ }
+ else return B_ERROR;
+}
+
+MBool MGHasBytesToOutput(const MMessageGateway * gw)
+{
+ return (gw->_curOutput != NULL);
+}
+
+int32 MGDoOutput(MMessageGateway * gw, uint32 maxBytes, MGSendFunc sendFunc, void * arg)
+{
+ int32 totalSent = 0;
+ while(gw->_curOutput != NULL)
+ {
+ int32 bytesSent;
+
+ uint32 bytesToSend = gw->_curOutput->numBytes - gw->_curOutputPos;
+ if (bytesToSend > maxBytes) bytesToSend = maxBytes;
+
+ bytesSent = sendFunc((&gw->_curOutput->bytes)+(gw->_curOutputPos), bytesToSend, arg);
+ if (bytesSent < 0) return -1; /* error! */
+ else
+ {
+ totalSent += bytesSent;
+ maxBytes -= bytesSent;
+ gw->_curOutputPos += bytesSent;
+ if (gw->_curOutputPos == gw->_curOutput->numBytes)
+ {
+ MByteBuffer * next = GetNextPointer(gw->_curOutput);
+ if (next == NULL) gw->_outputTail = NULL;
+ MBFreeByteBuffer(gw->_curOutput);
+ gw->_curOutput = next;
+ gw->_curOutputPos = sizeof(MByteBuffer *); /* send all data after the next-pointer */
+ }
+ }
+ if (bytesSent < bytesToSend) break; /* short write indicates that the output buffer is full for now */
+ }
+ return totalSent;
+}
+
+int32 MGDoInput(MMessageGateway * gw, uint32 maxBytes, MGReceiveFunc recvFunc, void * arg, MMessage ** optRetMsg)
+{
+ int32 totalRecvd = 0;
+
+ if (optRetMsg) *optRetMsg = NULL;
+ while(true)
+ {
+ int32 bytesReceived;
+ uint32 bytesToRecv = gw->_maxInputPos - gw->_curInputPos;
+ if (bytesToRecv > maxBytes) bytesToRecv = maxBytes;
+
+ bytesReceived = recvFunc((&gw->_curInput->bytes)+gw->_curInputPos, bytesToRecv, arg);
+ if (bytesReceived < 0) return -1; /* error */
+ else
+ {
+ totalRecvd += bytesReceived;
+ maxBytes -= bytesReceived;
+ gw->_curInputPos += bytesReceived;
+ if (gw->_curInputPos == gw->_maxInputPos)
+ {
+ if (gw->_curInputPos > (2*sizeof(uint32)))
+ {
+ /* We have received the Message body and we are ready to unflatten! */
+ MMessage * msg = MMAllocMessage(0);
+ if (msg == NULL) return -1; /* out of memory */
+
+ if (MMUnflattenMessage(msg, (&gw->_curInput->bytes)+(2*sizeof(uint32)), gw->_maxInputPos-(2*sizeof(uint32))) == B_NO_ERROR)
+ {
+ /* set parser up for the next go-round */
+ gw->_curInputPos = 0;
+ gw->_maxInputPos = 2*(sizeof(uint32));
+
+ /* For input buffers over 64KB, it's better to reclaim the extra space than avoid reallocating */
+ if (gw->_curInput->numBytes > 64*1024)
+ {
+ MByteBuffer * smallBuf = MBAllocByteBuffer(64*1024, false);
+ if (smallBuf == NULL)
+ {
+ MMFreeMessage(msg);
+ return -1;
+ }
+
+ MBFreeByteBuffer(gw->_curInput);
+ gw->_curInput = smallBuf;
+ }
+
+ if (optRetMsg)
+ {
+ *optRetMsg = msg;
+ break; /* If we have a Message for the user, return it to him now */
+ }
+ else MMFreeMessage(msg); /* User doesn't want it, so just throw it away */
+ }
+ else
+ {
+ MMFreeMessage(msg);
+ return -1; /* parse error! */
+ }
+ }
+ else
+ {
+ /* We have our fixed-size headers, now prepare to receive the actual Message body! */
+ const uint32 * h = (const uint32 *)(&gw->_curInput->bytes);
+ uint32 bodySize = B_LENDIAN_TO_HOST_INT32(h[0]);
+ if ((bodySize == 0)||(B_LENDIAN_TO_HOST_INT32(h[1]) != _MUSCLE_MESSAGE_ENCODING_DEFAULT)) return -1; /* unsupported encoding! */
+
+ bodySize += (2*sizeof(uint32)); /* we'll include the fixed headers in our body buffer too */
+ if (bodySize > gw->_curInput->numBytes)
+ {
+ /** Gotta trade up for a larger buffer, so that all our data will fit! */
+ MByteBuffer * bigBuf = MBAllocByteBuffer(2*bodySize, false); /* might as well alloc some extra space too */
+ if (bigBuf == NULL) return -1; /* out of memory! */
+
+ memcpy(&bigBuf->bytes, &gw->_curInput->bytes, gw->_curInputPos); /* not strictly necessary, but for form's sake... */
+ MBFreeByteBuffer(gw->_curInput); /* dispose of the too-small old input buffer */
+ gw->_curInput = bigBuf;
+ }
+ gw->_maxInputPos = bodySize;
+ }
+ }
+ }
+ if (bytesReceived < bytesToRecv) break; /* short read indicates that the input buffer is empty for now */
+ }
+ return totalRecvd;
+}
+
+#ifdef __cplusplus
+};
+#endif