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