#include "machdefs.h" #include #include #include #include "pexceptions.h" #include "ppersist.h" #include "anydataobj.h" #include #include #include #ifdef __mac__ #include "unixmac.h" #include #endif // strptime n'est pas defini sous Linux - Reza Mars 2000 #if defined(OS_LINUX) || defined(OS_MACOSX) extern "C" { char *strptime(char *buf, const char *format, const struct tm *tm); } #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_CONTEXT PIOPersist::ctx; PIOPersist::ClassList * PIOPersist::ppclassList = NULL; // $CHECK$ Reza 26/04/99 map * PIOPersist::ppclassNameList = NULL; map * PIOPersist::dobjclassNameList = NULL; //++ void PIOPersist::Initialize() // Initialisation globale (objets statiques) $CHECK$ Reza 26/04/99 //-- { ppclassList = new PIOPersist::ClassList; ppclassNameList = new map; dobjclassNameList = new map; } //++ void PIOPersist::RegisterPPHandlerClass(uint_8 classId, string ppclass_name, ClassCreatorFunc f) // // Register a new persistence handler (PPersist) class. // The classId is usually a hash of the class name, and // ppclass_name is typeid(PPersistClass).name() . // This method is called only through the PPersistRegistrar template // //-- { if (ppclassList->size() && (ppclassList->find(classId) != ppclassList->end()) ) { cerr << "RegisterClass : Error, " << hex << classId << dec << " already registered." << endl; throw(DuplicateIdExc("PIOPersist::RegisterPPHandlerClass() Already registered (1)")); } if (ppclassNameList->size() && (ppclassNameList->find(ppclass_name) != ppclassNameList->end())) { cerr << "RegisterClass : Error (2) " << ppclass_name << " already registered." << endl; throw(DuplicateIdExc("PIOPersist::RegisterPPHandlerClass() Already registered(2)")); } (*ppclassList)[classId] = f; (*ppclassNameList)[ppclass_name] = classId; } //++ void PIOPersist::RegisterDataObjClass(uint_8 classId, string class_name) // Register a new DataObj class corresponding to a PPersist classId // class_typename should be typeid(DataObject).name() //-- { if (ppclassList->find(classId) == ppclassList->end() ) { cerr << "PIOPersist::RegisterDataObjClass() Error (1) " << hex << classId << dec << " Not Found !" << endl; throw( NotFoundExc("PIOPersist::RegisterDataObjClass() Not found classId ") ); } if (dobjclassNameList->size() && (dobjclassNameList->find(class_name) != dobjclassNameList->end())) { cerr << "PIOPersist::RegisterDataObjClass() Error (2)" << class_name << " already registered." << endl; throw(DuplicateIdExc("PIOPersist::RegisterDataObjClass() - Already registered")); } (*dobjclassNameList)[class_name] = classId; } // class_typename should be typeid(DataObject).name(), to be // used by POutPersist::PutDataObject() methods. PIOPersist::ClassCreatorFunc PIOPersist::FindCreatorFunc(uint_8 classId) // Returns the PPersist class creator function for the specified classId { ClassList::iterator i = ppclassList->find(classId); if (i == ppclassList->end()) throw(NotFoundExc("PIOPersist::FindCreatorFunc() Not found classId")); return (*i).second; } string PIOPersist::getPPClassName(uint_8 classId) // Returns the PPersist class name for the specified classId { map::iterator i; for (i= ppclassNameList->begin(); i != ppclassNameList->end(); i++) if ( (*i).second == classId ) return (*i).first; throw(NotFoundExc("PIOPersist::getPPClassName() Not found classId")); } uint_8 PIOPersist::getPPClassId(string const & typ_name) // Returns the classId for the specified PPersist class type name { map::iterator i = ppclassNameList->find(typ_name); if (i == ppclassNameList->end()) throw(NotFoundExc("PIOPersist::getPPClassId() Not found className")); return (*i).second; } uint_8 PIOPersist::getPPClassId(PPersist const & ppo) // Returns the classId for the specified PPersist class { string typ_name = typeid(ppo).name() ; return (getPPClassId(typ_name) ); } string PIOPersist::getDataObjClassName(uint_8 classId) // Returns the PPersist class name for the specified classId { map::iterator i; for (i= dobjclassNameList->begin(); i != dobjclassNameList->end(); i++) if ( (*i).second == classId ) return (*i).first; throw(NotFoundExc("PIOPersist::getDataObjClassName() Not found classId")); } uint_8 PIOPersist::getDataObjClassId(string const & typ_name) // Returns the classId for the specified PPersist class type name { map::iterator i = dobjclassNameList->find(typ_name); if (i == dobjclassNameList->end()) throw(NotFoundExc("PIOPersist::getDataObjClassId() Not found className")); return (*i).second; } uint_8 PIOPersist::getDataObjClassId(AnyDataObj const & o) // Returns the classId for the specified PPersist class { string typ_name = typeid(o).name() ; return (getDataObjClassId(typ_name) ); } 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); } uint_8 PIOPersist::Hash(string const& typname) { md5_init(&ctx); md5_write(&ctx, (unsigned char*) typname.c_str(), typname.size()); md5_final(&ctx); uint_8 hash1 = *((uint_8*) ctx.buf); uint_8 hash2 = *((uint_8*) (ctx.buf+8)); #if IS_BIG_ENDIAN bswap8(&hash1); bswap8(&hash2); #endif return (hash1+hash2); } //++ // 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.PutPPObject(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 unsigned char ppstype,ppstag; s.GetTypeTag(ppstype); if ( (ppstype != PInPersist::PPS_OBJECT) && ( ppstype != PInPersist::PPS_REFERENCE ) ) { } if (ppstype == PInPersist::PPS_OBJECT) { // Check class id uint_8 classId; s.GetRawU8(classId); uint_8 oid,oid2; s.GetRawU8(oid); if (classId != PIOPersist::getPPClassId(*this) ) throw FileFormatExc("PPersist::Read (): not the same object type"); ReadSelf(s); // Read the ENDOBJECT s.GetRawUByte(ppstag); if (ppstag != PInPersist::PPS_ENDOBJECT) throw FileFormatExc("PPersist::Read() No PPS_ENDOBJECT tag"); s.GetRawU8(oid2); if (oid2 != oid) throw FileFormatExc("PPersist::Read() Inconsistent PPS-OId at PPS_ENDOBJECT "); s.KeepOId(oid, *this); // Object should be kept with its PPS_OId (if oid > 0) } else if ( ppstype == PInPersist::PPS_REFERENCE ) s.ReadReference(*this); else throw FileFormatExc("PPersist::Read() : not an object in flow"); } //++ void PPersist::Write(POutPersist& s, string const& tag) const // // Ecrit l'objet dans le fichier PPersist avec un tag //-- { s.WriteTag(tag); s.PutPPObject(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); } // Renvoie l'identificateur de l'objet - par defaut=0 uint_8 PPersist::getMemOId() const { return(0); } // Ces deux methodes doivent etre redefinies si getMemOId() renvoie non nul (>0) // ShareDataReference() et CloneSharedReference() void PPersist::ShareDataReference(PPersist & pcs) { throw NotAvailableOperation("PPersist::ShareDataReference() - Unsupported operation !"); } PPersist * PPersist::CloneSharedReference() { throw NotAvailableOperation("PPersist::CloneSharedReference() - Unsupported operation !"); } //++ // 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"); } rbuf[32] = '\0'; version = atoi(rbuf+25); if (version < 2) { cerr << "PInPersist::PInPersist(" << flnm << ") Version(=" << version << ") < 2 not supported !" << endl; throw FileFormatExc("PInPersist::PInPersist() - Unsupported (Old) Version"); } // 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; #if !(defined(__MWERKS__) || defined(OS_MACOSX)) strptime(rbuf,"%d/%m/%Y %H:%M:%S GMT",&tm); #else sscanf(rbuf,"%2d/%2d/%4d %2d:%2d:%2d GMT",&tm.tm_mday,&tm.tm_mon,&tm.tm_year, &tm.tm_hour,&tm.tm_min,&tm.tm_sec); tm.tm_mon --; tm.tm_year -= 1900; #endif creationdate = mktime(&tm); filename = flnm; // keep the filename seqread = true; // To flag non sequential reads if (scan) Scan(); } PInPersist::~PInPersist() { ObjList::iterator i; for(i=objList.begin(); i!= objList.end(); i++) if ((*i).second) delete (*i).second; delete s; } string PInPersist::CreationDateStr() { time_t cdt = CreationDate(); string cdate = ctime(&cdt); return(cdate); } void PInPersist::Scan() { // On cherche la liste des tags, a la fin du fichier unsigned 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 #if defined(Linux) && defined(__GNUG__) // There seems to be a bug where seekg with ios::end under Linux with g++ // So, we use seek with ios::beg s->seekg(0, ios::end); int_8 tagpos = s->tellg() - (sizeof(int_8)+1); s->seekg(tagpos, ios::beg); #else s->seekg(-(sizeof(int_8)+1), ios::end); #endif 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); seqread = false; // objList.clear(); $CHECK$ EA 171199 Ne pas faire ? Reza 03/2000 ? 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); seqread = false; // objList.clear(); $CHECK$ EA 171199 Ne pas faire ? Reza 03/2000 ? 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= (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. //-- void PInPersist::GetTypeTag(unsigned char& c) { c = PPS_TAG_MARK; while (c == PPS_TAG_MARK) GetRawUByte(c); // while (c == PPS_TAG_MARK) { Il ne faut plus faire ca ! // objList.clear(); $CHECK$ Reza 03/2000 // GetRawByte(c); // } } void PInPersist::GetRawByte(char& c) { GetRawBytes(&c, 1); } void PInPersist::GetRawUByte(unsigned 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, short datatype) // datatype = PPS_DATATYPE_CHAR or PPS_DATATYPE_FLOAT or PPS_DATATYPE_INTEGER or PPS_DATATYPE_UNSIGNED { unsigned char ppstype; GetTypeTag(ppstype); if (ppstype != PPS_SIMPLE + datasz + datatype) throw FileFormatExc("PInPersist::CheckTag bad type in ppersist file"); } void PInPersist::CheckArrayTag(short datasz, size_t sz, short datatype) // datatype = PPS_DATATYPE_CHAR or PPS_DATATYPE_FLOAT or PPS_DATATYPE_INTEGER or PPS_DATATYPE_UNSIGNED { unsigned char ppstype; GetTypeTag(ppstype); size_t filesz; if (sz <= 0x7fffffff) { if (ppstype != PPS_SIMPLE_ARRAY4 + datasz + datatype) throw FileFormatExc("PInPersist::CheckArrayTag bad type in ppersist file"); int_4 ff; GetRawI4(ff); filesz=ff; } else { if (ppstype != PPS_SIMPLE_ARRAY8 + datasz + datatype) throw FileFormatExc("PInPersist::CheckArrayTag bad type in ppersist file"); uint_8 ff; GetRawU8(ff); filesz=ff; } if (filesz != sz) throw FileFormatExc("PInPersist::CheckArrayTag bad array size in ppersist file"); } void PInPersist::GetByte(char& c) { CheckTag(1,PPS_DATATYPE_CHAR); GetRawBytes(&c, 1); } void PInPersist::GetBytes(void* ptr, size_t bytes) { CheckArrayTag(1, bytes, PPS_DATATYPE_CHAR); GetRawBytes(ptr, bytes); } void PInPersist::GetR4 (r_4& result) { CheckTag(4,PPS_DATATYPE_FLOAT); GetRawBytes(&result, sizeof(r_4)); if (bigEndian != IS_BIG_ENDIAN) bswap4(&result); } void PInPersist::GetR4s (r_4* tab, size_t n) { CheckArrayTag(4,n,PPS_DATATYPE_FLOAT); GetRawBytes(tab, n*sizeof(r_4)); if (bigEndian == IS_BIG_ENDIAN) return; for (unsigned int i=0; iSetDataObj(*po); object->ReadSelf(*this); unsigned char ppstag; // Read the ENDOBJECT GetRawUByte(ppstag); if (ppstag != PPS_ENDOBJECT) throw FileFormatExc("PInPersist::ReadObject No PPS_ENDOBJECT tag"); GetRawU8(oid2); if (oid2 != oid) throw FileFormatExc("PInPersist::ReadObject Inconsistent PPS-OId at PPS_ENDOBJECT "); KeepOId(oid, *object); return object; } else if (ppstype == PPS_REFERENCE) return ReadReference(); else throw FileFormatExc("PInPersist::ReadObject invalide Tag Type !"); } void PInPersist::AnalyseTags(int lev) { unsigned char ppstag=0; unsigned char ppst1,ppst2,ppst3; uint_8 cpos,fsize; uint_8 ui8,cid,oid; int_4 i4; int_8 i8; char * buff; string str; cout << "\n ---------------------------------------------------------- " << endl; cout << " PInPersist::AnalyseTags(Level= " << lev << ")" << endl; #ifdef STREAMPOS_IS_CLASS cpos = s->tellg().offset(); #else cpos = s->tellg(); #endif s->seekg(0,ios::end); #ifdef STREAMPOS_IS_CLASS fsize = s->tellg().offset(); #else fsize = s->tellg(); #endif s->seekg(cpos,ios::beg); cout << " Version= " << Version() << " FileSize= " << fsize << " Creation Date= " << CreationDateStr() << endl; uint_8 totntags = 0; bool eofok = false; while ( (ppstag != PPS_EOF) && (cpos < fsize) ) { #ifdef STREAMPOS_IS_CLASS cpos = s->tellg().offset(); #else cpos = s->tellg(); #endif GetRawUByte(ppstag); totntags++; ppst1 = ppstag&0x0f; // bits 0123 ppst2 = ppstag&0x30; // bits 45 ppst3 = ppstag&0xc0; // bits 67 if ((ppst2 == 0) && (ppst3 == 0) ) { switch (ppst1) { case PPS_NULL : if (lev > 1) cout << " tag at position " << hex << cpos << dec << endl; break; case PPS_STRING : GetRawI4(i4); if (lev > 1) cout << " tag at position " << hex << cpos << dec << " Length=" << i4 << endl; s->seekg(i4,ios::cur); break; case PPS_OBJECT : GetRawU8(cid); GetRawU8(oid); cout << " tag at position " << hex << cpos << " ClassId= " << cid << " ObjectId= " << oid << dec << endl; break; case PPS_REFERENCE : GetRawU8(oid); GetRawI8(i8); cout << " tag at position " << hex << cpos << " ObjectId= " << oid << " OrigPos=" << i8 << dec << endl; break; case PPS_TAG_MARK : cout << " tag at position " << hex << cpos << dec << endl; break; case PPS_ENDOBJECT : GetRawU8(oid); cout << " tag at position " << hex << cpos << " ObjectId= " << oid << dec << endl; break; case PPS_TAG : GetRawI8(i8); GetRawI4(i4); buff = new char[i4+1]; GetRawBytes(buff, i4); buff[i4] = '\0'; str = buff; delete[] buff; cout << " tag at position " << hex << cpos << dec << " Name= " << str << endl; break; case PPS_EOF : GetRawI8(i8); cout << " tag at position " << hex << cpos << " TagPos=" << i8 << dec << endl; eofok = true; break; default : cerr << " ERROR : Unexpected tag value " << hex << ppstag << " At position" << cpos << dec << endl; throw FileFormatExc("PInPersist::AnalyseTags() - Unexpected tag value !"); } } else { string dtype = "???? x"; if (ppst3 == PPS_DATATYPE_CHAR) dtype = "CHAR x"; else if (ppst3 == PPS_DATATYPE_FLOAT) dtype = "FLOAT x"; else if (ppst3 == PPS_DATATYPE_INTEGER) dtype = "INTEGER x"; else if (ppst3 == PPS_DATATYPE_UNSIGNED) dtype = "UNSIGNED x"; int_4 dsize = ppst1; char sb[16]; sprintf(sb, "%d", dsize); dtype += sb; switch (ppst2) { case PPS_SIMPLE : if (lev > 2) cout << " tag at position " << hex << cpos << dec << " DataType=" << dtype << endl; s->seekg(dsize, ios::cur); break; case PPS_SIMPLE_ARRAY4 : GetRawI4(i4); if (lev > 0) cout << " tag at position " << hex << cpos << dec << " DataType=" << dtype << " NElts= " << i4 << endl; s->seekg((uint_8)dsize*(uint_8)i4, ios::cur); break; case PPS_SIMPLE_ARRAY8 : GetRawU8(ui8); if (lev > 0) cout << " tag at position " << hex << cpos << dec << " DataType=" << dtype << " NElts= " << ui8 << endl; s->seekg((uint_8)dsize*ui8, ios::cur); break; } } } if (!eofok) throw FileFormatExc("PInPersist::AnalyseTags() - Not found tag "); cout << " PInPersist::AnalyseTags() - End - Total Number of Tags= " << totntags << endl; cout << " ---------------------------------------------------------- \n" << endl; return; } void PInPersist::ReadReference(PPersist & ppo) { PPersist * pr = ReadReference(); ppo.ShareDataReference(*pr); } PPersist * PInPersist::ReadReference() { uint_8 oid; int_8 pos; GetRawU8(oid); GetRawI8(pos); // cerr << " DBG - PInPersist::ReadReference-A " << oid << " Pos= " << pos << endl; map::iterator i = objList.find(oid); if (i != objList.end()) return (*i).second; else { // We may have skeeped it ! // Let's try to read it int_8 cpos; #ifdef STREAMPOS_IS_CLASS cpos = s->tellg().offset(); #else cpos = s->tellg(); #endif s->seekg(pos); PPersist* ppo = ReadObject(); s->seekg(cpos); delete ppo; // cerr << " DBG - PInPersist::ReadReference-B ... " << endl; map::iterator i2 = objList.find(oid); if (i2 == objList.end()) throw FileFormatExc("PInPersist::ReadReference() Not found PPS_OId "); return (*i2).second; } } void PInPersist::KeepOId(uint_8 oid, PPersist & ppo) { if ((oid&0x1) == 0) return; // This is not an object which can be referenced // cerr << " DBG - PInPersist::KeepOId() " << oid << endl; if ((objList.size() > 0) && (objList.find(oid) != objList.end()) ) { // Ceci ne devrait arriver que si on lit dans le desordre (avec GotoTag) // et pas avec une lecture sequentielle ... Reza 03/2000 // cerr << "PInPersist::KeepOId()/Warning - already present PPS_ObjectId ! " << oid << endl; if (seqread) throw FileFormatExc("PInPersist::KeepOId() already present PPS_ObjectId "); PPersist *pp = (*objList.find(oid)).second; ppo.ShareDataReference(*pp); } else { PPersist * npp = ppo.CloneSharedReference(); if (npp == NULL) throw PError("PInPersist::KeepOId() NULL returned by PPersist.Clone() ! "); objList[oid] = npp; } return; } //++ // 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; // PPS (POutPersist stream) Object Id initialisation pps_OId = 0; // Output stream creation s = new ofstream(flnm.c_str(),ios::out | IOS_BIN); // Header PutRawBytes("SOS-SOPHYA-PPersistFile V2 ",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 %H:%M:%S GMT",gmtime(&tm)); for(int i=l; i<32; i++) datestring[i] = ' '; datestring[32] = '\0'; PutRawBytes(datestring, 32); filename = flnm; } POutPersist::~POutPersist() { if (tags.size() == 0) { PutRawUByte(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; PutRawUByte(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". } PutRawUByte(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; PutRawUByte(PPS_TAG_MARK); // This is a tag // objList.clear(); // $CHECK$ EA 171199 - Ne pas faire ? Reza 03/2000 } //++ // 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::PutRawUByte(unsigned 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, short datatype) // datatype = PPS_DATATYPE_CHAR or PPS_DATATYPE_FLOAT or PPS_DATATYPE_INTEGER or PPS_DATATYPE_UNSIGNED { if (sz <= 0x7fffffff) { PutRawUByte(PPS_SIMPLE_ARRAY4 + datasz + datatype); PutRawI4(sz); } else { PutRawUByte(PPS_SIMPLE_ARRAY8 + datasz + datatype); PutRawU8(sz); } } void POutPersist::PutByte(char c) { PutRawByte(PPS_SIMPLE + 1 + PPS_DATATYPE_CHAR); PutRawBytes(&c, 1); } void POutPersist::PutBytes(void const* ptr, size_t bytes) { PutArrayTag(1, bytes, PPS_DATATYPE_CHAR); PutRawBytes(ptr, bytes); } void POutPersist::PutR4 (r_4 val) { PutRawUByte(PPS_SIMPLE + 4 + PPS_DATATYPE_FLOAT); 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, PPS_DATATYPE_FLOAT); if (bigEndian == IS_BIG_ENDIAN) { PutRawBytes(tab, n*sizeof(r_4)); } else { for (unsigned int i=0; iSetDataObj(o); PutPPObject(ppo); } void POutPersist::PutObject(AnyDataObj & o, string tagname) { WriteTag(tagname); PutObject(o); } void POutPersist::PutPPObject(PPersist const* obj) { if (serializeNullAndRepeat(obj)) return; // NULL object or already written in stream // We have to write the object uint_8 oid = assignObjectId(obj); // We assing a PPS Object Id PutRawUByte(PPS_OBJECT); // We write the Object Tag PutRawU8(getPPClassId(*obj)); // Writing the PPersist ClassId PutRawU8(oid); // Write the PPS Object Id obj->WriteSelf(*this); PutRawUByte(PPS_ENDOBJECT); // We write the End-Of-Object Tag PutRawU8(oid); // and again its PPS Object Id } bool POutPersist::serializeNullAndRepeat(PPersist const* x) { if (x == NULL) { PutRawUByte(PPS_NULL); return true; } int_8 pos; uint_8 id = findObjectId(x, pos); if (id > 0) { PutRawUByte(PPS_REFERENCE); PutRawU8(id); // Writing the corresponding object Id PutRawI8(pos); // The original object position return true; } return false; // Object have to be written in stream ... } uint_8 POutPersist::assignObjectId(PPersist const* x) { pps_OId += 16; // We keep the three first bytes for future usage // Bit 1 non zero -> Object can be referenced uint_8 id = pps_OId; uint_8 mid = x->getMemOId(); if (mid > 0) { int_8 pos; if (findObjectId(x,pos) > 0) throw PError("POutPersist::assignObjectId() Error - Already serialized object ! "); id += 1; // Bit 1 non zero -> Object can be referenced objreftag rt; rt.ppsoid = id; #ifdef STREAMPOS_IS_CLASS rt.ppspos = s->tellp().offset(); #else rt.ppspos = s->tellp(); #endif objList[mid] = rt; } return id; } uint_8 POutPersist::findObjectId(PPersist const* x, int_8 & pos) { pos = -1; uint_8 mid = x->getMemOId(); if (mid == 0) return(0); ObjList::iterator i = objList.find(mid); if (i == objList.end()) return 0; pos = (*i).second.ppspos; return (*i).second.ppsoid; }