source: Sophya/trunk/SophyaLib/BaseTools/ppersist.cc@ 2615

Last change on this file since 2615 was 2615, checked in by cmv, 21 years ago

using namespace sophya enleve de machdefs.h, nouveau sopnamsp.h cmv 10/09/2004

File size: 18.0 KB
RevLine 
[2615]1#include "sopnamsp.h"
[241]2#include "machdefs.h"
[251]3#include <stdio.h>
4#include <sys/types.h>
5#include <time.h>
[241]6#include "pexceptions.h"
[219]7#include "ppersist.h"
[802]8#include "anydataobj.h"
[2322]9#include <iostream>
[241]10#include <typeinfo>
[219]11
[2475]12// ------------------------- Historique ---------------------------
13// Le code de ppersist a ete separe en deux en Decembre 2003
14// a partir de la version CVS (1.26 - ppersist.cc) et
15// (1.19 - ppersist.h) .
16// la partie sur l'ecriture des donnees de base et leurs tableaux
17// a ete mis dans les fichiers ppfbinstream.h .cc
18// (Classes PPFBinaryInputStream et PPFBinaryOutputStream
19// -----------------------------------------------------------------
[219]20
21
[241]22#define MAXTAGLEN 255
23
[219]24//++
[241]25// Class PIOPersist
[219]26// Lib Outils++
27// include ppersist.h
28//
[241]29// Root class for persistant files. Handles the registration of
30// persistant classes
[219]31//--
32
33//++
[241]34// Links See
[219]35// PPersist
[241]36// PInPersist
37// POutPersist
[219]38//--
39
40
[742]41MD5_CONTEXT PIOPersist::ctx;
[802]42PIOPersist::ClassList * PIOPersist::ppclassList = NULL; // $CHECK$ Reza 26/04/99
43map<string, uint_8> * PIOPersist::ppclassNameList = NULL;
44map<string, uint_8> * PIOPersist::dobjclassNameList = NULL;
[241]45
[269]46//++
47void
48PIOPersist::Initialize()
49// Initialisation globale (objets statiques) $CHECK$ Reza 26/04/99
50//--
51{
[802]52ppclassList = new PIOPersist::ClassList;
53ppclassNameList = new map<string, uint_8>;
54dobjclassNameList = new map<string, uint_8>;
[1900]55cout << " PIOPersist::Initialize() Starting Sophya Persistence management service " << endl;
[269]56}
[241]57
[219]58//++
59void
[802]60PIOPersist::RegisterPPHandlerClass(uint_8 classId, string ppclass_name, ClassCreatorFunc f)
[219]61//
[802]62// Register a new persistence handler (PPersist) class.
[2475]63// The classId is usually a hash of the class< name, and
[802]64// ppclass_name is typeid(PPersistClass).name() .
65// This method is called only through the PPersistRegistrar template
[219]66//
67//--
68{
[802]69 if (ppclassList->size() && (ppclassList->find(classId) != ppclassList->end()) ) {
70 cerr << "RegisterClass : Error, " << hex << classId << dec
71 << " already registered." << endl;
[816]72 throw(DuplicateIdExc("PIOPersist::RegisterPPHandlerClass() Already registered (1)"));
[802]73 }
74 if (ppclassNameList->size() && (ppclassNameList->find(ppclass_name) != ppclassNameList->end())) {
75 cerr << "RegisterClass : Error (2) " << ppclass_name
76 << " already registered." << endl;
[816]77 throw(DuplicateIdExc("PIOPersist::RegisterPPHandlerClass() Already registered(2)"));
[219]78 }
79
[802]80 (*ppclassList)[classId] = f;
81 (*ppclassNameList)[ppclass_name] = classId;
[219]82}
83
[802]84//++
85void
86PIOPersist::RegisterDataObjClass(uint_8 classId, string class_name)
87// Register a new DataObj class corresponding to a PPersist classId
88// class_typename should be typeid(DataObject).name()
89//--
90{
[816]91 if (ppclassList->find(classId) == ppclassList->end() ) {
92 cerr << "PIOPersist::RegisterDataObjClass() Error (1) "
93 << hex << classId << dec << " Not Found !" << endl;
94 throw( NotFoundExc("PIOPersist::RegisterDataObjClass() Not found classId ") );
95 }
96 if (dobjclassNameList->size() && (dobjclassNameList->find(class_name) != dobjclassNameList->end())) {
97 cerr << "PIOPersist::RegisterDataObjClass() Error (2)" << class_name
98 << " already registered." << endl;
99 throw(DuplicateIdExc("PIOPersist::RegisterDataObjClass() - Already registered"));
100 }
[219]101
[802]102 (*dobjclassNameList)[class_name] = classId;
103}
104
105// class_typename should be typeid(DataObject).name(), to be
106// used by POutPersist::PutDataObject() methods.
107
[241]108PIOPersist::ClassCreatorFunc
109PIOPersist::FindCreatorFunc(uint_8 classId)
[802]110// Returns the PPersist class creator function for the specified classId
[219]111{
[802]112 ClassList::iterator i = ppclassList->find(classId);
113 if (i == ppclassList->end()) throw(NotFoundExc("PIOPersist::FindCreatorFunc() Not found classId"));
[241]114 return (*i).second;
[219]115}
116
[802]117string
118PIOPersist::getPPClassName(uint_8 classId)
119// Returns the PPersist class name for the specified classId
120{
121 map<string, uint_8>::iterator i;
122 for (i= ppclassNameList->begin(); i != ppclassNameList->end(); i++)
123 if ( (*i).second == classId ) return (*i).first;
[219]124
[802]125 throw(NotFoundExc("PIOPersist::getPPClassName() Not found classId"));
126}
127
128uint_8
129PIOPersist::getPPClassId(string const & typ_name)
130// Returns the classId for the specified PPersist class type name
131{
132 map<string, uint_8>::iterator i = ppclassNameList->find(typ_name);
133 if (i == ppclassNameList->end())
134 throw(NotFoundExc("PIOPersist::getPPClassId() Not found className"));
135 return (*i).second;
136}
137
138uint_8
139PIOPersist::getPPClassId(PPersist const & ppo)
140// Returns the classId for the specified PPersist class
141{
142 string typ_name = typeid(ppo).name() ;
143 return (getPPClassId(typ_name) );
144}
145
146
147string
148PIOPersist::getDataObjClassName(uint_8 classId)
149// Returns the PPersist class name for the specified classId
150{
151 map<string, uint_8>::iterator i;
152 for (i= dobjclassNameList->begin(); i != dobjclassNameList->end(); i++)
153 if ( (*i).second == classId ) return (*i).first;
154
155 throw(NotFoundExc("PIOPersist::getDataObjClassName() Not found classId"));
156}
157
158uint_8
159PIOPersist::getDataObjClassId(string const & typ_name)
160// Returns the classId for the specified PPersist class type name
161{
162 map<string, uint_8>::iterator i = dobjclassNameList->find(typ_name);
163 if (i == dobjclassNameList->end())
164 throw(NotFoundExc("PIOPersist::getDataObjClassId() Not found className"));
165 return (*i).second;
166}
167
168uint_8
169PIOPersist::getDataObjClassId(AnyDataObj const & o)
170// Returns the classId for the specified PPersist class
171{
172 string typ_name = typeid(o).name() ;
173 return (getDataObjClassId(typ_name) );
174}
175
[2476]176static inline void bswap8_hash(void* p)
177{
178 uint_8 tmp = *(uint_8*)p;
179 *(uint_8*)p = ((tmp >> (7*8)) & 0x000000FF) |
180 ((tmp >> (5*8)) & 0x0000FF00) |
181 ((tmp >> (3*8)) & 0x00FF0000) |
182 ((tmp >> (1*8)) & 0xFF000000) |
183 ((tmp & 0xFF000000) << (1*8)) |
184 ((tmp & 0x00FF0000) << (3*8)) |
185 ((tmp & 0x0000FF00) << (5*8)) |
186 ((tmp & 0x000000FF) << (7*8));
187}
[802]188
[1202]189
190
191uint_8 PIOPersist::Hash(string const& typname) {
192 md5_init(&ctx);
193 md5_write(&ctx, (unsigned char*) typname.c_str(), typname.size());
194 md5_final(&ctx);
195 uint_8 hash1 = *((uint_8*) ctx.buf);
196 uint_8 hash2 = *((uint_8*) (ctx.buf+8));
197#if IS_BIG_ENDIAN
[2476]198 bswap8_hash(&hash1);
199 bswap8_hash(&hash2);
[1202]200#endif
201
202 return (hash1+hash2);
203}
204
205
[219]206//++
207// Class PPersist
208// Lib Outils++
209// include ppersist.h
210//
211// Classe de base pour des objets persistants. Pour créer un objet
212// persistant :
213// - Hériter de PPersist.
214// - Définir un numéro d'identification de la classe, unique dans Peida
215// - Implémenter "ClassId()"
216// - Implémenter "WriteSelf" et "ReadSelf", qui doivent écrire toutes les variables
217// membres que l'on souhaite écrire, et les relire dans le même ordre.
218// Pour écrire une référence à un objet : l'objet doit être un PPersist,
219// et il suffit d'appeler "Write" sur cet objet, et "PPersistMgr::ReadObject".
220// Si plusieurs objets font référence au même, pour éviter de l'écrire plusieurs
221// fois, il faut que cet objet soit un PShPersist.
222// - Pour que le fichier soit portable, écrire et lire les variables membres en utilisant
223// les fonctions PutXX/GetXX de PInPersist/POutPersist.
224//
225// Attention: les méthodes à redéfinir sont WriteSelf et ReadSelf, mais il ne faut jamais
226// les appeler directement. Seuls Write et Read peuvent être appelées par l'utilisateur.
227//--
228
229//++
[241]230// Links See
[219]231// PInPersist
232// POutPersist
[241]233// PIOPersist
[219]234//--
235
236//++
237void
238PPersist::Write(string const& fn) const
239//
240// Ecrit l'objet dans un nouveau fichier ppersist "fn".
241//--
242{
243 POutPersist of(fn);
244 Write(of);
245}
246
247//++
248void
249PPersist::Read(string const& fn)
250//
251// Relit l'objet dans le fichier ppersist "fn". Il faut connaître a priori
252// le type de l'objet. Pour une relecture avec création automatique du bon
253// objet, utiliser PPersistMgr::ReadObject.
254//--
255{
256 PInPersist inf(fn);
257 Read(inf);
258}
259
260//++
261void
262PPersist::Write(POutPersist& s) const
263//
264// Ecrit l'objet dans le fichier PPersist.
265//--
266{
[802]267 s.PutPPObject(this);
[219]268}
269
270
271//++
272void
273PPersist::Read(PInPersist& s)
274//
275// Relit l'objet dans le fichier ppersist. Il faut connaître a priori
276// le type de l'objet. Pour une relecture avec création automatique du bon
[241]277// objet, utiliser PInPersist::ReadObject.
278// Il faut qu'on soit un objet ecrit
[219]279//--
280{
[241]281 // We should be the exact type
282 // Check tag value
[802]283 unsigned char ppstype,ppstag;
[588]284 s.GetTypeTag(ppstype);
[802]285 if ( (ppstype != PInPersist::PPS_OBJECT) && ( ppstype != PInPersist::PPS_REFERENCE ) ) {
[241]286 }
[802]287 if (ppstype == PInPersist::PPS_OBJECT) {
288 // Check class id
289 uint_8 classId;
290 s.GetRawU8(classId);
291 uint_8 oid,oid2;
292 s.GetRawU8(oid);
293 if (classId != PIOPersist::getPPClassId(*this) )
294 throw FileFormatExc("PPersist::Read (): not the same object type");
295 ReadSelf(s);
296 // Read the ENDOBJECT
297 s.GetRawUByte(ppstag);
298 if (ppstag != PInPersist::PPS_ENDOBJECT)
299 throw FileFormatExc("PPersist::Read() No PPS_ENDOBJECT tag");
300 s.GetRawU8(oid2);
301 if (oid2 != oid)
302 throw FileFormatExc("PPersist::Read() Inconsistent PPS-OId at PPS_ENDOBJECT ");
303 s.KeepOId(oid, *this); // Object should be kept with its PPS_OId (if oid > 0)
[241]304 }
[802]305 else if ( ppstype == PInPersist::PPS_REFERENCE )
306 s.ReadReference(*this);
[219]307
[802]308 else throw FileFormatExc("PPersist::Read() : not an object in flow");
309
[219]310}
311
312//++
[241]313void
314PPersist::Write(POutPersist& s, string const& tag) const
[219]315//
[241]316// Ecrit l'objet dans le fichier PPersist avec un tag
[219]317//--
318{
[2441]319 s.WriteNameTag(tag);
[802]320 s.PutPPObject(this);
[219]321}
322
323//++
324void
[241]325PPersist::ReadAtTag(PInPersist& s, string const& tag)
[219]326//
327// Lit l'objet à la position du tag numéro "tagid".
328//--
329{
[2459]330 if (!s.GotoNameTag(tag))
[241]331 throw NotFoundExc("PPersist::ReadAtTag tag not found");
332 Read(s);
[219]333}
334
[802]335// Renvoie l'identificateur de l'objet - par defaut=0
[219]336
[802]337uint_8
338PPersist::getMemOId() const
339{
340 return(0);
341}
342
343// Ces deux methodes doivent etre redefinies si getMemOId() renvoie non nul (>0)
344// ShareDataReference() et CloneSharedReference()
345void
346PPersist::ShareDataReference(PPersist & pcs)
347{
348 throw NotAvailableOperation("PPersist::ShareDataReference() - Unsupported operation !");
349}
350
351PPersist *
352PPersist::CloneSharedReference()
353{
354 throw NotAvailableOperation("PPersist::CloneSharedReference() - Unsupported operation !");
355}
356
[219]357//++
358// virtual void PPersist::ReadSelf(PInPersist&)=0
359// Méthode virtuelle pure à redéfinir. Elle est appelée par Read
360// et PPersistMgr::ReadObject. Il faut relire les variables membres,
361// dans l'ordre où elles ont été écrites par WriteSelf.
362// virtual void PPersist::WriteSelf(POutPersist&) const=0
363// Méthode virtuelle pure à redéfinir. Elle est appelée par Write.
364// Il faut écrire les variables membres,
365// dans l'ordre où elles seront relues par ReadSelf.
366//--
367
368
369
370//++
371// Class PInPersist
372// Lib Outils++
373// include ppersist.h
374//
375// Fichier d'objets persistants, en lecture.
376//--
377
[2482]378PInPersist::PInPersist(RawInOutStream * is, bool ad, bool scan)
379 : PPFBinaryInputStream(is, ad, scan)
380{
381}
382
[219]383PInPersist::PInPersist(string const& flnm, bool scan)
[2475]384 : PPFBinaryInputStream(flnm, scan)
[219]385{
386}
387
388
389
390PInPersist::~PInPersist()
391{
[802]392 ObjList::iterator i;
393 for(i=objList.begin(); i!= objList.end(); i++)
394 if ((*i).second) delete (*i).second;
[219]395}
396
397
[802]398
[582]399string
[802]400PInPersist::GetTagClassName(int itag)
401{
402 // A faire
403// if (itag<0 || itag >= (int)tags.size()) return "";
404// map<string, int_8>::iterator i = tags.begin();
405// for (int j=0; j<itag; j++) i++;
406// uint_8 cid = (*i).second;
407// return(GetClassName(cid));
408 return("");
409}
410
[241]411PPersist*
412PInPersist::ReadObject()
413{
[802]414 return(GetPPObject());
415}
416
417void
418PInPersist::GetObject(AnyDataObj & o)
419{
420 GetPPObject(&o);
421 return;
422}
423
424void
425PInPersist::GetObject(AnyDataObj & o, string tagname)
426{
[2459]427 GotoNameTag(tagname);
[802]428 GetPPObject(&o);
429 return;
430}
431
432PPersist*
433PInPersist::GetPPObject(AnyDataObj * po)
434{
[241]435 // Get tag
[802]436 unsigned char ppstype;
[588]437 GetTypeTag(ppstype);
[241]438 if (ppstype != PPS_OBJECT && ppstype != PPS_REFERENCE && ppstype != PPS_NULL) {
[256]439 throw FileFormatExc("PInPersist::ReadObject : not an object in flow");
[241]440 }
441
442 if (ppstype == PPS_NULL) {
443 return NULL;
444 } else if (ppstype == PPS_OBJECT) {
445 // Get class id
446 uint_8 classId;
447 GetRawU8(classId);
[802]448 uint_8 oid,oid2;
449 GetRawU8(oid);
[241]450
451 // Get factory method
452 ClassCreatorFunc f = FindCreatorFunc(classId);
453 if (!f) {
454 throw NotFoundExc("PInPersist::ReadObject class not registered");
455 }
456
457 // Create object
458 PPersist* object = f();
[802]459 // If a DataObject was specified , we assign it to the PPersistObject
460 if (po != NULL) object->SetDataObj(*po);
461
[241]462 object->ReadSelf(*this);
[802]463 unsigned char ppstag;
464 // Read the ENDOBJECT
465 GetRawUByte(ppstag);
466 if (ppstag != PPS_ENDOBJECT)
467 throw FileFormatExc("PInPersist::ReadObject No PPS_ENDOBJECT tag");
468 GetRawU8(oid2);
469 if (oid2 != oid)
470 throw FileFormatExc("PInPersist::ReadObject Inconsistent PPS-OId at PPS_ENDOBJECT ");
471
472 KeepOId(oid, *object);
[241]473 return object;
[802]474 }
475 else if (ppstype == PPS_REFERENCE)
476 return ReadReference();
477
478 else throw FileFormatExc("PInPersist::ReadObject invalide Tag Type !");
479}
480
481
482
483void
484PInPersist::ReadReference(PPersist & ppo)
[241]485{
[802]486 PPersist * pr = ReadReference();
487 ppo.ShareDataReference(*pr);
[241]488}
489
[802]490
491PPersist *
492PInPersist::ReadReference()
493{
494 uint_8 oid;
495 int_8 pos;
496 GetRawU8(oid);
497 GetRawI8(pos);
498 // cerr << " DBG - PInPersist::ReadReference-A " << oid << " Pos= " << pos << endl;
499 map<uint_8, PPersist *>::iterator i = objList.find(oid);
500 if (i != objList.end()) return (*i).second;
501 else { // We may have skeeped it !
502 // Let's try to read it
503 int_8 cpos;
504 cpos = s->tellg();
505 s->seekg(pos);
506 PPersist* ppo = ReadObject();
507 s->seekg(cpos);
508 delete ppo;
509 // cerr << " DBG - PInPersist::ReadReference-B ... " << endl;
510
511 map<uint_8, PPersist *>::iterator i2 = objList.find(oid);
512 if (i2 == objList.end())
513 throw FileFormatExc("PInPersist::ReadReference() Not found PPS_OId ");
514 return (*i2).second;
515 }
516}
517
518
519void
520PInPersist::KeepOId(uint_8 oid, PPersist & ppo)
521{
522 if ((oid&0x1) == 0) return; // This is not an object which can be referenced
523 // cerr << " DBG - PInPersist::KeepOId() " << oid << endl;
524 if ((objList.size() > 0) && (objList.find(oid) != objList.end()) ) {
[2459]525 // Ceci ne devrait arriver que si on lit dans le desordre (avec GotoNameTag)
[802]526 // et pas avec une lecture sequentielle ... Reza 03/2000
527 // cerr << "PInPersist::KeepOId()/Warning - already present PPS_ObjectId ! " << oid << endl;
528 if (seqread) throw FileFormatExc("PInPersist::KeepOId() already present PPS_ObjectId ");
529 PPersist *pp = (*objList.find(oid)).second;
530 ppo.ShareDataReference(*pp);
531 }
532 else {
533 PPersist * npp = ppo.CloneSharedReference();
534 if (npp == NULL) throw PError("PInPersist::KeepOId() NULL returned by PPersist.Clone() ! ");
535 objList[oid] = npp;
536 }
537 return;
538}
539
[219]540//++
541// Class POutPersist
542// Lib Outils++
543// include ppersist.h
544//
545// Fichier d'objets persistants, en écriture.
546//--
547
548
549//++
550// POutPersist(string const& flnm, int endianness = PPersist::PPS_NATIVE)
551//
552// Crée un nouveau fichier ppersist. Par défaut, il est petit=boutien
553// sur machines petit-boutiennes, et gros-boutien sur machines
554// gros-boutiennes. On peut explicitement spécifier PPersist::PPS_LITTLE_ENDIAN
555// ou PPersist::PPS_BIG_ENDIAN.
556//--
[2477]557POutPersist::POutPersist(RawInOutStream* os, bool ad, int endianness)
558 : PPFBinaryOutputStream(os, ad, endianness)
559{
560 pps_OId = 0;
561 wobj_level = 0;
562}
563
[219]564POutPersist::POutPersist(string const& flnm, int endianness)
[2475]565 : PPFBinaryOutputStream(flnm, endianness)
[219]566{
[802]567 // PPS (POutPersist stream) Object Id initialisation
568 pps_OId = 0;
[2477]569 wobj_level = 0;
[219]570}
571
572POutPersist::~POutPersist()
573{
574}
575
576
[241]577void
[802]578POutPersist::PutObject(AnyDataObj & o)
579{
580 ClassCreatorFunc f = FindCreatorFunc(getDataObjClassId(o));
581 if (!f)
582 throw NotFoundExc("PInPersist::PutObject() class not registered");
583 PPersist* ppo = f();
584 ppo->SetDataObj(o);
585 PutPPObject(ppo);
[219]586}
587
[241]588void
[802]589POutPersist::PutObject(AnyDataObj & o, string tagname)
[241]590{
[2441]591 WriteNameTag(tagname);
[802]592 PutObject(o);
593}
[219]594
[802]595
596void
597POutPersist::PutPPObject(PPersist const* obj)
598{
599 if (serializeNullAndRepeat(obj)) return; // NULL object or already written in stream
600
601 // We have to write the object
602 uint_8 oid = assignObjectId(obj); // We assing a PPS Object Id
603 PutRawUByte(PPS_OBJECT); // We write the Object Tag
[2477]604 wobj_level++; // Niveau d'imbrication d'ecriture d'objets
[802]605 PutRawU8(getPPClassId(*obj)); // Writing the PPersist ClassId
606 PutRawU8(oid); // Write the PPS Object Id
[241]607 obj->WriteSelf(*this);
[2477]608 // Comptage d'objets ecrits
609 _nbobjs++;
[2482]610 if (wobj_level > _maxnestlevel) _maxnestlevel = wobj_level;
[2477]611 if (wobj_level == 1) _nbtlobjs++;
612 wobj_level--;
[802]613 PutRawUByte(PPS_ENDOBJECT); // We write the End-Of-Object Tag
614 PutRawU8(oid); // and again its PPS Object Id
[241]615}
[219]616
[241]617bool
618POutPersist::serializeNullAndRepeat(PPersist const* x)
[219]619{
[241]620 if (x == NULL) {
[802]621 PutRawUByte(PPS_NULL);
[241]622 return true;
623 }
[219]624
[802]625 int_8 pos;
626 uint_8 id = findObjectId(x, pos);
627 if (id > 0) {
628 PutRawUByte(PPS_REFERENCE);
629 PutRawU8(id); // Writing the corresponding object Id
630 PutRawI8(pos); // The original object position
[2482]631 _nbrefs++; // Compteur de nombre de reference ecrits
[241]632 return true;
633 }
[219]634
[802]635 return false; // Object have to be written in stream ...
[219]636}
637
[802]638uint_8
[241]639POutPersist::assignObjectId(PPersist const* x)
[219]640{
[802]641 pps_OId += 16; // We keep the three first bytes for future usage
642 // Bit 1 non zero -> Object can be referenced
643 uint_8 id = pps_OId;
644 uint_8 mid = x->getMemOId();
645 if (mid > 0) {
646 int_8 pos;
647 if (findObjectId(x,pos) > 0)
648 throw PError("POutPersist::assignObjectId() Error - Already serialized object ! ");
[821]649 id += 1; // Bit 1 non zero -> Object can be referenced
[802]650 objreftag rt;
651 rt.ppsoid = id;
[2476]652 // cout << " DBG-rt.ppspos = s->tellp(); " << endl;
[802]653 rt.ppspos = s->tellp();
[2476]654 // cout << " DBG-rt.ppspos = s->tellp(); = " << rt.ppspos << endl;
[802]655 objList[mid] = rt;
656 }
[241]657 return id;
[219]658}
659
[802]660uint_8
661POutPersist::findObjectId(PPersist const* x, int_8 & pos)
[219]662{
[802]663 pos = -1;
664 uint_8 mid = x->getMemOId();
665 if (mid == 0) return(0);
666 ObjList::iterator i = objList.find(mid);
667 if (i == objList.end()) return 0;
668 pos = (*i).second.ppspos;
669 return (*i).second.ppsoid;
[219]670}
671
[241]672
Note: See TracBrowser for help on using the repository browser.