#include "machdefs.h" #include #include #include #include "pexceptions.h" #include "peidainit.h" #include "ppersist.h" #include #include #ifdef __mac__ #include "unixmac.h" #include #endif #define MAXTAGLEN 255 //++ // Class PIOPersist // Lib Outils++ // include ppersist.h // // Root class for persistant files. Handles the registration of // persistant classes //-- //++ // Links See // PPersist // PInPersist // POutPersist //-- MD5_CTX PIOPersist::ctx; PIOPersist::ClassList * PIOPersist::classList = NULL; // $CHECK$ Reza 26/04/99 map * PIOPersist::typeids = NULL; //++ void PIOPersist::Initialize() // Initialisation globale (objets statiques) $CHECK$ Reza 26/04/99 //-- { classList = new PIOPersist::ClassList; typeids = new map; } //++ void PIOPersist::RegisterClass(uint_8 classId, string typname, ClassCreatorFunc f) // // Register a new persistant class. // The classId is usually a hash of the class name, and this // method is called only through the PPersistRegistrar template // class, with the PPRegister(className) macro. // //-- { if (classList->size() && (classList->find(classId) != classList->end())) { cerr << "RegisterClass : Error, " << hex << classId << dec << " already registered." << endl; throw(DuplicateIdExc("PIOPersist::RegisterClass")); } (*classList)[classId] = f; (*typeids)[typname] = classId; } PIOPersist::ClassCreatorFunc PIOPersist::FindCreatorFunc(uint_8 classId) { ClassList::iterator i = classList->find(classId); if (i == classList->end()) throw(NotFoundExc("PIOPersist::FindCreatorFunc")); return (*i).second; } //++ // Class PPersist // Lib Outils++ // include ppersist.h // // Classe de base pour des objets persistants. Pour créer un objet // persistant : // - Hériter de PPersist. // - Définir un numéro d'identification de la classe, unique dans Peida // - Implémenter "ClassId()" // - Implémenter "WriteSelf" et "ReadSelf", qui doivent écrire toutes les variables // membres que l'on souhaite écrire, et les relire dans le même ordre. // Pour écrire une référence à un objet : l'objet doit être un PPersist, // et il suffit d'appeler "Write" sur cet objet, et "PPersistMgr::ReadObject". // Si plusieurs objets font référence au même, pour éviter de l'écrire plusieurs // fois, il faut que cet objet soit un PShPersist. // - Pour que le fichier soit portable, écrire et lire les variables membres en utilisant // les fonctions PutXX/GetXX de PInPersist/POutPersist. // // Attention: les méthodes à redéfinir sont WriteSelf et ReadSelf, mais il ne faut jamais // les appeler directement. Seuls Write et Read peuvent être appelées par l'utilisateur. //-- //++ // Links See // PInPersist // POutPersist // PIOPersist //-- //++ void PPersist::Write(string const& fn) const // // Ecrit l'objet dans un nouveau fichier ppersist "fn". //-- { POutPersist of(fn); Write(of); } //++ void PPersist::Read(string const& fn) // // Relit l'objet dans le fichier ppersist "fn". Il faut connaître a priori // le type de l'objet. Pour une relecture avec création automatique du bon // objet, utiliser PPersistMgr::ReadObject. //-- { PInPersist inf(fn); Read(inf); } //++ void PPersist::Write(POutPersist& s) const // // Ecrit l'objet dans le fichier PPersist. //-- { s.PutObject(this); } //++ void PPersist::Read(PInPersist& s) // // Relit l'objet dans le fichier ppersist. Il faut connaître a priori // le type de l'objet. Pour une relecture avec création automatique du bon // objet, utiliser PInPersist::ReadObject. // Il faut qu'on soit un objet ecrit //-- { // We should be the exact type // Check tag value char ppstype; s.GetTypeTag(ppstype); if (ppstype != PInPersist::PPS_OBJECT) { throw FileFormatExc("PPersist::Read : not an object in flow"); } // Check class id uint_8 classId; s.GetRawU8(classId); uint_8 myClassId = PIOPersist::getTypeId(typeid(*this).name()); if (classId != myClassId) { throw FileFormatExc("PPersist::Read : not the same object type"); } ReadSelf(s); } //++ void PPersist::Write(POutPersist& s, string const& tag) const // // Ecrit l'objet dans le fichier PPersist avec un tag //-- { s.WriteTag(tag); s.PutObject(this); } //++ void PPersist::ReadAtTag(PInPersist& s, string const& tag) // // Lit l'objet à la position du tag numéro "tagid". //-- { if (!s.GotoTag(tag)) throw NotFoundExc("PPersist::ReadAtTag tag not found"); Read(s); } //++ // virtual void PPersist::ReadSelf(PInPersist&)=0 // Méthode virtuelle pure à redéfinir. Elle est appelée par Read // et PPersistMgr::ReadObject. Il faut relire les variables membres, // dans l'ordre où elles ont été écrites par WriteSelf. // virtual void PPersist::WriteSelf(POutPersist&) const=0 // Méthode virtuelle pure à redéfinir. Elle est appelée par Write. // Il faut écrire les variables membres, // dans l'ordre où elles seront relues par ReadSelf. //-- //++ // Class PInPersist // Lib Outils++ // include ppersist.h // // Fichier d'objets persistants, en lecture. //-- //++ PInPersist::PInPersist(string const& flnm, bool scan) // // Constructeur. Ouvre le fichier. //-- { s = new ifstream(flnm.c_str(),ios::in | IOS_BIN); // Read and check header char rbuf[36]; GetRawBytes(rbuf, 32); if (strncmp(rbuf,"SOS-SOPHYA-PPersistFile", 23) != 0) { throw FileFormatExc("PInPersist::PInPersist bad header"); } version = atoi(rbuf+24); // read endianness GetRawBytes(rbuf, 32); if (strncmp(rbuf,"BIG-ENDIAN",10) == 0) bigEndian = true; else if (strncmp(rbuf,"LITTLE-ENDIAN",13) == 0) bigEndian = false; else { throw FileFormatExc("PInPersist::PInPersist bad header - endianness"); } // read creation date GetRawBytes(rbuf, 32); rbuf[32] = '\0'; struct tm tm; strptime(rbuf,"%d/%m/%Y %T GMT",&tm); creationdate = mktime(&tm); if (scan) Scan(); } PInPersist::~PInPersist() { delete s; } void PInPersist::Scan() { // On cherche la liste des tags, a la fin du fichier char ppstype; size_t debut; #ifdef STREAMPOS_IS_CLASS debut = s->tellg().offset(); #else debut = s->tellg(); #endif // Find tag entries at end of file s->seekg(-(sizeof(int_8)+1), ios::end); GetTypeTag(ppstype); if (ppstype != PPS_EOF) throw FileFormatExc("PInPersist::Scan corrupted file, no eof entry at end of file"); int_8 pos; GetRawI8(pos); if (pos < 0) { // no tags s->seekg(debut); return; } char buffer[MAXTAGLEN+1]; s->seekg(pos); while (true) { GetTypeTag(ppstype); if (ppstype == PPS_EOF) break; if (ppstype != PPS_TAG) throw FileFormatExc("PInPersist::Scan corrupted file, bad tag entry"); GetRawI8(pos); int_4 len; GetRawI4(len); if (len > MAXTAGLEN) throw FileFormatExc("PInPersist::Scan corrupted file, tag name too long"); GetRawBytes(buffer, len); buffer[len] = '\0'; tags[buffer] = pos; } s->seekg(debut); } int PInPersist::NbTags() { return tags.size(); } bool PInPersist::GotoTag(string const& name) { map::iterator i = tags.find(name); if (i == tags.end()) return false; // throw NotFoundExc("PInPersist::GotoTag tag not found"); s->seekg((*i).second); objList.clear(); // $CHECK$ EA 171199 return(true); } bool PInPersist::GotoTagNum(int itag) { if (itag<0 || itag >= (int)tags.size()) return false; map::iterator i = tags.begin(); for (int j=0; jseekg((*i).second); objList.clear(); // $CHECK$ EA 171199 return(true); } string PInPersist::GetTagName(int itag) { if (itag<0 || itag >= (int)tags.size()) return ""; map::iterator i = tags.begin(); for (int j=0; j * ret_tag_names = NULL; vector const & PInPersist::GetTagNames() { if (ret_tag_names) delete ret_tag_names; ret_tag_names = new vector ; map::iterator i; for(i=tags.begin(); i!=tags.end(); i++) ret_tag_names->push_back((*i).first); return(*ret_tag_names); } //++ // void PInPersist::GetByte(char& c) // void PInPersist::GetBytes(void* ptr, size_t bytes) // void PInPersist::GetR4 (r_4& result) // void PInPersist::GetR4s (r_4* tab, size_t n) // void PInPersist::GetR8 (r_8& result) // void PInPersist::GetR8s (r_8* tab, size_t n) // void PInPersist::GetI2 (int_2& result) // void PInPersist::GetI2s (int_2* tab, size_t n) // void PInPersist::GetU2 (uint_2& result) // void PInPersist::GetU2s (uint_2* tab, size_t n) // void PInPersist::GetI4 (int_4& result) // void PInPersist::GetI4s (int_4* tab, size_t n) // void PInPersist::GetU4 (uint_4& result) // void PInPersist::GetU4s (uint_4* tab, size_t n) // void PInPersist::GetI8 (int_8& result) // void PInPersist::GetI8s (int_8* tab, size_t n) // void PInPersist::GetU8 (uint_8& result) // void PInPersist::GetU8s (uint_8* tab, size_t n) // Lecture de données portables depuis le fichier PPersist. Pour chaque type // de données, on peut lire une valeur, ou un tableau de valeurs. // void PInPersist::GetLine(char* ptr, size_t len) // Lecture d'une ligne de texte depuis le fichier PPersist. //-- static inline void bswap8(void* p) { uint_8 tmp = *(uint_8*)p; *(uint_8*)p = ((tmp >> (7*8)) & 0x000000FF) | ((tmp >> (5*8)) & 0x0000FF00) | ((tmp >> (3*8)) & 0x00FF0000) | ((tmp >> (1*8)) & 0xFF000000) | ((tmp & 0xFF000000) << (1*8)) | ((tmp & 0x00FF0000) << (3*8)) | ((tmp & 0x0000FF00) << (5*8)) | ((tmp & 0x000000FF) << (7*8)); } static inline void bswap4(void* p) { uint_4 tmp = *(uint_4*)p; *(uint_4*)p = ((tmp >> 24) & 0x000000FF) | ((tmp >> 8) & 0x0000FF00) | ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24); } static inline void bswap2(void* p) { uint_2 tmp = *(uint_2*)p; *(uint_2*)p = ((tmp >> 8) & 0x00FF) | ((tmp & 0x00FF) << 8); } void PInPersist::GetTypeTag(char& c) { GetRawByte(c); while (c == PPS_TAG_MARK) { objList.clear(); GetRawByte(c); } } void PInPersist::GetRawByte(char& c) { GetRawBytes(&c, 1); } void PInPersist::GetRawBytes(void* ptr, size_t bytes) { s->read((char*)ptr, bytes); } void PInPersist::GetRawI2 (int_2& result) { GetRawBytes(&result, sizeof(int_2)); if (bigEndian != IS_BIG_ENDIAN) bswap2(&result); } void PInPersist::GetRawI4 (int_4& result) { GetRawBytes(&result, sizeof(int_4)); if (bigEndian != IS_BIG_ENDIAN) bswap4(&result); } void PInPersist::GetRawI8 (int_8& result) { GetRawBytes(&result, sizeof(int_8)); if (bigEndian != IS_BIG_ENDIAN) bswap8(&result); } void PInPersist::GetRawU8 (uint_8& result) { GetRawBytes(&result, sizeof(uint_8)); if (bigEndian != IS_BIG_ENDIAN) bswap8(&result); } void PInPersist::CheckTag(short datasz) { char ppstype; GetTypeTag(ppstype); if (ppstype != PPS_SIMPLE + datasz) throw FileFormatExc("PInPersist::CheckTag bad type in ppersist file"); } void PInPersist::CheckArrayTag(short datasz, size_t sz) { char ppstype; GetTypeTag(ppstype); size_t filesz; if (sz <= 0x7fff) { if (ppstype != PPS_SIMPLE_ARRAY + datasz) throw FileFormatExc("PInPersist::CheckTag bad type in ppersist file"); int_2 ff; GetRawI2(ff); filesz=ff; } else if (sz <= 0x7fffffff) { if (ppstype != PPS_SIMPLE_ARRAY4 + datasz) throw FileFormatExc("PInPersist::CheckTag bad type in ppersist file"); int_4 ff; GetRawI4(ff); filesz=ff; } else { if (ppstype != PPS_SIMPLE_ARRAY8 + datasz) throw FileFormatExc("PInPersist::CheckTag bad type in ppersist file"); uint_8 ff; GetRawU8(ff); filesz=ff; } if (filesz != sz) throw FileFormatExc("PInPersist::CheckTag bad array size in ppersist file"); } void PInPersist::GetByte(char& c) { CheckTag(1); GetRawBytes(&c, 1); } void PInPersist::GetBytes(void* ptr, size_t bytes) { CheckArrayTag(1, bytes); GetRawBytes(ptr, bytes); } void PInPersist::GetR4 (r_4& result) { CheckTag(4); GetRawBytes(&result, sizeof(r_4)); if (bigEndian != IS_BIG_ENDIAN) bswap4(&result); } void PInPersist::GetR4s (r_4* tab, size_t n) { CheckArrayTag(4,n); GetRawBytes(tab, n*sizeof(r_4)); if (bigEndian == IS_BIG_ENDIAN) return; for (unsigned int i=0; igetline(ptr, len, '\n'); } void PInPersist::GetStr(string& str) { char ppstype; GetTypeTag(ppstype); if (ppstype != PPS_STRING) throw FileFormatExc("PInPersist::GetLine bad type in ppersist file"); int_2 len; GetRawI2(len); char * buff = new char[len+1]; GetRawBytes(buff, len); buff[len] = '\0'; str = buff; delete[] buff; } PPersist* PInPersist::ReadObject() { // Get tag char ppstype; GetTypeTag(ppstype); if (ppstype != PPS_OBJECT && ppstype != PPS_REFERENCE && ppstype != PPS_NULL) { throw FileFormatExc("PInPersist::ReadObject : not an object in flow"); } if (ppstype == PPS_NULL) { return NULL; } else if (ppstype == PPS_OBJECT) { // Get class id uint_8 classId; GetRawU8(classId); // Get factory method ClassCreatorFunc f = FindCreatorFunc(classId); if (!f) { throw NotFoundExc("PInPersist::ReadObject class not registered"); } // Create object PPersist* object = f(); object->ReadSelf(*this); assignObjectId(object); return object; } else { // Get object id int_4 id; GetRawI4(id); if (id <0 || id>=objList.size()) { char msg[200]; sprintf(msg, "PInPersist::ReadObject invalid object id for reference: %d/%d",id,objList.size()); throw FileFormatExc(msg); } return objList[id]; } } int_4 PInPersist::assignObjectId(PPersist* x) { objList.push_back(x); return objList.size()-1; } //++ // Class POutPersist // Lib Outils++ // include ppersist.h // // Fichier d'objets persistants, en écriture. //-- //++ // POutPersist(string const& flnm, int endianness = PPersist::PPS_NATIVE) // // Crée un nouveau fichier ppersist. Par défaut, il est petit=boutien // sur machines petit-boutiennes, et gros-boutien sur machines // gros-boutiennes. On peut explicitement spécifier PPersist::PPS_LITTLE_ENDIAN // ou PPersist::PPS_BIG_ENDIAN. //-- POutPersist::POutPersist(string const& flnm, int endianness) { if (endianness == -1) bigEndian = IS_BIG_ENDIAN; else bigEndian = endianness; // Output stream creation s = new ofstream(flnm.c_str(),ios::out | IOS_BIN); // Header PutRawBytes("SOS-SOPHYA-PPersistFile V1 ",32); PutRawBytes(bigEndian ? "BIG-ENDIAN " : "LITTLE-ENDIAN ",32); // ---- GMT creation date of the file time_t tm = time(NULL); char datestring[33]; int l=strftime(datestring,32,"%d/%m/%Y %T GMT",gmtime(&tm)); for(int i=l; i<32; i++) datestring[i] = ' '; datestring[32] = '\0'; PutRawBytes(datestring, 32); } POutPersist::~POutPersist() { if (tags.size() == 0) { PutRawByte(PPS_EOF); PutRawI8(-1); } else { int_8 tagPos; #ifdef STREAMPOS_IS_CLASS tagPos = s->tellp().offset(); #else tagPos = s->tellp(); #endif for (map::iterator i = tags.begin(); i != tags.end(); i++) { string name = (*i).first; int_8 pos = (*i).second; PutRawByte(PPS_TAG); // This is a tag PutRawI8(pos); // position of previous tag PutRawI4(name.length()); // length of the name PutRawBytes(name.c_str(), name.length()); // name, without final "0". } PutRawByte(PPS_EOF); PutRawI8(tagPos); } delete s; // Close the stream } void POutPersist::WriteTag(string const& name) { if (name.length() > MAXTAGLEN) throw ParmError("POutPersist::WriteTag tag name too long"); if (tags.find(name) != tags.end()) throw DuplicateIdExc("POutPersist::WriteTag duplicate tag name"); // Get current file position int_8 tagPos; #ifdef STREAMPOS_IS_CLASS tagPos = s->tellp().offset(); #else tagPos = s->tellp(); #endif tags[name] = tagPos; PutRawByte(PPS_TAG_MARK); // This is a tag objList.clear(); // $CHECK$ EA 171199 } //++ // void POutPersist::PutByte(char& c) // void POutPersist::PutBytes(void const* ptr, size_t bytes) // void POutPersist::PutR4 (r_4 result) // void POutPersist::PutR4s (r_4 const* tab, size_t n) // void POutPersist::PutR8 (r_8 result) // void POutPersist::PutR8s (r_8 const* tab, size_t n) // void POutPersist::PutI2 (int_2 result) // void POutPersist::PutI2s (int_2 const* tab, size_t n) // void POutPersist::PutU2 (uint_2 result) // void POutPersist::PutU2s (uint_2 const* tab, size_t n) // void POutPersist::PutI4 (int_4 result) // void POutPersist::PutI4s (int_4 const* tab, size_t n) // void POutPersist::PutU4 (uint_4 result) // void POutPersist::PutU4s (uint_4 const* tab, size_t n) // void POutPersist::PutI8 (int_8 result) // void POutPersist::PutI8s (int_8 const* tab, size_t n) // void POutPersist::PutU8 (uint_8 result) // void POutPersist::PutU8s (uint_8 const* tab, size_t n) // void POutPersist::PutStr (string const&) // Ecriture de données portables.. Pour chaque type // de données, on peut écrire une valeur, ou un tableau de valeurs. // void POutPersist::PutLine(char const* ptr, size_t len) // Ecriture d'une ligne de texte dans le fichier PPersist. //-- void POutPersist::PutRawBytes(void const* ptr, size_t bytes) { s->write((char const*)ptr, bytes); } void POutPersist::PutRawByte(char c) { PutRawBytes(&c, 1); } void POutPersist::PutRawI2 (int_2 val) { if (bigEndian != IS_BIG_ENDIAN) bswap2(&val); PutRawBytes(&val, sizeof(int_2)); } void POutPersist::PutRawI4 (int_4 val) { if (bigEndian != IS_BIG_ENDIAN) bswap4(&val); PutRawBytes(&val, sizeof(int_4)); } void POutPersist::PutRawI8 (int_8 val) { if (bigEndian != IS_BIG_ENDIAN) bswap8(&val); PutRawBytes(&val, sizeof(int_8)); } void POutPersist::PutRawU8 (uint_8 val) { if (bigEndian != IS_BIG_ENDIAN) bswap8(&val); PutRawBytes(&val, sizeof(uint_8)); } void POutPersist::PutArrayTag(short datasz, size_t sz) { if (sz <= 0x7fff) { PutRawByte(PPS_SIMPLE_ARRAY + datasz); PutRawI2(sz); } else if (sz <= 0x7fffffff) { PutRawByte(PPS_SIMPLE_ARRAY4 + datasz); PutRawI4(sz); } else { PutRawByte(PPS_SIMPLE_ARRAY8 + datasz); PutRawU8(sz); } } void POutPersist::PutByte(char c) { PutRawByte(PPS_SIMPLE + 1); PutRawBytes(&c, 1); } void POutPersist::PutBytes(void const* ptr, size_t bytes) { PutArrayTag(1, bytes); PutRawBytes(ptr, bytes); } void POutPersist::PutR4 (r_4 val) { PutRawByte(PPS_SIMPLE + 4); if (bigEndian != IS_BIG_ENDIAN) bswap4(&val); PutRawBytes(&val, sizeof(r_4)); } void POutPersist::PutR4s (r_4 const* tab, size_t n) { PutArrayTag(4, n); if (bigEndian == IS_BIG_ENDIAN) { PutRawBytes(tab, n*sizeof(r_4)); } else { for (unsigned int i=0; iWriteSelf(*this); } bool POutPersist::serializeNullAndRepeat(PPersist const* x) { if (x == NULL) { PutRawByte(PPS_NULL); return true; } int_4 id = findObjectId(x); if (id >= 0) { PutRawByte(PPS_REFERENCE); PutRawI4(id); return true; } return false; } int_4 POutPersist::assignObjectId(PPersist const* x) { int_4 id = objList.size(); objList[x] = id; return id; } int_4 POutPersist::findObjectId(PPersist const* x) { ObjList::iterator i = objList.find(x); if (i == objList.end()) return -1; return (*i).second; }