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

Last change on this file since 597 was 588, checked in by ansari, 26 years ago

Gestion typeid/typename. Gestion simultanee tag+reference

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