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