cfl_token.cpp
Go to the documentation of this file.
1/** @file cfl_token.cpp @brief Class Token */
2
3/* FAU Discrete Event Systems Library (libfaudes)
4
5Copyright (C) 2006 Bernd Opitz
6Copyright (C) 2006, 2010, 2024 Thomas Moor
7Exclusive copyright is granted to Klaus Schmidt
8
9This library is free software; you can redistribute it and/or
10modify it under the terms of the GNU Lesser General Public
11License as published by the Free Software Foundation; either
12version 2.1 of the License, or (at your option) any later version.
13
14This library is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public
20License along with this library; if not, write to the Free Software
21Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23
24#include "cfl_token.h"
25
26namespace faudes {
27
28
29// Token::Token()
31 mType(None),
32 mStringValue(""),
33 mOptionValue(""),
34 mIntegerValue(0),
35 mFloatValue(0),
36 mPreceedingSpace(""),
37 mAttributeCount(0)
38{
39}
40
41// copy construct
42Token::Token(const Token& rToken) :
43 mType(rToken.mType),
44 mStringValue(rToken.mStringValue),
45 mOptionValue(rToken.mOptionValue),
46 mIntegerValue(rToken.mIntegerValue),
47 mFloatValue(rToken.mFloatValue),
48 mPreceedingSpace(rToken.mPreceedingSpace),
49 mAttributes(rToken.mAttributes),
50 mAttributeCount(rToken.mAttributeCount)
51{
52}
53
54
55// assignment
56Token& Token::operator=(const Token& rToken) {
57 mType=rToken.mType;
65 return *this;
66}
67
68// destructor
70}
71
72// Token::SetNone()
73void Token::SetNone(void ) {
74 mType=None;
75 mStringValue="";
76 mOptionValue="";
79 mAttributes.clear();
82}
83
84// Token::SetString(str)
85void Token::SetString(const std::string& rName) {
86 SetNone();
88 mStringValue=rName;
89}
90
91// Token::SetBegin(str)
92void Token::SetBegin(const std::string& rName) {
93 SetNone();
94 mType=Begin;
95 mStringValue=rName;
96}
97
98// Token::SetEnd(str)
99void Token::SetEnd(const std::string& rName) {
100 SetNone();
101 mType=End;
102 mStringValue=rName;
103}
104
105// Token::SetEmpty(str)
106void Token::SetEmpty(const std::string& rName) {
107 SetNone();
108 mType=End | Begin;
109 mStringValue=rName;
110}
111
112// Token::SetOption(str)
113void Token::SetOption(const std::string& rName) {
114 SetNone();
116 mStringValue="+"+rName+"+";
117 mOptionValue=rName;
118}
119
120// Token::SetInteger(number)
121void Token::SetInteger(const Int number) {
122 SetNone();
124 mIntegerValue=number;
125 mFloatValue=number;
126}
127
128// Token::SetInteger16(number)
129void Token::SetInteger16(const Int number) {
130 SetNone();
132 mIntegerValue=number;
133 mFloatValue=number;
134}
135
136// Token::SetBoolean(number)
137void Token::SetBoolean(const Int number) {
138 SetNone();
140 mIntegerValue=number;
141 mFloatValue=number;
142}
143
144// Token::SetFloat(number)
145void Token::SetFloat(const faudes::Float number) {
146 SetNone();
147 mType=Float;
148 mIntegerValue=(Int) number;
149 mFloatValue=number;
150}
151
152// Token::SetBinary
153void Token::SetBinary(const char* data, std::size_t len) {
154 SetNone();
156 mStringValue.assign(data,len);
157}
158
159
160// Token::ClrEnd()
161void Token::ClrEnd(void) {
162 mType&= ~End;
163}
164
165
166// access integer
168 return(mIntegerValue);
169}
170
171
172// access float
174 return(mFloatValue);
175}
176
177// access string
178const std::string& Token::StringValue(void) const {
179 if(mType & Option) return(mOptionValue); // compatibility
180 return(mStringValue);
181}
182
183// access option
184const std::string& Token::OptionValue(void) const {
185 return(mOptionValue);
186}
187
188// access raw data
189const std::string& Token::PreceedingSpace(void) const {
190 return mPreceedingSpace;
191}
192
193// access raw data
194void Token::PreceedingSpace(const std::string& sep) {
196}
197
198// access unique type (depreciated!)
200 if(mType & Begin) return Begin;
201 if(mType & End) return End;
202 if(mType & Integer16) return Integer16;
203 if(mType & Boolean) return Boolean;
204 if(mType & Integer) return Integer;
205 if(mType & Float) return Float;
206 if(mType & Option) return Option;
207 if(mType & Binary) return Binary;
208 if(mType & String) return String;
209 return None;
210}
211
212
213// test type
214bool Token::IsNone(void) const {
215 return mType == None;
216}
217
218// test type
219bool Token::IsInteger(void) const {
220 return mType & Integer;
221}
222
223// test type
224bool Token::IsInteger16(void) const {
225 return mType & Integer16;
226}
227
228// test type
229bool Token::IsBoolean(void) const {
230 return mType & Boolean;
231}
232
233// test type
234bool Token::IsFloat(void) const {
235 return mType & Float;
236}
237
238// test type
239bool Token::IsOption(void) const {
240 return mType & Option;
241}
242
243// test type
244bool Token::IsString(void) const {
245 return mType & String;
246}
247
248// test type
249bool Token::IsBinary(void) const {
250 return mType & Binary;
251}
252
253// test type
254bool Token::IsCdata(void) const {
255 return mType & Cdata;
256}
257
258// test type
259bool Token::IsBegin(void) const {
260 return mType & Begin;
261}
262
263// test type
264bool Token::IsBegin(const std::string& tag) const {
265 if(! (mType & Begin) ) return false;
266 return mStringValue==tag;
267}
268
269// test type
270bool Token::IsEnd(void) const {
271 return mType & End;
272}
273
274// test type
275bool Token::IsEnd(const std::string& tag) const {
276 if(! (mType & End) ) return false;
277 return mStringValue==tag;
278}
279
280// test type
281bool Token::IsEmpty(void) const {
282 return (mType & Begin) && (mType & End);
283}
284
285// clear attribute
286void Token::ClrAttribute(const std::string& name) {
287 aiterator ait=mAttributes.find(name);
288 if(ait==mAttributes.end()) return;
289 mAttributes.erase(ait);
290}
291
292// clear all attributes
294 mAttributes.clear();
296}
297
298
299// insert attribute for interpretation
300void Token::InsAttribute(const std::string& name, const std::string& value) {
301 AttributeValue aval;
302 aval.mStringValue=value;
303 aval.mType=None;
304 aval.mSort=mAttributeCount++;
305 mAttributes[name]=aval;
306}
307
308
309// insert string attribute
310void Token::InsAttributeString(const std::string& name, const std::string& value) {
311 AttributeValue aval;
312 aval.mStringValue=value;
313 aval.mType=String;
314 aval.mSort=mAttributeCount++;
315 mAttributes[name]=aval;
316}
317
318// insert integer attribute
319void Token::InsAttributeInteger(const std::string& name, Int value) {
320 AttributeValue aval;
321 aval.mStringValue=ToStringInteger(value);
322 aval.mType=Float | Integer;
323 aval.mSort=mAttributeCount++;
324 mAttributes[name]=aval;
325}
326
327// insert integer attribute
328void Token::InsAttributeInteger16(const std::string& name, Int value) {
329 AttributeValue aval;
331 aval.mType=Float | Integer;
332 aval.mSort=mAttributeCount++;
333 mAttributes[name]=aval;
334}
335
336// insert integer attribute
337void Token::InsAttributeBoolean(const std::string& name, Int value) {
338 AttributeValue aval;
339 if(value==0) aval.mStringValue="false";
340 else aval.mStringValue="true";
341 aval.mType=Float | Integer;
342 aval.mSort=mAttributeCount++;
343 mAttributes[name]=aval;
344}
345
346// insert float attribute
347void Token::InsAttributeFloat(const std::string& name, faudes::Float value) {
348 AttributeValue aval;
349 aval.mStringValue=ToStringFloat(value);
350 aval.mType=Float;
351 aval.mSort=mAttributeCount++;
352 mAttributes[name]=aval;
353}
354
355// test attribute type
356bool Token::ExistsAttributeString(const std::string& name) {
357 aiterator ait=mAttributes.find(name);
358 if(ait==mAttributes.end()) return false;
360 if(ait->second.mType & String) return true;
361 return false;
362}
363
364
365// test attribute type
366bool Token::ExistsAttributeInteger(const std::string& name) {
367 aiterator ait=mAttributes.find(name);
368 if(ait==mAttributes.end()) return false;
370 if(ait->second.mType & Integer) return true;
371 return false;
372}
373
374
375// test attribute type
376bool Token::ExistsAttributeFloat(const std::string& name) {
377 aiterator ait=mAttributes.find(name);
378 if(ait==mAttributes.end()) return false;
380 if(ait->second.mType & Float) return true;
381 return false;
382}
383
384
385// access attribute value
386const std::string& Token::AttributeStringValue(const std::string& name) {
387 static const std::string emptystr="";
388 aiterator ait=mAttributes.find(name);
389 if(ait==mAttributes.end()) return emptystr;
391 if(!(ait->second.mType & String)) return emptystr;
392 return ait->second.mStringValue;
393}
394
395
396// access attribute value
397Int Token::AttributeIntegerValue(const std::string& name) {
398 aiterator ait=mAttributes.find(name);
399 if(ait==mAttributes.end()) return 0;
401 if(!(ait->second.mType & Integer)) return 0;
402 return ait->second.mIntegerValue;
403}
404
405
406// access attribute value
408 aiterator ait=mAttributes.find(name);
409 if(ait==mAttributes.end()) return 0;
411 if(!(ait->second.mType & Float)) return 0;
412 return ait->second.mFloatValue;
413}
414
415
416// WriteVerbatim(pStream)
417 void Token::WriteVerbatim(std::ostream* pStream, const std::string& rData, bool lfflag) {
418 // markup
419 *pStream << "<![CDATA[";
420 // optional preceeding linefeed
421 if(lfflag) *pStream << std::endl;
422 // split up cdata sections
423 std::string esc="]]>";
424 std::size_t pos=0;
425 // loop segments
426 while(pos < rData.size()) {
427 std::size_t next= rData.find(esc,pos);
428 if(next==std::string::npos) next=rData.size()+1;
429 // write segment
430 *pStream << rData.substr(pos,next-pos);
431 // write split
432 if(next<=rData.size())
433 *pStream << "]]]]><![CDATA[>";
434 // proceed
435 pos=next+3;
436 }
437 // optional post linefeed
438 if(lfflag) *pStream << std::endl;
439 // markup
440 *pStream << "]]>";
441}
442
443
444
445// WriteBinary(pStream,data,len)
446 void Token::WriteBinary(std::ostream* pStream, const char* pData, std::size_t len) {
447
448 // my encoding (hardcoded in read, however)
449 static char Base64EncodingTable[]=
450 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
451
452 // start
453 *pStream << "=";
454
455 // loop vars
456 const char* src = pData;
457 std::size_t cnt=len;
458 int step=0;
459 unsigned char c0=0,c1=0,c2=0,c3=0;
460
461 // encode and output buffer
462 while(cnt>0) {
463 switch(step) {
464 // collect char for 1st byte
465 case 0:
466 c0= ((*src & 0xFC) >> 2);
467 c1= ((*src & 0x03) << 4);
468 c2=0;
469 c3=0;
470 step=1;
471 break;
472 // collect char for 2nd byte
473 case 1:
474 c1|= ((*src & 0xF0) >> 4);
475 c2|= ((*src & 0x0F) << 2);
476 step=2;
477 break;
478 // collect char for 3rd byte, plus output
479 case 2:
480 c2|= ((*src & 0xC0) >> 6);
481 c3|= (*src & 0x3F);
482 *pStream << Base64EncodingTable[c0] << Base64EncodingTable[c1] <<
483 Base64EncodingTable[c2] << Base64EncodingTable[c3];
484 step=0;
485 break;
486 default: break;
487 }
488 cnt--;
489 src++;
490 }
491 // flush left overs, incl padding
492 switch(step) {
493 case 0:
494 *pStream << "= ";
495 break;
496 case 1:
497 *pStream << Base64EncodingTable[c0] << Base64EncodingTable[c1] << "=== ";
498 break;
499 case 2:
500 *pStream << Base64EncodingTable[c0] << Base64EncodingTable[c1] <<
501 Base64EncodingTable[c2] << "== ";
502 break;
503 }
504}
505
506// WriteBinary(pStream)
507void Token::WriteBinary(std::ostream* pStream) const {
508 if(mType!=Binary) return;
509 WriteBinary(pStream,mStringValue.data(),mStringValue.size());
510}
511
512
513// ReadBinary ... to mStringValue
514int Token::ReadBinary(std::istream* pStream) {
515
516 // line count
517 int lc;
518
519 // swallow leading '='
520 char c1=pStream->get();
521 if(c1!='=') return -1;
522
523 // read as string, excl. marks '='
524 lc=ReadString(pStream,'=');
525
526 // swallow one trailing '='
527 c1=pStream->get();
528 if(c1!='=') return -1;
529
530 // take any extra trailing padding =
531 while(!pStream->eof()) {
532 if(pStream->peek()!='=') break;
533 pStream->get();
534 mStringValue.append("=");
535 }
536
537 // loop vars
538 std::string::iterator src=mStringValue.begin();
539 std::string::iterator dst=mStringValue.begin();
540 std::size_t cnt=0;
541 int c=0, d0=0, d1=0, d2=0;
542 unsigned char cs[4];
543 unsigned int step=0;
544
545 // loop
546 while(true) {
547
548 // get data
549 while(true) {
550 // sense eof
551 if(src==mStringValue.end()) { c = -1; break; }
552 // get char
553 c=*(src++);
554 // decode
555 if(c>='A' && c <='Z') { c-='A'; break; }
556 if(c>='a' && c <='z') { c-='a'; c+= ('Z'-'A')+1; break; }
557 if(c>='0' && c <='9') { c-='0'; c+= 2*('Z'-'A')+2; break; }
558 if(c=='+') {c= 62; break; }
559 if(c=='/') {c= 63; break; }
560 if(c=='=') {c= 0xFF; break; };
561 }
562 // pass on eof
563 if(c== -1) break;
564 // record and continue
565 cs[step++] = c;
566 if(step<=3) continue;
567 step=0;
568 // sort bits
569 d0= ((cs[0] << 2) & 0xFC) | ((cs[1] >> 4) & 0x03);
570 d1= ((cs[1] << 4) & 0xF0) | ((cs[2] >> 2) & 0x0F);
571 d2= ((cs[2] << 6) & 0xC0) | (cs[3] & 0x3F);
572 // record result
573 if(cs[0]!= 0xFF && cs[1]!=0xFF) {*(dst++)=d0; cnt++;}
574 if(cs[1]!= 0xFF && cs[2]!=0xFF) {*(dst++)=d1; cnt++;}
575 if(cs[2]!= 0xFF && cs[3]!=0xFF) {*(dst++)=d2; cnt++;}
576 // sense end
577 if(cs[3]==0xFF) break;
578 }
579
580 // set data length (sets the length incl termination char??)
581 mStringValue.resize(cnt);
582
583 // return padding error or line count
584 return step==0 ? lc : -1;
585}
586
587
588
589// ReadSpace(pStream)
590int Token::ReadSpace(std::istream* pStream, bool fcomments){
591 char c = '\0';
592 int lc = 0;
593 FD_DV("Token::ReadSpace()");
594 // check the whole pStream
595 while(*pStream) {
596 // swallow white space
597 while(*pStream) {
598 // check eof
599 if(pStream->eof()) return lc;
600 // look one character ahead
601 c = pStream->peek();
602 // count the next lines
603 if(c == '\n') {
604 ++lc;
605 pStream->get();
606 mPreceedingSpace.append(1,c);
607 continue;
608 }
609 // swallow controls
610 if(iscntrl(c)) {
611 pStream->get();
612 mPreceedingSpace.append(1,c);
613 continue;
614 }
615 // swallow space
616 if(isspace(c)) {
617 pStream->get();
618 mPreceedingSpace.append(1,c);
619 continue;
620 }
621 // regard this non-white
622 break;
623 }
624 // if the next character starts a faudes comment
625 if(!fcomments) break;
626 if(c != '%') break;
627 while(*pStream) {
628 // check eof
629 if(pStream->eof()) {return(lc);};
630 // get the next character
631 c = pStream->get();
632 // count the next lines
633 if (c == '\n') ++lc;
634 // terminate with the next new line character
635 if (c == '\n') break;
636 if (c == '\r') break;
637 }
638 }
639 // termination if the next character is neither a space, a control, or a '%'.
640 FD_DV("Token::ReadSpace(): lc " << lc << " c " << c);
641 return lc;
642}
643
644// InterpretAttribute(aval)
646 if(ait->second.mType != None) return;
648 ait->second.mStringValue, ait->second.mType,
649 ait->second.mIntegerValue, ait->second.mFloatValue);
650 ait->second.mType |= String;
651}
652
653// InterpretNumber(string)
657
658// InterpretNumber(string, ...)
659bool Token::InterpretNumber(const std::string& numstr, int& type, Int& ival, faudes::Float& fval) {
660 char c, vc;
661 faudes::Float fv=0;
662 Int iv=0;
663 int comma = -1;
664 bool minus = false;
665 int base=10;
666 bool ok=false;
667 int cnt=0;
668 type &= ~(Integer | Integer16 | Float);
669 // test for special cases
670 if(numstr=="inf" || numstr=="+inf") {
671 ival = std::numeric_limits<Int>::max();
672 fval = std::numeric_limits<faudes::Float>::max();
673 type|= (Integer | Float);
674 return true;
675 }
676 // test for special casess
677 if(numstr=="-inf") {
678 ival=std::numeric_limits<Int>::min()+1;
679 fval = -1* std::numeric_limits<faudes::Float>::max();
680 type|= (Integer | Float);
681 return true;
682 }
683 // test for special cases
684 if(numstr=="true" || numstr=="True") {
685 ival = 1;
686 fval = ival;
687 type|= (Integer | Boolean);
688 return true;
689 }
690 // test for special cases
691 if(numstr=="false" || numstr=="False") {
692 ival = 0;
693 fval = ival;
694 type|= (Integer | Boolean);
695 return true;
696 }
697 // iterate over string
698 std::string::const_iterator cit=numstr.begin();
699 for(;cit!=numstr.end(); cit++) {
700 // check next charakter
701 c = *cit;
702 cnt++;
703 // change base on x
704 if(c=='x' && iv==0 && cnt==2 && comma<0 && !minus)
705 {base = 16; continue;}
706 // change sign on -
707 if(c=='-' && cnt==1)
708 {minus = true; continue;}
709 // record comma
710 if(c=='.' && comma<0 && base==10)
711 {comma = 0; continue;}
712 // break if it is not a digit
713 if(!isdigit(c) && base==10) break;
714 if(!isxdigit(c) && base==16) break;
715 // compute the value of c
716 vc=0;
717 if(c>='0' && c<= '9') vc = c-'0';
718 else if(c>='a' && c<= 'f') vc = c-'a' + 10;
719 else if(c>='A' && c<= 'F') vc = c-'A' + 10;
720 // compute the corresponding number
721 iv = base * iv + vc;
722 fv = base * fv + vc;
723 if(comma>=0) comma++;
724 ok = true;
725 }
726 // detect error
727 if(cit!=numstr.end()) ok=false;
728 // fix sign
729 if(minus) {
730 iv=-iv;
731 fv=-fv;
732 }
733 // fix decimal point
734 for(;comma>0;comma--) {
735 iv/=base;
736 fv/=base;
737 }
738 // assign the numeric value and type in Token
739 if(ok) {
740 ival = iv;
741 fval = fv;
742 type |= Float;
743 if(comma<=0 && !minus) type |= Integer;
744 if(comma<=0 && !minus && base==16) type |= Integer16;
745 }
746 return ok;
747}
748
749// Write(pStream)
750void Token::Write(std::ostream* pStream) const {
751 FD_DV("Token::Write: mType=" << (int) mType
752 << "\" mStringValue=\"" << mStringValue
753 << "\" mIntegerValue=" <<mIntegerValue
754 << "\" mFloatValue=" <<mFloatValue <<"\n");
755 // numerics first
756 if(mType & Integer16) {
758 } else if(mType & Integer) {
760 } else if(mType & Float) {
761 *pStream << ExpandString(ToStringFloat(mFloatValue), FD_NAMELEN) << " ";
762 }
763 // mark up: begin
764 else if(mType & Begin) {
765 *pStream << '<' << mStringValue;
766 std::map<int,caiterator> sortnames;
767 for(caiterator ait=mAttributes.begin(); ait!=mAttributes.end(); ait++)
768 sortnames[ait->second.mSort]=ait;
769 std::map<int,caiterator>::iterator sit;
770 for(sit=sortnames.begin(); sit!=sortnames.end(); sit++) {
771 caiterator ait=sit->second;
772 *pStream << " ";
773 WriteEscapedString(pStream,ait->first);
774 *pStream << "=\"";
775 WriteEscapedString(pStream,ait->second.mStringValue);
776 *pStream << "\"";
777 }
778 if(mType & End) *pStream << "/";
779 *pStream << ">";
780 }
781 // mark up:end
782 else if(mType & End) {
783 *pStream << "</" << mStringValue << ">";
784 }
785 // cdata markup
786 else if(mType & Cdata) {
788 }
789 // string
790 else if(mType & Option) {
791 WriteString(pStream,""); // '+' is incl. mStringValue
792 } else if(mType & Binary) {
793 WriteBinary(pStream);
794 } else if(mType & String) {
795 // figure delimiter
796 bool quote=false;
797 if(mStringValue.size()==0) quote=true;
798 if(mStringValue.size()>0)
799 if(!isalpha(mStringValue[0])) quote=true;
800 static const std::string white=" \n\r\t\f";
801 if(mStringValue.find_first_of(white)!=std::string::npos)
802 quote=true;
803 if(quote)
804 WriteString(pStream,"\"");
805 else
806 WriteString(pStream,"");
807 }
808 // error (should we have an exception here?)
809 else { /* assert(0) */ };
810}
811
812// WriteEscapedString(pStream)
813int Token::WriteEscapedString(std::ostream* pStream, const std::string& outstr) {
814 // assemble escape character string
815 std::string escstr="<>&\"";
816 // no escape characters
817 if(outstr.find_first_of(escstr)==std::string::npos) {
818 *pStream << outstr;
819 return outstr.size();
820 }
821 // do escape substitution
822 int cc=0;
823 std::string::const_iterator cit=outstr.begin();
824 for(;cit!=outstr.end(); cit++) {
825 if(*cit=='<')
826 { *pStream << "&lt;"; cc+=4; continue;}
827 if(*cit=='>')
828 { *pStream << "&gt;"; cc+=4; continue;}
829 if(*cit=='&')
830 { *pStream << "&amp;"; cc+=5; continue;}
831 if(*cit=='"')
832 { *pStream << "&quot;"; cc+=6; continue;}
833 *pStream << *cit; cc++;
834 }
835 return cc;
836}
837
838// WriteString(pStream, delim)
839void Token::WriteString(std::ostream* pStream, const std::string& delim) const {
840 int cc=0;
841 *pStream << delim;
842 cc+=delim.size();
843 cc+=WriteEscapedString(pStream,mStringValue);
844 *pStream << delim << " ";
845 cc+=delim.size()+1;
846 while(cc< FD_NAMELEN) {
847 *pStream << " "; cc++;
848 }
849}
850
851// ReadString(pStream, char)
852int Token::ReadString(std::istream* pStream, char stop) {
853 return ReadEscapedString(pStream,stop,mStringValue);
854}
855
856
857// ReadEscapedString(pStream, rString, char)
858int Token::ReadEscapedString(std::istream* pStream, char stop, std::string& rString) {
859 int lc=0;
860 char c;
861 std::string entref="";
862 bool ctrlblank = false;
863 rString = "";
864 // check the whole pStream
865 while (*pStream) {
866 // check eof
867 if(pStream->eof()) return -1;
868 // test one character
869 c = pStream->peek();
870 // break on mark up
871 if(c == '<') break;
872 if(c == '>') break;
873 // break on stop
874 if(c == stop) break;
875 if(isblank(c) && stop==' ') break;
876 if(iscntrl(c) && stop==' ') break;
877 // get one character
878 c = pStream->get();
879 // count the next lines
880 if(c=='\n') ++lc;
881 // replace sequence of control characters by one blank
882 if(iscntrl(c) && ctrlblank) continue;
883 ctrlblank=false;
884 if(iscntrl(c)) { c=' '; ctrlblank=true;}
885 // if in escape mode ...
886 if(entref.size()!=0) {
887 //record reference
888 entref.append(1,c);
889 // error: reference must not contain a white space
890 if(c == ' ') return -1;
891 // decode reference
892 if(c == ';') {
893 if(entref=="&amp;") rString.append(1,'&');
894 else if(entref=="&quot;") rString.append(1,'"');
895 else if(entref=="&apos;") rString.append(1,'\'');
896 else if(entref=="&lt;") rString.append(1,'<');
897 else if(entref=="&gt;") rString.append(1,'>');
898 // plain copy unknown
899 else rString.append(entref);
900 entref="";
901 }
902 continue;
903 }
904 // ... sense escape
905 if(c == '&') entref.append(1,c);
906 // ... add character
907 if(c != '&') rString.append(1,c);
908 continue;
909 }
910 // report
911 FD_DV("Token::ReadEscapedString(): lc=" << lc << " val=" << rString);
912 // space seperated string must be nontrivial
913 if(stop==' ' && rString.size()==0) return -1;
914 return lc;
915}
916
917
918// ReadCharacterData(pStream, rString)
919int Token::ReadCharacterData(std::istream* pStream, std::string& rString, bool fcomments) {
920 rString = "";
921 // special case
922 if(pStream->eof()) return 0;
923 // check the whole pStream
924 int lc=0;
925 char c;
926 bool cm = false;
927 while (*pStream) {
928 // check other errors
929 if(!pStream->good()) { rString="I/O error"; return -1; }
930 // test one character
931 c = pStream->peek();
932 // break on eof
933 if(pStream->eof()) break;
934 // sense error: markup in faudes comment
935 if(fcomments && cm)
936 if((c=='<') || (c=='>')) { rString="'<' or '>' in faudes comment"; return -1; }
937 // break on mark up
938 if(c == '<') break;
939 // again: test state (peek may set eof, so dont use good() here)
940 if(pStream->bad()) { rString="I/O error"; return -1; }
941 // get one character
942 c = pStream->get();
943 // count the next lines
944 if(c=='\n') ++lc;
945 // track faudes comment mode
946 if(c=='%') cm=true;
947 if(c=='\n') cm=false;
948 // ... add character
949 if(!(fcomments && cm))
950 rString.append(1,c);
951 }
952 return lc;
953}
954
955
956// ReadAttributes(pStream)
957// (and swallow all space after the last attribute)
958int Token::ReadAttributes(std::istream* pStream) {
959 int lc=0;
960 char c=0;
961 FD_DV("Token::ReadAttributes()");
962 // scan until excl. '>'
963 while (*pStream) {
964 // skip space
965 while (*pStream) {
966 if(pStream->eof()) return -1;
967 c = pStream->peek();
968 if(!(isblank(c) || iscntrl(c))) break;
969 pStream->get();
970 if(c=='\n') ++lc;
971 }
972 // get attrname
973 std::string aname;
974 while (*pStream) {
975 if(pStream->eof()) return -1;
976 c = pStream->peek();
977 if(isblank(c) || iscntrl(c)) break;
978 if(c=='=') break;
979 if(c=='>') break;
980 if(c=='/') break;
981 pStream->get();
982 aname.append(1,c);
983 }
984 FD_DV("Token::ReadAttributes(): aname " << aname);
985 // no name so we're done
986 if(aname.size()==0) {
987 return lc;
988 }
989 // skip space
990 while(*pStream) {
991 if(pStream->eof()) return -1;
992 c = pStream->peek();
993 if(!(isblank(c) || iscntrl(c))) break;
994 pStream->get();
995 if(c=='\n') ++lc;
996 }
997 // insist in eq
998 if(c!='=') return -1;
999 pStream->get();
1000 // skip space
1001 while (*pStream) {
1002 if(pStream->eof()) return -1;
1003 c = pStream->peek();
1004 if(!(isblank(c) || iscntrl(c))) break;
1005 pStream->get();
1006 if(c=='\n') ++lc;
1007 }
1008 // strict version, value by '"'
1009 if(c == '"') {
1010 pStream->get();
1011 int ll=ReadString(pStream,'"');
1012 if(ll<0) return -1;
1013 pStream->get();
1014 lc+=ll;
1015 }
1016 // strict version, value by '''
1017 else if(c == '\'') {
1018 pStream->get();
1019 int ll=ReadString(pStream,'\'');
1020 if(ll<0) return -1;
1021 pStream->get();
1022 lc+=ll;
1023 }
1024 // relaxed version, value by "space"
1025 else {
1026 int ll=ReadString(pStream,' ');
1027 if(ll<0) return -1;
1028 lc+=ll;
1029 }
1030 std::string aval=mStringValue;
1031 FD_DV("Token::ReadAttributes(): aval " << aval);
1032 // record attribute
1033 InsAttribute(aname,aval);
1034 }
1035 // done
1036 return lc;
1037}
1038
1039// ReadMarkup(pStream)
1040// (leading "<" has allready been read)
1041int Token::ReadMarkup(std::istream* pStream) {
1042 int lc=0;
1043 int ll;
1044 char c=0;
1045 mStringValue = "";
1046 mType=None;
1047 // figure indicator character
1048 char p1=0;
1049 char p2=0;
1050 if(pStream->eof()) return -1;
1051 c = pStream->peek();
1052 if(!(isalpha(c) || c=='_' || c==':')) {
1053 p1 = pStream->get();
1054 if(pStream->eof()) return -1;
1055 p2 = pStream->peek();
1056 }
1057 FD_DV("Token::ReadMarkup: " << c << "-" << p1 << "-" << p2);
1058 // its a begin tag ...
1059 if(p1==0) {
1060 FD_DV("Token::ReadMarkup: sensed XML tag");
1061 // ... get the name
1062 std::string name;
1063 while (*pStream) {
1064 if(pStream->eof()) return -1;
1065 c = pStream->peek();
1066 if(c == '>') break;
1067 if(c == '/') break;
1068 if(isblank(c) || iscntrl(c)) break;
1069 pStream->get();
1070 name.append(1,c);
1071 }
1072 if(name.size()==0) return -1;
1073 mType = Begin;
1074 ll=ReadAttributes(pStream);
1075 if(ll<0) return -1;
1076 if(pStream->eof()) return -1;
1077 c = pStream->peek();
1078 if(c=='/') {
1079 mType |= End;
1080 pStream->get();
1081 }
1082 mStringValue=name;
1083 FD_DV("Token::ReadMarkup: sensed XML tag, type " << mType << " name " << mStringValue);
1084 }
1085 // its an end tag: get the name
1086 if(p1=='/') {
1087 std::string name;
1088 while(*pStream) {
1089 if(pStream->eof()) return -1;
1090 c = pStream->peek();
1091 if(c == '>') break;
1092 if(c == '/') break;
1093 if(isblank(c) || iscntrl(c)) break;
1094 pStream->get();
1095 name.append(1,c);
1096 }
1097 if(name.size()==0) return -1;
1098 if(c!='>') return -1;
1099 mType = End;
1100 mStringValue=name;
1101 }
1102 // its an xml comment
1103 if(p1=='!' && p2=='-') {
1104 FD_DV("Token::ReadMarkup: sensed XML comment <" << p1 << p2);
1105 c=pStream->get();
1106 if(pStream->eof()) return -1;
1107 c=pStream->get();
1108 if(c!='-') return -1;
1109 char c2=0;
1110 char c3=0;
1111 while (*pStream) {
1112 c3=c2; c2=c;
1113 if(pStream->eof()) return -1;
1114 c = pStream->peek();
1115 if(c3== '-' && c2=='-' && c == '>') break;
1116 pStream->get();
1117 if(c=='\n') ++lc;
1118 }
1119 FD_DV("Token::ReadMarkup: sensed XML comment end " << c3 << c2 << c);
1120 }
1121 // its an xml doctypedec (which we cannot handle properly)
1122 if(p1=='!' && (p2=='D' || p2=='d')) {
1123 FD_DV("Token::ReadMarkup doc.type.dec. not implemented (!)");
1124 c=pStream->get();
1125 while(*pStream) {
1126 if(pStream->eof()) return -1;
1127 c = pStream->peek();
1128 if(c == '>') break;
1129 pStream->get();
1130 if(c=='\n') ++lc;
1131 }
1132 }
1133 // its an xml cdata (interpret as string)
1134 if(p1=='!' && p2=='[' ) {
1135 FD_DV("Token::ReadMarkup: sense CDATA?");
1136 // sense "<![CDATA["
1137 c=pStream->get();
1138 if(pStream->eof()) return -1;
1139 if(pStream->get()!='C') return -1;
1140 if(pStream->eof()) return -1;
1141 if(pStream->get()!='D') return -1;
1142 if(pStream->eof()) return -1;
1143 if(pStream->get()!='A') return -1;
1144 if(pStream->eof()) return -1;
1145 if(pStream->get()!='T') return -1;
1146 if(pStream->eof()) return -1;
1147 if(pStream->get()!='A') return -1;
1148 if(pStream->eof()) return -1;
1149 if(pStream->get()!='[') return -1;
1150 // read until "]]>"
1151 FD_DV("Token::ReadMarkup: sense CDATA!");
1152 char c2=0;
1153 char c3=0;
1154 while(*pStream) {
1155 c3=c2; c2=c;
1156 if(pStream->eof()) return -1;
1157 c = pStream->peek();
1158 if(c3== ']' && c2==']' && c == '>') break;
1159 if(pStream->eof()) return -1;
1160 pStream->get();
1161 if(c=='\n') ++lc;
1162 mStringValue.append(1,c);
1163 }
1164 FD_DV("Token::ReadMarkup: sense CDATA:" << mStringValue);
1165 // drop "]]"
1166 if(mStringValue.size()>=2)
1167 mStringValue.erase(mStringValue.size()-2);
1168 mType |= String;
1169 mType |= Cdata;
1170 FD_DV("Token::ReadMarkup: sense CDATA:" << mStringValue);
1171 }
1172 // its an xml proc.intstruction (which we ignore)
1173 if(p1=='?') {
1174 if(pStream->eof()) return -1;
1175 c = pStream->get();
1176 char c2=0;
1177 while (*pStream) {
1178 c2=c;
1179 if(pStream->eof()) return -1;
1180 c = pStream->peek();
1181 if(c2=='?' && c == '>') break;
1182 pStream->get();
1183 if(c=='\n') ++lc;
1184 }
1185 }
1186 // error
1187 if(pStream->eof()) return -1;
1188 c = pStream->peek();
1189 if(c!='>') {
1190 FD_DV("Token::ReadMarkup: mismatch (?) " << mStringValue);
1191 while (*pStream) {
1192 if(pStream->eof()) return -1;
1193 c = pStream->peek();
1194 if(c == '>') break;
1195 if(c=='\n') ++lc;
1196 pStream->get();
1197 }
1198 }
1199 // done
1200 pStream->get();
1201 FD_DV("Token::ReadMarkup: return type " << mType << " string " << mStringValue << " lc" << lc);
1202 return lc;
1203}
1204
1205// Read(pStream)
1206int Token::Read(std::istream* pStream, bool fcomments){
1207 FD_DV("Token::Read(): fcomments=" << fcomments);
1208 char c1;
1209 int lc = 0;
1210 int ll = -1;
1211 // the token is initialized with the type "None"
1212 SetNone();
1213 // check eof
1214 if(pStream->eof()) return(lc);
1215 // read all white space
1216 lc += ReadSpace(pStream,fcomments);
1217 // check eof
1218 if(pStream->eof()) return(lc);
1219 // get the first useful character
1220 c1=pStream->peek();
1221 // token is a quoted string if it starts with '"'
1222 if(c1 == '"') {
1223 pStream->get();
1224 // read the string until '"'
1225 ll=ReadString(pStream,'"');
1226 if(ll>=0) {
1227 lc+=ll;
1228 mType |= String;
1229 pStream->get();
1230 }
1231 }
1232 // token is a quoted string if it starts with '''
1233 else if(c1 == '\'') {
1234 pStream->get();
1235 // read the string until '''
1236 ll=ReadString(pStream,'\'');
1237 if(ll>=0) {
1238 lc+=ll;
1239 mType |= String;
1240 pStream->get();
1241 }
1242 }
1243 // token is an option string if it starts with '+'
1244 else if(c1 == '+') {
1245 pStream->get();
1246 // read the string until '+'
1247 ll=ReadString(pStream,'+');
1249 mStringValue="+" + mOptionValue + "+";
1250 if(ll>=0) {
1251 lc+=ll;
1252 mType |= (Option | String);
1253 pStream->get();
1254 }
1255 }
1256 // token is a binary string if it starts with '='
1257 else if(c1 == '=') {
1258 // read the string until '=', incl padding
1259 ll=ReadBinary(pStream);
1260 if(ll>=0) {
1261 lc+=ll;
1262 mType |= (Binary | String);
1263 }
1264 }
1265 // token is markup if it starts with <
1266 else if(c1 == '<') {
1267 pStream->get();
1268 // check eof
1269 if(pStream->eof()) return(lc);
1270 // read and interpret
1271 ll=ReadMarkup(pStream);
1272 // recurse on non-faudes-recognised but parsable markup (effectively swallowing unrecognised)
1273 if(ll>=0) {
1274 lc+=ll;
1275 if(mType==None) return(Read(pStream));
1276 }
1277 }
1278 // token is a space seperated string, perhaps a number
1279 else if(c1 != '%') {
1280 ll=ReadString(pStream,' ');
1281 if(ll>=0) {
1282 mType |= String;
1284 }
1285 }
1286 // sense error
1287 if(ll<0) {
1288 FD_DV("Token::Read(): failed with '" << c1 <<"'");
1289 return -1;
1290 }
1291 FD_DV("Token::Read(): " << Str());
1292 return(lc);
1293}
1294
1295
1296// Str()
1297std::string Token::Str(void) const {
1298 std::stringstream ostr;
1299 ostr << "Token(--- Type=";
1300 if(IsNone()) ostr << "None";
1301 if(IsInteger()) ostr << "Integer";
1302 if(IsInteger16()) ostr << "Integer16";
1303 if(IsBoolean()) ostr << "Boolean";
1304 if(IsFloat()) ostr << "Float";
1305 if(IsString()) ostr << "String";
1306 if(IsEmpty()) ostr << "Begin/End";
1307 if(IsBegin()) ostr << "Begin";
1308 if(IsEnd()) ostr << "End";
1309 if(!IsNone()) {
1310 ostr << " Value=\"";
1311 if(IsFloat()) ostr << FloatValue();
1312 else if(IsBegin() || IsEnd()) ostr << StringValue();
1313 else if(IsString()) ostr << StringValue();
1314 ostr << "\"";
1315 }
1316 ostr << " sp #" << mPreceedingSpace.size();
1317 caiterator ait;
1318 for(ait=mAttributes.begin(); ait!=mAttributes.end(); ait++)
1319 ostr << " attr[" << ait->first << "=\"" << ait->second.mStringValue << "\"]";
1320 ostr << " ---)";
1321 return ostr.str();
1322}
1323
1324
1325
1326} // namespace faudes
#define FD_NAMELEN
#define FD_DV(message)
Class Token.
bool IsCdata(void) const
bool IsBinary(void) const
bool IsInteger16(void) const
void SetNone(void)
Definition cfl_token.cpp:73
int ReadMarkup(std::istream *pStream)
Token & operator=(const Token &rOther)
Definition cfl_token.cpp:56
const std::string & PreceedingSpace(void) const
std::string Str(void) const
void SetBinary(const char *data, std::size_t len)
std::map< std::string, AttributeValue >::const_iterator caiterator
Definition cfl_token.h:670
void WriteString(std::ostream *pStream, const std::string &delim) const
void SetInteger16(const Int number)
const std::string & StringValue(void) const
Int AttributeIntegerValue(const std::string &name)
void ClrEnd(void)
void SetInteger(const Int number)
void SetBoolean(const Int number)
bool ExistsAttributeFloat(const std::string &name)
@ Integer
1234 (non-negative integer)
Definition cfl_token.h:88
@ Option
+xyZ+ (option string, may not contain a "+")
Definition cfl_token.h:87
@ Float
-12.34 ("-" or "." turns an integer to a float)
Definition cfl_token.h:91
@ Boolean
True/False
Definition cfl_token.h:90
@ Cdata
... verbatim markup
Definition cfl_token.h:93
@ End
<\label> (end of section)
Definition cfl_token.h:85
@ Integer16
0x12fff ("0x" makes an integer an Integer16)
Definition cfl_token.h:89
@ Begin
<label> (begin of section)
Definition cfl_token.h:84
@ String
any string, space separated or quoted, must start with a letter
Definition cfl_token.h:86
@ Binary
=ABhlkjj= (base64 encoded binary data)
Definition cfl_token.h:92
@ None
Invalid/empty token
Definition cfl_token.h:83
bool IsString(void) const
static void WriteVerbatim(std::ostream *pStream, const std::string &rString, bool lfflag=0)
void Write(std::ostream *pStream) const
faudes::Float mFloatValue
Definition cfl_token.h:646
Int IntegerValue(void) const
bool IsNone(void) const
void InsAttributeBoolean(const std::string &name, Int value)
bool IsInteger(void) const
std::string mOptionValue
Definition cfl_token.h:640
void SetString(const std::string &rName)
Definition cfl_token.cpp:85
int ReadSpace(std::istream *pStream, bool fcomments=true)
faudes::Float AttributeFloatValue(const std::string &name)
static int ReadCharacterData(std::istream *pStream, std::string &rString, bool fcomments)
static int ReadEscapedString(std::istream *pStream, char stop, std::string &rString)
bool ExistsAttributeString(const std::string &name)
void SetOption(const std::string &rName)
bool IsEmpty(void) const
bool IsBegin(void) const
void SetFloat(const faudes::Float number)
void SetEmpty(const std::string &rName)
void InsAttribute(const std::string &name, const std::string &value)
bool IsBoolean(void) const
static void WriteBinary(std::ostream *pStream, const char *pData, std::size_t len)
int ReadAttributes(std::istream *pStream)
int ReadBinary(std::istream *pStream)
void InsAttributeFloat(const std::string &name, faudes::Float value)
void ClrAttribute(const std::string &name)
void ClearAttributes()
static int WriteEscapedString(std::ostream *pStream, const std::string &outstr)
const std::string & OptionValue(void) const
void SetBegin(const std::string &rName)
Definition cfl_token.cpp:92
int mAttributeCount
Definition cfl_token.h:666
bool ExistsAttributeInteger(const std::string &name)
void InsAttributeInteger(const std::string &name, Int value)
bool InterpretNumber(void)
int Read(std::istream *pStream, bool fcomments=true)
void InsAttributeString(const std::string &name, const std::string &value)
std::map< std::string, AttributeValue > mAttributes
Definition cfl_token.h:663
std::map< std::string, AttributeValue >::iterator aiterator
Definition cfl_token.h:669
bool IsEnd(void) const
bool IsFloat(void) const
int ReadString(std::istream *pStream, char stop)
std::string mPreceedingSpace
Definition cfl_token.h:649
bool IsOption(void) const
void SetEnd(const std::string &rName)
Definition cfl_token.cpp:99
const std::string & AttributeStringValue(const std::string &name)
void InterpretAttribute(aiterator ait)
void InsAttributeInteger16(const std::string &name, Int value)
faudes::Float FloatValue(void) const
std::string mStringValue
Definition cfl_token.h:637
TokenType Type(void) const
std::string ExpandString(const std::string &rString, unsigned int len)
Definition cfl_utils.cpp:80
std::string ToStringFloat(Float number)
Definition cfl_utils.cpp:64
std::string ToStringInteger16(Int number)
Definition cfl_utils.cpp:54
double Float
std::string ToStringInteger(Int number)
Definition cfl_utils.cpp:43
long int Int

libFAUDES 2.33k --- 2025.09.16 --- c++ api documentaion by doxygen