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

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

Separation ppersist.h .cc en deux : ajout de ppfbinstream.h .cc - Reza 4 Dec 2003

File size: 17.1 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
182
183
184
185uint_8 PIOPersist::Hash(string const& typname) {
186 md5_init(&ctx);
187 md5_write(&ctx, (unsigned char*) typname.c_str(), typname.size());
188 md5_final(&ctx);
189 uint_8 hash1 = *((uint_8*) ctx.buf);
190 uint_8 hash2 = *((uint_8*) (ctx.buf+8));
191#if IS_BIG_ENDIAN
192 bswap8(&hash1);
193 bswap8(&hash2);
194#endif
195
196 return (hash1+hash2);
197}
198
199
200//++
201// Class PPersist
202// Lib Outils++
203// include ppersist.h
204//
205// Classe de base pour des objets persistants. Pour créer un objet
206// persistant :
207// - Hériter de PPersist.
208// - Définir un numéro d'identification de la classe, unique dans Peida
209// - Implémenter "ClassId()"
210// - Implémenter "WriteSelf" et "ReadSelf", qui doivent écrire toutes les variables
211// membres que l'on souhaite écrire, et les relire dans le même ordre.
212// Pour écrire une référence à un objet : l'objet doit être un PPersist,
213// et il suffit d'appeler "Write" sur cet objet, et "PPersistMgr::ReadObject".
214// Si plusieurs objets font référence au même, pour éviter de l'écrire plusieurs
215// fois, il faut que cet objet soit un PShPersist.
216// - Pour que le fichier soit portable, écrire et lire les variables membres en utilisant
217// les fonctions PutXX/GetXX de PInPersist/POutPersist.
218//
219// Attention: les méthodes à redéfinir sont WriteSelf et ReadSelf, mais il ne faut jamais
220// les appeler directement. Seuls Write et Read peuvent être appelées par l'utilisateur.
221//--
222
223//++
224// Links See
225// PInPersist
226// POutPersist
227// PIOPersist
228//--
229
230//++
231void
232PPersist::Write(string const& fn) const
233//
234// Ecrit l'objet dans un nouveau fichier ppersist "fn".
235//--
236{
237 POutPersist of(fn);
238 Write(of);
239}
240
241//++
242void
243PPersist::Read(string const& fn)
244//
245// Relit l'objet dans le fichier ppersist "fn". Il faut connaître a priori
246// le type de l'objet. Pour une relecture avec création automatique du bon
247// objet, utiliser PPersistMgr::ReadObject.
248//--
249{
250 PInPersist inf(fn);
251 Read(inf);
252}
253
254//++
255void
256PPersist::Write(POutPersist& s) const
257//
258// Ecrit l'objet dans le fichier PPersist.
259//--
260{
261 s.PutPPObject(this);
262}
263
264
265//++
266void
267PPersist::Read(PInPersist& s)
268//
269// Relit l'objet dans le fichier ppersist. Il faut connaître a priori
270// le type de l'objet. Pour une relecture avec création automatique du bon
271// objet, utiliser PInPersist::ReadObject.
272// Il faut qu'on soit un objet ecrit
273//--
274{
275 // We should be the exact type
276 // Check tag value
277 unsigned char ppstype,ppstag;
278 s.GetTypeTag(ppstype);
279 if ( (ppstype != PInPersist::PPS_OBJECT) && ( ppstype != PInPersist::PPS_REFERENCE ) ) {
280 }
281 if (ppstype == PInPersist::PPS_OBJECT) {
282 // Check class id
283 uint_8 classId;
284 s.GetRawU8(classId);
285 uint_8 oid,oid2;
286 s.GetRawU8(oid);
287 if (classId != PIOPersist::getPPClassId(*this) )
288 throw FileFormatExc("PPersist::Read (): not the same object type");
289 ReadSelf(s);
290 // Read the ENDOBJECT
291 s.GetRawUByte(ppstag);
292 if (ppstag != PInPersist::PPS_ENDOBJECT)
293 throw FileFormatExc("PPersist::Read() No PPS_ENDOBJECT tag");
294 s.GetRawU8(oid2);
295 if (oid2 != oid)
296 throw FileFormatExc("PPersist::Read() Inconsistent PPS-OId at PPS_ENDOBJECT ");
297 s.KeepOId(oid, *this); // Object should be kept with its PPS_OId (if oid > 0)
298 }
299 else if ( ppstype == PInPersist::PPS_REFERENCE )
300 s.ReadReference(*this);
301
302 else throw FileFormatExc("PPersist::Read() : not an object in flow");
303
304}
305
306//++
307void
308PPersist::Write(POutPersist& s, string const& tag) const
309//
310// Ecrit l'objet dans le fichier PPersist avec un tag
311//--
312{
313 s.WriteNameTag(tag);
314 s.PutPPObject(this);
315}
316
317//++
318void
319PPersist::ReadAtTag(PInPersist& s, string const& tag)
320//
321// Lit l'objet à la position du tag numéro "tagid".
322//--
323{
324 if (!s.GotoNameTag(tag))
325 throw NotFoundExc("PPersist::ReadAtTag tag not found");
326 Read(s);
327}
328
329// Renvoie l'identificateur de l'objet - par defaut=0
330
331uint_8
332PPersist::getMemOId() const
333{
334 return(0);
335}
336
337// Ces deux methodes doivent etre redefinies si getMemOId() renvoie non nul (>0)
338// ShareDataReference() et CloneSharedReference()
339void
340PPersist::ShareDataReference(PPersist & pcs)
341{
342 throw NotAvailableOperation("PPersist::ShareDataReference() - Unsupported operation !");
343}
344
345PPersist *
346PPersist::CloneSharedReference()
347{
348 throw NotAvailableOperation("PPersist::CloneSharedReference() - Unsupported operation !");
349}
350
351//++
352// virtual void PPersist::ReadSelf(PInPersist&)=0
353// Méthode virtuelle pure à redéfinir. Elle est appelée par Read
354// et PPersistMgr::ReadObject. Il faut relire les variables membres,
355// dans l'ordre où elles ont été écrites par WriteSelf.
356// virtual void PPersist::WriteSelf(POutPersist&) const=0
357// Méthode virtuelle pure à redéfinir. Elle est appelée par Write.
358// Il faut écrire les variables membres,
359// dans l'ordre où elles seront relues par ReadSelf.
360//--
361
362
363
364//++
365// Class PInPersist
366// Lib Outils++
367// include ppersist.h
368//
369// Fichier d'objets persistants, en lecture.
370//--
371
372//++
373PInPersist::PInPersist(string const& flnm, bool scan)
374 : PPFBinaryInputStream(flnm, scan)
375//
376// Constructeur. Ouvre le fichier.
377//--
378{
379}
380
381
382
383PInPersist::~PInPersist()
384{
385 ObjList::iterator i;
386 for(i=objList.begin(); i!= objList.end(); i++)
387 if ((*i).second) delete (*i).second;
388}
389
390
391
392string
393PInPersist::GetTagClassName(int itag)
394{
395 // A faire
396// if (itag<0 || itag >= (int)tags.size()) return "";
397// map<string, int_8>::iterator i = tags.begin();
398// for (int j=0; j<itag; j++) i++;
399// uint_8 cid = (*i).second;
400// return(GetClassName(cid));
401 return("");
402}
403
404PPersist*
405PInPersist::ReadObject()
406{
407 return(GetPPObject());
408}
409
410void
411PInPersist::GetObject(AnyDataObj & o)
412{
413 GetPPObject(&o);
414 return;
415}
416
417void
418PInPersist::GetObject(AnyDataObj & o, string tagname)
419{
420 GotoNameTag(tagname);
421 GetPPObject(&o);
422 return;
423}
424
425PPersist*
426PInPersist::GetPPObject(AnyDataObj * po)
427{
428 // Get tag
429 unsigned char ppstype;
430 GetTypeTag(ppstype);
431 if (ppstype != PPS_OBJECT && ppstype != PPS_REFERENCE && ppstype != PPS_NULL) {
432 throw FileFormatExc("PInPersist::ReadObject : not an object in flow");
433 }
434
435 if (ppstype == PPS_NULL) {
436 return NULL;
437 } else if (ppstype == PPS_OBJECT) {
438 // Get class id
439 uint_8 classId;
440 GetRawU8(classId);
441 uint_8 oid,oid2;
442 GetRawU8(oid);
443
444 // Get factory method
445 ClassCreatorFunc f = FindCreatorFunc(classId);
446 if (!f) {
447 throw NotFoundExc("PInPersist::ReadObject class not registered");
448 }
449
450 // Create object
451 PPersist* object = f();
452 // If a DataObject was specified , we assign it to the PPersistObject
453 if (po != NULL) object->SetDataObj(*po);
454
455 object->ReadSelf(*this);
456 unsigned char ppstag;
457 // Read the ENDOBJECT
458 GetRawUByte(ppstag);
459 if (ppstag != PPS_ENDOBJECT)
460 throw FileFormatExc("PInPersist::ReadObject No PPS_ENDOBJECT tag");
461 GetRawU8(oid2);
462 if (oid2 != oid)
463 throw FileFormatExc("PInPersist::ReadObject Inconsistent PPS-OId at PPS_ENDOBJECT ");
464
465 KeepOId(oid, *object);
466 return object;
467 }
468 else if (ppstype == PPS_REFERENCE)
469 return ReadReference();
470
471 else throw FileFormatExc("PInPersist::ReadObject invalide Tag Type !");
472}
473
474
475
476void
477PInPersist::ReadReference(PPersist & ppo)
478{
479 PPersist * pr = ReadReference();
480 ppo.ShareDataReference(*pr);
481}
482
483
484PPersist *
485PInPersist::ReadReference()
486{
487 uint_8 oid;
488 int_8 pos;
489 GetRawU8(oid);
490 GetRawI8(pos);
491 // cerr << " DBG - PInPersist::ReadReference-A " << oid << " Pos= " << pos << endl;
492 map<uint_8, PPersist *>::iterator i = objList.find(oid);
493 if (i != objList.end()) return (*i).second;
494 else { // We may have skeeped it !
495 // Let's try to read it
496 int_8 cpos;
497 cpos = s->tellg();
498 s->seekg(pos);
499 PPersist* ppo = ReadObject();
500 s->seekg(cpos);
501 delete ppo;
502 // cerr << " DBG - PInPersist::ReadReference-B ... " << endl;
503
504 map<uint_8, PPersist *>::iterator i2 = objList.find(oid);
505 if (i2 == objList.end())
506 throw FileFormatExc("PInPersist::ReadReference() Not found PPS_OId ");
507 return (*i2).second;
508 }
509}
510
511
512void
513PInPersist::KeepOId(uint_8 oid, PPersist & ppo)
514{
515 if ((oid&0x1) == 0) return; // This is not an object which can be referenced
516 // cerr << " DBG - PInPersist::KeepOId() " << oid << endl;
517 if ((objList.size() > 0) && (objList.find(oid) != objList.end()) ) {
518 // Ceci ne devrait arriver que si on lit dans le desordre (avec GotoNameTag)
519 // et pas avec une lecture sequentielle ... Reza 03/2000
520 // cerr << "PInPersist::KeepOId()/Warning - already present PPS_ObjectId ! " << oid << endl;
521 if (seqread) throw FileFormatExc("PInPersist::KeepOId() already present PPS_ObjectId ");
522 PPersist *pp = (*objList.find(oid)).second;
523 ppo.ShareDataReference(*pp);
524 }
525 else {
526 PPersist * npp = ppo.CloneSharedReference();
527 if (npp == NULL) throw PError("PInPersist::KeepOId() NULL returned by PPersist.Clone() ! ");
528 objList[oid] = npp;
529 }
530 return;
531}
532
533//++
534// Class POutPersist
535// Lib Outils++
536// include ppersist.h
537//
538// Fichier d'objets persistants, en écriture.
539//--
540
541
542//++
543// POutPersist(string const& flnm, int endianness = PPersist::PPS_NATIVE)
544//
545// Crée un nouveau fichier ppersist. Par défaut, il est petit=boutien
546// sur machines petit-boutiennes, et gros-boutien sur machines
547// gros-boutiennes. On peut explicitement spécifier PPersist::PPS_LITTLE_ENDIAN
548// ou PPersist::PPS_BIG_ENDIAN.
549//--
550POutPersist::POutPersist(string const& flnm, int endianness)
551 : PPFBinaryOutputStream(flnm, endianness)
552{
553 // PPS (POutPersist stream) Object Id initialisation
554 pps_OId = 0;
555}
556
557POutPersist::~POutPersist()
558{
559}
560
561
562void
563POutPersist::PutObject(AnyDataObj & o)
564{
565 ClassCreatorFunc f = FindCreatorFunc(getDataObjClassId(o));
566 if (!f)
567 throw NotFoundExc("PInPersist::PutObject() class not registered");
568 PPersist* ppo = f();
569 ppo->SetDataObj(o);
570 PutPPObject(ppo);
571}
572
573void
574POutPersist::PutObject(AnyDataObj & o, string tagname)
575{
576 WriteNameTag(tagname);
577 PutObject(o);
578}
579
580
581void
582POutPersist::PutPPObject(PPersist const* obj)
583{
584 if (serializeNullAndRepeat(obj)) return; // NULL object or already written in stream
585
586 // We have to write the object
587 uint_8 oid = assignObjectId(obj); // We assing a PPS Object Id
588 PutRawUByte(PPS_OBJECT); // We write the Object Tag
589 PutRawU8(getPPClassId(*obj)); // Writing the PPersist ClassId
590 PutRawU8(oid); // Write the PPS Object Id
591 obj->WriteSelf(*this);
592 PutRawUByte(PPS_ENDOBJECT); // We write the End-Of-Object Tag
593 PutRawU8(oid); // and again its PPS Object Id
594}
595
596bool
597POutPersist::serializeNullAndRepeat(PPersist const* x)
598{
599 if (x == NULL) {
600 PutRawUByte(PPS_NULL);
601 return true;
602 }
603
604 int_8 pos;
605 uint_8 id = findObjectId(x, pos);
606 if (id > 0) {
607 PutRawUByte(PPS_REFERENCE);
608 PutRawU8(id); // Writing the corresponding object Id
609 PutRawI8(pos); // The original object position
610 return true;
611 }
612
613 return false; // Object have to be written in stream ...
614}
615
616uint_8
617POutPersist::assignObjectId(PPersist const* x)
618{
619 pps_OId += 16; // We keep the three first bytes for future usage
620 // Bit 1 non zero -> Object can be referenced
621 uint_8 id = pps_OId;
622 uint_8 mid = x->getMemOId();
623 if (mid > 0) {
624 int_8 pos;
625 if (findObjectId(x,pos) > 0)
626 throw PError("POutPersist::assignObjectId() Error - Already serialized object ! ");
627 id += 1; // Bit 1 non zero -> Object can be referenced
628 objreftag rt;
629 rt.ppsoid = id;
630 rt.ppspos = s->tellp();
631 objList[mid] = rt;
632 }
633 return id;
634}
635
636uint_8
637POutPersist::findObjectId(PPersist const* x, int_8 & pos)
638{
639 pos = -1;
640 uint_8 mid = x->getMemOId();
641 if (mid == 0) return(0);
642 ObjList::iterator i = objList.find(mid);
643 if (i == objList.end()) return 0;
644 pos = (*i).second.ppspos;
645 return (*i).second.ppsoid;
646}
647
648
Note: See TracBrowser for help on using the repository browser.