1 //------------------------------------------------------------------------------
2 // emRec.cpp - Recordable data structures
3 //
4 // Copyright (C) 2005-2010,2012,2014,2016,2018-2020 Oliver Hamann.
5 //
6 // Homepage: http://eaglemode.sourceforge.net/
7 //
8 // This program is free software: you can redistribute it and/or modify it under
9 // the terms of the GNU General Public License version 3 as published by the
10 // Free Software Foundation.
11 //
12 // This program is distributed in the hope that it will be useful, but WITHOUT
13 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 // FOR A PARTICULAR PURPOSE. See the GNU General Public License version 3 for
15 // more details.
16 //
17 // You should have received a copy of the GNU General Public License version 3
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //------------------------------------------------------------------------------
20
21 #include <emCore/emRec.h>
22
23
24 //==============================================================================
25 //================================= emRecNode ==================================
26 //==============================================================================
27
~emRecNode()28 emRecNode::~emRecNode()
29 {
30 }
31
32
33 //==============================================================================
34 //=================================== emRec ====================================
35 //==============================================================================
36
emRec(emStructRec * parent,const char * varIdentifier)37 emRec::emRec(emStructRec * parent, const char * varIdentifier)
38 {
39 UpperNode=NULL;
40 if (parent) parent->AddMember(this,varIdentifier);
41 }
42
43
~emRec()44 emRec::~emRec()
45 {
46 while (UpperNode && UpperNode->IsListener()) {
47 ((emRecListener*)UpperNode)->SetListenedRec(NULL);
48 }
49 }
50
51
GetParent()52 emRec * emRec::GetParent()
53 {
54 emRecNode * n;
55
56 for (n=UpperNode; n && n->IsListener(); n=n->UpperNode);
57 return (emRec*)n;
58 }
59
60
GetParent() const61 const emRec * emRec::GetParent() const
62 {
63 const emRecNode * n;
64
65 for (n=UpperNode; n && n->IsListener(); n=n->UpperNode);
66 return (const emRec*)n;
67 }
68
69
GetRoot()70 emRec * emRec::GetRoot()
71 {
72 emRecNode * n;
73 emRec * root;
74
75 root=this;
76 for (n=UpperNode; n; n=n->UpperNode) {
77 if (!n->IsListener()) root=(emRec*)n;
78 }
79 return root;
80 }
81
82
GetRoot() const83 const emRec * emRec::GetRoot() const
84 {
85 const emRecNode * n;
86 const emRec * root;
87
88 root=this;
89 for (n=UpperNode; n; n=n->UpperNode) {
90 if (!n->IsListener()) root=(const emRec*)n;
91 }
92 return root;
93 }
94
95
GetFormatName() const96 const char * emRec::GetFormatName() const
97 {
98 return NULL;
99 }
100
101
TryLoad(const emString & filePath)102 void emRec::TryLoad(const emString & filePath)
103 {
104 emRecFileReader reader;
105
106 reader.TryStartReading(*this,filePath);
107 reader.TryFinishReading();
108 }
109
110
TrySave(const emString & filePath)111 void emRec::TrySave(const emString & filePath)
112 {
113 emRecFileWriter writer;
114
115 writer.TryStartWriting(*this,filePath);
116 writer.TryFinishWriting();
117 }
118
119
TryLoadFromMem(const char * buf,int len)120 void emRec::TryLoadFromMem(const char * buf, int len)
121 {
122 emRecMemReader reader;
123
124 reader.TryStartReading(*this,buf,len);
125 reader.TryFinishReading();
126 }
127
128
TryLoadFromMem(const emArray<char> & buf)129 void emRec::TryLoadFromMem(const emArray<char> & buf)
130 {
131 TryLoadFromMem(buf.Get(),buf.GetCount());
132 }
133
134
SaveToMem(emArray<char> & buf)135 void emRec::SaveToMem(emArray<char> & buf)
136 {
137 emRecMemWriter writer;
138
139 try {
140 writer.TryStartWriting(*this,buf);
141 writer.TryFinishWriting();
142 }
143 catch (const emException & exception) {
144 emFatalError(
145 "Unexpected error from emRecMemWriter: %s",
146 exception.GetText().Get()
147 );
148 }
149 }
150
151
TryCopy(emRec & source)152 void emRec::TryCopy(emRec & source)
153 {
154 emArray<char> buf;
155
156 buf.SetTuningLevel(4);
157 source.SaveToMem(buf);
158 TryLoadFromMem(buf);
159 }
160
161
Copy(emRec & source)162 void emRec::Copy(emRec & source)
163 {
164 try {
165 TryCopy(source);
166 }
167 catch (const emException & exception) {
168 emFatalError("%s",exception.GetText().Get());
169 }
170 }
171
172
CheckIdentifier(const char * identifier)173 void emRec::CheckIdentifier(const char * identifier)
174 {
175 int i;
176
177 if (
178 (identifier[0]>='a' && identifier[0]<='z') ||
179 (identifier[0]>='A' && identifier[0]<='Z') ||
180 identifier[0]=='_'
181 ) {
182 i=0;
183 do {
184 i++;
185 if (identifier[i]==0) return;
186 } while (
187 (identifier[i]>='a' && identifier[i]<='z') ||
188 (identifier[i]>='A' && identifier[i]<='Z') ||
189 (identifier[i]>='0' && identifier[i]<='9') ||
190 identifier[i]=='_'
191 );
192 }
193 emFatalError("emRec: '%s' is not a valid identifier.",identifier);
194 }
195
196
BeTheParentOf(emRec * child)197 void emRec::BeTheParentOf(emRec * child)
198 {
199 emRecNode * * pn;
200 emRecNode * n;
201
202 n=child;
203 do {
204 pn=&n->UpperNode;
205 n=*pn;
206 } while (n && n->IsListener());
207 *pn=this;
208 }
209
210
IsListener() const211 bool emRec::IsListener() const
212 {
213 return false;
214 }
215
216
ChildChanged()217 void emRec::ChildChanged()
218 {
219 if (!UpperNode) return;
220 UpperNode->ChildChanged();
221 }
222
223
224 //==============================================================================
225 //=============================== emRecListener ================================
226 //==============================================================================
227
emRecListener(emRec * rec)228 emRecListener::emRecListener(emRec * rec)
229 {
230 UpperNode=NULL;
231 Rec=NULL;
232 SetListenedRec(rec);
233 }
234
235
~emRecListener()236 emRecListener::~emRecListener()
237 {
238 SetListenedRec(NULL);
239 }
240
241
SetListenedRec(emRec * rec)242 void emRecListener::SetListenedRec(emRec * rec)
243 {
244 emRecNode * * pn;
245 emRecNode * n;
246
247 if (Rec!=rec) {
248 if (Rec) {
249 n=Rec;
250 do {
251 pn=&n->UpperNode;
252 n=*pn;
253 } while (n!=this);
254 *pn=UpperNode;
255 UpperNode=NULL;
256 }
257 Rec=rec;
258 if (Rec) {
259 n=Rec;
260 do {
261 pn=&n->UpperNode;
262 n=*pn;
263 } while (n && n->IsListener());
264 UpperNode=n;
265 *pn=this;
266 }
267 }
268 }
269
270
IsListener() const271 bool emRecListener::IsListener() const
272 {
273 return true;
274 }
275
276
ChildChanged()277 void emRecListener::ChildChanged()
278 {
279 OnRecChanged();
280 if (!UpperNode) return;
281 UpperNode->ChildChanged();
282 }
283
284
285 //==============================================================================
286 //================================= emBoolRec ==================================
287 //==============================================================================
288
emBoolRec(bool defaultValue)289 emBoolRec::emBoolRec(bool defaultValue)
290 {
291 DefaultValue=defaultValue;
292 Value=DefaultValue;
293 }
294
295
emBoolRec(emStructRec * parent,const char * varIdentifier,bool defaultValue)296 emBoolRec::emBoolRec(
297 emStructRec * parent, const char * varIdentifier, bool defaultValue
298 )
299 : emRec(parent,varIdentifier)
300 {
301 DefaultValue=defaultValue;
302 Value=defaultValue;
303 }
304
305
Set(bool value)306 void emBoolRec::Set(bool value)
307 {
308 if (Value!=value) {
309 Value=value;
310 Changed();
311 }
312 }
313
314
Invert()315 void emBoolRec::Invert()
316 {
317 Value=!Value;
318 Changed();
319 }
320
321
SetToDefault()322 void emBoolRec::SetToDefault()
323 {
324 Set(DefaultValue);
325 }
326
327
IsSetToDefault() const328 bool emBoolRec::IsSetToDefault() const
329 {
330 return Value==DefaultValue;
331 }
332
333
TryStartReading(emRecReader & reader)334 void emBoolRec::TryStartReading(emRecReader & reader)
335 {
336 const char * idf;
337 int i;
338
339 if (reader.TryPeekNext()==emRecReader::ET_INT) {
340 i=reader.TryReadInt();
341 if (i==1) Set(true);
342 else if (i==0) Set(false);
343 else reader.ThrowSyntaxError();
344 }
345 else {
346 idf=reader.TryReadIdentifier();
347 if (strcasecmp(idf,"yes" )==0) Set(true);
348 else if (strcasecmp(idf,"no" )==0) Set(false);
349 else if (strcasecmp(idf,"y" )==0) Set(true);
350 else if (strcasecmp(idf,"n" )==0) Set(false);
351 else if (strcasecmp(idf,"true" )==0) Set(true);
352 else if (strcasecmp(idf,"false")==0) Set(false);
353 else reader.ThrowSyntaxError();
354 }
355 }
356
357
TryContinueReading(emRecReader & reader)358 bool emBoolRec::TryContinueReading(emRecReader & reader)
359 {
360 return true;
361 }
362
363
QuitReading()364 void emBoolRec::QuitReading()
365 {
366 }
367
368
TryStartWriting(emRecWriter & writer)369 void emBoolRec::TryStartWriting(emRecWriter & writer)
370 {
371 writer.TryWriteIdentifier(Value ? "yes" : "no");
372 }
373
374
TryContinueWriting(emRecWriter & writer)375 bool emBoolRec::TryContinueWriting(emRecWriter & writer)
376 {
377 return true;
378 }
379
380
QuitWriting()381 void emBoolRec::QuitWriting()
382 {
383 }
384
385
CalcRecMemNeed() const386 emUInt64 emBoolRec::CalcRecMemNeed() const
387 {
388 return sizeof(emBoolRec);
389 }
390
391
392 //==============================================================================
393 //================================== emIntRec ==================================
394 //==============================================================================
395
emIntRec(int defaultValue,int minValue,int maxValue)396 emIntRec::emIntRec(int defaultValue, int minValue, int maxValue)
397 {
398 if (maxValue<minValue) maxValue=minValue;
399 if (defaultValue<minValue) defaultValue=minValue;
400 if (defaultValue>maxValue) defaultValue=maxValue;
401 DefaultValue=defaultValue;
402 MinValue=minValue;
403 MaxValue=maxValue;
404 Value=defaultValue;
405 }
406
407
emIntRec(emStructRec * parent,const char * varIdentifier,int defaultValue,int minValue,int maxValue)408 emIntRec::emIntRec(
409 emStructRec * parent, const char * varIdentifier, int defaultValue,
410 int minValue, int maxValue
411 )
412 : emRec(parent,varIdentifier)
413 {
414 if (maxValue<minValue) maxValue=minValue;
415 if (defaultValue<minValue) defaultValue=minValue;
416 if (defaultValue>maxValue) defaultValue=maxValue;
417 DefaultValue=defaultValue;
418 MinValue=minValue;
419 MaxValue=maxValue;
420 Value=defaultValue;
421 }
422
423
Set(int value)424 void emIntRec::Set(int value)
425 {
426 if (value<MinValue) value=MinValue;
427 if (value>MaxValue) value=MaxValue;
428 if (Value!=value) {
429 Value=value;
430 Changed();
431 }
432 }
433
434
SetToDefault()435 void emIntRec::SetToDefault()
436 {
437 Set(DefaultValue);
438 }
439
440
IsSetToDefault() const441 bool emIntRec::IsSetToDefault() const
442 {
443 return Value==DefaultValue;
444 }
445
446
TryStartReading(emRecReader & reader)447 void emIntRec::TryStartReading(emRecReader & reader)
448 {
449 int i;
450
451 i=reader.TryReadInt();
452 if (i<MinValue) reader.ThrowElemError("Number too small.");
453 if (i>MaxValue) reader.ThrowElemError("Number too large.");
454 Set(i);
455 }
456
457
TryContinueReading(emRecReader & reader)458 bool emIntRec::TryContinueReading(emRecReader & reader)
459 {
460 return true;
461 }
462
463
QuitReading()464 void emIntRec::QuitReading()
465 {
466 }
467
468
TryStartWriting(emRecWriter & writer)469 void emIntRec::TryStartWriting(emRecWriter & writer)
470 {
471 writer.TryWriteInt(Value);
472 }
473
474
TryContinueWriting(emRecWriter & writer)475 bool emIntRec::TryContinueWriting(emRecWriter & writer)
476 {
477 return true;
478 }
479
480
QuitWriting()481 void emIntRec::QuitWriting()
482 {
483 }
484
485
CalcRecMemNeed() const486 emUInt64 emIntRec::CalcRecMemNeed() const
487 {
488 return sizeof(emIntRec);
489 }
490
491
492 //==============================================================================
493 //================================ emDoubleRec =================================
494 //==============================================================================
495
emDoubleRec(double defaultValue,double minValue,double maxValue)496 emDoubleRec::emDoubleRec(double defaultValue, double minValue, double maxValue)
497 {
498 if (maxValue<minValue) maxValue=minValue;
499 if (defaultValue<minValue) defaultValue=minValue;
500 if (defaultValue>maxValue) defaultValue=maxValue;
501 DefaultValue=defaultValue;
502 MinValue=minValue;
503 MaxValue=maxValue;
504 Value=defaultValue;
505 }
506
507
emDoubleRec(emStructRec * parent,const char * varIdentifier,double defaultValue,double minValue,double maxValue)508 emDoubleRec::emDoubleRec(
509 emStructRec * parent, const char * varIdentifier, double defaultValue,
510 double minValue, double maxValue
511 )
512 : emRec(parent,varIdentifier)
513 {
514 if (maxValue<minValue) maxValue=minValue;
515 if (defaultValue<minValue) defaultValue=minValue;
516 if (defaultValue>maxValue) defaultValue=maxValue;
517 DefaultValue=defaultValue;
518 MinValue=minValue;
519 MaxValue=maxValue;
520 Value=defaultValue;
521 }
522
523
~emDoubleRec()524 emDoubleRec::~emDoubleRec()
525 {
526 }
527
528
Set(double value)529 void emDoubleRec::Set(double value)
530 {
531 if (value<MinValue) value=MinValue;
532 if (value>MaxValue) value=MaxValue;
533 if (Value!=value) {
534 Value=value;
535 Changed();
536 }
537 }
538
539
SetToDefault()540 void emDoubleRec::SetToDefault()
541 {
542 Set(DefaultValue);
543 }
544
545
IsSetToDefault() const546 bool emDoubleRec::IsSetToDefault() const
547 {
548 return Value==DefaultValue;
549 }
550
551
TryStartReading(emRecReader & reader)552 void emDoubleRec::TryStartReading(emRecReader & reader)
553 {
554 double d;
555
556 d=reader.TryReadDouble();
557 if (d<MinValue) reader.ThrowElemError("Number too small.");
558 if (d>MaxValue) reader.ThrowElemError("Number too large.");
559 Set(d);
560 }
561
562
TryContinueReading(emRecReader & reader)563 bool emDoubleRec::TryContinueReading(emRecReader & reader)
564 {
565 return true;
566 }
567
568
QuitReading()569 void emDoubleRec::QuitReading()
570 {
571 }
572
573
TryStartWriting(emRecWriter & writer)574 void emDoubleRec::TryStartWriting(emRecWriter & writer)
575 {
576 writer.TryWriteDouble(Value);
577 }
578
579
TryContinueWriting(emRecWriter & writer)580 bool emDoubleRec::TryContinueWriting(emRecWriter & writer)
581 {
582 return true;
583 }
584
585
QuitWriting()586 void emDoubleRec::QuitWriting()
587 {
588 }
589
590
CalcRecMemNeed() const591 emUInt64 emDoubleRec::CalcRecMemNeed() const
592 {
593 return sizeof(emDoubleRec);
594 }
595
596
597 //==============================================================================
598 //================================= emEnumRec ==================================
599 //==============================================================================
600
emEnumRec(int defaultValue,const char * identifier0,...)601 emEnumRec::emEnumRec(int defaultValue, const char * identifier0, ...)
602 {
603 va_list args;
604
605 va_start(args,identifier0);
606 Init(defaultValue,identifier0,args);
607 va_end(args);
608 }
609
610
emEnumRec(emStructRec * parent,const char * varIdentifier,int defaultValue,const char * identifier0,...)611 emEnumRec::emEnumRec(
612 emStructRec * parent, const char * varIdentifier, int defaultValue,
613 const char * identifier0, ...
614 )
615 : emRec(parent,varIdentifier)
616 {
617 va_list args;
618
619 va_start(args,identifier0);
620 Init(defaultValue,identifier0,args);
621 va_end(args);
622 }
623
624
~emEnumRec()625 emEnumRec::~emEnumRec()
626 {
627 free(Identifiers);
628 }
629
630
Set(int value)631 void emEnumRec::Set(int value)
632 {
633 if (value<0) value=0;
634 if (value>=IdentifierCount) value=IdentifierCount-1;
635 if (Value!=value) {
636 Value=value;
637 Changed();
638 }
639 }
640
641
GetIdentifierOf(int value) const642 const char * emEnumRec::GetIdentifierOf(int value) const
643 {
644 if (value<0) return NULL;
645 if (value>=IdentifierCount) return NULL;
646 return Identifiers[value];
647 }
648
649
GetValueOf(const char * identifier) const650 int emEnumRec::GetValueOf(const char * identifier) const
651 {
652 int val;
653
654 for (val=IdentifierCount-1; val>=0; val--) {
655 if (strcasecmp(identifier,Identifiers[val])==0) break;
656 }
657 return val;
658 }
659
660
SetToDefault()661 void emEnumRec::SetToDefault()
662 {
663 Set(DefaultValue);
664 }
665
666
IsSetToDefault() const667 bool emEnumRec::IsSetToDefault() const
668 {
669 return Value==DefaultValue;
670 }
671
672
TryStartReading(emRecReader & reader)673 void emEnumRec::TryStartReading(emRecReader & reader)
674 {
675 const char * idf;
676 int val;
677
678 if (reader.TryPeekNext()==emRecReader::ET_INT) {
679 val=reader.TryReadInt();
680 if (val<0 || val>=IdentifierCount) {
681 reader.ThrowElemError("Value out of range.");
682 }
683 }
684 else {
685 idf=reader.TryReadIdentifier();
686 val=GetValueOf(idf);
687 if (val<0) reader.ThrowElemError("Unknown identifier.");
688 }
689 Set(val);
690 }
691
692
TryContinueReading(emRecReader & reader)693 bool emEnumRec::TryContinueReading(emRecReader & reader)
694 {
695 return true;
696 }
697
698
QuitReading()699 void emEnumRec::QuitReading()
700 {
701 }
702
703
TryStartWriting(emRecWriter & writer)704 void emEnumRec::TryStartWriting(emRecWriter & writer)
705 {
706 writer.TryWriteIdentifier(Identifiers[Value]);
707 }
708
709
TryContinueWriting(emRecWriter & writer)710 bool emEnumRec::TryContinueWriting(emRecWriter & writer)
711 {
712 return true;
713 }
714
715
QuitWriting()716 void emEnumRec::QuitWriting()
717 {
718 }
719
720
CalcRecMemNeed() const721 emUInt64 emEnumRec::CalcRecMemNeed() const
722 {
723 return sizeof(emEnumRec) + IdentifierCount*sizeof(const char *);
724 }
725
726
Init(int defaultValue,const char * identifier0,va_list args)727 void emEnumRec::Init(int defaultValue, const char * identifier0, va_list args)
728 {
729 const char * idf[512];
730 int cnt;
731
732 idf[0]=identifier0;
733 for (cnt=1; ; cnt++) {
734 if (cnt>=(int)(sizeof(idf)/sizeof(const char *))) {
735 emFatalError("emEnumRec: Too many identifiers.");
736 }
737 idf[cnt]=va_arg(args,const char *);
738 if (!idf[cnt]) break;
739 CheckIdentifier(idf[cnt]);
740 }
741 Identifiers=(const char * *)malloc(sizeof(const char*)*cnt);
742 memcpy(Identifiers,idf,sizeof(const char *)*cnt);
743 IdentifierCount=cnt;
744 if (defaultValue<0) defaultValue=0;
745 if (defaultValue>=IdentifierCount) defaultValue=IdentifierCount-1;
746 DefaultValue=defaultValue;
747 Value=DefaultValue;
748 }
749
750
751 //==============================================================================
752 //================================= emFlagsRec =================================
753 //==============================================================================
754
emFlagsRec(int defaultValue,const char * identifier0,...)755 emFlagsRec::emFlagsRec(int defaultValue, const char * identifier0, ...)
756 {
757 va_list args;
758
759 va_start(args,identifier0);
760 Init(defaultValue,identifier0,args);
761 va_end(args);
762 }
763
764
emFlagsRec(emStructRec * parent,const char * varIdentifier,int defaultValue,const char * identifier0,...)765 emFlagsRec::emFlagsRec(
766 emStructRec * parent, const char * varIdentifier, int defaultValue,
767 const char * identifier0, ...
768 )
769 : emRec(parent,varIdentifier)
770 {
771 va_list args;
772
773 va_start(args,identifier0);
774 Init(defaultValue,identifier0,args);
775 va_end(args);
776 }
777
778
~emFlagsRec()779 emFlagsRec::~emFlagsRec()
780 {
781 free(Identifiers);
782 }
783
784
Set(int value)785 void emFlagsRec::Set(int value)
786 {
787 value&=(1<<IdentifierCount)-1;
788 if (Value!=value) {
789 Value=value;
790 Changed();
791 }
792 }
793
794
GetIdentifierOf(int bit) const795 const char * emFlagsRec::GetIdentifierOf(int bit) const
796 {
797 if (bit<0 || bit>=IdentifierCount) return NULL;
798 return Identifiers[bit];
799 }
800
801
GetBitOf(const char * identifier) const802 int emFlagsRec::GetBitOf(const char * identifier) const
803 {
804 int bit;
805
806 for (bit=IdentifierCount-1; bit>=0; bit--) {
807 if (strcasecmp(identifier,Identifiers[bit])==0) break;
808 }
809 return bit;
810 }
811
812
SetToDefault()813 void emFlagsRec::SetToDefault()
814 {
815 Set(DefaultValue);
816 }
817
818
IsSetToDefault() const819 bool emFlagsRec::IsSetToDefault() const
820 {
821 return Value==DefaultValue;
822 }
823
824
TryStartReading(emRecReader & reader)825 void emFlagsRec::TryStartReading(emRecReader & reader)
826 {
827 const char * idf;
828 int val, bit;
829
830 if (reader.TryPeekNext()==emRecReader::ET_INT) {
831 val=reader.TryReadInt();
832 if (val&~((1<<IdentifierCount)-1)) {
833 reader.ThrowElemError("Value out of range.");
834 }
835 }
836 else {
837 reader.TryReadCertainDelimiter('{');
838 val=0;
839 while (reader.TryPeekNext()==emRecReader::ET_IDENTIFIER) {
840 idf=reader.TryReadIdentifier();
841 bit=GetBitOf(idf);
842 if (bit<0) reader.ThrowElemError("Unknown identifier.");
843 val|=1<<bit;
844 }
845 reader.TryReadCertainDelimiter('}');
846 }
847 Set(val);
848 }
849
850
TryContinueReading(emRecReader & reader)851 bool emFlagsRec::TryContinueReading(emRecReader & reader)
852 {
853 return true;
854 }
855
856
QuitReading()857 void emFlagsRec::QuitReading()
858 {
859 }
860
861
TryStartWriting(emRecWriter & writer)862 void emFlagsRec::TryStartWriting(emRecWriter & writer)
863 {
864 bool addSpaceBeforeNext;
865 int bit;
866
867 writer.TryWriteDelimiter('{');
868 addSpaceBeforeNext=false;
869 for (bit=0; bit<IdentifierCount; bit++) {
870 if (Value&(1<<bit)) {
871 if (addSpaceBeforeNext) writer.TryWriteSpace();
872 writer.TryWriteIdentifier(Identifiers[bit]);
873 addSpaceBeforeNext=true;
874 }
875 }
876 writer.TryWriteDelimiter('}');
877 }
878
879
TryContinueWriting(emRecWriter & writer)880 bool emFlagsRec::TryContinueWriting(emRecWriter & writer)
881 {
882 return true;
883 }
884
885
QuitWriting()886 void emFlagsRec::QuitWriting()
887 {
888 }
889
890
CalcRecMemNeed() const891 emUInt64 emFlagsRec::CalcRecMemNeed() const
892 {
893 return sizeof(emFlagsRec) + IdentifierCount*sizeof(const char *);
894 }
895
896
Init(int defaultValue,const char * identifier0,va_list args)897 void emFlagsRec::Init(int defaultValue, const char * identifier0, va_list args)
898 {
899 const char * idf[32];
900 const char * p;
901 int cnt;
902
903 idf[0]=identifier0;
904 for (cnt=1; ; cnt++) {
905 p=va_arg(args,const char *);
906 if (!p) break;
907 if (cnt>=32) emFatalError("emFlagsRec: Too many identifiers.");
908 CheckIdentifier(p);
909 idf[cnt]=p;
910 }
911 Identifiers=(const char * *)malloc(sizeof(const char*)*cnt);
912 memcpy(Identifiers,idf,sizeof(const char *)*cnt);
913 IdentifierCount=cnt;
914 defaultValue&=(1<<IdentifierCount)-1;
915 DefaultValue=defaultValue;
916 Value=DefaultValue;
917 }
918
919
920 //==============================================================================
921 //=============================== emAlignmentRec ===============================
922 //==============================================================================
923
emAlignmentRec(emAlignment defaultValue)924 emAlignmentRec::emAlignmentRec(emAlignment defaultValue)
925 {
926 DefaultValue=defaultValue;
927 Value=defaultValue;
928 }
929
930
emAlignmentRec(emStructRec * parent,const char * varIdentifier,emAlignment defaultValue)931 emAlignmentRec::emAlignmentRec(
932 emStructRec * parent, const char * varIdentifier, emAlignment defaultValue
933 )
934 : emRec(parent,varIdentifier)
935 {
936 DefaultValue=defaultValue;
937 Value=defaultValue;
938 }
939
940
~emAlignmentRec()941 emAlignmentRec::~emAlignmentRec()
942 {
943 }
944
945
Set(emAlignment value)946 void emAlignmentRec::Set(emAlignment value)
947 {
948 if (Value!=value) {
949 Value=value;
950 Changed();
951 }
952 }
953
954
SetToDefault()955 void emAlignmentRec::SetToDefault()
956 {
957 Set(DefaultValue);
958 }
959
960
IsSetToDefault() const961 bool emAlignmentRec::IsSetToDefault() const
962 {
963 return Value==DefaultValue;
964 }
965
966
TryStartReading(emRecReader & reader)967 void emAlignmentRec::TryStartReading(emRecReader & reader)
968 {
969 const char * idf;
970 char delimiter;
971 emAlignment val;
972
973 val=0;
974 for (;;) {
975 idf=reader.TryReadIdentifier();
976 if (strcasecmp(idf,"top" )==0) val|=EM_ALIGN_TOP;
977 else if (strcasecmp(idf,"bottom")==0) val|=EM_ALIGN_BOTTOM;
978 else if (strcasecmp(idf,"left" )==0) val|=EM_ALIGN_LEFT;
979 else if (strcasecmp(idf,"right" )==0) val|=EM_ALIGN_RIGHT;
980 else if (strcasecmp(idf,"center")==0) val|=EM_ALIGN_CENTER;
981 else reader.ThrowElemError("Unknown alignment identifier.");
982 if (reader.TryPeekNext(&delimiter)!=emRecReader::ET_DELIMITER) break;
983 if (delimiter!='-') break;
984 reader.TryReadCertainDelimiter('-');
985 }
986 Set(val);
987 }
988
989
TryContinueReading(emRecReader & reader)990 bool emAlignmentRec::TryContinueReading(emRecReader & reader)
991 {
992 return true;
993 }
994
995
QuitReading()996 void emAlignmentRec::QuitReading()
997 {
998 }
999
1000
TryStartWriting(emRecWriter & writer)1001 void emAlignmentRec::TryStartWriting(emRecWriter & writer)
1002 {
1003 bool someWritten;
1004
1005 someWritten = false;
1006 if (Value&EM_ALIGN_TOP) {
1007 writer.TryWriteIdentifier("top");
1008 someWritten=true;
1009 }
1010 if (Value&EM_ALIGN_BOTTOM) {
1011 if (someWritten) writer.TryWriteDelimiter('-');
1012 writer.TryWriteIdentifier("bottom");
1013 someWritten=true;
1014 }
1015 if (Value&EM_ALIGN_LEFT) {
1016 if (someWritten) writer.TryWriteDelimiter('-');
1017 writer.TryWriteIdentifier("left");
1018 someWritten=true;
1019 }
1020 if (Value&EM_ALIGN_RIGHT) {
1021 if (someWritten) writer.TryWriteDelimiter('-');
1022 writer.TryWriteIdentifier("right");
1023 someWritten=true;
1024 }
1025 if (!someWritten) writer.TryWriteIdentifier("center");
1026 }
1027
1028
TryContinueWriting(emRecWriter & writer)1029 bool emAlignmentRec::TryContinueWriting(emRecWriter & writer)
1030 {
1031 return true;
1032 }
1033
1034
QuitWriting()1035 void emAlignmentRec::QuitWriting()
1036 {
1037 }
1038
1039
CalcRecMemNeed() const1040 emUInt64 emAlignmentRec::CalcRecMemNeed() const
1041 {
1042 return sizeof(emAlignmentRec);
1043 }
1044
1045
1046 //==============================================================================
1047 //================================ emStringRec =================================
1048 //==============================================================================
1049
emStringRec(const emString & defaultValue)1050 emStringRec::emStringRec(const emString & defaultValue)
1051 : DefaultValue(defaultValue), Value(defaultValue)
1052 {
1053 }
1054
1055
~emStringRec()1056 emStringRec::~emStringRec()
1057 {
1058 }
1059
1060
emStringRec(emStructRec * parent,const char * varIdentifier,const emString & defaultValue)1061 emStringRec::emStringRec(
1062 emStructRec * parent, const char * varIdentifier,
1063 const emString & defaultValue
1064 )
1065 : emRec(parent,varIdentifier),
1066 DefaultValue(defaultValue),
1067 Value(defaultValue)
1068 {
1069 }
1070
1071
Set(const emString & value)1072 void emStringRec::Set(const emString & value)
1073 {
1074 if (Value!=value) {
1075 Value=value;
1076 Changed();
1077 }
1078 }
1079
1080
SetToDefault()1081 void emStringRec::SetToDefault()
1082 {
1083 Set(DefaultValue);
1084 }
1085
1086
IsSetToDefault() const1087 bool emStringRec::IsSetToDefault() const
1088 {
1089 return Value==DefaultValue;
1090 }
1091
1092
TryStartReading(emRecReader & reader)1093 void emStringRec::TryStartReading(emRecReader & reader)
1094 {
1095 const char * val;
1096
1097 val=reader.TryReadQuoted();
1098 Set(val);
1099 }
1100
1101
TryContinueReading(emRecReader & reader)1102 bool emStringRec::TryContinueReading(emRecReader & reader)
1103 {
1104 return true;
1105 }
1106
1107
QuitReading()1108 void emStringRec::QuitReading()
1109 {
1110 }
1111
1112
TryStartWriting(emRecWriter & writer)1113 void emStringRec::TryStartWriting(emRecWriter & writer)
1114 {
1115 writer.TryWriteQuoted(Value);
1116 }
1117
1118
TryContinueWriting(emRecWriter & writer)1119 bool emStringRec::TryContinueWriting(emRecWriter & writer)
1120 {
1121 return true;
1122 }
1123
1124
QuitWriting()1125 void emStringRec::QuitWriting()
1126 {
1127 }
1128
1129
CalcRecMemNeed() const1130 emUInt64 emStringRec::CalcRecMemNeed() const
1131 {
1132 return sizeof(emStringRec) + DefaultValue.GetLen() + Value.GetLen() + 32;
1133 }
1134
1135
1136 //==============================================================================
1137 //================================= emColorRec =================================
1138 //==============================================================================
1139
emColorRec(emColor defaultValue,bool haveAlpha)1140 emColorRec::emColorRec(emColor defaultValue, bool haveAlpha)
1141 {
1142 if (!haveAlpha) defaultValue.SetAlpha(255);
1143 DefaultValue=defaultValue;
1144 Value=defaultValue;
1145 HaveAlpha=haveAlpha;
1146 }
1147
1148
emColorRec(emStructRec * parent,const char * varIdentifier,emColor defaultValue,bool haveAlpha)1149 emColorRec::emColorRec(
1150 emStructRec * parent, const char * varIdentifier, emColor defaultValue,
1151 bool haveAlpha
1152 )
1153 : emRec(parent,varIdentifier)
1154 {
1155 if (!haveAlpha) defaultValue.SetAlpha(255);
1156 DefaultValue=defaultValue;
1157 Value=defaultValue;
1158 HaveAlpha=haveAlpha;
1159 }
1160
1161
Set(emColor value)1162 void emColorRec::Set(emColor value)
1163 {
1164 if (!HaveAlpha) value.SetAlpha(255);
1165 if (Value!=value) {
1166 Value=value;
1167 Changed();
1168 }
1169 }
1170
1171
SetToDefault()1172 void emColorRec::SetToDefault()
1173 {
1174 Set(DefaultValue);
1175 }
1176
1177
IsSetToDefault() const1178 bool emColorRec::IsSetToDefault() const
1179 {
1180 return Value==DefaultValue;
1181 }
1182
1183
TryStartReading(emRecReader & reader)1184 void emColorRec::TryStartReading(emRecReader & reader)
1185 {
1186 const char * str;
1187 emColor val;
1188 char c;
1189 int i;
1190
1191 if (reader.TryPeekNext()==emRecReader::ET_QUOTED) {
1192 str=reader.TryReadQuoted();
1193 try {
1194 val.TryParse(str);
1195 }
1196 catch (const emException & exception) {
1197 reader.ThrowElemError(exception.GetText());
1198 }
1199 }
1200 else {
1201 reader.TryReadCertainDelimiter('{');
1202 i=reader.TryReadInt();
1203 if (i<0 || i>255) reader.ThrowElemError("Value out of range.");
1204 val.SetRed((emByte)i);
1205 i=reader.TryReadInt();
1206 if (i<0 || i>255) reader.ThrowElemError("Value out of range.");
1207 val.SetGreen((emByte)i);
1208 i=reader.TryReadInt();
1209 if (i<0 || i>255) reader.ThrowElemError("Value out of range.");
1210 val.SetBlue((emByte)i);
1211 if (HaveAlpha) {
1212 if (reader.TryPeekNext(&c)!=emRecReader::ET_DELIMITER || c!='}') {
1213 i=reader.TryReadInt();
1214 if (i<0 || i>255) reader.ThrowElemError("Value out of range.");
1215 val.SetAlpha((emByte)i);
1216 }
1217 else {
1218 val.SetAlpha(255);
1219 }
1220 }
1221 reader.TryReadCertainDelimiter('}');
1222 }
1223 Set(val);
1224 }
1225
1226
TryContinueReading(emRecReader & reader)1227 bool emColorRec::TryContinueReading(emRecReader & reader)
1228 {
1229 return true;
1230 }
1231
1232
QuitReading()1233 void emColorRec::QuitReading()
1234 {
1235 }
1236
1237
TryStartWriting(emRecWriter & writer)1238 void emColorRec::TryStartWriting(emRecWriter & writer)
1239 {
1240 writer.TryWriteDelimiter('{');
1241 writer.TryWriteInt(Value.GetRed());
1242 writer.TryWriteSpace();
1243 writer.TryWriteInt(Value.GetGreen());
1244 writer.TryWriteSpace();
1245 writer.TryWriteInt(Value.GetBlue());
1246 if (HaveAlpha) {
1247 writer.TryWriteSpace();
1248 writer.TryWriteInt(Value.GetAlpha());
1249 }
1250 writer.TryWriteDelimiter('}');
1251 }
1252
1253
TryContinueWriting(emRecWriter & writer)1254 bool emColorRec::TryContinueWriting(emRecWriter & writer)
1255 {
1256 return true;
1257 }
1258
1259
QuitWriting()1260 void emColorRec::QuitWriting()
1261 {
1262 }
1263
1264
CalcRecMemNeed() const1265 emUInt64 emColorRec::CalcRecMemNeed() const
1266 {
1267 return sizeof(emColorRec);
1268 }
1269
1270
1271 //==============================================================================
1272 //================================ emStructRec =================================
1273 //==============================================================================
1274
emStructRec()1275 emStructRec::emStructRec()
1276 {
1277 Count=0;
1278 Capacity=0;
1279 Members=NULL;
1280 RWState=NULL;
1281 }
1282
1283
emStructRec(emStructRec * parent,const char * varIdentifier)1284 emStructRec::emStructRec(emStructRec * parent, const char * varIdentifier)
1285 : emRec(parent,varIdentifier)
1286 {
1287 Count=0;
1288 Capacity=0;
1289 Members=NULL;
1290 RWState=NULL;
1291 }
1292
1293
~emStructRec()1294 emStructRec::~emStructRec()
1295 {
1296 if (RWState) {
1297 free(RWState);
1298 RWState=NULL;
1299 }
1300 if (Members) {
1301 free(Members);
1302 Members=NULL;
1303 }
1304 }
1305
1306
GetIdentifierOf(int index) const1307 const char * emStructRec::GetIdentifierOf(int index) const
1308 {
1309 if (index<0 || index>=Count) return NULL;
1310 return Members[index].Identifier;
1311 }
1312
1313
GetIndexOf(const emRec * member) const1314 int emStructRec::GetIndexOf(const emRec * member) const
1315 {
1316 int i;
1317
1318 for (i=Count-1; i>=0; i--) {
1319 if (member==Members[i].Record) break;
1320 }
1321 return i;
1322 }
1323
1324
GetIndexOf(const char * identifier) const1325 int emStructRec::GetIndexOf(const char * identifier) const
1326 {
1327 int i;
1328
1329 for (i=Count-1; i>=0; i--) {
1330 if (strcasecmp(identifier,Members[i].Identifier)==0) break;
1331 }
1332 return i;
1333 }
1334
1335
ShallWriteOptionalOnly(const emRec * child) const1336 bool emStructRec::ShallWriteOptionalOnly(const emRec * child) const
1337 {
1338 return false;
1339 }
1340
1341
SetToDefault()1342 void emStructRec::SetToDefault()
1343 {
1344 int i;
1345
1346 for (i=0; i<Count; i++) Members[i].Record->SetToDefault();
1347 }
1348
1349
IsSetToDefault() const1350 bool emStructRec::IsSetToDefault() const
1351 {
1352 int i;
1353
1354 for (i=0; i<Count; i++) {
1355 if (!Members[i].Record->IsSetToDefault()) return false;
1356 }
1357 return true;
1358 }
1359
1360
TryStartReading(emRecReader & reader)1361 void emStructRec::TryStartReading(emRecReader & reader)
1362 {
1363 if (RWState) {
1364 free(RWState);
1365 RWState=NULL;
1366 }
1367 emStructRec::SetToDefault();
1368 if (reader.GetRootRec()!=this) {
1369 reader.TryReadCertainDelimiter('{');
1370 }
1371 RWState=(RWStateType*)malloc(sizeof(RWStateType)+Count);
1372 RWState->Pos=-1;
1373 RWState->ChildReady=true;
1374 memset(RWState->Map,0,Count);
1375 }
1376
1377
TryContinueReading(emRecReader & reader)1378 bool emStructRec::TryContinueReading(emRecReader & reader)
1379 {
1380 const char * idf;
1381 char delimiter;
1382
1383 if (!RWState->ChildReady) {
1384 if (Members[RWState->Pos].Record->TryContinueReading(reader)) {
1385 Members[RWState->Pos].Record->QuitReading();
1386 RWState->ChildReady=true;
1387 }
1388 return false;
1389 }
1390 if (reader.GetRootRec()!=this) {
1391 if (
1392 reader.TryPeekNext(&delimiter)==emRecReader::ET_DELIMITER &&
1393 delimiter=='}'
1394 ) {
1395 reader.TryReadCertainDelimiter('}');
1396 return true;
1397 }
1398 }
1399 else {
1400 if (reader.TryPeekNext()==emRecReader::ET_END) {
1401 return true;
1402 }
1403 }
1404 idf=reader.TryReadIdentifier();
1405 RWState->Pos=GetIndexOf(idf);
1406 if (RWState->Pos<0) reader.ThrowElemError("Unknown identifier.");
1407 if (RWState->Map[RWState->Pos]) reader.ThrowElemError("re-assignment");
1408 reader.TryReadCertainDelimiter('=');
1409 Members[RWState->Pos].Record->TryStartReading(reader);
1410 RWState->ChildReady=false;
1411 RWState->Map[RWState->Pos]=1;
1412 return false;
1413 }
1414
1415
QuitReading()1416 void emStructRec::QuitReading()
1417 {
1418 if (RWState) {
1419 if (!RWState->ChildReady) {
1420 Members[RWState->Pos].Record->QuitReading();
1421 }
1422 free(RWState);
1423 RWState=NULL;
1424 }
1425 }
1426
1427
TryStartWriting(emRecWriter & writer)1428 void emStructRec::TryStartWriting(emRecWriter & writer)
1429 {
1430 if (RWState) {
1431 free(RWState);
1432 RWState=NULL;
1433 }
1434 if (writer.GetRootRec()!=this) {
1435 writer.TryWriteDelimiter('{');
1436 writer.IncIndent();
1437 }
1438 RWState=(RWStateType*)malloc(sizeof(RWStateType)+Count);
1439 RWState->Pos=-1;
1440 RWState->ChildReady=true;
1441 RWState->Empty=true;
1442 memset(RWState->Map,0,Count);
1443 }
1444
1445
TryContinueWriting(emRecWriter & writer)1446 bool emStructRec::TryContinueWriting(emRecWriter & writer)
1447 {
1448 if (!RWState->ChildReady) {
1449 if (Members[RWState->Pos].Record->TryContinueWriting(writer)) {
1450 Members[RWState->Pos].Record->QuitWriting();
1451 RWState->ChildReady=true;
1452 }
1453 return false;
1454 }
1455 for (;;) {
1456 RWState->Pos++;
1457 if (RWState->Pos>=Count) {
1458 if (writer.GetRootRec()!=this) {
1459 writer.DecIndent();
1460 if (!RWState->Empty) {
1461 writer.TryWriteNewLine();
1462 writer.TryWriteIndent();
1463 }
1464 writer.TryWriteDelimiter('}');
1465 }
1466 return true;
1467 }
1468 RWState->Map[RWState->Pos]=1;
1469 if (
1470 !Members[RWState->Pos].Record->IsSetToDefault() ||
1471 !ShallWriteOptionalOnly(Members[RWState->Pos].Record)
1472 ) {
1473 if (writer.GetRootRec()!=this || !RWState->Empty) {
1474 writer.TryWriteNewLine();
1475 }
1476 writer.TryWriteIndent();
1477 writer.TryWriteIdentifier(Members[RWState->Pos].Identifier);
1478 writer.TryWriteSpace();
1479 writer.TryWriteDelimiter('=');
1480 writer.TryWriteSpace();
1481 Members[RWState->Pos].Record->TryStartWriting(writer);
1482 RWState->ChildReady=false;
1483 RWState->Empty=false;
1484 return false;
1485 }
1486 }
1487 }
1488
1489
QuitWriting()1490 void emStructRec::QuitWriting()
1491 {
1492 if (RWState) {
1493 if (!RWState->ChildReady) {
1494 Members[RWState->Pos].Record->QuitWriting();
1495 }
1496 free(RWState);
1497 RWState=NULL;
1498 }
1499 }
1500
1501
CalcRecMemNeed() const1502 emUInt64 emStructRec::CalcRecMemNeed() const
1503 {
1504 emUInt64 sum;
1505 int i;
1506
1507 sum=sizeof(emStructRec)+sizeof(MemberType)*Capacity;
1508 for (i=0; i<Count; i++) sum+=Members[i].Record->CalcRecMemNeed();
1509 return sum;
1510 }
1511
1512
AddMember(emRec * member,const char * identifier)1513 void emStructRec::AddMember(emRec * member, const char * identifier)
1514 {
1515 CheckIdentifier(identifier);
1516 if (Count>=Capacity) {
1517 Capacity=(Count+1)*2;
1518 Members=(MemberType*)realloc(Members,sizeof(MemberType)*Capacity);
1519 }
1520 Members[Count].Record=member;
1521 Members[Count].Identifier=identifier;
1522 Count++;
1523 BeTheParentOf(member);
1524 // Changed() is not called here because it should always be the
1525 // construction phase!
1526 }
1527
1528
1529 //==============================================================================
1530 //================================= emUnionRec =================================
1531 //==============================================================================
1532
emUnionRec(int defaultVariant,const char * identifier0,emRecAllocator allocator0,...)1533 emUnionRec::emUnionRec(
1534 int defaultVariant, const char * identifier0,
1535 emRecAllocator allocator0, ...
1536 )
1537 {
1538 va_list args;
1539
1540 va_start(args,allocator0);
1541 Init(defaultVariant,identifier0,allocator0,args);
1542 va_end(args);
1543 }
1544
1545
emUnionRec(emStructRec * parent,const char * varIdentifier,int defaultVariant,const char * identifier0,emRecAllocator allocator0,...)1546 emUnionRec::emUnionRec(
1547 emStructRec * parent, const char * varIdentifier, int defaultVariant,
1548 const char * identifier0, emRecAllocator allocator0, ...
1549 )
1550 : emRec(parent,varIdentifier)
1551 {
1552 va_list args;
1553
1554 va_start(args,allocator0);
1555 Init(defaultVariant,identifier0,allocator0,args);
1556 va_end(args);
1557 }
1558
1559
~emUnionRec()1560 emUnionRec::~emUnionRec()
1561 {
1562 delete Record;
1563 delete [] TypeArray;
1564 }
1565
1566
SetVariant(int variant)1567 void emUnionRec::SetVariant(int variant)
1568 {
1569 if (variant<0) variant=0;
1570 if (variant>=VariantCount) variant=VariantCount-1;
1571 if (Variant!=variant) {
1572 Variant=variant;
1573 delete Record;
1574 Record=TypeArray[Variant].Allocator();
1575 BeTheParentOf(Record);
1576 Changed();
1577 }
1578 }
1579
1580
GetIdentifierOf(int variant) const1581 const char * emUnionRec::GetIdentifierOf(int variant) const
1582 {
1583 if (variant<0) return NULL;
1584 if (variant>=VariantCount) return NULL;
1585 return TypeArray[variant].Identifier;
1586 }
1587
1588
GetVariantOf(const char * identifier) const1589 int emUnionRec::GetVariantOf(const char * identifier) const
1590 {
1591 int variant;
1592
1593 for (variant=VariantCount-1; variant>=0; variant--) {
1594 if (strcasecmp(identifier,TypeArray[variant].Identifier)==0) break;
1595 }
1596 return variant;
1597 }
1598
1599
SetToDefault()1600 void emUnionRec::SetToDefault()
1601 {
1602 SetVariant(DefaultVariant);
1603 Record->SetToDefault();
1604 }
1605
1606
IsSetToDefault() const1607 bool emUnionRec::IsSetToDefault() const
1608 {
1609 return Variant==DefaultVariant && Record->IsSetToDefault();
1610 }
1611
1612
TryStartReading(emRecReader & reader)1613 void emUnionRec::TryStartReading(emRecReader & reader)
1614 {
1615 const char * idf;
1616 int v;
1617
1618 idf=reader.TryReadIdentifier();
1619 v=GetVariantOf(idf);
1620 if (v<0) reader.ThrowElemError("Unknown identifier.");
1621 SetVariant(v);
1622 reader.TryReadCertainDelimiter(':');
1623 Record->TryStartReading(reader);
1624 }
1625
1626
TryContinueReading(emRecReader & reader)1627 bool emUnionRec::TryContinueReading(emRecReader & reader)
1628 {
1629 return Record->TryContinueReading(reader);
1630 }
1631
1632
QuitReading()1633 void emUnionRec::QuitReading()
1634 {
1635 Record->QuitReading();
1636 }
1637
1638
TryStartWriting(emRecWriter & writer)1639 void emUnionRec::TryStartWriting(emRecWriter & writer)
1640 {
1641 writer.TryWriteIdentifier(TypeArray[Variant].Identifier);
1642 writer.TryWriteDelimiter(':');
1643 writer.TryWriteSpace();
1644 Record->TryStartWriting(writer);
1645 }
1646
1647
TryContinueWriting(emRecWriter & writer)1648 bool emUnionRec::TryContinueWriting(emRecWriter & writer)
1649 {
1650 return Record->TryContinueWriting(writer);
1651 }
1652
1653
QuitWriting()1654 void emUnionRec::QuitWriting()
1655 {
1656 Record->QuitWriting();
1657 }
1658
1659
CalcRecMemNeed() const1660 emUInt64 emUnionRec::CalcRecMemNeed() const
1661 {
1662 return
1663 Record->CalcRecMemNeed() +
1664 sizeof(emUnionRec) +
1665 VariantCount*sizeof(VariantType);
1666 }
1667
1668
Init(int defaultVariant,const char * identifier0,emRecAllocator allocator0,va_list args)1669 void emUnionRec::Init(
1670 int defaultVariant, const char * identifier0, emRecAllocator allocator0,
1671 va_list args
1672 )
1673 {
1674 VariantType v[512];
1675 int cnt;
1676
1677 v[0].Allocator=allocator0;
1678 v[0].Identifier=identifier0;
1679 for (cnt=1; ; cnt++) {
1680 if (cnt>=(int)(sizeof(v)/sizeof(VariantType))) {
1681 emFatalError("emUnionRec: Too many variants.");
1682 }
1683 v[cnt].Identifier=va_arg(args,const char *);
1684 if (!v[cnt].Identifier) break;
1685 v[cnt].Allocator=va_arg(args,emRecAllocator);
1686 if (!v[cnt].Allocator) break;
1687 CheckIdentifier(v[cnt].Identifier);
1688 }
1689 TypeArray=new VariantType[cnt];
1690 memcpy(TypeArray,v,sizeof(VariantType)*cnt);
1691 VariantCount=cnt;
1692 if (defaultVariant<0) defaultVariant=0;
1693 if (defaultVariant>=VariantCount) defaultVariant=VariantCount-1;
1694 DefaultVariant=defaultVariant;
1695 Variant=DefaultVariant;
1696 Record=TypeArray[Variant].Allocator();
1697 BeTheParentOf(Record);
1698 }
1699
1700
1701 //==============================================================================
1702 //================================= emArrayRec =================================
1703 //==============================================================================
1704
emArrayRec(emRecAllocator allocator,int minCount,int maxCount)1705 emArrayRec::emArrayRec(emRecAllocator allocator, int minCount, int maxCount)
1706 {
1707 Init(allocator,minCount,maxCount);
1708 }
1709
1710
emArrayRec(emStructRec * parent,const char * varIdentifier,emRecAllocator allocator,int minCount,int maxCount)1711 emArrayRec::emArrayRec(
1712 emStructRec * parent, const char * varIdentifier,
1713 emRecAllocator allocator, int minCount, int maxCount
1714 )
1715 : emRec(parent,varIdentifier)
1716 {
1717 Init(allocator,minCount,maxCount);
1718 }
1719
1720
~emArrayRec()1721 emArrayRec::~emArrayRec()
1722 {
1723 int i;
1724
1725 if (Array) {
1726 for (i=0; i<Count; i++) delete Array[i];
1727 free(Array);
1728 }
1729 }
1730
1731
SetCount(int count)1732 void emArrayRec::SetCount(int count)
1733 {
1734 if (count<Count) Remove(count,Count-count);
1735 else Insert(Count,count-Count);
1736 }
1737
1738
Insert(int index,int insCount)1739 void emArrayRec::Insert(int index, int insCount)
1740 {
1741 int i,n;
1742
1743 if (insCount>MaxCount-Count) insCount=MaxCount-Count;
1744 if (insCount<=0) return;
1745 if (index<0) index=0;
1746 if (index>Count) index=Count;
1747 Count+=insCount;
1748 if (Capacity<Count) {
1749 Capacity=Count*2;
1750 if (Capacity>MaxCount) Capacity=MaxCount;
1751 Array=(emRec**)realloc(Array,sizeof(emRec*)*Capacity);
1752 }
1753 n=Count-index-insCount;
1754 if (n>0) memmove(Array+Count-n,Array+index,sizeof(emRec*)*n);
1755 for (i=index; i<index+insCount; i++) {
1756 Array[i]=Allocator();
1757 BeTheParentOf(Array[i]);
1758 }
1759 if (RWPos>=index) RWPos+=insCount;
1760 Changed();
1761 }
1762
1763
Remove(int index,int remCount)1764 void emArrayRec::Remove(int index, int remCount)
1765 {
1766 int i,n;
1767
1768 if (index<0) { remCount+=index; index=0; }
1769 if (remCount>Count-index) remCount=Count-index;
1770 if (remCount>Count-MinCount) remCount=Count-MinCount;
1771 if (remCount<=0) return;
1772 if (RWPos>=index) {
1773 if (RWPos>=index+remCount) {
1774 RWPos-=remCount;
1775 }
1776 else {
1777 RWPos=index-1;
1778 RWChildReady=true;
1779 }
1780 }
1781 for (i=index; i<index+remCount; i++) {
1782 delete Array[i];
1783 }
1784 n=Count-index-remCount;
1785 if (n>0) memmove(Array+index,Array+Count-n,sizeof(emRec*)*n);
1786 Count-=remCount;
1787 if (Capacity>=Count*3) {
1788 Capacity=Count*2;
1789 if (Capacity>MaxCount) Capacity=MaxCount;
1790 if (Capacity>0) {
1791 Array=(emRec**)realloc(Array,sizeof(emRec*)*Capacity);
1792 }
1793 else {
1794 free(Array);
1795 Array=NULL;
1796 }
1797 }
1798 Changed();
1799 }
1800
1801
SetToDefault()1802 void emArrayRec::SetToDefault()
1803 {
1804 int i;
1805
1806 SetCount(MinCount);
1807 for (i=0; i<Count; i++) Array[i]->SetToDefault();
1808 }
1809
1810
IsSetToDefault() const1811 bool emArrayRec::IsSetToDefault() const
1812 {
1813 int i;
1814
1815 if (Count!=MinCount) return false;
1816 for (i=0; i<Count; i++) {
1817 if (!Array[i]->IsSetToDefault()) return false;
1818 }
1819 return true;
1820 }
1821
1822
TryStartReading(emRecReader & reader)1823 void emArrayRec::TryStartReading(emRecReader & reader)
1824 {
1825 SetCount(MinCount);
1826 if (reader.GetRootRec()!=this) {
1827 reader.TryReadCertainDelimiter('{');
1828 }
1829 RWPos=-1;
1830 RWChildReady=true;
1831 }
1832
1833
TryContinueReading(emRecReader & reader)1834 bool emArrayRec::TryContinueReading(emRecReader & reader)
1835 {
1836 char delimiter;
1837 int i;
1838
1839 if (!RWChildReady) {
1840 if (Array[RWPos]->TryContinueReading(reader)) {
1841 Array[RWPos]->QuitReading();
1842 RWChildReady=true;
1843 }
1844 return false;
1845 }
1846 RWPos++;
1847 if (reader.GetRootRec()!=this) {
1848 if (
1849 reader.TryPeekNext(&delimiter)==emRecReader::ET_DELIMITER &&
1850 delimiter=='}'
1851 ) {
1852 reader.TryReadCertainDelimiter('}');
1853 if (RWPos<MinCount) reader.ThrowElemError("Too few elements.");
1854 return true;
1855 }
1856 }
1857 else {
1858 if (reader.TryPeekNext()==emRecReader::ET_END) {
1859 if (RWPos<MinCount) reader.ThrowElemError("Too few elements.");
1860 return true;
1861 }
1862 }
1863 if (RWPos>=MaxCount) reader.ThrowElemError("Too many elements.");
1864 if (RWPos>=Count) {
1865 i=RWPos;
1866 SetCount(RWPos+1);
1867 RWPos=i;
1868 }
1869 Array[RWPos]->TryStartReading(reader);
1870 RWChildReady=false;
1871 return false;
1872 }
1873
1874
QuitReading()1875 void emArrayRec::QuitReading()
1876 {
1877 if (!RWChildReady) {
1878 if (RWPos>=0 && RWPos<Count) Array[RWPos]->QuitReading();
1879 RWChildReady=true;
1880 }
1881 RWPos=-1;
1882 }
1883
1884
TryStartWriting(emRecWriter & writer)1885 void emArrayRec::TryStartWriting(emRecWriter & writer)
1886 {
1887 if (writer.GetRootRec()!=this) {
1888 writer.TryWriteDelimiter('{');
1889 writer.IncIndent();
1890 }
1891 RWPos=-1;
1892 RWChildReady=true;
1893 }
1894
1895
TryContinueWriting(emRecWriter & writer)1896 bool emArrayRec::TryContinueWriting(emRecWriter & writer)
1897 {
1898 if (!RWChildReady) {
1899 if (Array[RWPos]->TryContinueWriting(writer)) {
1900 Array[RWPos]->QuitWriting();
1901 RWChildReady=true;
1902 }
1903 return false;
1904 }
1905 RWPos++;
1906 if (RWPos<Count) {
1907 if (writer.GetRootRec()!=this || RWPos>0) writer.TryWriteNewLine();
1908 writer.TryWriteIndent();
1909 Array[RWPos]->TryStartWriting(writer);
1910 RWChildReady=false;
1911 return false;
1912 }
1913 if (writer.GetRootRec()!=this) {
1914 writer.DecIndent();
1915 if (Count>0) {
1916 writer.TryWriteNewLine();
1917 writer.TryWriteIndent();
1918 }
1919 writer.TryWriteDelimiter('}');
1920 }
1921 return true;
1922 }
1923
1924
QuitWriting()1925 void emArrayRec::QuitWriting()
1926 {
1927 if (!RWChildReady) {
1928 if (RWPos>=0 && RWPos<Count) Array[RWPos]->QuitWriting();
1929 RWChildReady=true;
1930 }
1931 RWPos=-1;
1932 }
1933
1934
CalcRecMemNeed() const1935 emUInt64 emArrayRec::CalcRecMemNeed() const
1936 {
1937 emUInt64 sum;
1938 int i;
1939
1940 sum=sizeof(emArrayRec)+sizeof(emRec*)*Capacity;
1941 for (i=0; i<Count; i++) sum+=Array[i]->CalcRecMemNeed();
1942 return sum;
1943 }
1944
1945
Init(emRecAllocator allocator,int minCount,int maxCount)1946 void emArrayRec::Init(emRecAllocator allocator, int minCount, int maxCount)
1947 {
1948 int i;
1949
1950 if (minCount<0) minCount=0;
1951 if (maxCount<minCount) maxCount=minCount;
1952 Allocator=allocator;
1953 MinCount=minCount;
1954 MaxCount=maxCount;
1955 Count=MinCount;
1956 Capacity=Count*2;
1957 if (Capacity>MaxCount) Capacity=MaxCount;
1958 if (Capacity>0) {
1959 Array=(emRec**)malloc(sizeof(emRec*)*Capacity);
1960 for (i=0; i<Count; i++) {
1961 Array[i]=Allocator();
1962 BeTheParentOf(Array[i]);
1963 }
1964 }
1965 else {
1966 Array=NULL;
1967 }
1968 RWPos=-1;
1969 RWChildReady=true;
1970 }
1971
1972
1973 //==============================================================================
1974 //================================ emRecReader =================================
1975 //==============================================================================
1976
emRecReader()1977 emRecReader::emRecReader()
1978 {
1979 Root=NULL;
1980 RootQuitPending=false;
1981 ClosePending=false;
1982 Line=1;
1983 NextEaten=true;
1984 NextLine=1;
1985 NextType=ET_END;
1986 NextDelimiter=0;
1987 NextBuf=NULL;
1988 NextBufSize=0;
1989 NextInt=0;
1990 NextDouble=0.0;
1991 NextChar=-1;
1992 }
1993
1994
~emRecReader()1995 emRecReader::~emRecReader()
1996 {
1997 // Never do a Root->QuitReading() here, because of destruction of
1998 // emRecFileModel...
1999 Root=NULL;
2000 if (NextBuf) {
2001 free(NextBuf);
2002 NextBuf=NULL;
2003 }
2004 }
2005
2006
TryStartReading(emRec & root)2007 void emRecReader::TryStartReading(emRec & root)
2008 {
2009 const char * formatName;
2010 emString magic;
2011 int mlen,rlen;
2012
2013 try {
2014 ClosePending=true;
2015 Root=&root;
2016 Line=1;
2017 NextLine=1;
2018 NextEaten=true;
2019 NextChar=-1;
2020 formatName=Root->GetFormatName();
2021 if (formatName) {
2022 magic=emString("#%rec:")+formatName+"%";
2023 mlen=magic.GetLen();
2024 SetMinNextBufSize(mlen);
2025 rlen=TryRead(NextBuf,mlen);
2026 if (rlen!=mlen || memcmp(NextBuf,magic.Get(),mlen)!=0) {
2027 throw emException(
2028 "File format of \"%s\" is not \"rec:%s\".",
2029 GetSourceName(),
2030 formatName
2031 );
2032 }
2033 }
2034 TryNextChar();
2035 RootQuitPending=true;
2036 Root->TryStartReading(*this);
2037 }
2038 catch (const emException & exception) {
2039 QuitReading();
2040 throw exception;
2041 }
2042 }
2043
2044
TryContinueReading()2045 bool emRecReader::TryContinueReading()
2046 {
2047 try {
2048 if (Root) {
2049 if (!Root->TryContinueReading(*this)) return false;
2050 RootQuitPending=false;
2051 Root->QuitReading();
2052 if (NextEaten) TryParseNext();
2053 Line=NextLine;
2054 if (NextType!=ET_END) ThrowElemError("Unexpected content.");
2055 ClosePending=false;
2056 TryClose();
2057 QuitReading();
2058 }
2059 return true;
2060 }
2061 catch (const emException & exception) {
2062 QuitReading();
2063 throw exception;
2064 }
2065 }
2066
2067
TryFinishReading()2068 void emRecReader::TryFinishReading()
2069 {
2070 for (;;) {
2071 if (TryContinueReading()) break;
2072 }
2073 }
2074
2075
QuitReading()2076 void emRecReader::QuitReading()
2077 {
2078 if (Root && RootQuitPending) Root->QuitReading();
2079 if (ClosePending) {
2080 try {
2081 TryClose();
2082 }
2083 catch (const emException &) {
2084 }
2085 }
2086 Root=NULL;
2087 RootQuitPending=false;
2088 ClosePending=false;
2089 Line=1;
2090 NextEaten=true;
2091 NextLine=1;
2092 NextType=ET_END;
2093 NextDelimiter=0;
2094 if (NextBuf) {
2095 free(NextBuf);
2096 NextBuf=NULL;
2097 NextBufSize=0;
2098 }
2099 NextInt=0;
2100 NextDouble=0.0;
2101 NextChar=-1;
2102 }
2103
2104
TryPeekNext(char * pDelimiter)2105 emRecReader::ElementType emRecReader::TryPeekNext(
2106 char * pDelimiter
2107 )
2108 {
2109 if (NextEaten) TryParseNext();
2110 if (pDelimiter) {
2111 if (NextType==ET_DELIMITER) *pDelimiter=NextDelimiter;
2112 else *pDelimiter=0;
2113 }
2114 return NextType;
2115 }
2116
2117
TryReadDelimiter()2118 char emRecReader::TryReadDelimiter()
2119 {
2120 if (NextEaten) TryParseNext();
2121 Line=NextLine;
2122 NextEaten=true;
2123 if (NextType!=ET_DELIMITER) ThrowElemError("Delimiter expected.");
2124 return NextDelimiter;
2125 }
2126
2127
TryReadCertainDelimiter(char delimiter)2128 void emRecReader::TryReadCertainDelimiter(char delimiter)
2129 {
2130 char tmp[256];
2131
2132 if (NextEaten) TryParseNext();
2133 Line=NextLine;
2134 NextEaten=true;
2135 if (NextType!=ET_DELIMITER || NextDelimiter!=delimiter) {
2136 sprintf(tmp,"'%c' expected.",delimiter);
2137 ThrowElemError(tmp);
2138 }
2139 }
2140
2141
TryReadIdentifier()2142 const char * emRecReader::TryReadIdentifier()
2143 {
2144 if (NextEaten) TryParseNext();
2145 Line=NextLine;
2146 NextEaten=true;
2147 if (NextType!=ET_IDENTIFIER) ThrowElemError("Identifier expected.");
2148 return NextBuf;
2149 }
2150
2151
TryReadInt()2152 int emRecReader::TryReadInt()
2153 {
2154 if (NextEaten) TryParseNext();
2155 Line=NextLine;
2156 NextEaten=true;
2157 if (NextType!=ET_INT) ThrowElemError("Integer expected.");
2158 return NextInt;
2159 }
2160
2161
TryReadDouble()2162 double emRecReader::TryReadDouble()
2163 {
2164 if (NextEaten) TryParseNext();
2165 Line=NextLine;
2166 NextEaten=true;
2167 if (NextType==ET_INT) return (double)NextInt;
2168 if (NextType==ET_DOUBLE) return NextDouble;
2169 ThrowElemError("Floating point number expected.");
2170 return 0;
2171 }
2172
2173
TryReadQuoted()2174 const char * emRecReader::TryReadQuoted()
2175 {
2176 if (NextEaten) TryParseNext();
2177 Line=NextLine;
2178 NextEaten=true;
2179 if (NextType!=ET_QUOTED) ThrowElemError("Quoted string expected.");
2180 return NextBuf;
2181 }
2182
2183
ThrowElemError(const char * text) const2184 void emRecReader::ThrowElemError(const char * text) const
2185 {
2186 throw emException("File \"%s\", line %d: %s",GetSourceName(),Line,text);
2187 }
2188
2189
ThrowSyntaxError() const2190 void emRecReader::ThrowSyntaxError() const
2191 {
2192 ThrowElemError("Syntax error.");
2193 }
2194
2195
SetMinNextBufSize(int minSize)2196 void emRecReader::SetMinNextBufSize(int minSize)
2197 {
2198 if (NextBufSize<minSize) {
2199 NextBufSize=minSize+256;
2200 NextBuf=(char*)realloc(NextBuf,NextBufSize);
2201 }
2202 }
2203
2204
TryNextChar()2205 void emRecReader::TryNextChar()
2206 {
2207 char buf[1];
2208
2209 if (TryRead(buf,1)!=1) NextChar=-1;
2210 else NextChar=(int)((unsigned char)buf[0]);
2211 }
2212
2213
TryParseNext()2214 void emRecReader::TryParseNext()
2215 {
2216 int i,j,k,n;
2217
2218 NextEaten=false;
2219
2220 // Parse white spaces, comments and end-of-file.
2221 for (;;) {
2222 if (NextChar<=0x20) {
2223 if (NextChar==0x20 || NextChar==0x09) {
2224 TryNextChar();
2225 }
2226 else if (NextChar==0x0a) {
2227 NextLine++;
2228 TryNextChar();
2229 }
2230 else if (NextChar==0x0d) {
2231 NextLine++;
2232 TryNextChar();
2233 if (NextChar==0x0a) TryNextChar();
2234 }
2235 else if (NextChar==-1) {
2236 NextType=ET_END;
2237 return;
2238 }
2239 else {
2240 TryNextChar();
2241 }
2242 }
2243 else if (NextChar=='#') {
2244 do {
2245 TryNextChar();
2246 } while (NextChar!='\n' && NextChar!='\r' && NextChar!=-1);
2247 }
2248 else {
2249 break;
2250 }
2251 }
2252
2253 // Parse identifier.
2254 if (
2255 (NextChar>='a' && NextChar<='z') ||
2256 (NextChar>='A' && NextChar<='Z') ||
2257 NextChar=='_'
2258 ) {
2259 n=0;
2260 do {
2261 SetMinNextBufSize(n+1);
2262 NextBuf[n++]=(char)NextChar;
2263 if (n>10000000) {
2264 Line=NextLine;
2265 ThrowElemError("Identifier too long.");
2266 }
2267 TryNextChar();
2268 } while (
2269 (NextChar>='a' && NextChar<='z') ||
2270 (NextChar>='A' && NextChar<='Z') ||
2271 (NextChar>='0' && NextChar<='9') ||
2272 NextChar=='_'
2273 );
2274 SetMinNextBufSize(n+1);
2275 NextBuf[n]=0;
2276 NextType=ET_IDENTIFIER;
2277 return;
2278 }
2279
2280 // Parse quoted String.
2281 if (NextChar=='"') {
2282 for (n=0; ; ) {
2283 TryNextChar();
2284 if (NextChar=='"') {
2285 TryNextChar();
2286 break;
2287 }
2288 if (NextChar=='\\') {
2289 SetMinNextBufSize(n+1);
2290 NextBuf[n++]='\\';
2291 TryNextChar();
2292 }
2293 if (NextChar==-1) {
2294 Line=NextLine;
2295 ThrowElemError("Unterminated string.");
2296 }
2297 if (
2298 NextChar==0x0d ||
2299 (NextChar==0x0a && (n<=0 || NextBuf[n-1]!=0x0d))
2300 ) NextLine++;
2301 SetMinNextBufSize(n+1);
2302 NextBuf[n++]=(char)NextChar;
2303 if (n>10000000) {
2304 Line=NextLine;
2305 ThrowElemError("String too long.");
2306 }
2307 }
2308 SetMinNextBufSize(n+1);
2309 NextBuf[n]=0;
2310 for (j=0, i=0; i<n; i++) {
2311 if (NextBuf[i]=='\\') {
2312 i++;
2313 if (NextBuf[i]=='a') NextBuf[j++]=0x07;
2314 else if (NextBuf[i]=='b') NextBuf[j++]=0x08;
2315 else if (NextBuf[i]=='e') NextBuf[j++]=0x1b;
2316 else if (NextBuf[i]=='f') NextBuf[j++]=0x0c;
2317 else if (NextBuf[i]=='n') NextBuf[j++]=0x0a;
2318 else if (NextBuf[i]=='r') NextBuf[j++]=0x0d;
2319 else if (NextBuf[i]=='t') NextBuf[j++]=0x09;
2320 else if (NextBuf[i]=='v') NextBuf[j++]=0x0b;
2321 else if (NextBuf[i]=='x') {
2322 i++;
2323 if (NextBuf[i]>='0' && NextBuf[i]<='9') {
2324 k=NextBuf[i]-'0';
2325 }
2326 else if (NextBuf[i]>='a' && NextBuf[i]<='f') {
2327 k=NextBuf[i]-('a'-10);
2328 }
2329 else if (NextBuf[i]>='A' && NextBuf[i]<='F') {
2330 k=NextBuf[i]-('A'-10);
2331 }
2332 else {
2333 k=-1;
2334 }
2335 if (k>=0) {
2336 i++;
2337 if (NextBuf[i]>='0' && NextBuf[i]<='9') {
2338 k=(k<<4)|(NextBuf[i]-'0');
2339 }
2340 else if (NextBuf[i]>='a' && NextBuf[i]<='f') {
2341 k=(k<<4)|(NextBuf[i]-('a'-10));
2342 }
2343 else if (NextBuf[i]>='A' && NextBuf[i]<='F') {
2344 k=(k<<4)|(NextBuf[i]-('A'-10));
2345 }
2346 else {
2347 i--;
2348 }
2349 NextBuf[j++]=(char)k;
2350 }
2351 else {
2352 NextBuf[j++]='\\';
2353 NextBuf[j++]='x';
2354 i--;
2355 }
2356 }
2357 else if (NextBuf[i]>='0' && NextBuf[i]<='7') {
2358 k=NextBuf[i]-'0';
2359 i++;
2360 if (NextBuf[i]>='0' && NextBuf[i]<='7') {
2361 k=(k<<3)|(NextBuf[i]-'0');
2362 i++;
2363 if (NextBuf[i]>='0' && NextBuf[i]<='7') {
2364 k=(k<<3)|(NextBuf[i]-'0');
2365 i++;
2366 }
2367 }
2368 NextBuf[j++]=(char)k;
2369 i--;
2370 }
2371 else {
2372 NextBuf[j++]=NextBuf[i];
2373 }
2374 }
2375 else {
2376 NextBuf[j++]=NextBuf[i];
2377 }
2378 }
2379 NextBuf[j]=0;
2380 NextType=ET_QUOTED;
2381 return;
2382 }
2383
2384 // Parse numeric or fall back to a delimiter.
2385 if (
2386 (NextChar>='0' && NextChar<='9') ||
2387 NextChar=='-' || NextChar=='+' || NextChar=='.'
2388 ) {
2389 n=0;
2390 i=0;
2391 k=0;
2392 if (NextChar=='+' || NextChar=='-') {
2393 SetMinNextBufSize(n+1);
2394 NextBuf[n++]=(char)NextChar;
2395 TryNextChar();
2396 }
2397 while (NextChar>='0' && NextChar<='9') {
2398 i=1;
2399 if (n>100) {
2400 Line=NextLine;
2401 ThrowElemError("Numeric constant too long.");
2402 }
2403 SetMinNextBufSize(n+1);
2404 NextBuf[n++]=(char)NextChar;
2405 TryNextChar();
2406 }
2407 if (NextChar=='.') {
2408 k=1;
2409 SetMinNextBufSize(n+1);
2410 NextBuf[n++]=(char)NextChar;
2411 TryNextChar();
2412 while (NextChar>='0' && NextChar<='9') {
2413 i=1;
2414 if (n>100) {
2415 Line=NextLine;
2416 ThrowElemError("Numeric constant too long.");
2417 }
2418 SetMinNextBufSize(n+1);
2419 NextBuf[n++]=(char)NextChar;
2420 TryNextChar();
2421 }
2422 }
2423 if (NextChar=='E' || NextChar=='e') {
2424 k=1;
2425 SetMinNextBufSize(n+1);
2426 NextBuf[n++]=(char)NextChar;
2427 TryNextChar();
2428 if (NextChar=='+' || NextChar=='-') {
2429 SetMinNextBufSize(n+1);
2430 NextBuf[n++]=(char)NextChar;
2431 TryNextChar();
2432 }
2433 if (NextChar<'0' || NextChar>'9') {
2434 Line=NextLine;
2435 ThrowSyntaxError();
2436 }
2437 while (NextChar>='0' && NextChar<='9') {
2438 if (n>100) {
2439 Line=NextLine;
2440 ThrowElemError("Numeric constant too long.");
2441 }
2442 SetMinNextBufSize(n+1);
2443 NextBuf[n++]=(char)NextChar;
2444 TryNextChar();
2445 }
2446 }
2447 SetMinNextBufSize(n+1);
2448 NextBuf[n]=0;
2449 if (n==1) {
2450 if (NextBuf[0]=='.' || NextBuf[0]=='-' || NextBuf[0]=='+') {
2451 NextDelimiter=NextBuf[0];
2452 NextType=ET_DELIMITER;
2453 return;
2454 }
2455 }
2456 if (i==0) {
2457 Line=NextLine;
2458 ThrowSyntaxError();
2459 }
2460 if (NextBuf[0]=='+') i=1; else i=0;
2461 if (k) {
2462 k=sscanf(NextBuf+i,"%lf",&NextDouble);
2463 NextType=ET_DOUBLE;
2464 }
2465 else {
2466 k=sscanf(NextBuf+i,"%d",&NextInt);
2467 NextType=ET_INT;
2468 }
2469 if (k!=1) {
2470 Line=NextLine;
2471 ThrowSyntaxError();
2472 }
2473 return;
2474 }
2475
2476 // Everything else is a delimiter...
2477 NextDelimiter=(char)NextChar;
2478 NextType=ET_DELIMITER;
2479 TryNextChar();
2480 }
2481
2482
2483 //==============================================================================
2484 //================================ emRecWriter =================================
2485 //==============================================================================
2486
emRecWriter()2487 emRecWriter::emRecWriter()
2488 {
2489 Root=NULL;
2490 RootQuitPending=false;
2491 ClosePending=false;
2492 Indent=0;
2493 }
2494
2495
~emRecWriter()2496 emRecWriter::~emRecWriter()
2497 {
2498 // Never do a Root->QuitWriting() here, because of destruction of
2499 // emRecFileModel...
2500 Root=NULL;
2501 }
2502
2503
TryStartWriting(emRec & root)2504 void emRecWriter::TryStartWriting(emRec & root)
2505 {
2506 const char * formatName;
2507
2508 try {
2509 ClosePending=true;
2510 Root=&root;
2511 Indent=0;
2512 formatName=Root->GetFormatName();
2513 if (formatName) {
2514 TryWriteString("#%rec:");
2515 TryWriteString(formatName);
2516 TryWriteString("%#\n\n");
2517 }
2518 RootQuitPending=true;
2519 Root->TryStartWriting(*this);
2520 }
2521 catch (const emException & exception) {
2522 QuitWriting();
2523 throw exception;
2524 }
2525 }
2526
2527
TryContinueWriting()2528 bool emRecWriter::TryContinueWriting()
2529 {
2530 try {
2531 if (Root) {
2532 if (!Root->TryContinueWriting(*this)) return false;
2533 RootQuitPending=false;
2534 Root->QuitWriting();
2535 TryWriteNewLine();
2536 ClosePending=false;
2537 TryClose();
2538 QuitWriting();
2539 }
2540 return true;
2541 }
2542 catch (const emException & exception) {
2543 QuitWriting();
2544 throw exception;
2545 }
2546 }
2547
2548
TryFinishWriting()2549 void emRecWriter::TryFinishWriting()
2550 {
2551 for (;;) {
2552 if (TryContinueWriting()) break;
2553 }
2554 }
2555
2556
QuitWriting()2557 void emRecWriter::QuitWriting()
2558 {
2559 if (Root && RootQuitPending) Root->QuitWriting();
2560 if (ClosePending) {
2561 try {
2562 TryClose();
2563 }
2564 catch (const emException &) {
2565 }
2566 }
2567 Root=NULL;
2568 RootQuitPending=false;
2569 ClosePending=false;
2570 Indent=0;
2571 }
2572
2573
TryWriteDelimiter(char c)2574 void emRecWriter::TryWriteDelimiter(char c)
2575 {
2576 TryWriteChar(c);
2577 }
2578
2579
TryWriteIdentifier(const char * idf)2580 void emRecWriter::TryWriteIdentifier(const char * idf)
2581 {
2582 TryWriteString(idf);
2583 }
2584
2585
TryWriteInt(int i)2586 void emRecWriter::TryWriteInt(int i)
2587 {
2588 char tmp[256];
2589
2590 sprintf(tmp,"%d",i);
2591 TryWriteString(tmp);
2592 }
2593
2594
TryWriteDouble(double d)2595 void emRecWriter::TryWriteDouble(double d)
2596 {
2597 char tmp[256];
2598
2599 sprintf(tmp,"%.9G",d);
2600 if (!strchr(tmp,'.') && !strchr(tmp,'E') && !strchr(tmp,'e')) {
2601 strcat(tmp,".0");
2602 }
2603 TryWriteString(tmp);
2604 }
2605
2606
TryWriteQuoted(const char * q)2607 void emRecWriter::TryWriteQuoted(const char * q)
2608 {
2609 char c;
2610
2611 TryWriteChar('"');
2612 for (;;) {
2613 c=*q++;
2614 if (!c) break;
2615 if (c>=0x20 && c<=0x7e) {
2616 if (c=='"' || c=='\\') TryWriteChar('\\');
2617 TryWriteChar(c);
2618 }
2619 else if (((unsigned char)c)>=0xa0) {
2620 TryWriteChar(c);
2621 }
2622 else if (c=='\a') TryWriteString("\\a");
2623 else if (c=='\b') TryWriteString("\\b");
2624 else if (c=='\f') TryWriteString("\\f");
2625 else if (c=='\n') TryWriteString("\\n");
2626 else if (c=='\r') TryWriteString("\\r");
2627 else if (c=='\t') TryWriteString("\\t");
2628 else if (c=='\v') TryWriteString("\\v");
2629 else {
2630 TryWriteChar('\\');
2631 TryWriteChar((char)(((c>>6)&7)+'0'));
2632 TryWriteChar((char)(((c>>3)&7)+'0'));
2633 TryWriteChar((char)(( c &7)+'0'));
2634 }
2635 }
2636 TryWriteChar('"');
2637 }
2638
2639
TryWriteSpace()2640 void emRecWriter::TryWriteSpace()
2641 {
2642 TryWriteChar(' ');
2643 }
2644
2645
TryWriteNewLine()2646 void emRecWriter::TryWriteNewLine()
2647 {
2648 TryWriteChar('\n');
2649 }
2650
2651
TryWriteIndent()2652 void emRecWriter::TryWriteIndent()
2653 {
2654 int i;
2655
2656 for (i=0; i<Indent; i++) TryWriteChar('\t');
2657 }
2658
2659
TryWriteChar(char c)2660 void emRecWriter::TryWriteChar(char c)
2661 {
2662 TryWrite(&c,1);
2663 }
2664
2665
TryWriteString(const char * s)2666 void emRecWriter::TryWriteString(const char * s)
2667 {
2668 TryWrite(s,strlen(s));
2669 }
2670
2671
2672 //==============================================================================
2673 //============================== emRecFileReader ===============================
2674 //==============================================================================
2675
emRecFileReader()2676 emRecFileReader::emRecFileReader()
2677 {
2678 File=NULL;
2679 FileSize=0;
2680 FilePos=0;
2681 }
2682
2683
~emRecFileReader()2684 emRecFileReader::~emRecFileReader()
2685 {
2686 if (File) fclose(File);
2687 }
2688
2689
TryStartReading(emRec & root,const emString & filePath)2690 void emRecFileReader::TryStartReading(
2691 emRec & root, const emString & filePath
2692 )
2693 {
2694 emInt64 l;
2695
2696 if (File) {
2697 fclose(File);
2698 File=NULL;
2699 }
2700
2701 FilePath=filePath;
2702
2703 File=fopen(FilePath.Get(),"rb");
2704 if (!File) goto Err;
2705 l=fseek(File,0,SEEK_END);
2706 if (l) goto Err;
2707 l=ftell(File);
2708 if (l<0) goto Err;
2709 FileSize=l;
2710 l=fseek(File,0,SEEK_SET);
2711 if (l) goto Err;
2712
2713 FilePos=0;
2714
2715 emRecReader::TryStartReading(root);
2716
2717 return;
2718
2719 Err:
2720 if (File) {
2721 fclose(File);
2722 File=NULL;
2723 }
2724 throw emException(
2725 "Failed to read \"%s\": %s",
2726 FilePath.Get(),
2727 emGetErrorText(errno).Get()
2728 );
2729 }
2730
2731
GetProgress() const2732 double emRecFileReader::GetProgress() const
2733 {
2734 if (!File || !FileSize) return 0.0;
2735 if (FilePos>=FileSize) return 100.0;
2736 return ((double)FilePos)*100.0/FileSize;
2737 }
2738
2739
TryRead(char * buf,int maxLen)2740 int emRecFileReader::TryRead(char * buf, int maxLen)
2741 {
2742 size_t sz;
2743 int len;
2744
2745 if (!File) return 0;
2746 len=0;
2747 do {
2748 sz=fread(buf+len,1,maxLen-len,File);
2749 if (ferror(File)) {
2750 throw emException(
2751 "Failed to read \"%s\": %s",
2752 FilePath.Get(),
2753 emGetErrorText(errno).Get()
2754 );
2755 }
2756 len+=sz;
2757 } while (len<maxLen && !feof(File));
2758 FilePos+=len;
2759 return len;
2760 }
2761
2762
TryClose()2763 void emRecFileReader::TryClose()
2764 {
2765 int i;
2766
2767 if (!File) return;
2768 i=fclose(File);
2769 File=NULL;
2770 if (i!=0) {
2771 throw emException(
2772 "Failed to read \"%s\": %s",
2773 FilePath.Get(),
2774 emGetErrorText(errno).Get()
2775 );
2776 }
2777 }
2778
2779
GetSourceName() const2780 const char * emRecFileReader::GetSourceName() const
2781 {
2782 return FilePath.Get();
2783 }
2784
2785
2786 //==============================================================================
2787 //============================== emRecFileWriter ===============================
2788 //==============================================================================
2789
emRecFileWriter()2790 emRecFileWriter::emRecFileWriter()
2791 {
2792 File=NULL;
2793 }
2794
2795
~emRecFileWriter()2796 emRecFileWriter::~emRecFileWriter()
2797 {
2798 if (File) fclose(File);
2799 }
2800
2801
TryStartWriting(emRec & root,const emString & filePath)2802 void emRecFileWriter::TryStartWriting(emRec & root, const emString & filePath)
2803 {
2804 if (File) {
2805 fclose(File);
2806 File=NULL;
2807 }
2808 FilePath=filePath;
2809 File=fopen(FilePath.Get(),"wb");
2810 if (!File) {
2811 throw emException(
2812 "Failed to open \"%s\" for writing: %s",
2813 FilePath.Get(),
2814 emGetErrorText(errno).Get()
2815 );
2816 }
2817 emRecWriter::TryStartWriting(root);
2818 }
2819
2820
TryWrite(const char * buf,int len)2821 void emRecFileWriter::TryWrite(const char * buf, int len)
2822 {
2823 size_t sz;
2824
2825 if (!File) return;
2826 do {
2827 sz=fwrite(buf,1,len,File);
2828 if (ferror(File)) {
2829 throw emException(
2830 "Failed to write \"%s\": %s",
2831 FilePath.Get(),
2832 emGetErrorText(errno).Get()
2833 );
2834 }
2835 len-=sz;
2836 buf+=sz;
2837 } while (len>0);
2838 }
2839
2840
TryClose()2841 void emRecFileWriter::TryClose()
2842 {
2843 int i;
2844
2845 if (!File) return;
2846 i=fclose(File);
2847 File=NULL;
2848 if (i!=0) {
2849 throw emException(
2850 "Failed to write \"%s\": %s",
2851 FilePath.Get(),
2852 emGetErrorText(errno).Get()
2853 );
2854 }
2855 }
2856
2857
2858 //==============================================================================
2859 //=============================== emRecMemReader ===============================
2860 //==============================================================================
2861
emRecMemReader()2862 emRecMemReader::emRecMemReader()
2863 {
2864 MemPos=NULL;
2865 MemEnd=NULL;
2866 }
2867
2868
TryStartReading(emRec & root,const char * buf,int len)2869 void emRecMemReader::TryStartReading(emRec & root, const char * buf, int len)
2870 {
2871 MemPos=buf;
2872 MemEnd=buf+len;
2873 emRecReader::TryStartReading(root);
2874 }
2875
2876
TryRead(char * buf,int maxLen)2877 int emRecMemReader::TryRead(char * buf, int maxLen)
2878 {
2879 int len;
2880
2881 len=MemEnd-MemPos;
2882 if (len>maxLen) len=maxLen;
2883 if (len>0) {
2884 memcpy(buf,MemPos,len);
2885 MemPos+=len;
2886 }
2887 return len;
2888 }
2889
2890
TryClose()2891 void emRecMemReader::TryClose()
2892 {
2893 MemPos=NULL;
2894 MemEnd=NULL;
2895 }
2896
2897
GetSourceName() const2898 const char * emRecMemReader::GetSourceName() const
2899 {
2900 return "rec memory buffer";
2901 }
2902
2903
2904 //==============================================================================
2905 //=============================== emRecMemWriter ===============================
2906 //==============================================================================
2907
emRecMemWriter()2908 emRecMemWriter::emRecMemWriter()
2909 {
2910 Buf=NULL;
2911 }
2912
2913
~emRecMemWriter()2914 emRecMemWriter::~emRecMemWriter()
2915 {
2916 }
2917
2918
TryStartWriting(emRec & root,emArray<char> & buf)2919 void emRecMemWriter::TryStartWriting(emRec & root, emArray<char> & buf)
2920 {
2921 Buf=&buf;
2922 emRecWriter::TryStartWriting(root);
2923 }
2924
2925
TryWrite(const char * buf,int len)2926 void emRecMemWriter::TryWrite(const char * buf, int len)
2927 {
2928 if (!Buf) return;
2929 Buf->Add(buf,len);
2930 }
2931
2932
TryClose()2933 void emRecMemWriter::TryClose()
2934 {
2935 Buf=NULL;
2936 }
2937