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