/*
docCopyright("Steve Dekorte", 2004)
docLicense("BSD revised")
*/
#include "Base.h"
//#define BStream_C
#include "BStream.h"
//#undef BStream_C
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <limits.h>
#define BSTREAM_IS_BIG_ENDIAN 1
BStream *BStream_new(void)
{
BStream *self = (BStream *)calloc(1, sizeof(BStream));
self->ba = ByteArray_new();
self->ownsByteArray = 1;
self->tmp = ByteArray_new();
self->errorBa = ByteArray_new();
self->index = 0;
self->typeBuf = (unsigned char *)malloc(512);
return self;
}
BStream *BStream_clone(BStream *self)
{
BStream *child = BStream_new();
ByteArray_copy_(child->ba, self->ba);
child->index = self->index;
return child;
}
void BStream_free(BStream *self)
{
if (self->ownsByteArray) ByteArray_free(self->ba);
ByteArray_free(self->tmp);
ByteArray_free(self->errorBa);
free(self->typeBuf);
free(self);
}
void BStream_error_(BStream *self, const char *s)
{
ByteArray_setCString_(self->errorBa, s);
}
char *BStream_error(BStream *self)
{
return (char *)ByteArray_bytes(self->errorBa);
}
void BStream_setByteArray_(BStream *self, ByteArray *ba)
{
if (self->ownsByteArray)
{
ByteArray_free(ba);
self->ownsByteArray = 0;
}
self->ba = ba;
self->index = 0;
}
Datum BStream_datum(BStream *self)
{
return ByteArray_asDatum(self->ba);
}
void BStream_setData_length_(BStream *self, unsigned char *data, size_t length)
{
ByteArray_setData_size_(self->ba, data, length);
self->index = 0;
}
ByteArray *BStream_byteArray(BStream *self)
{
return self->ba;
}
void BStream_empty(BStream *self)
{
self->index = 0;
ByteArray_setSize_(self->ba, 0);
}
int BStream_isEmpty(BStream *self)
{
return ByteArray_size(self->ba) == 0;
}
// writing --------------------------------------
void BStream_writeByte_(BStream *self, unsigned char v)
{
BStream_writeUint8_(self, v);
}
void BStream_writeUint8_(BStream *self, uint8_t v)
{
ByteArray_appendByte_(self->ba, v);
self->index ++;
}
static void reverseBytes(unsigned char *d, size_t length)
{
size_t a = 0;
size_t b = length - 1;
while ( a < b)
{
unsigned char c = d[a];
d[a] = d[b];
d[b] = c;
a ++;
b --;
}
}
void BStream_writeNumber_size_(BStream *self, unsigned char *v, size_t length)
{
memcpy(self->typeBuf, v, length);
if (self->flipEndian)
{
reverseBytes(self->typeBuf, length);
}
ByteArray_appendBytes_size_(self->ba, (unsigned char *)self->typeBuf, length);
self->index += length;
}
void BStream_writeData_length_(BStream *self, const unsigned char *data, size_t length)
{
ByteArray_appendBytes_size_(self->ba, (unsigned char *)data, length);
self->index += length;
}
void BStream_writeInt32_(BStream *self, int32_t v)
{
BStream_writeNumber_size_(self, (unsigned char *)(&v), sizeof(int32_t));
}
void BStream_writeUint32_(BStream *self, uint32_t v)
{
BStream_writeNumber_size_(self, (unsigned char *)(&v), sizeof(uint32_t));
}
#if !defined(__SYMBIAN32__)
void BStream_writeInt64_(BStream *self, int64_t v)
{
BStream_writeNumber_size_(self, (unsigned char *)(&v), sizeof(int64_t));
}
#endif
void BStream_writeDouble_(BStream *self, double v)
{
BStream_writeNumber_size_(self, (unsigned char *)(&v), sizeof(double));
}
void BStream_writeCString_(BStream *self, const char *s)
{
int length = strlen(s);
BStream_writeInt32_(self, length);
BStream_writeData_length_(self, (unsigned char *)s, length);
}
void BStream_writeByteArray_(BStream *self, ByteArray *ba)
{
BStream_writeInt32_(self, ByteArray_size(ba));
ByteArray_append_(self->ba, ba);
self->index += ByteArray_size(ba);
}
// reading --------------------------------------
unsigned char BStream_readByte(BStream *self)
{
return BStream_readUint8(self);
}
uint8_t BStream_readUint8(BStream *self)
{
if (self->index < ByteArray_size(self->ba))
{
unsigned char b = ByteArray_bytes(self->ba)[self->index];
self->index ++;
return b;
}
return 0;
}
void BStream_readNumber_size_(BStream *self, unsigned char *v, int size)
{
if (self->index + size <= ByteArray_size(self->ba))
{
unsigned char *b = ByteArray_bytes(self->ba);
memcpy(v, b + self->index, size);
if (self->flipEndian)
{
reverseBytes(v, size);
}
self->index += size;
return;
}
while (size--)
{
*v = 0;
v ++;
}
}
uint32_t BStream_readUint32(BStream *self)
{
uint32_t v;
BStream_readNumber_size_(self, (unsigned char *)(&v), sizeof(uint32_t));
return v;
}
int32_t BStream_readInt32(BStream *self)
{
int32_t v;
BStream_readNumber_size_(self, (unsigned char *)(&v), sizeof(int32_t));
return v;
}
#if !defined(__SYMBIAN32__)
int64_t BStream_readInt64(BStream *self)
{
int64_t v;
BStream_readNumber_size_(self, (unsigned char *)(&v), sizeof(int64_t));
return v;
}
#endif
double BStream_readDouble(BStream *self)
{
double v;
BStream_readNumber_size_(self, (unsigned char *)(&v), sizeof(double));
return v;
}
unsigned char *BStream_readDataOfLength_(BStream *self, size_t length)
{
if (self->index + length <= ByteArray_size(self->ba))
{
unsigned char *b = ByteArray_bytes(self->ba) + self->index;
self->index += length;
return b;
}
return NULL;
}
void BStream_readByteArray_(BStream *self, ByteArray *b)
{
size_t size = BStream_readInt32(self);
unsigned char *data = BStream_readDataOfLength_(self, size);
ByteArray_setData_size_(b, data, size);
}
ByteArray *BStream_readByteArray(BStream *self)
{
BStream_readByteArray_(self, self->tmp);
return self->tmp;
}
const char *BStream_readCString(BStream *self)
{
BStream_readByteArray_(self, self->tmp);
return (const char *)ByteArray_bytes(self->tmp);
}
// tagged writing --------------------------------------
void BStream_writeTag(BStream *self, unsigned int t, unsigned int b, unsigned int a)
{
BStreamTag tag;
tag.isArray = a;
tag.type = t;
tag.byteCount = b;
{
unsigned char c = BStreamTag_asUnsignedChar(&tag);
BStreamTag tag2 = BStreamTag_FromUnsignedChar(c);
if (tag2.isArray != tag.isArray ||
tag2.type != tag.type ||
tag2.byteCount != tag.byteCount)
{
printf("tags don't match\n");
exit(-1);
}
BStream_writeUint8_(self, c);
}
}
void BStream_writeTaggedUint8_(BStream *self, uint8_t v)
{
BStream_writeTag(self, BSTREAM_UNSIGNED_INT, 1, 0);
BStream_writeUint8_(self, v);
}
void BStream_writeTaggedUint32_(BStream *self, uint32_t v)
{
BStream_writeTag(self, BSTREAM_UNSIGNED_INT, 4, 0);
BStream_writeUint32_(self, v);
}
void BStream_writeTaggedInt32_(BStream *self, int32_t v)
{
/*
if (v =< MAX_INT && v -128)
{
BStream_writeTag(self, BSTREAM_SIGNED_INT, 1, 0);
BStream_writeInt8_(self, (int8_t)v);
}
else
*/
{
BStream_writeTag(self, BSTREAM_SIGNED_INT, 4, 0);
BStream_writeInt32_(self, v);
}
}
#if !defined(__SYMBIAN32__)
void BStream_writeTaggedInt64_(BStream *self, int64_t v)
{
BStream_writeTag(self, BSTREAM_SIGNED_INT, 8, 0);
BStream_writeInt64_(self, v);
}
#endif
/*
#if sizeof(double) != 8
#error BStream expects doubles to be 64bit
#endif
*/
void BStream_writeTaggedDouble_(BStream *self, double v)
{
BStream_writeTag(self, BSTREAM_FLOAT, 8, 0);
BStream_writeDouble_(self, v);
}
void BStream_writeTaggedData_length_(BStream *self, const unsigned char *data, size_t length)
{
BStream_writeTag(self, BSTREAM_UNSIGNED_INT, 1, 1);
BStream_writeTaggedInt32_(self, length);
ByteArray_appendBytes_size_(self->ba, (unsigned char *)data, length);
self->index += length;
}
void BStream_writeTaggedCString_(BStream *self, const char *s)
{
BStream_writeTaggedData_length_(self, (unsigned char *)s, strlen(s));
}
void BStream_writeTaggedByteArray_(BStream *self, ByteArray *ba)
{
BStream_writeTaggedData_length_(self, ByteArray_bytes(ba), ByteArray_size(ba));
}
// reading --------------------------------------
int BStream_readTag(BStream *self, unsigned int t, unsigned int b, unsigned int a)
{
unsigned char c = BStream_readUint8(self);
BStreamTag readTag = BStreamTag_FromUnsignedChar(c);
BStreamTag expectedTag = BStreamTag_TagArray_type_byteCount_(a, t, b);
if (!BStreamTag_isEqual_(&readTag, &expectedTag))
{
printf("BStream error: read:\n ");
BStreamTag_print(&readTag);
printf(" but expected:\n ");
BStreamTag_print(&expectedTag);
printf("\n");
BStream_show(self);
printf("\n");
return -1;
}
return 0;
}
/*
unsigned char BStream_readTaggedByte(BStream *self)
{
BStream_readTag(self, BSTREAM_UNSIGNED_INT, 1, 0);
return BStream_readByte(self);
}
int BStream_readTaggedInt(BStream *self)
{
BStream_readTag(self, BSTREAM_SIGNED_INT, 4, 0);
return BStream_readInt32(self);
}
*/
uint8_t BStream_readTaggedUint8(BStream *self)
{
return BStream_readTaggedInt32(self);
}
uint32_t BStream_readTaggedUint32(BStream *self)
{
unsigned char c = BStream_readByte(self);
BStreamTag t = BStreamTag_FromUnsignedChar(c);
if (t.type == BSTREAM_UNSIGNED_INT && t.byteCount == 1)
{ return (uint32_t)BStream_readUint8(self); }
if (t.type == BSTREAM_UNSIGNED_INT && t.byteCount == 4)
{ return (uint32_t)BStream_readUint32(self); }
BStream_error_(self, "unhandled int type/size combination");
return 0;
}
int32_t BStream_readTaggedInt32(BStream *self)
{
unsigned char c = BStream_readByte(self);
BStreamTag t = BStreamTag_FromUnsignedChar(c);
if (t.type == BSTREAM_UNSIGNED_INT && t.byteCount == 1)
{
return (int32_t)BStream_readUint8(self);
}
if (t.type == BSTREAM_SIGNED_INT && t.byteCount == 4)
{
return (int32_t)BStream_readInt32(self);
}
/*
if (t.type == BSTREAM_SIGNED_INT && t.byteCount == 8)
{
return (int32_t)BStream_readInt64(self);
}
*/
BStream_error_(self, "unhandled int type/size combination");
return 0;
}
ptrdiff_t BStream_readTaggedPointer(BStream *self)
{
unsigned char c = BStream_readByte(self);
BStreamTag t = BStreamTag_FromUnsignedChar(c);
if (t.type == BSTREAM_POINTER)
{
BStream_error_(self, "expected pointer");
return 0;
}
if (t.byteCount == 1)
{
return (ptrdiff_t)BStream_readUint8(self);
}
if (t.byteCount == 4)
{
return (ptrdiff_t)BStream_readInt32(self);
}
#if !defined(__SYMBIAN32__)
if (t.byteCount == 8)
{
return (ptrdiff_t)BStream_readInt64(self);
}
#endif
BStream_error_(self, "unhandled pointer size");
return 0;
}
double BStream_readTaggedDouble(BStream *self)
{
unsigned char c = BStream_readByte(self);
BStreamTag t = BStreamTag_FromUnsignedChar(c);
/*
if (t.type == BSTREAM_FLOAT && t.byteCount == 4)
{
return BStream_readFloat(self);
}
*/
if (t.type == BSTREAM_FLOAT && t.byteCount == 8)
{
return BStream_readDouble(self);
}
BStream_error_(self, "unhandled float type/size combination");
return 0;
}
void BStream_readTaggedByteArray_(BStream *self, ByteArray *b)
{
BStream_readTag(self, BSTREAM_UNSIGNED_INT, 1, 1);
{
size_t size = BStream_readTaggedInt32(self);
unsigned char *data = BStream_readDataOfLength_(self, size);
ByteArray_setData_size_(b, data, size);
}
}
ByteArray *BStream_readTaggedByteArray(BStream *self)
{
BStream_readTaggedByteArray_(self, self->tmp);
return self->tmp;
}
const char *BStream_readTaggedCString(BStream *self)
{
BStream_readTag(self, BSTREAM_UNSIGNED_INT, 1, 1);
{
size_t size = BStream_readTaggedInt32(self);
return (char *)BStream_readDataOfLength_(self, size);
}
}
int BStream_atEnd(BStream *self)
{
return self->index >= ByteArray_size(self->ba);
}
int BStream_showInt(BStream *self)
{
unsigned char c = BStream_readUint8(self);
BStreamTag t = BStreamTag_FromUnsignedChar(c);
int v = 0;
printf("%s%i ", BStreamTag_typeName(&t), t.byteCount * 8);
if (t.byteCount < 5)
{
BStream_readNumber_size_(self, (unsigned char *)(&v), t.byteCount);
}
else
{
printf("ERROR: byteCount out of range\n");
exit(-1);
}
printf("%i", v);
return v;
}
void BStream_show(BStream *self)
{
int pos = self->index;
int v = 0;
self->index = 0;
while (!BStream_atEnd(self))
{
unsigned char c = BStream_readUint8(self);
BStreamTag t = BStreamTag_FromUnsignedChar(c);
/*printf("isArray:%i type:%s byteCount:%i value:", t.isArray, BStreamTag_typeName(t), t.byteCount);*/
printf(" %s%i %s", BStreamTag_typeName(&t), t.byteCount * 8, t.isArray ? "array " : "");
fflush(stdout);
if (t.isArray)
{
printf("[");
if (t.byteCount == 1)
{
int size = BStream_showInt(self);
if (size == 0)
{
printf(" '']\n");
}
else
{
unsigned char *data = BStream_readDataOfLength_(self, size);
printf(" '%s']\n", data);
}
}
else
{
printf("ERROR: array element byteCount not 1\n");
exit(-1);
}
}
else
{
if (t.byteCount > 0 && t.byteCount < 5)
{
BStream_readNumber_size_(self, (unsigned char *)(&v), t.byteCount);
}
else
{
printf("ERROR: byteCount out of range\n");
exit(1);
}
/*
if (t.byteCount == 1)
{
printf("%c\n", v);
}
else
{
*/
printf("%i\n", v);
/*}*/
}
}
self->index = pos;
}
syntax highlighted by Code2HTML, v. 0.9.1