1 /*  $Id: objistrjson.cpp 624386 2021-01-28 19:46:31Z ivanov $
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: Andrei Gourianov
27 *
28 * File Description:
29 *   JSON object input stream
30 *
31 */
32 
33 #include <ncbi_pch.hpp>
34 #include <corelib/ncbistd.hpp>
35 #include <corelib/ncbi_limits.h>
36 
37 #include <serial/objistrjson.hpp>
38 
39 #define NCBI_USE_ERRCODE_X   Serial_OStream
40 
41 BEGIN_NCBI_SCOPE
42 
CreateObjectIStreamJson()43 CObjectIStream* CObjectIStream::CreateObjectIStreamJson()
44 {
45     return new CObjectIStreamJson();
46 }
47 
48 
CObjectIStreamJson(void)49 CObjectIStreamJson::CObjectIStreamJson(void)
50     : CObjectIStream(eSerial_Json),
51     m_FileHeader(false),
52     m_BlockStart(false),
53     m_ExpectValue(false),
54     m_GotNameless(false),
55     m_Closing(0),
56     m_StringEncoding( eEncoding_UTF8 ),
57     m_BinaryFormat(eDefault)
58 {
59     m_Utf8Pos = m_Utf8Buf.begin();
60 }
61 
CObjectIStreamJson(CNcbiIstream & in,EOwnership deleteIn)62 CObjectIStreamJson::CObjectIStreamJson(CNcbiIstream& in, EOwnership deleteIn)
63     : CObjectIStream(eSerial_Json),
64     m_FileHeader(false),
65     m_BlockStart(false),
66     m_ExpectValue(false),
67     m_GotNameless(false),
68     m_Closing(0),
69     m_StringEncoding( eEncoding_UTF8 ),
70     m_BinaryFormat(eDefault)
71 {
72     m_Utf8Pos = m_Utf8Buf.begin();
73     Open(in, deleteIn);
74 }
75 
~CObjectIStreamJson(void)76 CObjectIStreamJson::~CObjectIStreamJson(void)
77 {
78 }
79 
ResetState(void)80 void CObjectIStreamJson::ResetState(void)
81 {
82     CObjectIStream::ResetState();
83     if (GetStackDepth() > 1) {
84         return;
85     }
86     m_LastTag.clear();
87     m_RejectedTag.clear();
88     m_Utf8Buf.clear();
89     m_Utf8Pos = m_Utf8Buf.begin();
90 }
91 
EndOfData(void)92 bool CObjectIStreamJson::EndOfData(void)
93 {
94     if (CObjectIStream::EndOfData()) {
95         return true;
96     }
97     try {
98         SkipWhiteSpace();
99     } catch (...) {
100         return true;
101     }
102     return false;
103 }
104 
GetPosition(void) const105 string CObjectIStreamJson::GetPosition(void) const
106 {
107     return "line "+NStr::SizetToString(m_Input.GetLine());
108 }
109 
SetDefaultStringEncoding(EEncoding enc)110 void CObjectIStreamJson::SetDefaultStringEncoding(EEncoding enc)
111 {
112     m_StringEncoding = enc;
113 }
114 
GetDefaultStringEncoding(void) const115 EEncoding CObjectIStreamJson::GetDefaultStringEncoding(void) const
116 {
117     return m_StringEncoding;
118 }
119 
120 CObjectIStreamJson::EBinaryDataFormat
GetBinaryDataFormat(void) const121 CObjectIStreamJson::GetBinaryDataFormat(void) const
122 {
123     return m_BinaryFormat;
124 }
SetBinaryDataFormat(CObjectIStreamJson::EBinaryDataFormat fmt)125 void CObjectIStreamJson::SetBinaryDataFormat(CObjectIStreamJson::EBinaryDataFormat fmt)
126 {
127     m_BinaryFormat = fmt;
128 }
129 
GetChar(void)130 char CObjectIStreamJson::GetChar(void)
131 {
132     return m_Input.GetChar();
133 }
134 
PeekChar(void)135 char CObjectIStreamJson::PeekChar(void)
136 {
137     return m_Input.PeekChar();
138 }
139 
GetChar(bool skipWhiteSpace)140 char CObjectIStreamJson::GetChar(bool skipWhiteSpace)
141 {
142     return skipWhiteSpace? SkipWhiteSpaceAndGetChar(): m_Input.GetChar();
143 }
144 
PeekChar(bool skipWhiteSpace)145 char CObjectIStreamJson::PeekChar(bool skipWhiteSpace)
146 {
147     return skipWhiteSpace? SkipWhiteSpace(): m_Input.PeekChar();
148 }
149 
SkipEndOfLine(char c)150 void CObjectIStreamJson::SkipEndOfLine(char c)
151 {
152     m_Input.SkipEndOfLine(c);
153 }
154 
SkipWhiteSpace(void)155 char CObjectIStreamJson::SkipWhiteSpace(void)
156 {
157     try { // catch CEofException
158         for ( ;; ) {
159             char c = m_Input.SkipSpaces();
160             switch ( c ) {
161             case '\t':
162                 m_Input.SkipChar();
163                 continue;
164             case '\r':
165             case '\n':
166                 m_Input.SkipChar();
167                 SkipEndOfLine(c);
168                 continue;
169             default:
170                 return c;
171             }
172         }
173     } catch (CEofException& e) {
174         ThrowError(fEOF, e.what());
175     }
176     return '\0';
177 }
178 
SkipWhiteSpaceAndGetChar(void)179 char CObjectIStreamJson::SkipWhiteSpaceAndGetChar(void)
180 {
181     char c = SkipWhiteSpace();
182     m_Input.SkipChar();
183     return c;
184 }
185 
GetChar(char expect,bool skipWhiteSpace)186 bool CObjectIStreamJson::GetChar(char expect, bool skipWhiteSpace /* = false*/)
187 {
188     if ( PeekChar(skipWhiteSpace) != expect ) {
189         return false;
190     }
191     m_Input.SkipChar();
192     return true;
193 }
194 
Expect(char expect,bool skipWhiteSpace)195 void CObjectIStreamJson::Expect(char expect, bool skipWhiteSpace /* = false*/)
196 {
197     if ( !GetChar(expect, skipWhiteSpace) ) {
198         string msg("\'");
199         msg += expect;
200         msg += "' expected";
201         ThrowError(fFormatError, msg);
202     }
203 }
204 
UnexpectedMember(const CTempString & id,const CItemsInfo & items)205 void CObjectIStreamJson::UnexpectedMember(const CTempString& id,
206                                           const CItemsInfo& items)
207 {
208     string message =
209         "\""+string(id)+"\": unexpected member, should be one of: ";
210     for ( CItemsInfo::CIterator i(items); i.Valid(); ++i ) {
211         message += '\"' + items.GetItemInfo(i)->GetId().ToString() + "\" ";
212     }
213     ThrowError(fFormatError, message);
214 }
215 
216 template<typename Type> inline
x_UseMemberDefault(void)217 Type CObjectIStreamJson::x_UseMemberDefault(void)
218 {
219     return GetMemberDefault() ? CTypeConverter<Type>::Get(GetMemberDefault()) : Type();
220 }
221 
ReadEscapedChar(bool * encoded)222 int CObjectIStreamJson::ReadEscapedChar(bool* encoded /*=0*/)
223 {
224     char c = GetChar();
225     if (c == '\\') {
226         if (encoded) {
227             *encoded = true;
228         }
229         c = GetChar();
230         if (c == 'u') {
231             int v = 0;
232             for (int p=0; p<4; ++p) {
233                 c = GetChar();
234                 if (c >= '0' && c <= '9') {
235                     v = v * 16 + (c - '0');
236                 } else if (c >= 'A' && c <= 'F') {
237                     v = v * 16 + (c - 'A' + 0xA);
238                 } else if (c >= 'a' && c <= 'f') {
239                     v = v * 16 + (c - 'a' + 0xA);
240                 } else {
241                     ThrowError(fFormatError,
242                         "invalid symbol in escape sequence");
243                 }
244             }
245             return v;
246         }
247     } else {
248         if (encoded) {
249             *encoded = false;
250         }
251     }
252     return c & 0xFF;
253 }
254 
ReadEncodedChar(EStringType type,bool & encoded)255 char CObjectIStreamJson::ReadEncodedChar(EStringType type, bool& encoded)
256 {
257     EEncoding enc_out( type == eStringTypeUTF8 ? eEncoding_UTF8 : m_StringEncoding);
258     EEncoding enc_in(eEncoding_UTF8);
259 
260     if (enc_out == eEncoding_UTF8 &&
261         !m_Utf8Buf.empty() && m_Utf8Pos != m_Utf8Buf.end()) {
262         if (++m_Utf8Pos != m_Utf8Buf.end()) {
263             return char(*m_Utf8Pos & 0xFF);
264         } else {
265             m_Utf8Buf.clear();
266         }
267     }
268     int c = ReadEscapedChar(&encoded);
269     if (enc_out != eEncoding_Unknown) {
270         if (encoded) {
271             TUnicodeSymbol chU = c;
272             if (enc_out == eEncoding_UTF8) {
273                 m_Utf8Buf = CUtf8::AsUTF8( &chU, 1);
274                 m_Utf8Pos = m_Utf8Buf.begin();
275                 return char(*m_Utf8Pos & 0xFF);
276             } else {
277                 return CUtf8::SymbolToChar( chU, enc_out);
278             }
279         }
280         if (enc_in != enc_out) {
281             if (enc_out != eEncoding_UTF8) {
282                 TUnicodeSymbol chU = enc_in == eEncoding_UTF8 ?
283                     ReadUtf8Char((char)c) : CUtf8::CharToSymbol((char)c, enc_in);
284                 Uint1 ch = CUtf8::SymbolToChar( chU, enc_out);
285                 return char(ch & 0xFF);
286             }
287             if ((c & 0x80) == 0) {
288                 return (char)c;
289             }
290             char ch = (char)c;
291             m_Utf8Buf = CUtf8::AsUTF8( CTempString(&ch,1), enc_in);
292             m_Utf8Pos = m_Utf8Buf.begin();
293             return char(*m_Utf8Pos & 0xFF);
294         }
295     }
296     return (char)c;
297 }
298 
ReadUtf8Char(char c)299 TUnicodeSymbol CObjectIStreamJson::ReadUtf8Char(char c)
300 {
301     size_t more = 0;
302     TUnicodeSymbol chU = CUtf8::DecodeFirst(c, more);
303     while (chU && more--) {
304         chU = CUtf8::DecodeNext(chU, m_Input.GetChar());
305     }
306     if (chU == 0) {
307         ThrowError(fInvalidData, "invalid UTF8 string");
308     }
309     return chU;
310 }
311 
x_ReadString(EStringType type)312 string CObjectIStreamJson::x_ReadString(EStringType type)
313 {
314     m_ExpectValue = false;
315     Expect('\"',true);
316     string str;
317     for (;;) {
318         bool encoded = false;
319         char c = ReadEncodedChar(type, encoded);
320         if (!encoded) {
321             if (c == '\r' || c == '\n') {
322                 ThrowError(fFormatError, "end of line: expected '\"'");
323             } else if (c == '\"') {
324                 break;
325             }
326         }
327         str += char(c);
328         // pre-allocate memory for long strings
329         if ( str.size() > 128  &&  (double)str.capacity()/((double)str.size()+1.0) < 1.1 ) {
330             str.reserve(str.size()*2);
331         }
332     }
333     str.reserve(str.size());
334     return str;
335 }
336 
x_ReadData(string & str,EStringType type)337 void CObjectIStreamJson::x_ReadData(string& str, EStringType type /*= eStringTypeVisible*/)
338 {
339     SkipWhiteSpace();
340     for (;;) {
341         bool encoded = false;
342         char c = ReadEncodedChar(type, encoded);
343         if (!encoded && strchr(",]} \r\n", c)) {
344             m_Input.UngetChar(c);
345             break;
346         }
347         str += char(c);
348         // pre-allocate memory for long strings
349         if ( str.size() > 128  &&  (double)str.capacity()/((double)str.size()+1.0) < 1.1 ) {
350             str.reserve(str.size()*2);
351         }
352     }
353     str.reserve(str.size());
354 }
355 
x_ReadDataAndCheck(string & str,EStringType type)356 bool CObjectIStreamJson::x_ReadDataAndCheck(string& str, EStringType type)
357 {
358     x_ReadData(str, type);
359     if (str == "null") {
360         if ((ExpectSpecialCase() & CObjectIStream::eReadAsNil)!=0) {
361             SetSpecialCaseUsed(CObjectIStream::eReadAsNil);
362             return false;
363         } else {
364             NCBI_THROW(CSerialException,eNullValue, kEmptyStr);
365         }
366     }
367     return true;
368 }
369 
x_SkipData(void)370 void  CObjectIStreamJson::x_SkipData(void)
371 {
372     m_ExpectValue = false;
373     char to = GetChar(true);
374     for (;;) {
375         bool encoded = false;
376         char c = ReadEncodedChar(eStringTypeUTF8, encoded);
377         if (!encoded) {
378             if (to == '\"') {
379                 if (c == to) {
380                     break;
381                 }
382             }
383             else if (strchr(",]} \r\n", c)) {
384                 m_Input.UngetChar(c);
385                 break;
386             }
387         }
388     }
389 }
390 
ReadKey(void)391 string CObjectIStreamJson::ReadKey(void)
392 {
393     if (!m_RejectedTag.empty()) {
394         m_LastTag = m_RejectedTag;
395         m_RejectedTag.erase();
396     } else {
397         SkipWhiteSpace();
398         m_LastTag = x_ReadString(eStringTypeVisible);
399         Expect(':', true);
400         SkipWhiteSpace();
401     }
402     m_ExpectValue = true;
403     return m_LastTag;
404 }
405 
ReadValue(EStringType type)406 string CObjectIStreamJson::ReadValue(EStringType type /*= eStringTypeVisible*/)
407 {
408     return x_ReadString(type);
409 }
410 
411 
StartBlock(char expect)412 void CObjectIStreamJson::StartBlock(char expect)
413 {
414     if (expect) {
415         Expect(expect, true);
416     }
417     m_BlockStart = true;
418     m_ExpectValue = false;
419 }
420 
EndBlock(char expect)421 void CObjectIStreamJson::EndBlock(char expect)
422 {
423     if (expect) {
424         Expect(expect, true);
425     }
426     m_BlockStart = false;
427     m_ExpectValue = false;
428 }
429 
NextElement(void)430 bool CObjectIStreamJson::NextElement(void)
431 {
432     if (!m_RejectedTag.empty()) {
433         m_BlockStart = false;
434         return true;
435     }
436     char c = SkipWhiteSpace();
437     if ( m_BlockStart ) {
438         // first element
439         m_BlockStart = false;
440         return c != '}' && c != ']';
441     }
442     else {
443         // next element
444         if ( c == ',' ) {
445             m_Input.SkipChar();
446             return true;
447         }
448         else if ( c != '}' && c != ']' )
449             ThrowError(fFormatError, "',' or '}' or ']' expected");
450         return false;
451     }
452 }
453 
ReadFileHeader(void)454 string CObjectIStreamJson::ReadFileHeader(void)
455 {
456     {
457         char c = m_Input.PeekChar();
458         if ((unsigned char)c == 0xEF) {
459             if ((unsigned char)m_Input.PeekChar(1) == 0xBB &&
460                 (unsigned char)m_Input.PeekChar(2) == 0xBF) {
461                 m_Input.SkipChars(3);
462             }
463         }
464     }
465     if (!StackIsEmpty() && TopFrame().GetTypeInfo()->GetDataSpec() == EDataSpec::eJSON) {
466         return kEmptyStr;
467     }
468     m_FileHeader = true;
469     StartBlock('{');
470     string str( ReadKey());
471     if (!StackIsEmpty() && TopFrame().HasTypeInfo()) {
472         const string& tname = TopFrame().GetTypeInfo()->GetName();
473         if (tname.empty()) {
474             UndoClassMember();
475         }
476         if (str != tname) {
477             if (str == NStr::Replace(tname,"-","_")) {
478                 return tname;
479             }
480         }
481     }
482     return str;
483 }
484 
EndOfRead(void)485 void CObjectIStreamJson::EndOfRead(void)
486 {
487     EndBlock(m_FileHeader ? '}' : 0);
488     m_FileHeader = false;
489     CObjectIStream::EndOfRead();
490 }
491 
492 
493 
ReadBool(void)494 bool CObjectIStreamJson::ReadBool(void)
495 {
496     string str;
497     return x_ReadDataAndCheck(str) ? NStr::StringToBool(str) : x_UseMemberDefault<bool>();
498 }
499 
SkipBool(void)500 void CObjectIStreamJson::SkipBool(void)
501 {
502     x_SkipData();
503 }
504 
ReadChar(void)505 char CObjectIStreamJson::ReadChar(void)
506 {
507     string str;
508     return x_ReadDataAndCheck(str) ? str.at(0) : x_UseMemberDefault<char>();
509 }
510 
SkipChar(void)511 void CObjectIStreamJson::SkipChar(void)
512 {
513     x_SkipData();
514 }
515 
ReadInt8(void)516 Int8 CObjectIStreamJson::ReadInt8(void)
517 {
518     string str;
519     if (x_ReadDataAndCheck(str)) {
520         if (str.empty() || !(isdigit(str[0]) || str[0] == '+' || str[0] == '-')) {
521             ThrowError(fFormatError, string("invalid number: ") + str);
522         }
523         return NStr::StringToInt8(str);
524     }
525     return x_UseMemberDefault<Int8>();
526 }
527 
ReadUint8(void)528 Uint8 CObjectIStreamJson::ReadUint8(void)
529 {
530     string str;
531     if (x_ReadDataAndCheck(str)) {
532         if (str.empty() || !(isdigit(str[0]) || str[0] == '+')) {
533             ThrowError(fFormatError, string("invalid number: ") + str);
534         }
535         return NStr::StringToUInt8(str);
536     }
537     return x_UseMemberDefault<Uint8>();
538 }
539 
SkipSNumber(void)540 void CObjectIStreamJson::SkipSNumber(void)
541 {
542     x_SkipData();
543 }
544 
SkipUNumber(void)545 void CObjectIStreamJson::SkipUNumber(void)
546 {
547     x_SkipData();
548 }
549 
ReadDouble(void)550 double CObjectIStreamJson::ReadDouble(void)
551 {
552     string str;
553     if (x_ReadDataAndCheck(str)) {
554         char* endptr = nullptr;
555         double result = NStr::StringToDoublePosix( str.c_str(), &endptr, NStr::fDecimalPosixFinite);
556         if ( *endptr != 0 ) {
557             ThrowError(fFormatError, string("invalid number: ") + str);
558         }
559         return result;
560     }
561     return x_UseMemberDefault<double>();
562 }
563 
SkipFNumber(void)564 void CObjectIStreamJson::SkipFNumber(void)
565 {
566     x_SkipData();
567 }
568 
ReadString(string & s,EStringType type)569 void CObjectIStreamJson::ReadString(string& s,
570     EStringType type /*= eStringTypeVisible*/)
571 {
572     char c = PeekChar(true);
573     if (c == 'n') {
574         if (m_Input.PeekChar(1) == 'u' &&
575             m_Input.PeekChar(2) == 'l' &&
576             m_Input.PeekChar(3) == 'l') {
577             m_ExpectValue = false;
578             m_Input.SkipChars(4);
579             if ((ExpectSpecialCase() & CObjectIStream::eReadAsNil)!=0) {
580                 SetSpecialCaseUsed(CObjectIStream::eReadAsNil);
581                 return;
582             }
583             NCBI_THROW(CSerialException,eNullValue, kEmptyStr);
584         }
585     }
586     s = ReadValue(type);
587 }
588 
SkipString(EStringType)589 void CObjectIStreamJson::SkipString(EStringType /*type*/)
590 {
591     x_SkipData();
592 }
593 
ReadNull(void)594 void CObjectIStreamJson::ReadNull(void)
595 {
596     if (m_ExpectValue) {
597         string str;
598         x_ReadData(str);
599     }
600 }
601 
SkipNull(void)602 void CObjectIStreamJson::SkipNull(void)
603 {
604     if (m_ExpectValue) {
605         x_SkipData();
606     }
607 }
608 
ReadAnyContentObject(CAnyContentObject & obj)609 void CObjectIStreamJson::ReadAnyContentObject(CAnyContentObject& obj)
610 {
611     m_ExpectValue = false;
612     obj.Reset();
613     string value;
614     if (!m_RejectedTag.empty()) {
615         obj.SetName( m_RejectedTag);
616         m_RejectedTag.erase();
617     } else if (!StackIsEmpty() && TopFrame().HasMemberId()) {
618         obj.SetName( TopFrame().GetMemberId().GetName());
619     } else {
620         obj.SetName( ReadKey());
621     }
622 
623     if (PeekChar(true) == '{') {
624         ThrowError(fNotImplemented, "Not Implemented");
625 #if 0
626         StartBlock('{');
627         while (NextElement()) {
628             string name = ReadKey();
629             value = ReadValue(eStringTypeUTF8);
630             if (name[0] != '#') {
631                 obj.AddAttribute(name,kEmptyStr,CUtf8::AsUTF8(value,eEncoding_UTF8));
632             } else {
633                 obj.SetValue(CUtf8::AsUTF8(value,eEncoding_UTF8));
634             }
635         }
636         EndBlock('}');
637 #endif
638         return;
639     }
640     if (PeekChar(true) == '\"') {
641         value = ReadValue(eStringTypeUTF8);
642     } else {
643         x_ReadData(value);
644     }
645     obj.SetValue(CUtf8::AsUTF8(value,eEncoding_UTF8));
646 }
647 
SkipAnyContent(void)648 void CObjectIStreamJson::SkipAnyContent(void)
649 {
650     char to = GetChar(true);
651     if (to == '{') {
652         to = '}';
653     } else if (to == '[') {
654         to = ']';
655     } else if (to == '\"') {
656     } else {
657         to = '\n';
658     }
659     for (char c = m_Input.PeekChar(); ; c = m_Input.PeekChar()) {
660         if (to == '\n') {
661             if (c == ',') {
662                 return;
663             }
664         }
665         if (c == to) {
666             m_Input.SkipChar();
667             if (c == '\n') {
668                 SkipEndOfLine(c);
669             }
670             return;
671         }
672         if (to != '\"') {
673             if (c == '\"' || c == '{' || c == '[') {
674                 SkipAnyContent();
675                 continue;
676             }
677         }
678 
679         m_Input.SkipChar();
680         if (c == '\n') {
681             SkipEndOfLine(c);
682         }
683     }
684 }
685 
SkipAnyContentObject(void)686 void CObjectIStreamJson::SkipAnyContentObject(void)
687 {
688     if (!m_RejectedTag.empty()) {
689         m_RejectedTag.erase();
690     }
691     SkipAnyContent();
692 }
693 
ReadBitString(CBitString & obj)694 void CObjectIStreamJson::ReadBitString(CBitString& obj)
695 {
696     m_ExpectValue = false;
697 #if BITSTRING_AS_VECTOR
698     ThrowError(fNotImplemented, "Not Implemented");
699 #else
700     if (IsCompressed()) {
701         ThrowError(fNotImplemented, "Not Implemented");
702         return;
703     }
704     Expect('\"');
705     obj.clear();
706     obj.resize(0);
707     CBitString::size_type len = 0;
708     for ( ;; ++len) {
709         char c = GetChar();
710         if (c == '1') {
711             obj.resize(len+1);
712             obj.set_bit(len);
713         } else if (c != '0') {
714             if ( c != 'B' ) {
715                 ThrowError(fFormatError, "invalid char in bit string");
716             }
717             break;
718         }
719     }
720     obj.resize(len);
721     Expect('\"');
722 #endif
723 }
724 
SkipBitString(void)725 void CObjectIStreamJson::SkipBitString(void)
726 {
727     CBitString obj;
728     ReadBitString(obj);
729 }
730 
731 
SkipByteBlock(void)732 void CObjectIStreamJson::SkipByteBlock(void)
733 {
734     CObjectIStream::ByteBlock block(*this);
735     char buf[4096];
736     while ( block.Read(buf, sizeof(buf)) != 0 )
737         ;
738     block.End();
739 }
740 
ReadEnum(const CEnumeratedTypeValues & values)741 TEnumValueType CObjectIStreamJson::ReadEnum(const CEnumeratedTypeValues& values)
742 {
743     m_ExpectValue = false;
744     TEnumValueType value;
745     char c = SkipWhiteSpace();
746     if (c == '\"') {
747         value = values.FindValue( ReadValue());
748     } else {
749         value = (TEnumValueType)ReadInt8();
750     }
751     return value;
752 }
753 
754 #ifdef VIRTUAL_MID_LEVEL_IO
ReadClassSequential(const CClassTypeInfo * classType,TObjectPtr classPtr)755 void CObjectIStreamJson::ReadClassSequential(
756     const CClassTypeInfo* classType, TObjectPtr classPtr)
757 {
758     ReadClassRandom( classType, classPtr);
759 }
760 
SkipClassSequential(const CClassTypeInfo * classType)761 void CObjectIStreamJson::SkipClassSequential(const CClassTypeInfo* classType)
762 {
763     SkipClassRandom(classType);
764 }
765 #endif
766 
767 // container
BeginContainer(const CContainerTypeInfo * containerType)768 void CObjectIStreamJson::BeginContainer(const CContainerTypeInfo* containerType)
769 {
770     CObjectTypeInfo type(GetRealTypeInfo(containerType->GetElementType()));
771     if (type.GetTypeFamily() == eTypeFamilyPrimitive && type.GetPrimitiveValueType() == ePrimitiveValueAny) {
772         TopFrame().SetNotag();
773         m_BlockStart = true;
774         m_ExpectValue = false;
775         return;
776     }
777     StartBlock('[');
778 }
779 
EndContainer(void)780 void CObjectIStreamJson::EndContainer(void)
781 {
782     if (TopFrame().GetNotag()) {
783         TopFrame().SetNotag(false);
784         return;
785     }
786     EndBlock(']');
787 }
788 
BeginContainerElement(TTypeInfo)789 bool CObjectIStreamJson::BeginContainerElement(TTypeInfo /*elementType*/)
790 {
791     return NextElement();
792 }
EndContainerElement(void)793 void CObjectIStreamJson::EndContainerElement(void)
794 {
795 }
796 
797 // class
BeginClass(const CClassTypeInfo *)798 void CObjectIStreamJson::BeginClass(const CClassTypeInfo* /*classInfo*/)
799 {
800     StartBlock((GetStackDepth() > 1 && FetchFrameFromTop(1).GetNotag()) ? 0 : '{');
801 }
802 
EndClass(void)803 void CObjectIStreamJson::EndClass(void)
804 {
805     m_GotNameless = false;
806     EndBlock((GetStackDepth() > 1 && FetchFrameFromTop(1).GetNotag()) ? 0 : '}');
807 }
808 
FindDeep(const CItemsInfo & items,const CTempString & name,bool & deep) const809 TMemberIndex CObjectIStreamJson::FindDeep(
810     const CItemsInfo& items, const CTempString& name, bool& deep) const
811 {
812     TMemberIndex i = items.Find(name);
813     if (i != kInvalidMember) {
814         deep = false;
815         return i;
816     }
817     i = items.FindDeep(name, true);
818     if (i != kInvalidMember) {
819         deep = true;
820         return i;
821     }
822 // on writing, we replace hyphens with underscores;
823 // on reading, it complicates our life
824     if (name.find_first_of("_") != CTempString::npos) {
825         TMemberIndex first = items.FirstIndex();
826         TMemberIndex last = items.LastIndex();
827         for (i = first; i <= last; ++i) {
828             const CItemInfo *itemInfo = items.GetItemInfo(i);
829             string item_name = itemInfo->GetId().GetName();
830             NStr::ReplaceInPlace(item_name,"-","_");
831             if (name == item_name) {
832                 deep = false;
833                 return i;
834             }
835         }
836         for (i = first; i <= last; ++i) {
837             const CItemInfo* itemInfo = items.GetItemInfo(i);
838             const CMemberId& id = itemInfo->GetId();
839             if (id.IsAttlist() || id.HasNotag()) {
840                 const CClassTypeInfoBase* classType =
841                     dynamic_cast<const CClassTypeInfoBase*>(
842                         CItemsInfo::FindRealTypeInfo(itemInfo->GetTypeInfo()));
843                 if (classType) {
844                     if (FindDeep(classType->GetItems(), name, deep) != kInvalidMember) {
845                         deep = true;
846                         return i;
847                     }
848                 }
849             }
850         }
851     }
852     deep = true;
853     return kInvalidMember;
854 }
855 
BeginClassMember(const CClassTypeInfo * classType)856 TMemberIndex CObjectIStreamJson::BeginClassMember(const CClassTypeInfo* classType)
857 {
858     TMemberIndex first = classType->GetMembers().FirstIndex();
859     TMemberIndex last = classType->GetMembers().LastIndex();
860 
861     if ( !NextElement() ) {
862         if (!m_GotNameless &&
863             classType->GetMemberInfo(last)->GetId().HasNotag() &&
864             classType->GetMemberInfo(last)->GetTypeInfo()->GetTypeFamily() == eTypeFamilyPrimitive) {
865             TopFrame().SetNotag();
866             m_GotNameless = true;
867             return last;
868         }
869         return kInvalidMember;
870     }
871     m_GotNameless = false;
872 
873     char c = PeekChar();
874     if (m_RejectedTag.empty() && (c == '[' || c == '{')) {
875         for (TMemberIndex i = first; i <= last; ++i) {
876             if (classType->GetMemberInfo(i)->GetId().HasNotag()) {
877                 TopFrame().SetNotag();
878                 return i;
879             }
880         }
881     }
882     string tagName = ReadKey();
883 
884     if (tagName[0] == '#') {
885         tagName = tagName.substr(1);
886         TopFrame().SetNotag();
887         m_GotNameless = true;
888     }
889 
890     bool deep = false;
891     TMemberIndex ind = FindDeep(classType->GetMembers(), tagName, deep);
892     if (ind == kInvalidMember) {
893         if (m_TypeAlias && classType->GetMembers().GetItemInfo(last)->GetId().HasNotag()) {
894             m_TypeAlias = nullptr;
895             return last;
896         }
897         if (classType->GetMembers().GetItemInfo(last)->GetId().HasAnyContent()) {
898             UndoClassMember();
899             return last;
900         }
901     } else {
902         if (classType->GetMembers().GetItemInfo(ind)->GetId().HasNotag()) {
903             TopFrame().SetNotag();
904             m_GotNameless = true;
905         }
906     }
907 
908 /*
909     skipping unknown members is not present here
910     this method has to do with random order of members, for example in XML attribute list
911     there is no special marker for end-of-list, so it is "ended" by unknown member.
912     In theory, I could find out memberId and check if it is Attlist
913     If the data type is SET and not attlist, then skipping unknowns can be dangerous
914 */
915     if (deep) {
916         if (ind != kInvalidMember) {
917             TopFrame().SetNotag();
918         }
919         UndoClassMember();
920     }
921     return ind;
922 }
923 
BeginClassMember(const CClassTypeInfo * classType,TMemberIndex pos)924 TMemberIndex CObjectIStreamJson::BeginClassMember(const CClassTypeInfo* classType,
925                                       TMemberIndex pos)
926 {
927     TMemberIndex first = classType->GetMembers().FirstIndex();
928     TMemberIndex last = classType->GetMembers().LastIndex();
929     if (m_RejectedTag.empty()) {
930         if (pos == first) {
931             if (classType->GetMemberInfo(first)->GetId().IsAttlist()) {
932                 TopFrame().SetNotag();
933                 return first;
934             }
935         }
936     }
937 
938     if ( !NextElement() ) {
939         if (pos == last &&
940             classType->GetMemberInfo(pos)->GetId().HasNotag() &&
941             classType->GetMemberInfo(pos)->GetTypeInfo()->GetTypeFamily() == eTypeFamilyPrimitive) {
942             TopFrame().SetNotag();
943             return pos;
944         }
945         return kInvalidMember;
946     }
947     char c = PeekChar();
948     if (m_RejectedTag.empty() && (c == '[' || c == '{')) {
949         for (TMemberIndex i = pos; i <= last; ++i) {
950             if (classType->GetMemberInfo(i)->GetId().HasNotag()) {
951                 TopFrame().SetNotag();
952                 return i;
953             }
954         }
955     }
956     string tagName = ReadKey();
957     if (tagName[0] == '#') {
958         tagName = tagName.substr(1);
959         TopFrame().SetNotag();
960     }
961     bool deep = false;
962     TMemberIndex ind = FindDeep(classType->GetMembers(), tagName, deep);
963     if ( ind == kInvalidMember ) {
964         if (CanSkipUnknownMembers()) {
965             SetFailFlags(fUnknownValue);
966             SkipAnyContent();
967             m_ExpectValue = false;
968             return BeginClassMember(classType,pos);
969         } else {
970             UnexpectedMember(tagName, classType->GetMembers());
971         }
972     }
973     if (deep) {
974         if (ind != kInvalidMember) {
975             TopFrame().SetNotag();
976         }
977         UndoClassMember();
978     } else if (ind != kInvalidMember) {
979         if (classType->GetMembers().GetItemInfo(ind)->GetId().HasAnyContent()) {
980             UndoClassMember();
981         }
982     }
983     return ind;
984 }
EndClassMember(void)985 void CObjectIStreamJson::EndClassMember(void)
986 {
987     TopFrame().SetNotag(false);
988 }
989 
UndoClassMember(void)990 void CObjectIStreamJson::UndoClassMember(void)
991 {
992     m_RejectedTag = m_LastTag;
993 }
994 
995 // choice
BeginChoice(const CChoiceTypeInfo *)996 void CObjectIStreamJson::BeginChoice(const CChoiceTypeInfo* /*choiceType*/)
997 {
998     StartBlock((GetStackDepth() > 1 && FetchFrameFromTop(1).GetNotag()) ? 0 : '{');
999 }
1000 
EndChoice(void)1001 void CObjectIStreamJson::EndChoice(void)
1002 {
1003     EndBlock((GetStackDepth() > 1 && FetchFrameFromTop(1).GetNotag()) ? 0 : '}');
1004 }
1005 
BeginChoiceVariant(const CChoiceTypeInfo * choiceType)1006 TMemberIndex CObjectIStreamJson::BeginChoiceVariant(const CChoiceTypeInfo* choiceType)
1007 {
1008     if ( !NextElement() )
1009         return kInvalidMember;
1010     string tagName = ReadKey();
1011     bool deep = false;
1012     TMemberIndex ind = FindDeep(choiceType->GetVariants(), tagName, deep);
1013     if ( ind == kInvalidMember ) {
1014         if (CanSkipUnknownVariants()) {
1015             SetFailFlags(fUnknownValue);
1016         } else {
1017             UnexpectedMember(tagName, choiceType->GetVariants());
1018         }
1019     }
1020     if (deep) {
1021         if (ind != kInvalidMember) {
1022             TopFrame().SetNotag();
1023         }
1024         UndoClassMember();
1025     }
1026     return ind;
1027 }
1028 
EndChoiceVariant(void)1029 void CObjectIStreamJson::EndChoiceVariant(void)
1030 {
1031     TopFrame().SetNotag(false);
1032 }
1033 
1034 // byte block
BeginBytes(ByteBlock &)1035 void CObjectIStreamJson::BeginBytes(ByteBlock& /*block*/)
1036 {
1037     char c = SkipWhiteSpaceAndGetChar();
1038     if (c == '\"') {
1039         m_Closing = '\"';
1040     } else if (c == '[') {
1041         m_Closing = ']';
1042     } else {
1043         ThrowError(fFormatError, "'\"' or '[' expected");
1044     }
1045 }
1046 
EndBytes(const ByteBlock &)1047 void CObjectIStreamJson::EndBytes(const ByteBlock& /*block*/)
1048 {
1049     Expect(m_Closing);
1050     m_Closing = 0;
1051 }
1052 
GetHexChar(void)1053 int CObjectIStreamJson::GetHexChar(void)
1054 {
1055     char c = m_Input.GetChar();
1056     if ( c >= '0' && c <= '9' ) {
1057         return c - '0';
1058     }
1059     else if ( c >= 'A' && c <= 'Z' ) {
1060         return c - 'A' + 10;
1061     }
1062     else if ( c >= 'a' && c <= 'z' ) {
1063         return c - 'a' + 10;
1064     }
1065     else {
1066         m_Input.UngetChar(c);
1067     }
1068     return -1;
1069 }
1070 
GetBase64Char(void)1071 int CObjectIStreamJson::GetBase64Char(void)
1072 {
1073     char c = SkipWhiteSpace();
1074     if ( (c >= '0' && c <= '9') ||
1075          (c >= 'A' && c <= 'Z') ||
1076          (c >= 'a' && c <= 'z') ||
1077          (c == '+' || c == '/'  || c == '=')) {
1078         return c;
1079     }
1080     return -1;
1081 }
1082 
ReadBytes(ByteBlock & block,char * dst,size_t length)1083 size_t CObjectIStreamJson::ReadBytes(
1084     ByteBlock& block, char* dst, size_t length)
1085 {
1086     m_ExpectValue = false;
1087     if (m_BinaryFormat != CObjectIStreamJson::eDefault) {
1088         return ReadCustomBytes(block,dst,length);
1089     }
1090     if (IsCompressed()) {
1091         return ReadBase64Bytes( block, dst, length );
1092     }
1093     return ReadHexBytes( block, dst, length );
1094 }
1095 
ReadCustomBytes(ByteBlock & block,char * dst,size_t length)1096 size_t CObjectIStreamJson::ReadCustomBytes(
1097     ByteBlock& block, char* dst, size_t length)
1098 {
1099     if (m_BinaryFormat == eString_Base64) {
1100         return ReadBase64Bytes(block, dst, length);
1101     } else if (m_BinaryFormat == eString_Hex) {
1102         return ReadHexBytes(block, dst, length);
1103     }
1104     bool end_of_data = false;
1105     size_t count = 0;
1106     while ( !end_of_data && length-- > 0 ) {
1107         Uint1 c = 0;
1108         Uint1 mask=0x80;
1109         switch (m_BinaryFormat) {
1110         case eArray_Bool:
1111             for (; !end_of_data && mask!=0; mask = Uint1(mask >> 1)) {
1112                 if (ReadBool()) {
1113                     c |= mask;
1114                 }
1115                 end_of_data = !GetChar(',', true);
1116             }
1117             ++count;
1118             *dst++ = c;
1119             break;
1120         case eArray_01:
1121             for (; !end_of_data && mask!=0; mask = Uint1(mask >> 1)) {
1122                 if (ReadChar() != '0') {
1123                     c |= mask;
1124                 }
1125                 end_of_data = !GetChar(',', true);
1126             }
1127             ++count;
1128             *dst++ = c;
1129             break;
1130         default:
1131         case eArray_Uint:
1132             c = (Uint1)ReadUint8();
1133             end_of_data = !GetChar(',', true);
1134             ++count;
1135             *dst++ = c;
1136             break;
1137         case eString_01:
1138         case eString_01B:
1139             for (; !end_of_data && mask!=0; mask = Uint1(mask >> 1)) {
1140                 char t = GetChar();
1141                 end_of_data = t == '\"' || t == 'B';
1142                 if (!end_of_data && t != '0') {
1143                     c |= mask;
1144                 }
1145                 if (t == '\"') {
1146                     m_Input.UngetChar(t);
1147                 }
1148             }
1149             if (mask != 0x40) {
1150                 ++count;
1151                 *dst++ = c;
1152             }
1153             break;
1154         }
1155     }
1156     if (end_of_data) {
1157         block.EndOfBlock();
1158     }
1159     return count;
1160 }
1161 
ReadBase64Bytes(ByteBlock & block,char * dst,size_t length)1162 size_t CObjectIStreamJson::ReadBase64Bytes(
1163     ByteBlock& block, char* dst, size_t length)
1164 {
1165     size_t count = 0;
1166     bool end_of_data = false;
1167     const size_t chunk_in = 80;
1168     char src_buf[chunk_in];
1169     size_t bytes_left = length;
1170     size_t src_size, src_read, dst_written;
1171     while (!end_of_data && bytes_left > chunk_in && bytes_left <= length) {
1172         for ( src_size = 0; src_size < chunk_in; ) {
1173             int c = GetBase64Char();
1174             if (c < 0) {
1175                 end_of_data = true;
1176                 break;
1177             }
1178             /*if (c != '=')*/ {
1179                 src_buf[ src_size++ ] = (char)c;
1180             }
1181             m_Input.SkipChar();
1182         }
1183         BASE64_Decode( src_buf, src_size, &src_read,
1184                     dst, bytes_left, &dst_written);
1185         if (src_size != src_read) {
1186             ThrowError(fFail, "error decoding base64Binary data");
1187         }
1188         count += dst_written;
1189         bytes_left -= dst_written;
1190         dst += dst_written;
1191     }
1192     if (end_of_data) {
1193         block.EndOfBlock();
1194     }
1195     return count;
1196 }
1197 
ReadHexBytes(ByteBlock & block,char * dst,size_t length)1198 size_t CObjectIStreamJson::ReadHexBytes(
1199     ByteBlock& block, char* dst, size_t length)
1200 {
1201     size_t count = 0;
1202     while ( length-- > 0 ) {
1203         int c1 = GetHexChar();
1204         if ( c1 < 0 ) {
1205             block.EndOfBlock();
1206             return count;
1207         }
1208         int c2 = GetHexChar();
1209         if ( c2 < 0 ) {
1210             *dst++ = char(c1 << 4);
1211             count++;
1212             block.EndOfBlock();
1213             return count;
1214         }
1215         else {
1216             *dst++ = char((c1 << 4) | c2);
1217             count++;
1218         }
1219     }
1220     return count;
1221 }
1222 
1223 // char block
BeginChars(CharBlock &)1224 void CObjectIStreamJson::BeginChars(CharBlock& /*block*/)
1225 {
1226 }
ReadChars(CharBlock &,char *,size_t)1227 size_t CObjectIStreamJson::ReadChars(CharBlock& /*block*/, char* /*buffer*/, size_t /*count*/)
1228 {
1229     ThrowError(fNotImplemented, "Not Implemented");
1230     return 0;
1231 }
EndChars(const CharBlock &)1232 void CObjectIStreamJson::EndChars(const CharBlock& /*block*/)
1233 {
1234 }
1235 
ReadPointerType(void)1236 CObjectIStream::EPointerType CObjectIStreamJson::ReadPointerType(void)
1237 {
1238     char c = PeekChar(true);
1239     if (c == 'n') {
1240         string s;
1241         x_ReadData(s);
1242         if (s != "null") {
1243             ThrowError(fFormatError, "null expected");
1244         }
1245         return eNullPointer;
1246     }
1247     return eThisPointer;
1248 }
1249 
ReadObjectPointer(void)1250 CObjectIStream::TObjectIndex CObjectIStreamJson::ReadObjectPointer(void)
1251 {
1252     ThrowError(fNotImplemented, "Not Implemented");
1253     return 0;
1254 }
1255 
ReadOtherPointer(void)1256 string CObjectIStreamJson::ReadOtherPointer(void)
1257 {
1258     ThrowError(fNotImplemented, "Not Implemented");
1259     return "";
1260 }
1261 
1262 END_NCBI_SCOPE
1263