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

Last change on this file since 2476 was 2476, checked in by ansari, 22 years ago

Debug/correction des ppersist suite a la separation des PInOutPersist en PPFInOutStream - Reza 5 Dec 2003

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