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