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 *pStream << " ";
850}
851
852// ReadString(pStream, char)
853int Token::ReadString(std::istream* pStream, char stop) {
854 return ReadEscapedString(pStream,stop,mStringValue);
855}
856
857
858// ReadEscapedString(pStream, rString, char)
859int Token::ReadEscapedString(std::istream* pStream, char stop, std::string& rString) {
860 int lc=0;
861 char c;
862 std::string entref="";
863 bool ctrlblank = false;
864 rString = "";
865 // check the whole pStream
866 while (*pStream) {
867 // check eof
868 if(pStream->eof()) return -1;
869 // test one character
870 c = pStream->peek();
871 // break on mark up
872 if(c == '<') break;
873 if(c == '>') break;
874 // break on stop
875 if(c == stop) break;
876 if(isblank(c) && stop==' ') break;
877 if(iscntrl(c) && stop==' ') break;
878 // get one character
879 c = pStream->get();
880 // count the next lines
881 if(c=='\n') ++lc;
882 // replace sequence of control characters by one blank
883 if(iscntrl(c) && ctrlblank) continue;
884 ctrlblank=false;
885 if(iscntrl(c)) { c=' '; ctrlblank=true;}
886 // if in escape mode ...
887 if(entref.size()!=0) {
888 //record reference
889 entref.append(1,c);
890 // error: reference must not contain a white space
891 if(c == ' ') return -1;
892 // decode reference
893 if(c == ';') {
894 if(entref=="&amp;") rString.append(1,'&');
895 else if(entref=="&quot;") rString.append(1,'"');
896 else if(entref=="&apos;") rString.append(1,'\'');
897 else if(entref=="&lt;") rString.append(1,'<');
898 else if(entref=="&gt;") rString.append(1,'>');
899 // plain copy unknown
900 else rString.append(entref);
901 entref="";
902 }
903 continue;
904 }
905 // ... sense escape
906 if(c == '&') entref.append(1,c);
907 // ... add character
908 if(c != '&') rString.append(1,c);
909 continue;
910 }
911 // report
912 FD_DV("Token::ReadEscapedString(): lc=" << lc << " val=" << rString);
913 // space seperated string must be nontrivial
914 if(stop==' ' && rString.size()==0) return -1;
915 return lc;
916}
917
918
919// ReadCharacterData(pStream, rString)
920int Token::ReadCharacterData(std::istream* pStream, std::string& rString, bool fcomments) {
921 rString = "";
922 // special case
923 if(pStream->eof()) return 0;
924 // check the whole pStream
925 int lc=0;
926 char c;
927 bool cm = false;
928 while (*pStream) {
929 // check other errors
930 if(!pStream->good()) { rString="I/O error"; return -1; }
931 // test one character
932 c = pStream->peek();
933 // break on eof
934 if(pStream->eof()) break;
935 // sense error: markup in faudes comment
936 if(fcomments && cm)
937 if((c=='<') || (c=='>')) { rString="'<' or '>' in faudes comment"; return -1; }
938 // break on mark up
939 if(c == '<') break;
940 // again: test state (peek may set eof, so dont use good() here)
941 if(pStream->bad()) { rString="I/O error"; return -1; }
942 // get one character
943 c = pStream->get();
944 // count the next lines
945 if(c=='\n') ++lc;
946 // track faudes comment mode
947 if(c=='%') cm=true;
948 if(c=='\n') cm=false;
949 // ... add character
950 if(!(fcomments && cm))
951 rString.append(1,c);
952 }
953 return lc;
954}
955
956
957// ReadAttributes(pStream)
958// (and swallow all space after the last attribute)
959int Token::ReadAttributes(std::istream* pStream) {
960 int lc=0;
961 char c=0;
962 FD_DV("Token::ReadAttributes()");
963 // scan until excl. '>'
964 while (*pStream) {
965 // skip space
966 while (*pStream) {
967 if(pStream->eof()) return -1;
968 c = pStream->peek();
969 if(!(isblank(c) || iscntrl(c))) break;
970 pStream->get();
971 if(c=='\n') ++lc;
972 }
973 // get attrname
974 std::string aname;
975 while (*pStream) {
976 if(pStream->eof()) return -1;
977 c = pStream->peek();
978 if(isblank(c) || iscntrl(c)) break;
979 if(c=='=') break;
980 if(c=='>') break;
981 if(c=='/') break;
982 pStream->get();
983 aname.append(1,c);
984 }
985 FD_DV("Token::ReadAttributes(): aname " << aname);
986 // no name so we're done
987 if(aname.size()==0) {
988 return lc;
989 }
990 // skip space
991 while(*pStream) {
992 if(pStream->eof()) return -1;
993 c = pStream->peek();
994 if(!(isblank(c) || iscntrl(c))) break;
995 pStream->get();
996 if(c=='\n') ++lc;
997 }
998 // insist in eq
999 if(c!='=') return -1;
1000 pStream->get();
1001 // skip space
1002 while (*pStream) {
1003 if(pStream->eof()) return -1;
1004 c = pStream->peek();
1005 if(!(isblank(c) || iscntrl(c))) break;
1006 pStream->get();
1007 if(c=='\n') ++lc;
1008 }
1009 // strict version, value by '"'
1010 if(c == '"') {
1011 pStream->get();
1012 int ll=ReadString(pStream,'"');
1013 if(ll<0) return -1;
1014 pStream->get();
1015 lc+=ll;
1016 }
1017 // strict version, value by '''
1018 else if(c == '\'') {
1019 pStream->get();
1020 int ll=ReadString(pStream,'\'');
1021 if(ll<0) return -1;
1022 pStream->get();
1023 lc+=ll;
1024 }
1025 // relaxed version, value by "space"
1026 else {
1027 int ll=ReadString(pStream,' ');
1028 if(ll<0) return -1;
1029 lc+=ll;
1030 }
1031 std::string aval=mStringValue;
1032 FD_DV("Token::ReadAttributes(): aval " << aval);
1033 // record attribute
1034 InsAttribute(aname,aval);
1035 }
1036 // done
1037 return lc;
1038}
1039
1040// ReadMarkup(pStream)
1041// (leading "<" has allready been read)
1042int Token::ReadMarkup(std::istream* pStream) {
1043 int lc=0;
1044 int ll;
1045 char c=0;
1046 mStringValue = "";
1047 mType=None;
1048 // figure indicator character
1049 char p1=0;
1050 char p2=0;
1051 if(pStream->eof()) return -1;
1052 c = pStream->peek();
1053 if(!(isalpha(c) || c=='_' || c==':')) {
1054 p1 = pStream->get();
1055 if(pStream->eof()) return -1;
1056 p2 = pStream->peek();
1057 }
1058 FD_DV("Token::ReadMarkup: " << c << "-" << p1 << "-" << p2);
1059 // its a begin tag ...
1060 if(p1==0) {
1061 FD_DV("Token::ReadMarkup: sensed XML tag");
1062 // ... get the name
1063 std::string name;
1064 while (*pStream) {
1065 if(pStream->eof()) return -1;
1066 c = pStream->peek();
1067 if(c == '>') break;
1068 if(c == '/') break;
1069 if(isblank(c) || iscntrl(c)) break;
1070 pStream->get();
1071 name.append(1,c);
1072 }
1073 if(name.size()==0) return -1;
1074 mType = Begin;
1075 ll=ReadAttributes(pStream);
1076 if(ll<0) return -1;
1077 if(pStream->eof()) return -1;
1078 c = pStream->peek();
1079 if(c=='/') {
1080 mType |= End;
1081 pStream->get();
1082 }
1083 mStringValue=name;
1084 FD_DV("Token::ReadMarkup: sensed XML tag, type " << mType << " name " << mStringValue);
1085 }
1086 // its an end tag: get the name
1087 if(p1=='/') {
1088 std::string name;
1089 while(*pStream) {
1090 if(pStream->eof()) return -1;
1091 c = pStream->peek();
1092 if(c == '>') break;
1093 if(c == '/') break;
1094 if(isblank(c) || iscntrl(c)) break;
1095 pStream->get();
1096 name.append(1,c);
1097 }
1098 if(name.size()==0) return -1;
1099 if(c!='>') return -1;
1100 mType = End;
1101 mStringValue=name;
1102 }
1103 // its an xml comment
1104 if(p1=='!' && p2=='-') {
1105 FD_DV("Token::ReadMarkup: sensed XML comment <" << p1 << p2);
1106 c=pStream->get();
1107 if(pStream->eof()) return -1;
1108 c=pStream->get();
1109 if(c!='-') return -1;
1110 char c2=0;
1111 char c3=0;
1112 while (*pStream) {
1113 c3=c2; c2=c;
1114 if(pStream->eof()) return -1;
1115 c = pStream->peek();
1116 if(c3== '-' && c2=='-' && c == '>') break;
1117 pStream->get();
1118 if(c=='\n') ++lc;
1119 }
1120 FD_DV("Token::ReadMarkup: sensed XML comment end " << c3 << c2 << c);
1121 }
1122 // its an xml doctypedec (which we cannot handle properly)
1123 if(p1=='!' && (p2=='D' || p2=='d')) {
1124 FD_DV("Token::ReadMarkup doc.type.dec. not implemented (!)");
1125 c=pStream->get();
1126 while(*pStream) {
1127 if(pStream->eof()) return -1;
1128 c = pStream->peek();
1129 if(c == '>') break;
1130 pStream->get();
1131 if(c=='\n') ++lc;
1132 }
1133 }
1134 // its an xml cdata (interpret as string)
1135 if(p1=='!' && p2=='[' ) {
1136 FD_DV("Token::ReadMarkup: sense CDATA?");
1137 // sense "<![CDATA["
1138 c=pStream->get();
1139 if(pStream->eof()) return -1;
1140 if(pStream->get()!='C') return -1;
1141 if(pStream->eof()) return -1;
1142 if(pStream->get()!='D') return -1;
1143 if(pStream->eof()) return -1;
1144 if(pStream->get()!='A') return -1;
1145 if(pStream->eof()) return -1;
1146 if(pStream->get()!='T') return -1;
1147 if(pStream->eof()) return -1;
1148 if(pStream->get()!='A') return -1;
1149 if(pStream->eof()) return -1;
1150 if(pStream->get()!='[') return -1;
1151 // read until "]]>"
1152 FD_DV("Token::ReadMarkup: sense CDATA!");
1153 char c2=0;
1154 char c3=0;
1155 while(*pStream) {
1156 c3=c2; c2=c;
1157 if(pStream->eof()) return -1;
1158 c = pStream->peek();
1159 if(c3== ']' && c2==']' && c == '>') break;
1160 if(pStream->eof()) return -1;
1161 pStream->get();
1162 if(c=='\n') ++lc;
1163 mStringValue.append(1,c);
1164 }
1165 FD_DV("Token::ReadMarkup: sense CDATA:" << mStringValue);
1166 // drop "]]"
1167 if(mStringValue.size()>=2)
1168 mStringValue.erase(mStringValue.size()-2);
1169 mType |= String;
1170 mType |= Cdata;
1171 FD_DV("Token::ReadMarkup: sense CDATA:" << mStringValue);
1172 }
1173 // its an xml proc.intstruction (which we ignore)
1174 if(p1=='?') {
1175 if(pStream->eof()) return -1;
1176 c = pStream->get();
1177 char c2=0;
1178 while (*pStream) {
1179 c2=c;
1180 if(pStream->eof()) return -1;
1181 c = pStream->peek();
1182 if(c2=='?' && c == '>') break;
1183 pStream->get();
1184 if(c=='\n') ++lc;
1185 }
1186 }
1187 // error
1188 if(pStream->eof()) return -1;
1189 c = pStream->peek();
1190 if(c!='>') {
1191 FD_DV("Token::ReadMarkup: mismatch (?) " << mStringValue);
1192 while (*pStream) {
1193 if(pStream->eof()) return -1;
1194 c = pStream->peek();
1195 if(c == '>') break;
1196 if(c=='\n') ++lc;
1197 pStream->get();
1198 }
1199 }
1200 // done
1201 pStream->get();
1202 FD_DV("Token::ReadMarkup: return type " << mType << " string " << mStringValue << " lc" << lc);
1203 return lc;
1204}
1205
1206// Read(pStream)
1207int Token::Read(std::istream* pStream, bool fcomments){
1208 FD_DV("Token::Read(): fcomments=" << fcomments);
1209 char c1;
1210 int lc = 0;
1211 int ll = -1;
1212 // the token is initialized with the type "None"
1213 SetNone();
1214 // check eof
1215 if(pStream->eof()) return(lc);
1216 // read all white space
1217 lc += ReadSpace(pStream,fcomments);
1218 // check eof
1219 if(pStream->eof()) return(lc);
1220 // get the first useful character
1221 c1=pStream->peek();
1222 // token is a quoted string if it starts with '"'
1223 if(c1 == '"') {
1224 pStream->get();
1225 // read the string until '"'
1226 ll=ReadString(pStream,'"');
1227 if(ll>=0) {
1228 lc+=ll;
1229 mType |= String;
1230 pStream->get();
1231 }
1232 }
1233 // token is a quoted string if it starts with '''
1234 else if(c1 == '\'') {
1235 pStream->get();
1236 // read the string until '''
1237 ll=ReadString(pStream,'\'');
1238 if(ll>=0) {
1239 lc+=ll;
1240 mType |= String;
1241 pStream->get();
1242 }
1243 }
1244 // token is an option string if it starts with '+'
1245 else if(c1 == '+') {
1246 pStream->get();
1247 // read the string until '+'
1248 ll=ReadString(pStream,'+');
1250 mStringValue="+" + mOptionValue + "+";
1251 if(ll>=0) {
1252 lc+=ll;
1253 mType |= (Option | String);
1254 pStream->get();
1255 }
1256 }
1257 // token is a binary string if it starts with '='
1258 else if(c1 == '=') {
1259 // read the string until '=', incl padding
1260 ll=ReadBinary(pStream);
1261 if(ll>=0) {
1262 lc+=ll;
1263 mType |= (Binary | String);
1264 }
1265 }
1266 // token is markup if it starts with <
1267 else if(c1 == '<') {
1268 pStream->get();
1269 // check eof
1270 if(pStream->eof()) return(lc);
1271 // read and interpret
1272 ll=ReadMarkup(pStream);
1273 // recurse on non-faudes-recognised but parsable markup (effectively swallowing unrecognised)
1274 if(ll>=0) {
1275 lc+=ll;
1276 if(mType==None) return(Read(pStream));
1277 }
1278 }
1279 // token is a space seperated string, perhaps a number
1280 else if(c1 != '%') {
1281 ll=ReadString(pStream,' ');
1282 if(ll>=0) {
1283 mType |= String;
1285 }
1286 }
1287 // sense error
1288 if(ll<0) {
1289 FD_DV("Token::Read(): failed with '" << c1 <<"'");
1290 return -1;
1291 }
1292 FD_DV("Token::Read(): " << Str());
1293 return(lc);
1294}
1295
1296
1297// Str()
1298std::string Token::Str(void) const {
1299 std::stringstream ostr;
1300 ostr << "Token(--- Type=";
1301 if(IsNone()) ostr << "None";
1302 if(IsInteger()) ostr << "Integer";
1303 if(IsInteger16()) ostr << "Integer16";
1304 if(IsBoolean()) ostr << "Boolean";
1305 if(IsFloat()) ostr << "Float";
1306 if(IsString()) ostr << "String";
1307 if(IsEmpty()) ostr << "Begin/End";
1308 if(IsBegin()) ostr << "Begin";
1309 if(IsEnd()) ostr << "End";
1310 if(!IsNone()) {
1311 ostr << " Value=\"";
1312 if(IsFloat()) ostr << FloatValue();
1313 else if(IsBegin() || IsEnd()) ostr << StringValue();
1314 else if(IsString()) ostr << StringValue();
1315 ostr << "\"";
1316 }
1317 ostr << " sp #" << mPreceedingSpace.size();
1318 caiterator ait;
1319 for(ait=mAttributes.begin(); ait!=mAttributes.end(); ait++)
1320 ostr << " attr[" << ait->first << "=\"" << ait->second.mStringValue << "\"]";
1321 ostr << " ---)";
1322 return ostr.str();
1323}
1324
1325
1326
1327} // 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:81
std::string ToStringFloat(Float number)
Definition cfl_utils.cpp:65
std::string ToStringInteger16(Int number)
Definition cfl_utils.cpp:55
double Float
std::string ToStringInteger(Int number)
Definition cfl_utils.cpp:44
long int Int

libFAUDES 2.34g --- 2026.04.09 --- c++ api documentaion by doxygen