1 /*  $Id: objistrasn.cpp 574303 2018-11-08 19:59:04Z gouriano $
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Eugene Vasilchenko
27 *
28 * File Description:
29 *   !!! PUT YOUR DESCRIPTION HERE !!!
30 */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbistd.hpp>
34 #include <corelib/ncbiutil.hpp>
35 #include <corelib/ncbifloat.h>
36 #include <serial/objistrasn.hpp>
37 #include <serial/impl/member.hpp>
38 #include <serial/enumvalues.hpp>
39 #include <serial/impl/memberlist.hpp>
40 #include <serial/objhook.hpp>
41 #include <serial/impl/classinfo.hpp>
42 #include <serial/impl/choice.hpp>
43 #include <serial/impl/continfo.hpp>
44 #include <serial/impl/objistrimpl.hpp>
45 #include <math.h>
46 #if !defined(DBL_MAX_10_EXP) || !defined(FLT_MAX)
47 # include <float.h>
48 #endif
49 
50 BEGIN_NCBI_SCOPE
51 
CreateObjectIStreamAsn(void)52 CObjectIStream* CObjectIStream::CreateObjectIStreamAsn(void)
53 {
54     return new CObjectIStreamAsn();
55 }
56 
CObjectIStreamAsn(EFixNonPrint how)57 CObjectIStreamAsn::CObjectIStreamAsn(EFixNonPrint how)
58     : CObjectIStream(eSerial_AsnText)
59 {
60     FixNonPrint(how);
61 }
62 
CObjectIStreamAsn(CNcbiIstream & in,EFixNonPrint how)63 CObjectIStreamAsn::CObjectIStreamAsn(CNcbiIstream& in,
64                                      EFixNonPrint how)
65     : CObjectIStream(eSerial_AsnText)
66 {
67     FixNonPrint(how);
68     Open(in);
69 }
70 
CObjectIStreamAsn(CNcbiIstream & in,bool deleteIn,EFixNonPrint how)71 CObjectIStreamAsn::CObjectIStreamAsn(CNcbiIstream& in,
72                                      bool deleteIn,
73                                      EFixNonPrint how)
74     : CObjectIStream(eSerial_AsnText)
75 {
76     FixNonPrint(how);
77     Open(in, deleteIn ? eTakeOwnership : eNoOwnership);
78 }
79 
CObjectIStreamAsn(CNcbiIstream & in,EOwnership deleteIn,EFixNonPrint how)80 CObjectIStreamAsn::CObjectIStreamAsn(CNcbiIstream& in,
81                                      EOwnership deleteIn,
82                                      EFixNonPrint how)
83     : CObjectIStream(eSerial_AsnText)
84 {
85     FixNonPrint(how);
86     Open(in, deleteIn);
87 }
88 
CObjectIStreamAsn(const char * buffer,size_t size,EFixNonPrint how)89 CObjectIStreamAsn::CObjectIStreamAsn(const char* buffer,
90                                      size_t size,
91                                      EFixNonPrint how)
92     : CObjectIStream(eSerial_AsnText)
93 {
94     FixNonPrint(how);
95     OpenFromBuffer(buffer, size);
96 }
97 
EndOfData(void)98 bool CObjectIStreamAsn::EndOfData(void)
99 {
100     if (CObjectIStream::EndOfData()) {
101         return true;
102     }
103     try {
104         SkipWhiteSpace();
105     } catch (...) {
106         return true;
107     }
108     return false;
109 }
110 
GetPosition(void) const111 string CObjectIStreamAsn::GetPosition(void) const
112 {
113     return "line "+NStr::SizetToString(m_Input.GetLine());
114 }
115 
116 inline
FirstIdChar(char c)117 bool CObjectIStreamAsn::FirstIdChar(char c)
118 {
119     return isalpha((unsigned char) c) || c == '_';
120 }
121 
122 inline
IdChar(char c)123 bool CObjectIStreamAsn::IdChar(char c)
124 {
125     return isalnum((unsigned char) c) || c == '_' || c == '.';
126 }
127 
128 inline
GetChar(void)129 char CObjectIStreamAsn::GetChar(void)
130 {
131     return m_Input.GetChar();
132 }
133 
134 inline
PeekChar(void)135 char CObjectIStreamAsn::PeekChar(void)
136 {
137     return m_Input.PeekChar();
138 }
139 
140 inline
SkipEndOfLine(char c)141 void CObjectIStreamAsn::SkipEndOfLine(char c)
142 {
143     m_Input.SkipEndOfLine(c);
144 }
145 
146 inline
SkipWhiteSpaceAndGetChar(void)147 char CObjectIStreamAsn::SkipWhiteSpaceAndGetChar(void)
148 {
149     char c = SkipWhiteSpace();
150     m_Input.SkipChar();
151     return c;
152 }
153 
154 inline
GetChar(bool skipWhiteSpace)155 char CObjectIStreamAsn::GetChar(bool skipWhiteSpace)
156 {
157     return skipWhiteSpace? SkipWhiteSpaceAndGetChar(): m_Input.GetChar();
158 }
159 
160 inline
PeekChar(bool skipWhiteSpace)161 char CObjectIStreamAsn::PeekChar(bool skipWhiteSpace)
162 {
163     return skipWhiteSpace? SkipWhiteSpace(): m_Input.PeekChar();
164 }
165 
166 inline
GetChar(char expect,bool skipWhiteSpace)167 bool CObjectIStreamAsn::GetChar(char expect, bool skipWhiteSpace)
168 {
169     if ( PeekChar(skipWhiteSpace) != expect ) {
170         return false;
171     }
172     m_Input.SkipChar();
173     return true;
174 }
175 
Expect(char expect,bool skipWhiteSpace)176 void CObjectIStreamAsn::Expect(char expect, bool skipWhiteSpace)
177 {
178     if ( !GetChar(expect, skipWhiteSpace) ) {
179         string msg("\'");
180         msg += expect;
181         msg += "' expected";
182         ThrowError(fFormatError, msg);
183     }
184 }
185 
Expect(char choiceTrue,char choiceFalse,bool skipWhiteSpace)186 bool CObjectIStreamAsn::Expect(char choiceTrue, char choiceFalse,
187                                bool skipWhiteSpace)
188 {
189     char c = GetChar(skipWhiteSpace);
190     if ( c == choiceTrue ) {
191         return true;
192     }
193     else if ( c == choiceFalse ) {
194         return false;
195     }
196     m_Input.UngetChar(c);
197     string msg("\'");
198     msg += choiceTrue;
199     msg += "' or '";
200     msg += choiceFalse;
201     msg += "' expected";
202     ThrowError(fFormatError, msg);
203     return false;
204 }
205 
SkipWhiteSpace(void)206 char CObjectIStreamAsn::SkipWhiteSpace(void)
207 {
208     try { // catch CEofException
209         for ( ;; ) {
210             char c = m_Input.SkipSpaces();
211             switch ( c ) {
212             case '\t':
213                 m_Input.SkipChar();
214                 continue;
215             case '\r':
216             case '\n':
217                 m_Input.SkipChar();
218                 SkipEndOfLine(c);
219                 continue;
220             case '-':
221                 // check for comments
222                 if ( m_Input.PeekChar(1) != '-' ) {
223                     return '-';
224                 }
225                 m_Input.SkipChars(2);
226                 // skip comments
227                 SkipComments();
228                 continue;
229             default:
230                 return c;
231             }
232         }
233     } catch (CEofException& e) {
234         if (GetStackDepth() <= 2) {
235             throw;
236         } else {
237             // There should be no eof here, report as error
238             ThrowError(fEOF, e.what());
239         }
240     }
241     return '\0';
242 }
243 
SkipComments(void)244 void CObjectIStreamAsn::SkipComments(void)
245 {
246     try {
247         for ( ;; ) {
248             char c = GetChar();
249             switch ( c ) {
250             case '\r':
251             case '\n':
252                 SkipEndOfLine(c);
253                 return;
254             case '-':
255                 c = GetChar();
256                 switch ( c ) {
257                 case '\r':
258                 case '\n':
259                     SkipEndOfLine(c);
260                     return;
261                 case '-':
262                     return;
263                 }
264                 continue;
265             default:
266                 continue;
267             }
268         }
269     }
270     catch ( CEofException& /* ignored */ ) {
271         return;
272     }
273 }
274 
ScanEndOfId(bool isId)275 CTempString CObjectIStreamAsn::ScanEndOfId(bool isId)
276 {
277     if ( isId ) {
278         for ( size_t i = 1; ; ++i ) {
279             char c = m_Input.PeekCharNoEOF(i);
280             if ( !IdChar(c) &&
281                  (c != '-' || !IdChar(m_Input.PeekChar(i + 1))) ) {
282                 const char* ptr = m_Input.GetCurrentPos();
283                 m_Input.SkipChars(i);
284                 return CTempString(ptr, i);
285             }
286         }
287     }
288     return CTempString();
289 }
290 
ReadTypeId(char c)291 CTempString CObjectIStreamAsn::ReadTypeId(char c)
292 {
293     if ( c == '[' ) {
294         for ( size_t i = 1; ; ++i ) {
295             switch ( m_Input.PeekChar(i) ) {
296             case '\r':
297             case '\n':
298                 ThrowError(fFormatError, "end of line: expected ']'");
299                 break;
300             case ']':
301                 {
302                     const char* ptr = m_Input.GetCurrentPos();
303                     m_Input.SkipChars(i);
304                     return CTempString(ptr + 1, i - 2);
305                 }
306             }
307         }
308     }
309     else {
310         return ScanEndOfId(FirstIdChar(c));
311     }
312 }
313 
ReadNumber(void)314 CTempString CObjectIStreamAsn::ReadNumber(void)
315 {
316     char c = SkipWhiteSpace();
317     if ( c != '-' && c != '+' && !isdigit((unsigned char) c) )
318         ThrowError(fFormatError, "invalid number");
319     for ( size_t i = 1; ; ++i ) {
320         c = m_Input.PeekChar(i);
321         if ( !isdigit((unsigned char) c) ) {
322             const char* ptr = m_Input.GetCurrentPos();
323             m_Input.SkipChars(i);
324             return CTempString(ptr, i);
325         }
326     }
327 }
328 
329 inline
ReadUCaseId(char c)330 CTempString CObjectIStreamAsn::ReadUCaseId(char c)
331 {
332     return ScanEndOfId(isupper((unsigned char) c) != 0);
333 }
334 
335 inline
ReadLCaseId(char c)336 CTempString CObjectIStreamAsn::ReadLCaseId(char c)
337 {
338     return ScanEndOfId(islower((unsigned char) c) != 0);
339 }
340 
341 inline
ReadMemberId(char c)342 CTempString CObjectIStreamAsn::ReadMemberId(char c)
343 {
344     if ( c == '[' ) {
345         for ( size_t i = 1; ; ++i ) {
346             switch ( m_Input.PeekChar(i) ) {
347             case '\r':
348             case '\n':
349                 ThrowError(fFormatError, "end of line: expected ']'");
350                 break;
351             case ']':
352                 {
353                     const char* ptr = m_Input.GetCurrentPos();
354                     m_Input.SkipChars(++i);
355                     return CTempString(ptr + 1, i - 2);
356                 }
357             }
358         }
359     }
360     else {
361         return ScanEndOfId(islower((unsigned char) c) != 0);
362     }
363 }
364 
GetAltItemIndex(const CClassTypeInfoBase * classType,const CTempString & id,const TMemberIndex pos)365 TMemberIndex CObjectIStreamAsn::GetAltItemIndex(
366     const CClassTypeInfoBase* classType,
367     const CTempString& id,
368     const TMemberIndex pos /*= kInvalidMember*/)
369 {
370     TMemberIndex idx = kInvalidMember;
371     if (!id.empty()) {
372         const CItemsInfo& info = classType->GetItems();
373         string id_alt = string(id);
374         id_alt[0] = (char)toupper((unsigned char)id_alt[0]);
375         if (pos != kInvalidMember) {
376             idx = info.Find(CTempString(id_alt),pos);
377         } else {
378             idx = info.Find(CTempString(id_alt));
379         }
380         if (idx != kInvalidMember &&
381             !info.GetItemInfo(idx)->GetId().HaveNoPrefix()) {
382             idx = kInvalidMember;
383         }
384     }
385     return idx;
386 }
387 
GetMemberIndex(const CClassTypeInfo * classType,const CTempString & id)388 TMemberIndex CObjectIStreamAsn::GetMemberIndex
389     (const CClassTypeInfo* classType,
390      const CTempString& id)
391 {
392     TMemberIndex idx;
393     if (!id.empty()  &&  isdigit((unsigned char) id[0])) {
394         idx = classType->GetMembers().Find
395             (CMemberId::TTag(NStr::StringToInt(id)), CAsnBinaryDefs::eContextSpecific);
396     }
397     else {
398         idx = classType->GetMembers().Find(id);
399         if (idx == kInvalidMember) {
400             idx = GetAltItemIndex(classType,id);
401         }
402     }
403     return idx;
404 }
405 
GetMemberIndex(const CClassTypeInfo * classType,const CTempString & id,const TMemberIndex pos)406 TMemberIndex CObjectIStreamAsn::GetMemberIndex
407     (const CClassTypeInfo* classType,
408      const CTempString& id,
409      const TMemberIndex pos)
410 {
411     TMemberIndex idx;
412     if (!id.empty()  &&  isdigit((unsigned char) id[0])) {
413         idx = classType->GetMembers().Find
414             (CMemberId::TTag(NStr::StringToInt(id)), CAsnBinaryDefs::eContextSpecific, pos);
415     }
416     else {
417         idx = classType->GetMembers().Find(id, pos);
418         if (idx == kInvalidMember) {
419             idx = GetAltItemIndex(classType,id,pos);
420         }
421     }
422     return idx;
423 }
424 
GetChoiceIndex(const CChoiceTypeInfo * choiceType,const CTempString & id)425 TMemberIndex CObjectIStreamAsn::GetChoiceIndex
426     (const CChoiceTypeInfo* choiceType,
427      const CTempString& id)
428 {
429     TMemberIndex idx;
430     if (!id.empty()  &&  isdigit((unsigned char) id[0])) {
431         idx = choiceType->GetVariants().Find
432             (CMemberId::TTag(NStr::StringToInt(id)), CAsnBinaryDefs::eContextSpecific);
433     }
434     else {
435         idx = choiceType->GetVariants().Find(id);
436         if (idx == kInvalidMember) {
437             idx = GetAltItemIndex(choiceType,id);
438         }
439     }
440     return idx;
441 }
442 
ReadNull(void)443 void CObjectIStreamAsn::ReadNull(void)
444 {
445     if ( SkipWhiteSpace() == 'N' &&
446          m_Input.PeekCharNoEOF(1) == 'U' &&
447          m_Input.PeekCharNoEOF(2) == 'L' &&
448          m_Input.PeekCharNoEOF(3) == 'L' &&
449          !IdChar(m_Input.PeekCharNoEOF(4)) ) {
450         m_Input.SkipChars(4);
451     }
452     else
453         ThrowError(fFormatError, "'NULL' expected");
454 }
455 
ReadAnyContent(string & value)456 void CObjectIStreamAsn::ReadAnyContent(string& value)
457 {
458     char buf[128];
459     size_t pos=0;
460     const size_t maxpos=128;
461 
462     char to = GetChar(true);
463     buf[pos++] = to;
464     if (to == '{') {
465         to = '}';
466     } else if (to == '\"') {
467     } else {
468         to = '\0';
469     }
470 
471     bool space = false;
472     for (char c = m_Input.PeekChar(); ; c = m_Input.PeekChar()) {
473         if (to != '\"') {
474             if (to != '}' && c == '\n') {
475                 value.append(buf,pos);
476                 return;
477             }
478             if (isspace((unsigned char) c)) {
479                 if (space) {
480                     m_Input.SkipChar();
481                     continue;
482                 }
483                 c = ' ';
484                 space = true;
485             } else {
486                 space = false;;
487             }
488             if (to != '}' && (c == ',' || c == '}')) {
489                 value.append(buf,pos);
490                 return;
491             } else if (c == '\"' || c == '{') {
492                 value.append(buf,pos);
493                 ReadAnyContent(value);
494                 pos = 0;
495                 continue;
496             }
497         }
498         if (c == to) {
499             if (pos >= maxpos) {
500                 value.append(buf,pos);
501                 pos = 0;
502             }
503             buf[pos++] = c;
504             value.append(buf,pos);
505             m_Input.SkipChar();
506             return;
507         }
508         if (c == '\"' || c == '{') {
509             value.append(buf,pos);
510             ReadAnyContent(value);
511             pos = 0;
512             continue;
513         }
514         if (pos >= maxpos) {
515             value.append(buf,pos);
516             pos = 0;
517         }
518         buf[pos++] = c;
519         m_Input.SkipChar();
520     }
521 }
522 
ReadAnyContentObject(CAnyContentObject & obj)523 void CObjectIStreamAsn::ReadAnyContentObject(CAnyContentObject& obj)
524 {
525     obj.SetName(ReadMemberId(SkipWhiteSpace()));
526     string value;
527     ReadAnyContent(value);
528     obj.SetValue(CUtf8::AsUTF8(value,eEncoding_UTF8));
529 }
530 
SkipAnyContent(void)531 void CObjectIStreamAsn::SkipAnyContent(void)
532 {
533     bool ap = false;
534     char to = GetChar(true);
535     if (to == '{') {
536         to = '}';
537     } else if (to == '\"') {
538     } else if (to == '\'') {
539         ap = true;
540         to = '\0';
541     } else {
542         to = '\0';
543     }
544     for (char c = m_Input.PeekChar(); ; c = m_Input.PeekChar()) {
545         if (!ap && to != '\"') {
546             if (to != '}' && (c == '\n' || c == ',' || c == '}')) {
547                 return;
548             } else if (c == '\"' || c == '{') {
549                 SkipAnyContent();
550                 continue;
551             }
552         }
553         if (c == to) {
554             m_Input.SkipChar();
555             return;
556         }
557         if (c == '\"' || (c == '{' && to != '\"')) {
558             SkipAnyContent();
559             continue;
560         }
561         if (c == '\'' && to != '\"') {
562             ap = !ap;
563         }
564         m_Input.SkipChar();
565         if (c == '\n') {
566             SkipEndOfLine(c);
567         }
568     }
569 }
570 
SkipAnyContentObject(void)571 void CObjectIStreamAsn::SkipAnyContentObject(void)
572 {
573     SkipAnyContent();
574 }
575 
ReadBitString(CBitString & obj)576 void CObjectIStreamAsn::ReadBitString(CBitString& obj)
577 {
578     obj.clear();
579 #if BITSTRING_AS_VECTOR
580 // CBitString is vector<bool>
581     Expect('\'', true);
582     string data;
583     size_t reserve;
584     const size_t step=128;
585     data.reserve(reserve=step);
586     bool hex=false;
587     int c;
588     for ( ; !hex; hex= c > 0x1) {
589         c = GetHexChar();
590         if (c < 0) {
591             break;
592         }
593         data.append(1, char(c));
594         if (--reserve == 0) {
595             data.reserve(data.size() + (reserve=step));
596         }
597     }
598     if (c<0 && !hex) {
599         hex = m_Input.PeekChar() == 'H';
600     }
601     if (hex) {
602         obj.reserve( data.size() * 4 );
603         Uint1 byte;
604         ITERATE( string, i, data) {
605             byte = *i;
606             for (Uint1 mask= 0x8; mask != 0; mask = Uint1(mask >> 1)) {
607                 obj.push_back( (byte & mask) != 0 );
608             }
609         }
610         if (c > 0) {
611             obj.reserve(obj.size() + (reserve=step));
612             for (c= GetHexChar(); c >= 0; c= GetHexChar()) {
613                 byte = c;
614                 for (Uint1 mask= 0x8; mask != 0; mask >>= 1) {
615                     obj.push_back( (byte & mask) != 0 );
616                     if (--reserve == 0) {
617                         obj.reserve(obj.size() + (reserve=step));
618                     }
619                 }
620             }
621         }
622         Expect('H');
623     } else {
624         obj.reserve( data.size() );
625         ITERATE( string, i, data) {
626             obj.push_back( *i != 0 );
627         }
628         Expect('B');
629     }
630     obj.reserve(obj.size());
631 #else
632     obj.resize(0);
633     if (IsCompressed()) {
634         ReadCompressedBitString(obj);
635         return;
636     }
637     Expect('\'', true);
638     string data;
639     size_t reserve;
640     const size_t step=128;
641     data.reserve(reserve=step);
642     bool hex=false;
643     int c;
644     for ( ; !hex; hex= c > 0x1) {
645         c = GetHexChar();
646         if (c < 0) {
647             break;
648         }
649         data.append(1, char(c));
650         if (--reserve == 0) {
651             data.reserve(data.size() + (reserve=step));
652         }
653     }
654     if (c<0 && !hex) {
655         hex = m_Input.PeekChar() == 'H';
656     }
657     CBitString::size_type len = 0;
658     if (hex) {
659         Uint1 byte;
660         obj.resize(CBitString::size_type(4*data.size()));
661         ITERATE( string, i, data) {
662             byte = *i;
663             if (byte) {
664                 for (Uint1 mask=0x8; mask != 0; mask = Uint1(mask >> 1), ++len) {
665                     if ((byte & mask) != 0) {
666                         obj.set_bit(len);
667                     }
668                 }
669             } else {
670                 len += 4;
671             }
672         }
673         if (c > 0) {
674             for (c= GetHexChar(); c >= 0; c= GetHexChar()) {
675                 obj.resize( 4 + obj.size());
676                 byte = (Uint1)c;
677                 if (byte) {
678                     for (Uint1 mask= 0x8; mask != 0; mask = Uint1(mask >> 1), ++len) {
679                         if ((byte & mask) != 0) {
680                             obj.set_bit(len);
681                         }
682                     }
683                 } else {
684                     len += 4;
685                 }
686             }
687         }
688         Expect('H');
689     } else {
690         obj.resize(CBitString::size_type(data.size()));
691         ITERATE( string, i, data) {
692             if ( *i != 0 ) {
693                 obj.set_bit(len);
694             }
695             ++len;
696         }
697         Expect('B');
698     }
699     obj.resize(len);
700 #endif
701 }
702 
SkipBitString(void)703 void CObjectIStreamAsn::SkipBitString(void)
704 {
705     SkipByteBlock();
706 }
707 
ReadFileHeader()708 string CObjectIStreamAsn::ReadFileHeader()
709 {
710     CTempString id = ReadTypeId(SkipWhiteSpace());
711     string s(id);
712     if ( SkipWhiteSpace() == ':' &&
713          m_Input.PeekCharNoEOF(1) == ':' &&
714          m_Input.PeekCharNoEOF(2) == '=' ) {
715         m_Input.SkipChars(3);
716     }
717     else
718         ThrowError(fFormatError, "'::=' expected");
719     return s;
720 }
721 
ReadEnum(const CEnumeratedTypeValues & values)722 TEnumValueType CObjectIStreamAsn::ReadEnum(const CEnumeratedTypeValues& values)
723 {
724     // not integer
725     CTempString id = ReadLCaseId(SkipWhiteSpace());
726     if ( !id.empty() ) {
727         // enum element by name
728         return values.FindValue(id);
729     }
730     // enum element by value
731     TEnumValueType value = m_Input.GetInt4();
732     if ( !values.IsInteger() ) // check value
733         values.FindName(value, false);
734 
735     return value;
736 }
737 
ReadBool(void)738 bool CObjectIStreamAsn::ReadBool(void)
739 {
740     switch ( SkipWhiteSpace() ) {
741     case 'T':
742         if ( m_Input.PeekCharNoEOF(1) == 'R' &&
743              m_Input.PeekCharNoEOF(2) == 'U' &&
744              m_Input.PeekCharNoEOF(3) == 'E' &&
745              !IdChar(m_Input.PeekCharNoEOF(4)) ) {
746             m_Input.SkipChars(4);
747             return true;
748         }
749         break;
750     case 'F':
751         if ( m_Input.PeekCharNoEOF(1) == 'A' &&
752              m_Input.PeekCharNoEOF(2) == 'L' &&
753              m_Input.PeekCharNoEOF(3) == 'S' &&
754              m_Input.PeekCharNoEOF(4) == 'E' &&
755              !IdChar(m_Input.PeekCharNoEOF(5)) ) {
756             m_Input.SkipChars(5);
757             return false;
758         }
759         break;
760     }
761     ThrowError(fFormatError, "TRUE or FALSE expected");
762     return false;
763 }
764 
ReadChar(void)765 char CObjectIStreamAsn::ReadChar(void)
766 {
767     string s;
768     ReadString(s);
769     if ( s.size() != 1 ) {
770         ThrowError(fFormatError,
771                    "\"" + s + "\": one char string expected");
772     }
773     return s[0];
774 }
775 
ReadInt4(void)776 Int4 CObjectIStreamAsn::ReadInt4(void)
777 {
778     SkipWhiteSpace();
779     return m_Input.GetInt4();
780 }
781 
ReadUint4(void)782 Uint4 CObjectIStreamAsn::ReadUint4(void)
783 {
784     SkipWhiteSpace();
785     return m_Input.GetUint4();
786 }
787 
ReadInt8(void)788 Int8 CObjectIStreamAsn::ReadInt8(void)
789 {
790     SkipWhiteSpace();
791     return m_Input.GetInt8();
792 }
793 
ReadUint8(void)794 Uint8 CObjectIStreamAsn::ReadUint8(void)
795 {
796     SkipWhiteSpace();
797     return m_Input.GetUint8();
798 }
799 
ReadDouble(void)800 double CObjectIStreamAsn::ReadDouble(void)
801 {
802     double result = 0;
803     if (PeekChar(true) != '{') {
804         CTempString tmp( ScanEndOfId(true) );
805         if (NStr::strncasecmp(tmp.data(), "PLUS-INFINITY", 13) == 0) {
806             return HUGE_VAL;
807         } else if (NStr::strncasecmp(tmp.data(),"MINUS-INFINITY", 14) == 0) {
808             return -HUGE_VAL;
809         } else if (NStr::strncasecmp(tmp.data(),"NOT-A-NUMBER", 12) == 0) {
810 	    return HUGE_VAL/HUGE_VAL; /* NCBI_FAKE_WARNING */
811         }
812         char* endptr;
813         return NStr::StringToDoublePosix( string(tmp).c_str(), &endptr, NStr::fDecimalPosixFinite );
814     }
815     Expect('{', true);
816     bool is_negative = PeekChar(true) == '-';
817     CTempString mantissaStr = ReadNumber();
818     size_t mantissaLength = mantissaStr.size();
819     char buffer[128];
820     if ( mantissaLength >= sizeof(buffer) - 1 )
821         ThrowError(fOverflow, "buffer overflow");
822     memcpy(buffer, mantissaStr.data(), mantissaLength);
823     buffer[mantissaLength] = '\0';
824     char* endptr;
825     double mantissa = NStr::StringToDoublePosix(buffer, &endptr);
826     if ( *endptr != 0 )
827         ThrowError(fFormatError, "bad double in line "
828             + NStr::SizetToString(m_Input.GetLine()));
829     Expect(',', true);
830     unsigned base = ReadUint4();
831     Expect(',', true);
832     int exp = ReadInt4();
833     Expect('}', true);
834     if ( base != 2 && base != 10 ) {
835         ThrowError(fFormatError, "illegal REAL base (must be 2 or 10)");
836     }
837     if (mantissa == 0.) {
838         return mantissa;
839     }
840     if (is_negative) {
841         mantissa = -mantissa;
842     }
843 
844     if ( base == 10 ) {
845         result = mantissa * pow((double)10.0, exp);
846     } else {
847         result = ldexp( mantissa, exp);
848     }
849 
850     if (result >= 0 && result <= DBL_MIN) {
851         result = DBL_MIN;
852     } else if (!finite(result)) {
853         result = DBL_MAX;
854     }
855     return is_negative ? -result : result;
856 }
857 
BadStringChar(size_t startLine,char c)858 void CObjectIStreamAsn::BadStringChar(size_t startLine, char c)
859 {
860     ThrowError(fFormatError,
861                "bad char in string starting at line "+
862                NStr::SizetToString(startLine)+": "+
863                NStr::IntToString(c));
864 }
865 
UnendedString(size_t startLine)866 void CObjectIStreamAsn::UnendedString(size_t startLine)
867 {
868     ThrowError(fFormatError,
869                "unclosed string starts at line "+
870                NStr::SizetToString(startLine));
871 }
872 
873 
874 inline
AppendStringData(string & s,size_t count,EFixNonPrint fix_method,size_t)875 void CObjectIStreamAsn::AppendStringData(string& s,
876                                          size_t count,
877                                          EFixNonPrint fix_method,
878                                          size_t /*line*/)
879 {
880     const char* data = m_Input.GetCurrentPos();
881     if ( fix_method != eFNP_Allow ) {
882         size_t done = 0, valid = 0;
883         for ( size_t i = 0; i < count; ++i ) {
884             char c = data[i];
885             if ( !GoodVisibleChar(c) ) {
886 #if SERIAL_ALLOW_UTF8_IN_VISIBLESTRING_ON_READING
887                 if (valid == 0) {
888                     if (CUtf8::EvaluateFirst(c, valid)) {
889                         ++valid;
890                     }
891                 }
892 #endif
893                 if (valid == 0) {
894                     if ( i > done ) {
895                         s.append(data + done, i - done);
896                     }
897                     c = ReplaceVisibleChar(c, fix_method, this, CTempString(data,count), x_FixCharsSubst());
898                     if (c != 0) {
899                         s += c;
900                     }
901                     done = i + 1;
902                 }
903             }
904             if (valid != 0) {
905                 --valid;
906             }
907         }
908         if ( done < count ) {
909             s.append(data + done, count - done);
910         }
911     }
912     else {
913         s.append(data, count);
914     }
915     if ( count > 0 ) {
916         m_Input.SkipChars(count);
917     }
918 }
919 
920 
AppendLongStringData(string & s,size_t count,EFixNonPrint fix_method,size_t line)921 void CObjectIStreamAsn::AppendLongStringData(string& s,
922                                              size_t count,
923                                              EFixNonPrint fix_method,
924                                              size_t line)
925 {
926     // Reserve extra-space to reduce heap reallocation
927     if ( s.empty() ) {
928         s.reserve(count*2);
929     }
930     else if ( s.capacity() < double(s.size()+1)*1.1 ) {
931         s.reserve(s.size()*2);
932     }
933     AppendStringData(s, count, fix_method, line);
934 }
935 
936 
ReadStringValue(string & s,EFixNonPrint fix_method)937 void CObjectIStreamAsn::ReadStringValue(string& s, EFixNonPrint fix_method)
938 {
939     Expect('\"', true);
940     size_t startLine = m_Input.GetLine();
941     size_t i = 0;
942     s.erase();
943     try {
944         for (;;) {
945             char c = m_Input.PeekChar(i);
946             switch ( c ) {
947             case '\r':
948             case '\n':
949                 // flush string
950                 AppendLongStringData(s, i, fix_method, startLine);
951                 m_Input.SkipChar(); // '\r' or '\n'
952                 i = 0;
953                 // skip end of line
954                 SkipEndOfLine(c);
955                 break;
956             case '\"':
957                 s.reserve(s.size() + i);
958                 AppendStringData(s, i, fix_method, startLine);
959                 m_Input.SkipChar(); // quote
960                 if ( m_Input.PeekCharNoEOF() != '\"' ) {
961                     // end of string
962                     return;
963                 }
964                 else {
965                     // double quote -> one quote
966                     i = 1;
967                 }
968                 break;
969             default:
970                 // ok: append char
971                 if ( ++i == 128 ) {
972                     // too long string -> flush it
973                     AppendLongStringData(s, i, fix_method, startLine);
974                     i = 0;
975                 }
976                 break;
977             }
978         }
979     }
980     catch ( CEofException& ) {
981         SetFailFlags(fEOF);
982         UnendedString(startLine);
983         throw;
984     }
985 }
986 
ReadString(string & s,EStringType type)987 void CObjectIStreamAsn::ReadString(string& s, EStringType type)
988 {
989     ReadStringValue(s, type == eStringTypeUTF8? eFNP_Allow: x_FixCharsMethod());
990 }
991 
SkipBool(void)992 void CObjectIStreamAsn::SkipBool(void)
993 {
994     switch ( SkipWhiteSpace() ) {
995     case 'T':
996         if ( m_Input.PeekCharNoEOF(1) == 'R' &&
997              m_Input.PeekCharNoEOF(2) == 'U' &&
998              m_Input.PeekCharNoEOF(3) == 'E' &&
999              !IdChar(m_Input.PeekCharNoEOF(4)) ) {
1000             m_Input.SkipChars(4);
1001             return;
1002         }
1003         break;
1004     case 'F':
1005         if ( m_Input.PeekCharNoEOF(1) == 'A' &&
1006              m_Input.PeekCharNoEOF(2) == 'L' &&
1007              m_Input.PeekCharNoEOF(3) == 'S' &&
1008              m_Input.PeekCharNoEOF(4) == 'E' &&
1009              !IdChar(m_Input.PeekCharNoEOF(5)) ) {
1010             m_Input.SkipChars(5);
1011             return;
1012         }
1013         break;
1014     }
1015     ThrowError(fFormatError, "TRUE or FALSE expected");
1016 }
1017 
SkipChar(void)1018 void CObjectIStreamAsn::SkipChar(void)
1019 {
1020     // TODO: check string length to be 1
1021     SkipString();
1022 }
1023 
SkipSNumber(void)1024 void CObjectIStreamAsn::SkipSNumber(void)
1025 {
1026     size_t i;
1027     char c = SkipWhiteSpace();
1028     switch ( c ) {
1029     case '-':
1030     case '+':
1031         c = m_Input.PeekChar(1);
1032         // next char
1033         i = 2;
1034         break;
1035     default:
1036         // next char
1037         i = 1;
1038         break;
1039     }
1040     if ( c < '0' || c > '9' ) {
1041         ThrowError(fFormatError, "bad signed integer in line "
1042             + NStr::SizetToString(m_Input.GetLine()));
1043     }
1044     while ( (c = m_Input.PeekChar(i)) >= '0' && c <= '9' ) {
1045         ++i;
1046     }
1047     m_Input.SkipChars(i);
1048 }
1049 
SkipUNumber(void)1050 void CObjectIStreamAsn::SkipUNumber(void)
1051 {
1052     size_t i;
1053     char c = SkipWhiteSpace();
1054     switch ( c ) {
1055     case '+':
1056         c = m_Input.PeekChar(1);
1057         // next char
1058         i = 2;
1059         break;
1060     default:
1061         // next char
1062         i = 1;
1063         break;
1064     }
1065     if ( c < '0' || c > '9' ) {
1066         ThrowError(fFormatError, "bad unsigned integer in line "
1067             + NStr::SizetToString(m_Input.GetLine()));
1068     }
1069     while ( (c = m_Input.PeekCharNoEOF(i)) >= '0' && c <= '9' ) {
1070         ++i;
1071     }
1072     m_Input.SkipChars(i);
1073 }
1074 
SkipFNumber(void)1075 void CObjectIStreamAsn::SkipFNumber(void)
1076 {
1077     if (PeekChar(true) != '{') {
1078         ScanEndOfId(true);
1079         return;
1080     }
1081     Expect('{', true);
1082     SkipSNumber();
1083     Expect(',', true);
1084     unsigned base = ReadUint4();
1085     Expect(',', true);
1086     SkipSNumber();
1087     Expect('}', true);
1088     if ( base != 2 && base != 10 )
1089         ThrowError(fFormatError, "illegal REAL base (must be 2 or 10)");
1090 }
1091 
SkipString(EStringType type)1092 void CObjectIStreamAsn::SkipString(EStringType type)
1093 {
1094     Expect('\"', true);
1095     size_t startLine = m_Input.GetLine();
1096     size_t i = 0, valid = 0;
1097     try {
1098         for (;;) {
1099             char c = m_Input.PeekChar(i);
1100             switch ( c ) {
1101             case '\r':
1102             case '\n':
1103                 // flush string
1104                 m_Input.SkipChars(i + 1);
1105                 i = 0;
1106                 // skip end of line
1107                 SkipEndOfLine(c);
1108                 break;
1109             case '\"':
1110                 if ( m_Input.PeekCharNoEOF(i + 1) == '\"' ) {
1111                     // double quote -> one quote
1112                     m_Input.SkipChars(i + 2);
1113                     i = 0;
1114                 }
1115                 else {
1116                     // end of string
1117                     m_Input.SkipChars(i + 1);
1118                     return;
1119                 }
1120                 break;
1121             default:
1122                 if (type == eStringTypeVisible) {
1123                     if ( !GoodVisibleChar(c) ) {
1124 #if SERIAL_ALLOW_UTF8_IN_VISIBLESTRING_ON_READING
1125                         if (valid == 0) {
1126                             if (CUtf8::EvaluateFirst(c, valid)) {
1127                                 ++valid;
1128                             }
1129                         }
1130 #endif
1131                         if (valid == 0) {
1132                             c = ReplaceVisibleChar(c, x_FixCharsMethod(), this, kEmptyStr, x_FixCharsSubst());
1133                         }
1134                     }
1135                 }
1136                 // ok: skip char
1137                 if ( ++i == 128 ) {
1138                     // too long string -> flush it
1139                     m_Input.SkipChars(i);
1140                     i = 0;
1141                 }
1142                 break;
1143             }
1144             if (valid != 0) {
1145                 --valid;
1146             }
1147         }
1148     }
1149     catch ( CEofException& ) {
1150         SetFailFlags(fEOF);
1151         UnendedString(startLine);
1152         throw;
1153     }
1154 }
1155 
SkipNull(void)1156 void CObjectIStreamAsn::SkipNull(void)
1157 {
1158     if ( SkipWhiteSpace() == 'N' &&
1159          m_Input.PeekCharNoEOF(1) == 'U' &&
1160          m_Input.PeekCharNoEOF(2) == 'L' &&
1161          m_Input.PeekCharNoEOF(3) == 'L' &&
1162          !IdChar(m_Input.PeekCharNoEOF(4)) ) {
1163         m_Input.SkipChars(4);
1164         return;
1165     }
1166     ThrowError(fFormatError, "NULL expected");
1167 }
1168 
SkipByteBlock(void)1169 void CObjectIStreamAsn::SkipByteBlock(void)
1170 {
1171     Expect('\'', true);
1172     for ( ;; ) {
1173         char c = GetChar();
1174         if ( c >= '0' && c <= '9' ) {
1175             continue;
1176         }
1177         else if ( c >= 'A' && c <= 'F' ) {
1178             continue;
1179         }
1180         else if ( c >= 'a' && c <= 'f' ) {
1181             continue;
1182         }
1183         else if ( c == '\'' ) {
1184             break;
1185         }
1186         else if ( c == '\r' || c == '\n' ) {
1187             SkipEndOfLine(c);
1188         }
1189         else {
1190             m_Input.UngetChar(c);
1191             ThrowError(fFormatError, "bad char in octet string: #"
1192                 + NStr::IntToString(c));
1193         }
1194     }
1195     Expect('H', 'B', true);
1196 }
1197 
StartBlock(void)1198 void CObjectIStreamAsn::StartBlock(void)
1199 {
1200     Expect('{', true);
1201     m_BlockStart = true;
1202 }
1203 
NextElement(void)1204 bool CObjectIStreamAsn::NextElement(void)
1205 {
1206     char c = SkipWhiteSpace();
1207     if ( m_BlockStart ) {
1208         // first element
1209         m_BlockStart = false;
1210         return c != '}';
1211     }
1212     else {
1213         // next element
1214         if ( c == ',' ) {
1215             m_Input.SkipChar();
1216             return true;
1217         }
1218         else if ( c != '}' )
1219             ThrowError(fFormatError, "',' or '}' expected");
1220         return false;
1221     }
1222 }
1223 
EndBlock(void)1224 void CObjectIStreamAsn::EndBlock(void)
1225 {
1226     Expect('}');
1227 }
1228 
BeginContainer(const CContainerTypeInfo *)1229 void CObjectIStreamAsn::BeginContainer(const CContainerTypeInfo* /*cType*/)
1230 {
1231     StartBlock();
1232 }
1233 
EndContainer(void)1234 void CObjectIStreamAsn::EndContainer(void)
1235 {
1236     EndBlock();
1237 }
1238 
BeginContainerElement(TTypeInfo)1239 bool CObjectIStreamAsn::BeginContainerElement(TTypeInfo /*elementType*/)
1240 {
1241     return NextElement();
1242 }
1243 
1244 #ifdef VIRTUAL_MID_LEVEL_IO
ReadContainer(const CContainerTypeInfo * contType,TObjectPtr contPtr)1245 void CObjectIStreamAsn::ReadContainer(const CContainerTypeInfo* contType,
1246                                       TObjectPtr contPtr)
1247 {
1248     BEGIN_OBJECT_FRAME2(eFrameArray, contType);
1249     StartBlock();
1250 
1251     BEGIN_OBJECT_FRAME(eFrameArrayElement);
1252 
1253     CContainerTypeInfo::CIterator iter;
1254     bool old_element = contType->InitIterator(iter, contPtr);
1255     TTypeInfo elementType = contType->GetElementType();
1256     while ( NextElement() ) {
1257         if ( old_element ) {
1258             elementType->ReadData(*this, contType->GetElementPtr(iter));
1259             old_element = contType->NextElement(iter);
1260         }
1261         else {
1262             contType->AddElement(contPtr, *this);
1263         }
1264     }
1265     if ( old_element ) {
1266         contType->EraseAllElements(iter);
1267     }
1268 
1269     END_OBJECT_FRAME();
1270 
1271     EndBlock();
1272     END_OBJECT_FRAME();
1273 }
1274 
SkipContainer(const CContainerTypeInfo * contType)1275 void CObjectIStreamAsn::SkipContainer(const CContainerTypeInfo* contType)
1276 {
1277     BEGIN_OBJECT_FRAME2(eFrameArray, contType);
1278     StartBlock();
1279 
1280     TTypeInfo elementType = contType->GetElementType();
1281     BEGIN_OBJECT_FRAME(eFrameArrayElement);
1282 
1283     while ( NextElement() ) {
1284         SkipObject(elementType);
1285     }
1286 
1287     END_OBJECT_FRAME();
1288 
1289     EndBlock();
1290     END_OBJECT_FRAME();
1291 }
1292 #endif
1293 
BeginClass(const CClassTypeInfo *)1294 void CObjectIStreamAsn::BeginClass(const CClassTypeInfo* /*classInfo*/)
1295 {
1296     StartBlock();
1297 }
1298 
EndClass(void)1299 void CObjectIStreamAsn::EndClass(void)
1300 {
1301     EndBlock();
1302 }
1303 
UnexpectedMember(const CTempString & id,const CItemsInfo & items)1304 void CObjectIStreamAsn::UnexpectedMember(const CTempString& id,
1305                                          const CItemsInfo& items)
1306 {
1307     string message =
1308         "\""+string(id)+"\": unexpected member, should be one of: ";
1309     for ( CItemsInfo::CIterator i(items); i.Valid(); ++i ) {
1310         message += '\"' + items.GetItemInfo(i)->GetId().ToString() + "\" ";
1311     }
1312     ThrowError(fFormatError, message);
1313 }
1314 
1315 TMemberIndex
BeginClassMember(const CClassTypeInfo * classType)1316 CObjectIStreamAsn::BeginClassMember(const CClassTypeInfo* classType)
1317 {
1318     if ( !NextElement() )
1319         return kInvalidMember;
1320 
1321     CTempString id = ReadMemberId(SkipWhiteSpace());
1322     TMemberIndex index = GetMemberIndex(classType, id);
1323     if ( index == kInvalidMember ) {
1324         if (CanSkipUnknownMembers()) {
1325             SetFailFlags(fUnknownValue);
1326             SkipAnyContent();
1327             return BeginClassMember(classType);
1328         } else {
1329             UnexpectedMember(id, classType->GetMembers());
1330         }
1331     }
1332     return index;
1333 }
1334 
1335 TMemberIndex
BeginClassMember(const CClassTypeInfo * classType,TMemberIndex pos)1336 CObjectIStreamAsn::BeginClassMember(const CClassTypeInfo* classType,
1337                                     TMemberIndex pos)
1338 {
1339     if ( !NextElement() )
1340         return kInvalidMember;
1341 
1342     CTempString id = ReadMemberId(SkipWhiteSpace());
1343     TMemberIndex index = GetMemberIndex(classType, id, pos);
1344     if ( index == kInvalidMember ) {
1345         if (m_TypeAlias && classType->GetMembers().GetItemInfo(pos)->GetId().HasNotag()) {
1346             m_TypeAlias = nullptr;
1347             return pos;
1348         } else if (CanSkipUnknownMembers()) {
1349             SetFailFlags(fUnknownValue);
1350             SkipAnyContent();
1351             return BeginClassMember(classType, pos);
1352         } else {
1353             UnexpectedMember(id, classType->GetMembers());
1354         }
1355     }
1356     return index;
1357 }
1358 
1359 #ifdef VIRTUAL_MID_LEVEL_IO
ReadClassRandom(const CClassTypeInfo * classType,TObjectPtr classPtr)1360 void CObjectIStreamAsn::ReadClassRandom(const CClassTypeInfo* classType,
1361                                         TObjectPtr classPtr)
1362 {
1363     BEGIN_OBJECT_FRAME3(eFrameClass, classType, classPtr);
1364     StartBlock();
1365 
1366     ReadClassRandomContentsBegin(classType);
1367 
1368     TMemberIndex index;
1369     while ( (index = BeginClassMember(classType)) != kInvalidMember ) {
1370         ReadClassRandomContentsMember(classPtr);
1371     }
1372 
1373     ReadClassRandomContentsEnd();
1374 
1375     EndBlock();
1376     END_OBJECT_FRAME();
1377 }
1378 
ReadClassSequential(const CClassTypeInfo * classType,TObjectPtr classPtr)1379 void CObjectIStreamAsn::ReadClassSequential(const CClassTypeInfo* classType,
1380                                             TObjectPtr classPtr)
1381 {
1382     BEGIN_OBJECT_FRAME3(eFrameClass, classType, classPtr);
1383     StartBlock();
1384 
1385     ReadClassSequentialContentsBegin(classType);
1386 
1387     TMemberIndex index;
1388     while ( (index = BeginClassMember(classType,*pos)) != kInvalidMember ) {
1389         ReadClassSequentialContentsMember(classPtr);
1390     }
1391 
1392     ReadClassSequentialContentsEnd(classPtr);
1393 
1394     EndBlock();
1395     END_OBJECT_FRAME();
1396 }
1397 
SkipClassRandom(const CClassTypeInfo * classType)1398 void CObjectIStreamAsn::SkipClassRandom(const CClassTypeInfo* classType)
1399 {
1400     BEGIN_OBJECT_FRAME2(eFrameClass, classType);
1401     StartBlock();
1402 
1403     SkipClassRandomContentsBegin(classType);
1404 
1405     TMemberIndex index;
1406     while ( (index = BeginClassMember(classType)) != kInvalidMember ) {
1407         SkipClassRandomContentsMember();
1408     }
1409 
1410     SkipClassRandomContentsEnd();
1411 
1412     EndBlock();
1413     END_OBJECT_FRAME();
1414 }
1415 
SkipClassSequential(const CClassTypeInfo * classType)1416 void CObjectIStreamAsn::SkipClassSequential(const CClassTypeInfo* classType)
1417 {
1418     BEGIN_OBJECT_FRAME2(eFrameClass, classType);
1419     StartBlock();
1420 
1421     SkipClassSequentialContentsBegin(classType);
1422 
1423     TMemberIndex index;
1424     while ( (index = BeginClassMember(classType,*pos)) != kInvalidMember ) {
1425         SkipClassSequentialContentsMember();
1426     }
1427 
1428     SkipClassSequentialContentsEnd();
1429 
1430     EndBlock();
1431     END_OBJECT_FRAME();
1432 }
1433 #endif
1434 
BeginChoice(const CChoiceTypeInfo * choiceType)1435 void CObjectIStreamAsn::BeginChoice(const CChoiceTypeInfo* choiceType)
1436 {
1437     if (choiceType->GetVariantInfo(kFirstMemberIndex)->GetId().IsAttlist()) {
1438         TopFrame().SetNotag();
1439         StartBlock();
1440     }
1441     m_BlockStart = true;
1442 }
EndChoice(void)1443 void CObjectIStreamAsn::EndChoice(void)
1444 {
1445     if (TopFrame().GetNotag()) {
1446         SkipWhiteSpace();
1447         EndBlock();
1448     }
1449     m_BlockStart = false;
1450 }
1451 
BeginChoiceVariant(const CChoiceTypeInfo * choiceType)1452 TMemberIndex CObjectIStreamAsn::BeginChoiceVariant(const CChoiceTypeInfo* choiceType)
1453 {
1454     bool skipname = !m_BlockStart;
1455     if ( !NextElement() )
1456         return kInvalidMember;
1457     CTempString id = ReadMemberId(SkipWhiteSpace());
1458     if (skipname) {
1459         id = ReadMemberId(SkipWhiteSpace());
1460     }
1461     if ( id.empty() )
1462         ThrowError(fFormatError, "choice variant id expected");
1463 
1464     TMemberIndex index = GetChoiceIndex(choiceType, id);
1465     if ( index == kInvalidMember ) {
1466         if (CanSkipUnknownVariants()) {
1467             SetFailFlags(fUnknownValue);
1468         } else {
1469             UnexpectedMember(id, choiceType->GetVariants());
1470         }
1471     }
1472 
1473     return index;
1474 }
1475 
BeginBytes(ByteBlock &)1476 void CObjectIStreamAsn::BeginBytes(ByteBlock& )
1477 {
1478     Expect('\'', true);
1479 }
1480 
GetHexChar(void)1481 int CObjectIStreamAsn::GetHexChar(void)
1482 {
1483     for ( ;; ) {
1484         char c = GetChar();
1485         if ( c >= '0' && c <= '9' ) {
1486             return c - '0';
1487         }
1488         else if ( c >= 'A' && c <= 'F' ) {
1489             return c - 'A' + 10;
1490         }
1491         else if ( c >= 'a' && c <= 'f' ) {
1492             return c - 'a' + 10;
1493         }
1494         switch ( c ) {
1495         case '\'':
1496             return -1;
1497         case '\r':
1498         case '\n':
1499             SkipEndOfLine(c);
1500             break;
1501         default:
1502             m_Input.UngetChar(c);
1503             ThrowError(fFormatError, "bad char in octet string: #"
1504                 + NStr::IntToString(c));
1505         }
1506     }
1507 }
1508 
ReadBytes(ByteBlock & block,char * dst,size_t length)1509 size_t CObjectIStreamAsn::ReadBytes(ByteBlock& block,
1510                                     char* dst, size_t length)
1511 {
1512     size_t count = 0;
1513     while ( length-- > 0 ) {
1514         int c1 = GetHexChar();
1515         if ( c1 < 0 ) {
1516             block.EndOfBlock();
1517             return count;
1518         }
1519         int c2 = GetHexChar();
1520         if ( c2 < 0 ) {
1521             *dst++ = char(c1 << 4);
1522             count++;
1523             block.EndOfBlock();
1524             return count;
1525         }
1526         else {
1527             *dst++ = char((c1 << 4) | c2);
1528             count++;
1529         }
1530     }
1531     return count;
1532 }
1533 
EndBytes(const ByteBlock &)1534 void CObjectIStreamAsn::EndBytes(const ByteBlock& )
1535 {
1536     Expect('H');
1537 }
1538 
BeginChars(CharBlock &)1539 void CObjectIStreamAsn::BeginChars(CharBlock& )
1540 {
1541     Expect('\"', true);
1542 }
1543 
ReadChars(CharBlock & block,char * dst,size_t length)1544 size_t CObjectIStreamAsn::ReadChars(CharBlock& block,
1545                                     char* dst, size_t length)
1546 {
1547     size_t count = 0, valid = 0;
1548     try {
1549         while (length-- > 0) {
1550             char c = m_Input.GetChar();
1551             switch ( c ) {
1552             case '\r':
1553             case '\n':
1554                 break;
1555             case '\"':
1556                 if ( m_Input.PeekCharNoEOF() == '\"' ) {
1557                     m_Input.SkipChar();
1558                     dst[count++] = c;
1559                 }
1560                 else {
1561                     // end of string
1562                     // Check the string for non-printable characters
1563                     EFixNonPrint fix_method = x_FixCharsMethod();
1564                     if ( fix_method != eFNP_Allow ) {
1565                         for (size_t i = 0;  i < count;  i++) {
1566                             if ( !GoodVisibleChar(dst[i]) ) {
1567 #if SERIAL_ALLOW_UTF8_IN_VISIBLESTRING_ON_READING
1568                                 if (valid == 0) {
1569                                     if (CUtf8::EvaluateFirst(dst[i], valid)) {
1570                                         ++valid;
1571                                     }
1572                                 }
1573 #endif
1574                                 if (valid == 0) {
1575                                      char c = ReplaceVisibleChar(dst[i], fix_method, this, CTempString(dst, count), x_FixCharsSubst());
1576                                      dst[i] = c == '\0' ? '#' : c;
1577                                 }
1578                             }
1579                             if (valid != 0) {
1580                                 --valid;
1581                             }
1582                         }
1583                     }
1584                     block.EndOfBlock();
1585                     return count;
1586                 }
1587                 break;
1588             default:
1589                 // ok: append char
1590                 {
1591                     dst[count++] = c;
1592                 }
1593                 break;
1594             }
1595         }
1596     }
1597     catch ( CEofException& ) {
1598         SetFailFlags(fEOF);
1599         UnendedString(m_Input.GetLine());
1600         throw;
1601     }
1602     return count;
1603 }
1604 
ReadPointerType(void)1605 CObjectIStream::EPointerType CObjectIStreamAsn::ReadPointerType(void)
1606 {
1607     switch ( PeekChar(true) ) {
1608     case 'N':
1609         if ( m_Input.PeekCharNoEOF(1) == 'U' &&
1610              m_Input.PeekCharNoEOF(2) == 'L' &&
1611              m_Input.PeekCharNoEOF(3) == 'L' &&
1612              !IdChar(m_Input.PeekCharNoEOF(4)) ) {
1613             // "NULL"
1614             m_Input.SkipChars(4);
1615             return eNullPointer;
1616         }
1617         break;
1618     case '@':
1619         m_Input.SkipChar();
1620         return eObjectPointer;
1621     case ':':
1622         m_Input.SkipChar();
1623         return eOtherPointer;
1624     default:
1625         break;
1626     }
1627     return eThisPointer;
1628 }
1629 
ReadObjectPointer(void)1630 CObjectIStream::TObjectIndex CObjectIStreamAsn::ReadObjectPointer(void)
1631 {
1632     if ( sizeof(TObjectIndex) == sizeof(Int4) )
1633         return ReadInt4();
1634     else if ( sizeof(TObjectIndex) == sizeof(Int8) )
1635         return TObjectIndex(ReadInt8());
1636     else
1637         ThrowError(fIllegalCall, "invalid size of TObjectIndex:"
1638             " must be either sizeof(Int4) or sizeof(Int8)");
1639     return 0;
1640 }
1641 
ReadOtherPointer(void)1642 string CObjectIStreamAsn::ReadOtherPointer(void)
1643 {
1644     return ReadTypeId(SkipWhiteSpace());
1645 }
1646 
StartDelayBuffer(void)1647 void CObjectIStreamAsn::StartDelayBuffer(void)
1648 {
1649     SkipWhiteSpace();
1650     CObjectIStream::StartDelayBuffer();
1651 }
1652 
1653 END_NCBI_SCOPE
1654