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

Last change on this file since 690 was 661, checked in by ansari, 26 years ago

Preparation pour tag V_Oct99 , Reza 29/11/99

File size: 26.0 KB
RevLine 
[241]1#include "machdefs.h"
[251]2#include <stdio.h>
3#include <sys/types.h>
4#include <time.h>
[241]5#include "pexceptions.h"
[219]6#include "peidainit.h"
7#include "ppersist.h"
8#include <fstream.h>
[661]9#include <iostream.h>
[241]10#include <typeinfo>
[219]11
12
13#ifdef __mac__
14#include "unixmac.h"
15#include <SIOUX.h>
16#endif
17
[241]18#define MAXTAGLEN 255
19
[219]20//++
[241]21// Class PIOPersist
[219]22// Lib Outils++
23// include ppersist.h
24//
[241]25// Root class for persistant files. Handles the registration of
26// persistant classes
[219]27//--
28
29//++
[241]30// Links See
[219]31// PPersist
[241]32// PInPersist
33// POutPersist
[219]34//--
35
36
[241]37MD5_CTX PIOPersist::ctx;
[269]38PIOPersist::ClassList * PIOPersist::classList = NULL; // $CHECK$ Reza 26/04/99
[588]39map<string, uint_8> * PIOPersist::typeids = NULL;
[241]40
[269]41//++
42void
43PIOPersist::Initialize()
44// Initialisation globale (objets statiques) $CHECK$ Reza 26/04/99
45//--
46{
47classList = new PIOPersist::ClassList;
[588]48typeids = new map<string, uint_8>;
[269]49}
[241]50
[219]51//++
52void
[588]53PIOPersist::RegisterClass(uint_8 classId, string typname, ClassCreatorFunc f)
[219]54//
[241]55// Register a new persistant class.
56// The classId is usually a hash of the class name, and this
57// method is called only through the PPersistRegistrar template
58// class, with the PPRegister(className) macro.
[219]59//
60//--
61{
[269]62 if (classList->size() && (classList->find(classId) != classList->end())) {
[219]63 cerr << "RegisterClass : Error, " << hex << classId << dec
64 << " already registered." << endl;
[241]65 throw(DuplicateIdExc("PIOPersist::RegisterClass"));
[219]66 }
67
[269]68 (*classList)[classId] = f;
[588]69 (*typeids)[typname] = classId;
[219]70}
71
72
[241]73PIOPersist::ClassCreatorFunc
74PIOPersist::FindCreatorFunc(uint_8 classId)
[219]75{
[269]76 ClassList::iterator i = classList->find(classId);
77 if (i == classList->end()) throw(NotFoundExc("PIOPersist::FindCreatorFunc"));
[241]78 return (*i).second;
[219]79}
80
81
82//++
83// Class PPersist
84// Lib Outils++
85// include ppersist.h
86//
87// Classe de base pour des objets persistants. Pour créer un objet
88// persistant :
89// - Hériter de PPersist.
90// - Définir un numéro d'identification de la classe, unique dans Peida
91// - Implémenter "ClassId()"
92// - Implémenter "WriteSelf" et "ReadSelf", qui doivent écrire toutes les variables
93// membres que l'on souhaite écrire, et les relire dans le même ordre.
94// Pour écrire une référence à un objet : l'objet doit être un PPersist,
95// et il suffit d'appeler "Write" sur cet objet, et "PPersistMgr::ReadObject".
96// Si plusieurs objets font référence au même, pour éviter de l'écrire plusieurs
97// fois, il faut que cet objet soit un PShPersist.
98// - Pour que le fichier soit portable, écrire et lire les variables membres en utilisant
99// les fonctions PutXX/GetXX de PInPersist/POutPersist.
100//
101// Attention: les méthodes à redéfinir sont WriteSelf et ReadSelf, mais il ne faut jamais
102// les appeler directement. Seuls Write et Read peuvent être appelées par l'utilisateur.
103//--
104
105//++
[241]106// Links See
[219]107// PInPersist
108// POutPersist
[241]109// PIOPersist
[219]110//--
111
112//++
113void
114PPersist::Write(string const& fn) const
115//
116// Ecrit l'objet dans un nouveau fichier ppersist "fn".
117//--
118{
119 POutPersist of(fn);
120 Write(of);
121}
122
123//++
124void
125PPersist::Read(string const& fn)
126//
127// Relit l'objet dans le fichier ppersist "fn". Il faut connaître a priori
128// le type de l'objet. Pour une relecture avec création automatique du bon
129// objet, utiliser PPersistMgr::ReadObject.
130//--
131{
132 PInPersist inf(fn);
133 Read(inf);
134}
135
136//++
137void
138PPersist::Write(POutPersist& s) const
139//
140// Ecrit l'objet dans le fichier PPersist.
141//--
142{
[241]143 s.PutObject(this);
[219]144}
145
146
147//++
148void
149PPersist::Read(PInPersist& s)
150//
151// Relit l'objet dans le fichier ppersist. Il faut connaître a priori
152// le type de l'objet. Pour une relecture avec création automatique du bon
[241]153// objet, utiliser PInPersist::ReadObject.
154// Il faut qu'on soit un objet ecrit
[219]155//--
156{
[241]157 // We should be the exact type
158 // Check tag value
159 char ppstype;
[588]160 s.GetTypeTag(ppstype);
[241]161 if (ppstype != PInPersist::PPS_OBJECT) {
[256]162 throw FileFormatExc("PPersist::Read : not an object in flow");
[241]163 }
164
165 // Check class id
166 uint_8 classId;
167 s.GetRawU8(classId);
[588]168 uint_8 myClassId = PIOPersist::getTypeId(typeid(*this).name());
169 if (classId != myClassId) {
[256]170 throw FileFormatExc("PPersist::Read : not the same object type");
[241]171 }
[219]172
[241]173 ReadSelf(s);
[219]174}
175
176//++
[241]177void
178PPersist::Write(POutPersist& s, string const& tag) const
[219]179//
[241]180// Ecrit l'objet dans le fichier PPersist avec un tag
[219]181//--
182{
[241]183 s.WriteTag(tag);
184 s.PutObject(this);
[219]185}
186
187//++
188void
[241]189PPersist::ReadAtTag(PInPersist& s, string const& tag)
[219]190//
191// Lit l'objet à la position du tag numéro "tagid".
192//--
193{
[241]194 if (!s.GotoTag(tag))
195 throw NotFoundExc("PPersist::ReadAtTag tag not found");
196 Read(s);
[219]197}
198
199
200//++
201// virtual void PPersist::ReadSelf(PInPersist&)=0
202// Méthode virtuelle pure à redéfinir. Elle est appelée par Read
203// et PPersistMgr::ReadObject. Il faut relire les variables membres,
204// dans l'ordre où elles ont été écrites par WriteSelf.
205// virtual void PPersist::WriteSelf(POutPersist&) const=0
206// Méthode virtuelle pure à redéfinir. Elle est appelée par Write.
207// Il faut écrire les variables membres,
208// dans l'ordre où elles seront relues par ReadSelf.
209//--
210
211
212
213//++
214// Class PInPersist
215// Lib Outils++
216// include ppersist.h
217//
218// Fichier d'objets persistants, en lecture.
219//--
220
221//++
222PInPersist::PInPersist(string const& flnm, bool scan)
223//
224// Constructeur. Ouvre le fichier.
225//--
226{
[241]227 s = new ifstream(flnm.c_str(),ios::in | IOS_BIN);
228
229 // Read and check header
230
[219]231 char rbuf[36];
[241]232 GetRawBytes(rbuf, 32);
[576]233 if (strncmp(rbuf,"SOS-SOPHYA-PPersistFile", 23) != 0) {
[241]234 throw FileFormatExc("PInPersist::PInPersist bad header");
[219]235 }
[241]236 version = atoi(rbuf+24);
237
238 // read endianness
239 GetRawBytes(rbuf, 32);
240 if (strncmp(rbuf,"BIG-ENDIAN",10) == 0)
241 bigEndian = true;
242 else if (strncmp(rbuf,"LITTLE-ENDIAN",13) == 0)
243 bigEndian = false;
244 else {
245 throw FileFormatExc("PInPersist::PInPersist bad header - endianness");
246 }
247
248 // read creation date
249 GetRawBytes(rbuf, 32);
250 rbuf[32] = '\0';
251 struct tm tm;
252 strptime(rbuf,"%d/%m/%Y %T GMT",&tm);
253 creationdate = mktime(&tm);
254
255 if (scan) Scan();
[219]256}
257
258
259
260PInPersist::~PInPersist()
261{
262 delete s;
263}
264
265
266void
267PInPersist::Scan()
268{
[241]269 // On cherche la liste des tags, a la fin du fichier
[219]270
[241]271 char ppstype;
272 size_t debut;
273#ifdef STREAMPOS_IS_CLASS
[219]274 debut = s->tellg().offset();
[241]275#else
[219]276 debut = s->tellg();
[241]277#endif
[219]278
[241]279 // Find tag entries at end of file
280 s->seekg(-(sizeof(int_8)+1), ios::end);
[588]281 GetTypeTag(ppstype);
[241]282 if (ppstype != PPS_EOF)
283 throw FileFormatExc("PInPersist::Scan corrupted file, no eof entry at end of file");
[219]284
[241]285 int_8 pos;
286 GetRawI8(pos);
287 if (pos < 0) { // no tags
288 s->seekg(debut);
289 return;
290 }
[219]291
[241]292 char buffer[MAXTAGLEN+1];
293 s->seekg(pos);
294 while (true) {
[588]295 GetTypeTag(ppstype);
[241]296 if (ppstype == PPS_EOF) break;
297
298 if (ppstype != PPS_TAG)
299 throw FileFormatExc("PInPersist::Scan corrupted file, bad tag entry");
[219]300
[241]301 GetRawI8(pos);
302 int_4 len;
303 GetRawI4(len);
304 if (len > MAXTAGLEN)
305 throw FileFormatExc("PInPersist::Scan corrupted file, tag name too long");
306 GetRawBytes(buffer, len);
307 buffer[len] = '\0';
[219]308
[241]309 tags[buffer] = pos;
[219]310 }
[241]311 s->seekg(debut);
[219]312}
313
314
[256]315int
316PInPersist::NbTags()
317{
318 return tags.size();
319}
320
[219]321bool
[241]322PInPersist::GotoTag(string const& name)
[219]323{
[241]324 map<string, int_8>::iterator i = tags.find(name);
325 if (i == tags.end())
326 return false;
327 // throw NotFoundExc("PInPersist::GotoTag tag not found");
328 s->seekg((*i).second);
[588]329 objList.clear(); // $CHECK$ EA 171199
[219]330 return(true);
331}
332
[256]333bool
334PInPersist::GotoTagNum(int itag)
335{
[582]336 if (itag<0 || itag >= (int)tags.size()) return false;
[256]337 map<string, int_8>::iterator i = tags.begin();
338 for (int j=0; j<itag; j++) i++;
339 s->seekg((*i).second);
[588]340 objList.clear(); // $CHECK$ EA 171199
[256]341 return(true);
342}
343
[582]344string
345PInPersist::GetTagName(int itag)
346{
347 if (itag<0 || itag >= (int)tags.size()) return "";
348 map<string, int_8>::iterator i = tags.begin();
349 for (int j=0; j<itag; j++) i++;
350 return((*i).first);
351}
[256]352
[582]353static vector<string> * ret_tag_names = NULL;
354vector<string> const &
355PInPersist::GetTagNames()
356{
357if (ret_tag_names) delete ret_tag_names;
358ret_tag_names = new vector<string> ;
359map<string, int_8>::iterator i;
360for(i=tags.begin(); i!=tags.end(); i++) ret_tag_names->push_back((*i).first);
361return(*ret_tag_names);
362}
363
[219]364//++
365// void PInPersist::GetByte(char& c)
366// void PInPersist::GetBytes(void* ptr, size_t bytes)
367// void PInPersist::GetR4 (r_4& result)
368// void PInPersist::GetR4s (r_4* tab, size_t n)
369// void PInPersist::GetR8 (r_8& result)
370// void PInPersist::GetR8s (r_8* tab, size_t n)
371// void PInPersist::GetI2 (int_2& result)
372// void PInPersist::GetI2s (int_2* tab, size_t n)
373// void PInPersist::GetU2 (uint_2& result)
374// void PInPersist::GetU2s (uint_2* tab, size_t n)
375// void PInPersist::GetI4 (int_4& result)
376// void PInPersist::GetI4s (int_4* tab, size_t n)
377// void PInPersist::GetU4 (uint_4& result)
378// void PInPersist::GetU4s (uint_4* tab, size_t n)
379// void PInPersist::GetI8 (int_8& result)
380// void PInPersist::GetI8s (int_8* tab, size_t n)
381// void PInPersist::GetU8 (uint_8& result)
382// void PInPersist::GetU8s (uint_8* tab, size_t n)
383// Lecture de données portables depuis le fichier PPersist. Pour chaque type
384// de données, on peut lire une valeur, ou un tableau de valeurs.
385// void PInPersist::GetLine(char* ptr, size_t len)
386// Lecture d'une ligne de texte depuis le fichier PPersist.
387//--
388
389
390static inline void bswap8(void* p)
391{
392 uint_8 tmp = *(uint_8*)p;
393 *(uint_8*)p = ((tmp >> (7*8)) & 0x000000FF) |
394 ((tmp >> (5*8)) & 0x0000FF00) |
395 ((tmp >> (3*8)) & 0x00FF0000) |
396 ((tmp >> (1*8)) & 0xFF000000) |
397 ((tmp & 0xFF000000) << (1*8)) |
398 ((tmp & 0x00FF0000) << (3*8)) |
399 ((tmp & 0x0000FF00) << (5*8)) |
400 ((tmp & 0x000000FF) << (7*8));
401}
402
403static inline void bswap4(void* p)
404{
405 uint_4 tmp = *(uint_4*)p;
406 *(uint_4*)p = ((tmp >> 24) & 0x000000FF) |
407 ((tmp >> 8) & 0x0000FF00) |
408 ((tmp & 0x0000FF00) << 8) |
409 ((tmp & 0x000000FF) << 24);
410}
411
412static inline void bswap2(void* p)
413{
414 uint_2 tmp = *(uint_2*)p;
415 *(uint_2*)p = ((tmp >> 8) & 0x00FF) |
416 ((tmp & 0x00FF) << 8);
417}
418
[588]419void
420PInPersist::GetTypeTag(char& c)
421{
422 GetRawByte(c);
423 while (c == PPS_TAG_MARK) {
424 objList.clear();
425 GetRawByte(c);
426 }
427}
[241]428
[588]429
[219]430void
[241]431PInPersist::GetRawByte(char& c)
432{
433 GetRawBytes(&c, 1);
434}
435
436void
437PInPersist::GetRawBytes(void* ptr, size_t bytes)
438{
439 s->read((char*)ptr, bytes);
440}
441
442void
443PInPersist::GetRawI2 (int_2& result)
444{
445 GetRawBytes(&result, sizeof(int_2));
446 if (bigEndian != IS_BIG_ENDIAN)
447 bswap2(&result);
448}
449
450void
451PInPersist::GetRawI4 (int_4& result)
452{
453 GetRawBytes(&result, sizeof(int_4));
454 if (bigEndian != IS_BIG_ENDIAN)
455 bswap4(&result);
456}
457
458void
459PInPersist::GetRawI8 (int_8& result)
460{
461 GetRawBytes(&result, sizeof(int_8));
462 if (bigEndian != IS_BIG_ENDIAN)
463 bswap8(&result);
464}
465
466void
467PInPersist::GetRawU8 (uint_8& result)
468{
469 GetRawBytes(&result, sizeof(uint_8));
470 if (bigEndian != IS_BIG_ENDIAN)
471 bswap8(&result);
472}
473
474void
475PInPersist::CheckTag(short datasz)
476{
477 char ppstype;
[588]478 GetTypeTag(ppstype);
[241]479 if (ppstype != PPS_SIMPLE + datasz)
[256]480 throw FileFormatExc("PInPersist::CheckTag bad type in ppersist file");
[241]481}
482
483void
484PInPersist::CheckArrayTag(short datasz, size_t sz)
485{
486 char ppstype;
[588]487 GetTypeTag(ppstype);
[241]488 size_t filesz;
489 if (sz <= 0x7fff) {
490 if (ppstype != PPS_SIMPLE_ARRAY + datasz)
[256]491 throw FileFormatExc("PInPersist::CheckTag bad type in ppersist file");
[241]492 int_2 ff;
493 GetRawI2(ff); filesz=ff;
494 } else if (sz <= 0x7fffffff) {
495 if (ppstype != PPS_SIMPLE_ARRAY4 + datasz)
[256]496 throw FileFormatExc("PInPersist::CheckTag bad type in ppersist file");
[241]497 int_4 ff;
498 GetRawI4(ff); filesz=ff;
499 } else {
500 if (ppstype != PPS_SIMPLE_ARRAY8 + datasz)
[256]501 throw FileFormatExc("PInPersist::CheckTag bad type in ppersist file");
[241]502 uint_8 ff;
503 GetRawU8(ff); filesz=ff;
504 }
505 if (filesz != sz)
[256]506 throw FileFormatExc("PInPersist::CheckTag bad array size in ppersist file");
[241]507}
508
509void
510PInPersist::GetByte(char& c)
511{
512 CheckTag(1);
513 GetRawBytes(&c, 1);
514}
515
516void
517PInPersist::GetBytes(void* ptr, size_t bytes)
518{
519 CheckArrayTag(1, bytes);
520 GetRawBytes(ptr, bytes);
521}
522void
[219]523PInPersist::GetR4 (r_4& result)
524{
[241]525 CheckTag(4);
526 GetRawBytes(&result, sizeof(r_4));
[219]527 if (bigEndian != IS_BIG_ENDIAN)
528 bswap4(&result);
529}
530
531
532void
533PInPersist::GetR4s (r_4* tab, size_t n)
534{
[241]535 CheckArrayTag(4,n);
536 GetRawBytes(tab, n*sizeof(r_4));
[219]537 if (bigEndian == IS_BIG_ENDIAN) return;
538
539 for (unsigned int i=0; i<n; i++)
540 bswap4(tab+i);
541
542 return;
543}
544
545void
546PInPersist::GetR8 (r_8& result)
547{
[241]548 CheckTag(8);
549 GetRawBytes(&result, sizeof(r_8));
[219]550 if (bigEndian != IS_BIG_ENDIAN)
551 bswap8(&result);
552}
553
554void
555PInPersist::GetR8s (r_8* tab, size_t n)
556{
[241]557 CheckArrayTag(8,n);
558 GetRawBytes(tab, n*sizeof(r_8));
[219]559 if (bigEndian == IS_BIG_ENDIAN) return;
560
561 for (unsigned int i=0; i<n; i++)
562 bswap8(tab+i);
563
564 return;
565}
566
567void
568PInPersist::GetI2 (int_2& result)
569{
[241]570 CheckTag(2);
571 GetRawBytes(&result, sizeof(int_2));
[219]572 if (bigEndian != IS_BIG_ENDIAN)
573 bswap2(&result);
574}
575
576void
577PInPersist::GetI2s (int_2* tab, size_t n)
578{
[241]579 CheckArrayTag(2,n);
580 GetRawBytes(tab, n*sizeof(int_2));
[219]581 if (bigEndian == IS_BIG_ENDIAN) return;
582
583 for (unsigned int i=0; i<n; i++)
584 bswap2(tab+i);
585
586 return;
587}
588
589void
590PInPersist::GetU2 (uint_2& result)
591{
[241]592 CheckTag(2);
593 GetRawBytes(&result, sizeof(uint_2));
[219]594 if (bigEndian != IS_BIG_ENDIAN)
595 bswap2(&result);
596}
597
598void
599PInPersist::GetU2s (uint_2* tab, size_t n)
600{
[241]601 CheckArrayTag(2,n);
602 GetRawBytes(tab, n*sizeof(uint_2));
[219]603 if (bigEndian == IS_BIG_ENDIAN) return;
604
605 for (unsigned int i=0; i<n; i++)
606 bswap2(tab+i);
607
608 return;
609}
610
611void
612PInPersist::GetI4 (int_4& result)
613{
[241]614 CheckTag(4);
615 GetRawBytes(&result, sizeof(int_4));
[219]616 if (bigEndian != IS_BIG_ENDIAN)
617 bswap4(&result);
618}
619
620void
621PInPersist::GetI4s (int_4* tab, size_t n)
622{
[241]623 CheckArrayTag(4,n);
624 GetRawBytes(tab, n*sizeof(int_4));
[219]625 if (bigEndian == IS_BIG_ENDIAN) return;
626
627 for (unsigned int i=0; i<n; i++)
628 bswap4(tab+i);
629
630 return;
631}
632
633void
634PInPersist::GetU4 (uint_4& result)
635{
[241]636 CheckTag(4);
637 GetRawBytes(&result, sizeof(uint_4));
[219]638 if (bigEndian != IS_BIG_ENDIAN)
639 bswap4(&result);
640}
641
642void
643PInPersist::GetU4s (uint_4* tab, size_t n)
644{
[241]645 CheckArrayTag(4,n);
646 GetRawBytes(tab, n*sizeof(uint_4));
[219]647 if (bigEndian == IS_BIG_ENDIAN) return;
648
649 for (unsigned int i=0; i<n; i++)
650 bswap4(tab+i);
651
652 return;
653}
654
655
656void
657PInPersist::GetI8 (int_8& result)
658{
[241]659 CheckTag(8);
660 GetRawBytes(&result, sizeof(int_8));
[219]661 if (bigEndian != IS_BIG_ENDIAN)
662 bswap8(&result);
663}
664
665void
666PInPersist::GetI8s (int_8* tab, size_t n)
667{
[241]668 CheckArrayTag(8,n);
669 GetRawBytes(tab, n*sizeof(int_8));
[219]670 if (bigEndian == IS_BIG_ENDIAN) return;
671
672 for (unsigned int i=0; i<n; i++)
673 bswap8(tab+i);
674
675 return;
676}
677
678void
679PInPersist::GetU8 (uint_8& result)
680{
[241]681 CheckTag(8);
682 GetRawBytes(&result, sizeof(uint_8));
[219]683 if (bigEndian != IS_BIG_ENDIAN)
684 bswap8(&result);
685}
686
687void
688PInPersist::GetU8s (uint_8* tab, size_t n)
689{
[241]690 CheckArrayTag(8,n);
691 GetRawBytes(tab, n*sizeof(uint_8));
[219]692 if (bigEndian == IS_BIG_ENDIAN) return;
693
694 for (unsigned int i=0; i<n; i++)
695 bswap8(tab+i);
696
697 return;
698}
699
700
701void
702PInPersist::GetLine(char* ptr, size_t len)
703{
[241]704 char ppstype;
[588]705 GetTypeTag(ppstype);
[241]706 if (ppstype != PPS_LINE)
[256]707 throw FileFormatExc("PInPersist::GetLine bad type in ppersist file");
[241]708 s->getline(ptr, len, '\n');
[219]709}
710
[241]711void
712PInPersist::GetStr(string& str)
713{
714 char ppstype;
[588]715 GetTypeTag(ppstype);
[241]716 if (ppstype != PPS_STRING)
[256]717 throw FileFormatExc("PInPersist::GetLine bad type in ppersist file");
[241]718 int_2 len;
719 GetRawI2(len);
[582]720 char * buff = new char[len+1];
[241]721 GetRawBytes(buff, len);
722 buff[len] = '\0';
723 str = buff;
724 delete[] buff;
725}
[219]726
[241]727PPersist*
728PInPersist::ReadObject()
729{
730 // Get tag
731 char ppstype;
[588]732 GetTypeTag(ppstype);
[241]733 if (ppstype != PPS_OBJECT && ppstype != PPS_REFERENCE && ppstype != PPS_NULL) {
[256]734 throw FileFormatExc("PInPersist::ReadObject : not an object in flow");
[241]735 }
736
737 if (ppstype == PPS_NULL) {
738 return NULL;
739 } else if (ppstype == PPS_OBJECT) {
740 // Get class id
741 uint_8 classId;
742 GetRawU8(classId);
743
744 // Get factory method
745 ClassCreatorFunc f = FindCreatorFunc(classId);
746 if (!f) {
747 throw NotFoundExc("PInPersist::ReadObject class not registered");
748 }
749
750 // Create object
751 PPersist* object = f();
752 object->ReadSelf(*this);
753 assignObjectId(object);
754 return object;
755 } else {
756 // Get object id
757 int_4 id;
758 GetRawI4(id);
759 if (id <0 || id>=objList.size()) {
[588]760 char msg[200];
761 sprintf(msg, "PInPersist::ReadObject invalid object id for reference: %d/%d",id,objList.size());
762 throw FileFormatExc(msg);
[241]763 }
764 return objList[id];
765 }
766}
767
768int_4
769PInPersist::assignObjectId(PPersist* x)
770{
771 objList.push_back(x);
772 return objList.size()-1;
773}
774
[219]775//++
776// Class POutPersist
777// Lib Outils++
778// include ppersist.h
779//
780// Fichier d'objets persistants, en écriture.
781//--
782
783
784//++
785// POutPersist(string const& flnm, int endianness = PPersist::PPS_NATIVE)
786//
787// Crée un nouveau fichier ppersist. Par défaut, il est petit=boutien
788// sur machines petit-boutiennes, et gros-boutien sur machines
789// gros-boutiennes. On peut explicitement spécifier PPersist::PPS_LITTLE_ENDIAN
790// ou PPersist::PPS_BIG_ENDIAN.
791//--
792POutPersist::POutPersist(string const& flnm, int endianness)
793{
794 if (endianness == -1)
795 bigEndian = IS_BIG_ENDIAN;
796 else
797 bigEndian = endianness;
798
[241]799 // Output stream creation
800 s = new ofstream(flnm.c_str(),ios::out | IOS_BIN);
801
802 // Header
[576]803 PutRawBytes("SOS-SOPHYA-PPersistFile V1 ",32);
[241]804 PutRawBytes(bigEndian
805 ? "BIG-ENDIAN "
806 : "LITTLE-ENDIAN ",32);
807
808// ---- GMT creation date of the file
809 time_t tm = time(NULL);
810 char datestring[33];
811 int l=strftime(datestring,32,"%d/%m/%Y %T GMT",gmtime(&tm));
812 for(int i=l; i<32; i++) datestring[i] = ' ';
813 datestring[32] = '\0';
814 PutRawBytes(datestring, 32);
[219]815}
816
817POutPersist::~POutPersist()
818{
[241]819 if (tags.size() == 0) {
820 PutRawByte(PPS_EOF);
821 PutRawI8(-1);
822 } else {
823 int_8 tagPos;
824#ifdef STREAMPOS_IS_CLASS
825 tagPos = s->tellp().offset();
826#else
827 tagPos = s->tellp();
828#endif
829 for (map<string,int_8>::iterator i = tags.begin(); i != tags.end(); i++) {
830 string name = (*i).first;
831 int_8 pos = (*i).second;
832 PutRawByte(PPS_TAG); // This is a tag
833 PutRawI8(pos); // position of previous tag
834 PutRawI4(name.length()); // length of the name
835 PutRawBytes(name.c_str(), name.length()); // name, without final "0".
836 }
837 PutRawByte(PPS_EOF);
838 PutRawI8(tagPos);
839 }
840
841 delete s; // Close the stream
[219]842}
843
844
[241]845void
846POutPersist::WriteTag(string const& name)
[219]847{
[241]848 if (name.length() > MAXTAGLEN)
849 throw ParmError("POutPersist::WriteTag tag name too long");
[219]850
[241]851 if (tags.find(name) != tags.end())
852 throw DuplicateIdExc("POutPersist::WriteTag duplicate tag name");
853
854 // Get current file position
855 int_8 tagPos;
856
[219]857 #ifdef STREAMPOS_IS_CLASS
[241]858 tagPos = s->tellp().offset();
[219]859 #else
[241]860 tagPos = s->tellp();
[219]861 #endif
[241]862
863 tags[name] = tagPos;
[588]864 PutRawByte(PPS_TAG_MARK); // This is a tag
865 objList.clear(); // $CHECK$ EA 171199
[219]866}
867
868//++
869// void POutPersist::PutByte(char& c)
870// void POutPersist::PutBytes(void const* ptr, size_t bytes)
871// void POutPersist::PutR4 (r_4 result)
872// void POutPersist::PutR4s (r_4 const* tab, size_t n)
873// void POutPersist::PutR8 (r_8 result)
874// void POutPersist::PutR8s (r_8 const* tab, size_t n)
875// void POutPersist::PutI2 (int_2 result)
876// void POutPersist::PutI2s (int_2 const* tab, size_t n)
877// void POutPersist::PutU2 (uint_2 result)
878// void POutPersist::PutU2s (uint_2 const* tab, size_t n)
879// void POutPersist::PutI4 (int_4 result)
880// void POutPersist::PutI4s (int_4 const* tab, size_t n)
881// void POutPersist::PutU4 (uint_4 result)
882// void POutPersist::PutU4s (uint_4 const* tab, size_t n)
883// void POutPersist::PutI8 (int_8 result)
884// void POutPersist::PutI8s (int_8 const* tab, size_t n)
885// void POutPersist::PutU8 (uint_8 result)
886// void POutPersist::PutU8s (uint_8 const* tab, size_t n)
[241]887// void POutPersist::PutStr (string const&)
[219]888// Ecriture de données portables.. Pour chaque type
889// de données, on peut écrire une valeur, ou un tableau de valeurs.
890// void POutPersist::PutLine(char const* ptr, size_t len)
891// Ecriture d'une ligne de texte dans le fichier PPersist.
892//--
893
894
895
896
897void
[241]898POutPersist::PutRawBytes(void const* ptr, size_t bytes)
899{
900 s->write((char const*)ptr, bytes);
901}
902
903void
904POutPersist::PutRawByte(char c)
905{
906 PutRawBytes(&c, 1);
907}
908
909void
910POutPersist::PutRawI2 (int_2 val)
911{
912 if (bigEndian != IS_BIG_ENDIAN)
913 bswap2(&val);
914
915 PutRawBytes(&val, sizeof(int_2));
916}
917
918void
919POutPersist::PutRawI4 (int_4 val)
920{
921 if (bigEndian != IS_BIG_ENDIAN)
922 bswap4(&val);
923
924 PutRawBytes(&val, sizeof(int_4));
925}
926
927void
928POutPersist::PutRawI8 (int_8 val)
929{
930 if (bigEndian != IS_BIG_ENDIAN)
931 bswap8(&val);
932
933 PutRawBytes(&val, sizeof(int_8));
934}
935
936void
937POutPersist::PutRawU8 (uint_8 val)
938{
939 if (bigEndian != IS_BIG_ENDIAN)
940 bswap8(&val);
941
942 PutRawBytes(&val, sizeof(uint_8));
943}
944
945void
946POutPersist::PutArrayTag(short datasz, size_t sz)
947{
948 if (sz <= 0x7fff) {
949 PutRawByte(PPS_SIMPLE_ARRAY + datasz);
950 PutRawI2(sz);
951 } else if (sz <= 0x7fffffff) {
952 PutRawByte(PPS_SIMPLE_ARRAY4 + datasz);
953 PutRawI4(sz);
954 } else {
955 PutRawByte(PPS_SIMPLE_ARRAY8 + datasz);
956 PutRawU8(sz);
957 }
958}
959
960void
[219]961POutPersist::PutByte(char c)
962{
[241]963 PutRawByte(PPS_SIMPLE + 1);
964 PutRawBytes(&c, 1);
[219]965}
966
[241]967
968
[219]969void
970POutPersist::PutBytes(void const* ptr, size_t bytes)
971{
[241]972 PutArrayTag(1, bytes);
973 PutRawBytes(ptr, bytes);
[219]974}
975
976void
977POutPersist::PutR4 (r_4 val)
978{
[241]979 PutRawByte(PPS_SIMPLE + 4);
980
[219]981 if (bigEndian != IS_BIG_ENDIAN)
982 bswap4(&val);
983
[241]984 PutRawBytes(&val, sizeof(r_4));
[219]985}
986
987void
988POutPersist::PutR4s (r_4 const* tab, size_t n)
989{
[241]990 PutArrayTag(4, n);
991
992 if (bigEndian == IS_BIG_ENDIAN) {
993 PutRawBytes(tab, n*sizeof(r_4));
994 } else {
995 for (unsigned int i=0; i<n; i++) {
996 r_4 val = tab[i];
997 bswap4(&val);
998 PutRawBytes(&val, sizeof(r_4));
999 }
1000 }
[219]1001}
1002
1003void
1004POutPersist::PutR8 (r_8 val)
1005{
[241]1006 PutRawByte(PPS_SIMPLE + 8);
1007
[219]1008 if (bigEndian != IS_BIG_ENDIAN)
1009 bswap8(&val);
1010
[241]1011 PutRawBytes(&val, sizeof(r_8));
[219]1012}
1013
1014void
1015POutPersist::PutR8s (r_8 const* tab, size_t n)
1016{
[241]1017 PutArrayTag(8, n);
1018
1019 if (bigEndian == IS_BIG_ENDIAN) {
1020 PutRawBytes(tab, n*sizeof(r_8));
1021 } else {
1022 for (unsigned int i=0; i<n; i++) {
1023 r_8 val = tab[i];
1024 bswap8(&val);
1025 PutRawBytes(&val, sizeof(r_8));
1026 }
1027 }
[219]1028}
1029
1030void
1031POutPersist::PutI2 (int_2 val)
1032{
[241]1033 PutRawByte(PPS_SIMPLE + 2);
1034
[219]1035 if (bigEndian != IS_BIG_ENDIAN)
1036 bswap2(&val);
1037
[241]1038 PutRawBytes(&val, sizeof(int_2));
[219]1039}
1040
1041void
1042POutPersist::PutI2s (int_2 const* tab, size_t n)
1043{
[241]1044 PutArrayTag(2, n);
1045
1046 if (bigEndian == IS_BIG_ENDIAN) {
1047 PutRawBytes(tab, n*sizeof(int_2));
1048 } else {
1049 for (unsigned int i=0; i<n; i++) {
1050 int_2 val = tab[i];
1051 bswap2(&val);
1052 PutRawBytes(&val, sizeof(int_2));
1053 }
1054 }
[219]1055}
1056
1057void
1058POutPersist::PutU2 (uint_2 val)
1059{
[241]1060 PutRawByte(PPS_SIMPLE + 2);
1061
[219]1062 if (bigEndian != IS_BIG_ENDIAN)
1063 bswap2(&val);
1064
[241]1065 PutRawBytes(&val, sizeof(uint_2));
[219]1066}
1067
1068void
1069POutPersist::PutU2s (uint_2 const* tab, size_t n)
1070{
[241]1071 PutArrayTag(2, n);
1072
1073 if (bigEndian == IS_BIG_ENDIAN) {
1074 PutRawBytes(tab, n*sizeof(uint_2));
1075 } else {
1076 for (unsigned int i=0; i<n; i++) {
1077 uint_2 val = tab[i];
1078 bswap2(&val);
1079 PutRawBytes(&val, sizeof(uint_2));
1080 }
1081 }
[219]1082}
1083
1084void
1085POutPersist::PutI4 (int_4 val)
1086{
[241]1087 PutRawByte(PPS_SIMPLE + 4);
1088
[219]1089 if (bigEndian != IS_BIG_ENDIAN)
1090 bswap4(&val);
1091
[241]1092 PutRawBytes(&val, sizeof(int_4));
[219]1093}
1094
1095void
1096POutPersist::PutI4s (int_4 const* tab, size_t n)
1097{
[241]1098 PutArrayTag(4, n);
1099
1100 if (bigEndian == IS_BIG_ENDIAN) {
1101 PutRawBytes(tab, n*sizeof(int_4));
1102 } else {
1103 for (unsigned int i=0; i<n; i++) {
1104 int_4 val = tab[i];
1105 bswap4(&val);
1106 PutRawBytes(&val, sizeof(int_4));
1107 }
1108 }
[219]1109}
1110
1111void
1112POutPersist::PutU4 (uint_4 val)
1113{
[241]1114 PutRawByte(PPS_SIMPLE + 4);
1115
[219]1116 if (bigEndian != IS_BIG_ENDIAN)
1117 bswap4(&val);
1118
[241]1119 PutRawBytes(&val, sizeof(uint_4));
[219]1120}
1121
1122void
1123POutPersist::PutU4s (uint_4 const* tab, size_t n)
1124{
[241]1125 PutArrayTag(4, n);
1126
1127 if (bigEndian == IS_BIG_ENDIAN) {
1128 PutRawBytes(tab, n*sizeof(uint_4));
1129 } else {
1130 for (unsigned int i=0; i<n; i++) {
1131 uint_4 val = tab[i];
1132 bswap4(&val);
1133 PutRawBytes(&val, sizeof(uint_4));
1134 }
1135 }
[219]1136}
1137
1138void
1139POutPersist::PutI8 (int_8 val)
1140{
[241]1141 PutRawByte(PPS_SIMPLE + 8);
1142
[219]1143 if (bigEndian != IS_BIG_ENDIAN)
1144 bswap8(&val);
1145
[241]1146 PutRawBytes(&val, sizeof(int_8));
[219]1147}
1148
1149void
1150POutPersist::PutI8s (int_8 const* tab, size_t n)
1151{
[241]1152 PutArrayTag(8, n);
1153
1154 if (bigEndian == IS_BIG_ENDIAN) {
1155 PutRawBytes(tab, n*sizeof(int_8));
1156 } else {
1157 for (unsigned int i=0; i<n; i++) {
1158 int_8 val = tab[i];
1159 bswap8(&val);
1160 PutRawBytes(&val, sizeof(int_8));
1161 }
1162 }
[219]1163}
1164
1165void
1166POutPersist::PutU8 (uint_8 val)
1167{
[241]1168 PutRawByte(PPS_SIMPLE + 8);
1169
[219]1170 if (bigEndian != IS_BIG_ENDIAN)
1171 bswap8(&val);
1172
[241]1173 PutRawBytes(&val, sizeof(uint_8));
[219]1174}
1175
1176void
1177POutPersist::PutU8s (uint_8 const* tab, size_t n)
1178{
[241]1179 PutArrayTag(8, n);
1180
1181 if (bigEndian == IS_BIG_ENDIAN) {
1182 PutRawBytes(tab, n*sizeof(uint_8));
1183 } else {
1184 for (unsigned int i=0; i<n; i++) {
1185 uint_8 val = tab[i];
1186 bswap8(&val);
1187 PutRawBytes(&val, sizeof(uint_8));
1188 }
1189 }
[219]1190}
1191
1192void
[241]1193POutPersist::PutStr(string const& str)
1194{
1195 PutRawByte(PPS_STRING);
1196 PutRawI2(str.length());
1197 PutRawBytes(str.c_str(), str.length());
1198}
1199
1200void
[219]1201POutPersist::PutLine(char const* ptr, size_t len)
1202{
[241]1203 PutRawByte(PPS_LINE);
1204
[219]1205 if (len == 0) len = strlen(ptr);
[241]1206 PutRawBytes(ptr, len);
1207 PutRawByte('\n');
[219]1208}
1209
[241]1210void
1211POutPersist::PutObject(PPersist const* obj)
1212{
1213 if (serializeNullAndRepeat(obj)) return;
[219]1214
[241]1215 PutRawByte(PPS_OBJECT);
[588]1216 PutRawU8(getTypeId(typeid(*obj).name()));
1217 //PutRawU8(PIOPersist::Hash(typeid(*obj).name()));
[241]1218 assignObjectId(obj);
1219 obj->WriteSelf(*this);
1220}
[219]1221
[241]1222bool
1223POutPersist::serializeNullAndRepeat(PPersist const* x)
[219]1224{
[241]1225 if (x == NULL) {
1226 PutRawByte(PPS_NULL);
1227 return true;
1228 }
[219]1229
[241]1230 int_4 id = findObjectId(x);
1231 if (id >= 0) {
1232 PutRawByte(PPS_REFERENCE);
1233 PutRawI4(id);
1234 return true;
1235 }
[219]1236
[241]1237 return false;
[219]1238}
1239
[241]1240int_4
1241POutPersist::assignObjectId(PPersist const* x)
[219]1242{
[241]1243 int_4 id = objList.size();
1244 objList[x] = id;
1245 return id;
[219]1246}
1247
[241]1248int_4
1249POutPersist::findObjectId(PPersist const* x)
[219]1250{
[241]1251 ObjList::iterator i = objList.find(x);
1252 if (i == objList.end()) return -1;
1253 return (*i).second;
[219]1254}
1255
[241]1256
Note: See TracBrowser for help on using the repository browser.