Lucking they are easily handled with templates and reinterpret_cast. Here is some code demonstrating a blob handling class, with a streaming interface and fileIO capabilities. As you can see I got a little ambitious while coding it and so not all of the code is compile tested(ie templates dont compile unless used..) But it will build as is and execute, and I will sooner or latter get back and check the rest of it.
//build with g++
#include <stdint.h>
#include <istream>
#include <iostream>
#include <iomanip>
#include <string>
#include <cstring>
#include <stdexcept>
using namespace std;
class Blob
{
public:
//******* CONSTRUCTION ***********//
Blob(uint32_t _size)
{
data = new char[_size];
size = _size;
memset(data, 0, size);
}
//******* SIZING ***********//
uint32_t getSize() const
{ return size; }
void resize(uint32_t _size)
{
uint32_t copySize = std::min(_size,size);
char* old_data = data;
data = new char[_size];
if(_size > size)
memset(&data[size], 0, _size - size); //zero new part
memcpy(data, old_data, copySize); //copy old
size = _size;
delete old_data;
}
//******* IMPORT/EXPORT ***********//
template<typename T>
bool importObject(const T& src,
uint32_t offset = 0)
{
if((offset + sizeof(T)) > size)
return false;
memcpy(&data[offset], &src, sizeof(T));
return true;
}
template<typename T>
bool exportObject(T& dst,
uint32_t offset = 0)
{
if((offset + sizeof(T)) > size)
return false;
T* value = reinterpret_cast<T*>(&data[offset]);
dst = *value;
return true;
}
template<typename T, typename P>
bool importObjectGetter(const T& src,
const P& (T::*get)() const,
uint32_t offset = 0)
{
if((offset + sizeof(P)) > size)
return false;
const P& value = (src.*get)();
memcpy(&data[offset], &value, sizeof(P));
return true;
}
template<typename T, typename P>
bool exportObjectSetter(T& dst,
bool (T::*set)(P*),
uint32_t offset = 0)
{
if((offset + sizeof(P)) > size)
return false;
P* value = reinterpret_cast<P*>(&data[offset]);
(dst.*set)(value);
return true;
}
template<typename T>
bool importPointer(const T* src,
uint32_t len,
uint32_t offset = 0)
{
if((offset + len) > size)
return false;
memcpy(&data[offset], src, len);
return true;
}
template<typename T>
bool exportPointer(T* dst,
uint32_t len,
uint32_t offset = 0)
{
if((offset + len) > size)
return false;
memcpy(dst, &data[offset], len);
return true;
}
bool importZeroTermed(const string src,
uint32_t offset = 0)
{
uint32_t len = src.length();
if((offset + len) > size)
return false;
memcpy(&data[offset], src.c_str(), len);
return true;
}
bool exportZeroTermed(string& dst,
uint32_t offset = 0)
{
uint32_t len = strlen(&data[offset]);
if((offset + len) > size)
return false;
dst = &data[offset];
return true;
}
//********* DIRECT ACCESS ***********//
template<typename T>
T* accessAsObject(uint32_t offset = 0)
{
if((offset + sizeof(T)) > size)
throw runtime_error("Out of Range");
return reinterpret_cast<T*>(&data[offset]);
}
//********* DUMPING ***********//
void print(ostream& out)
{
const int spaceStep = 4;
const int lineStep = 16;
int totOffset=0;
int subOffset=0;
out << "Size(in hex): " << hex << size << endl;
while(totOffset < size)
{
// the label..
out << hex << setfill('0') << setw(2*sizeof(uint32_t))
<< totOffset << ": ";
// the hex..
int subOffset=0;
while(subOffset < lineStep)
{
int offset = totOffset + subOffset;
if(offset < size)
{
uint16_t number = (0xff & data[offset]);
out << hex << setfill('0') << setw(2)
<< number;
}
else
out << " ";
subOffset++;
if((subOffset % spaceStep) == 0)
out << " ";
}
out << " : ";
//the text
subOffset=0;
while(subOffset < lineStep)
{
int offset = totOffset + subOffset;
if(offset < size)
{
if(
(data[offset] >= 33 ) &&
(data[offset] <= 126 )
)
out << data[offset];
else
out << " ";
}
else
out << " ";
subOffset++;
}
out << endl;
totOffset += lineStep;
}
out << dec;
}
//*********** FILE IO *************//
void writeToFile(iostream& file)
{ file.write(data, size); }
void readFromFile(iostream& file)
{ file.read(data, size); }
void writeSizedToFile(iostream& file)
{
file.write(reinterpret_cast<char*>(&size), sizeof(uint32_t));
file.write(data, size);
}
void readSizedFromFile(iostream& file)
{
file.read(reinterpret_cast<char*>(&size), sizeof(uint32_t));
resize(size);
file.read(data, size);
}
private:
char* data;
uint32_t size;
};
ostream& operator<<(ostream& out, Blob& val)
{
val.print(out);
return out;
}
class BlobStream
{
public:
BlobStream(uint32_t _size, bool _autoScale=true, uint32_t _autoScaleFactor=4) :
blob(_size),
offset(0),
autoScaleEnabled(_autoScale),
autoScaleFactor(_autoScaleFactor)
{}
//********* ACCESSORS ***********//
uint32_t getOffset()
{ return offset; }
Blob& getBlob()
{ return blob; }
//********* SIZERS ***********//
void resetOffset()
{ offset = 0; }
void finaliseSize()
{
blob.resize(offset);
autoScaleEnabled = false;
}
void autoScaleUp(uint32_t min = 0)
{
if( !autoScaleEnabled)
throw runtime_error("Buffer Size locked!");
uint32_t size = blob.getSize();
if(size == 0) size = 1;
blob.resize(std::max(autoScaleFactor*size, min));
}
//********* STREAMERS ***********//
template<typename T>
BlobStream& operator<<(T& src)
{
while( !blob.importObject(src, offset) )
autoScaleUp(sizeof(T));
offset += sizeof(T);
return *this;
}
BlobStream& operator<<(string& src)
{
while( !blob.importZeroTermed(src, offset) )
autoScaleUp(src.length());
offset += src.length();
return *this;
}
BlobStream& operator<<(char* src)
{
while( !blob.importZeroTermed(src, offset) )
autoScaleUp(strlen(src));
offset += strlen(src);
return *this;
}
template<typename T>
BlobStream& operator>>(T& src)
{
if( !blob.exportObject(src, offset) )
throw runtime_error("Lack of Buffer Data");
offset += sizeof(T);
return *this;
}
BlobStream& operator>>(string& src)
{
if( !blob.exportZeroTermed(src, offset) )
throw runtime_error("Lack of Buffer Data OR no termination");
offset += src.length();
return *this;
}
private:
bool autoScaleEnabled;
uint32_t autoScaleFactor;
Blob blob;
uint32_t offset;
};
//Test
struct A
{
char a1;
int a2;
};
struct B
{
char b1[10];
float b2;
};
int main()
{
BlobStream bs(0);
A a;
B b;
a.a1 = '#';
a.a2 = 10;
memcpy(b.b1, "here it is", 10);
b.b2 = 0.2;
bs << a << b << " -- and then some";
cout << "Before Finalisation" << endl;
bs.getBlob().print(cout);
bs.finaliseSize();
bs.resetOffset();
cout << endl << "After Finalisation" << endl;
bs.getBlob().print(cout);
A c;
B d;
string e;
bs >> c >> d >> e;
cout << endl
<< "Retrived Data:" << endl
<< " " << c.a1 << endl
<< " " << c.a2 << endl
<< " " << d.b1 << endl
<< " " << d.b2 << endl
<< " " << e << endl;
}
The result looks like this:
Before Finalisation Size(in hex): 80 00000000: 231e1a66 0a000000 68657265 20697420 : # f here it 00000010: 69732200 cdcc4c3e 202d2d20 616e6420 : is" L> -- and 00000020: 7468656e 20736f6d 65000000 00000000 : then some 00000030: 00000000 00000000 00000000 00000000 : 00000040: 00000000 00000000 00000000 00000000 : 00000050: 00000000 00000000 00000000 00000000 : 00000060: 00000000 00000000 00000000 00000000 : 00000070: 00000000 00000000 00000000 00000000 : After Finalisation Size(in hex): 2a 00000000: 231e1a66 0a000000 68657265 20697420 : # f here it 00000010: 69732200 cdcc4c3e 202d2d20 616e6420 : is" L> -- and 00000020: 7468656e 20736f6d 6500 : then some Retrived Data: # 10 here it is" 0.2 -- and then some
No comments:
Post a Comment