1 /* $Id: objostrjson.cpp 608769 2020-05-20 19:18:29Z vasilche $
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 output stream
30 *
31 */
32
33 #include <ncbi_pch.hpp>
34 #include <corelib/ncbistd.hpp>
35 #include <corelib/ncbi_limits.h>
36
37 #include <serial/objostrjson.hpp>
38 #include <serial/objistr.hpp>
39 #include <serial/objcopy.hpp>
40 #include <serial/impl/memberid.hpp>
41 #include <serial/impl/memberlist.hpp>
42 #include <serial/enumvalues.hpp>
43 #include <serial/objhook.hpp>
44 #include <serial/impl/classinfo.hpp>
45 #include <serial/impl/choice.hpp>
46 #include <serial/impl/continfo.hpp>
47 #include <serial/delaybuf.hpp>
48 #include <serial/impl/ptrinfo.hpp>
49 #include <serial/error_codes.hpp>
50
51 #include <stdio.h>
52 #include <math.h>
53
54
55 #define NCBI_USE_ERRCODE_X Serial_OStream
56
57 BEGIN_NCBI_SCOPE
58
59
OpenObjectOStreamJson(CNcbiOstream & out,EOwnership deleteOut)60 CObjectOStream* CObjectOStream::OpenObjectOStreamJson(CNcbiOstream& out,
61 EOwnership deleteOut)
62 {
63 return new CObjectOStreamJson(out, deleteOut);
64 }
65
66
67
CObjectOStreamJson(CNcbiOstream & out,bool deleteOut)68 CObjectOStreamJson::CObjectOStreamJson(CNcbiOstream& out, bool deleteOut)
69 : CObjectOStream(eSerial_Json, out, deleteOut ? eTakeOwnership : eNoOwnership),
70 m_FileHeader(false),
71 m_BlockStart(false),
72 m_ExpectValue(false),
73 m_StringEncoding(eEncoding_UTF8),
74 m_BinaryFormat(eDefault),
75 m_WrapAt(0)
76 {
77 m_WriteNamedIntegersByValue = true;
78 m_EnforceWritingDefaults = true;
79 }
80
CObjectOStreamJson(CNcbiOstream & out,EOwnership deleteOut)81 CObjectOStreamJson::CObjectOStreamJson(CNcbiOstream& out, EOwnership deleteOut)
82 : CObjectOStream(eSerial_Json, out, deleteOut),
83 m_FileHeader(false),
84 m_BlockStart(false),
85 m_ExpectValue(false),
86 m_StringEncoding(eEncoding_UTF8),
87 m_BinaryFormat(eDefault),
88 m_WrapAt(0)
89 {
90 m_WriteNamedIntegersByValue = true;
91 m_EnforceWritingDefaults = true;
92 }
93
~CObjectOStreamJson(void)94 CObjectOStreamJson::~CObjectOStreamJson(void)
95 {
96 }
97
SetDefaultStringEncoding(EEncoding enc)98 void CObjectOStreamJson::SetDefaultStringEncoding(EEncoding enc)
99 {
100 m_StringEncoding = enc;
101 }
102
GetDefaultStringEncoding(void) const103 EEncoding CObjectOStreamJson::GetDefaultStringEncoding(void) const
104 {
105 return m_StringEncoding;
106 }
107
108 CObjectOStreamJson::EBinaryDataFormat
GetBinaryDataFormat(void) const109 CObjectOStreamJson::GetBinaryDataFormat(void) const
110 {
111 return m_BinaryFormat;
112 }
SetBinaryDataFormat(CObjectOStreamJson::EBinaryDataFormat fmt)113 void CObjectOStreamJson::SetBinaryDataFormat(CObjectOStreamJson::EBinaryDataFormat fmt)
114 {
115 m_BinaryFormat = fmt;
116 }
117
SetJsonpMode(const string & function_name)118 void CObjectOStreamJson::SetJsonpMode(const string& function_name)
119 {
120 m_JsonpPrefix = function_name + "(";
121 m_JsonpSuffix = ");";
122 }
123
GetJsonpPadding(string * prefix,string * suffix) const124 void CObjectOStreamJson::GetJsonpPadding(string* prefix, string* suffix) const
125 {
126 if (prefix) {*prefix = m_JsonpPrefix;}
127 if (suffix) {*suffix = m_JsonpSuffix;}
128 }
129
GetPosition(void) const130 string CObjectOStreamJson::GetPosition(void) const
131 {
132 return "line "+NStr::SizetToString(m_Output.GetLine());
133 }
134
WriteFileHeader(TTypeInfo type)135 void CObjectOStreamJson::WriteFileHeader(TTypeInfo type)
136 {
137 if (!m_JsonpPrefix.empty() || !m_JsonpSuffix.empty()) {
138 m_Output.PutString(m_JsonpPrefix);
139 }
140 if (type->GetDataSpec() != EDataSpec::eJSON) {
141 m_FileHeader = true;
142 StartBlock();
143 if (!type->GetName().empty()) {
144 m_Output.PutEol();
145 WriteKey(type->GetName());
146 }
147 }
148 }
149
EndOfWrite(void)150 void CObjectOStreamJson::EndOfWrite(void)
151 {
152 if (m_FileHeader) {
153 EndBlock();
154 m_FileHeader = false;
155 } else {
156 m_BlockStart = false;
157 m_ExpectValue = false;
158 }
159 if (!m_JsonpPrefix.empty() || !m_JsonpSuffix.empty()) {
160 m_Output.PutString(m_JsonpSuffix);
161 }
162 m_Output.PutEol();
163 CObjectOStream::EndOfWrite();
164 }
165
WriteBool(bool data)166 void CObjectOStreamJson::WriteBool(bool data)
167 {
168 WriteKeywordValue( data ? "true" : "false");
169 }
170
WriteChar(char data)171 void CObjectOStreamJson::WriteChar(char data)
172 {
173 string s;
174 s += data;
175 WriteString(s);
176 }
177
WriteInt4(Int4 data)178 void CObjectOStreamJson::WriteInt4(Int4 data)
179 {
180 WriteKeywordValue(NStr::IntToString(data));
181 }
182
WriteUint4(Uint4 data)183 void CObjectOStreamJson::WriteUint4(Uint4 data)
184 {
185 WriteKeywordValue(NStr::UIntToString(data));
186 }
187
WriteInt8(Int8 data)188 void CObjectOStreamJson::WriteInt8(Int8 data)
189 {
190 WriteKeywordValue(NStr::Int8ToString(data));
191 }
192
WriteUint8(Uint8 data)193 void CObjectOStreamJson::WriteUint8(Uint8 data)
194 {
195 WriteKeywordValue(NStr::UInt8ToString(data));
196 }
197
WriteFloat(float data)198 void CObjectOStreamJson::WriteFloat(float data)
199 {
200 WriteDouble2(data,FLT_DIG);
201 }
202
WriteDouble(double data)203 void CObjectOStreamJson::WriteDouble(double data)
204 {
205 WriteDouble2(data,DBL_DIG);
206 }
207
WriteDouble2(double data,unsigned digits)208 void CObjectOStreamJson::WriteDouble2(double data, unsigned digits)
209 {
210 if (isnan(data)) {
211 ThrowError(fInvalidData, "invalid double: not a number");
212 }
213 if (!finite(data)) {
214 ThrowError(fInvalidData, "invalid double: infinite");
215 }
216 if (m_FastWriteDouble) {
217 char buffer[64];
218 WriteKeywordValue( string(buffer,
219 NStr::DoubleToStringPosix(data, digits, buffer, sizeof(buffer))));
220 } else {
221 WriteKeywordValue(NStr::DoubleToString(data,digits, NStr::fDoublePosix));
222 }
223 }
224
WriteCString(const char * str)225 void CObjectOStreamJson::WriteCString(const char* str)
226 {
227 WriteValue(str);
228 }
229
WriteString(const string & str,EStringType type)230 void CObjectOStreamJson::WriteString(const string& str,
231 EStringType type)
232 {
233 WriteValue(str,type);
234 }
235
WriteStringStore(const string & s)236 void CObjectOStreamJson::WriteStringStore(const string& s)
237 {
238 WriteString(s);
239 }
240
CopyString(CObjectIStream & in,EStringType type)241 void CObjectOStreamJson::CopyString(CObjectIStream& in,
242 EStringType type)
243 {
244 string s;
245 in.ReadString(s, type);
246 WriteString(s, type);
247 }
248
CopyStringStore(CObjectIStream & in)249 void CObjectOStreamJson::CopyStringStore(CObjectIStream& in)
250 {
251 string s;
252 in.ReadStringStore(s);
253 WriteStringStore(s);
254 }
255
WriteNullPointer(void)256 void CObjectOStreamJson::WriteNullPointer(void)
257 {
258 CObjectStackFrame::EFrameType ftype = TopFrame().GetFrameType();
259 if (m_ExpectValue ||
260 ftype == CObjectStackFrame::eFrameArrayElement ||
261 ftype == CObjectStackFrame::eFrameClassMember ||
262 ftype == CObjectStackFrame::eFrameChoiceVariant) {
263 WriteKeywordValue("null");
264 }
265 }
266
WriteObjectReference(TObjectIndex)267 void CObjectOStreamJson::WriteObjectReference(TObjectIndex /*index*/)
268 {
269 ThrowError(fNotImplemented, "Not Implemented");
270 }
271
WriteOtherBegin(TTypeInfo)272 void CObjectOStreamJson::WriteOtherBegin(TTypeInfo /*typeInfo*/)
273 {
274 ThrowError(fNotImplemented, "Not Implemented");
275 }
276
WriteOtherEnd(TTypeInfo)277 void CObjectOStreamJson::WriteOtherEnd(TTypeInfo /*typeInfo*/)
278 {
279 ThrowError(fNotImplemented, "Not Implemented");
280 }
281
WriteOther(TConstObjectPtr,TTypeInfo)282 void CObjectOStreamJson::WriteOther(TConstObjectPtr /*object*/, TTypeInfo /*typeInfo*/)
283 {
284 ThrowError(fNotImplemented, "Not Implemented");
285 }
286
WriteNull(void)287 void CObjectOStreamJson::WriteNull(void)
288 {
289 if (!m_ExpectValue && !m_SkippedMemberId.empty()) {
290 m_SkippedMemberId.erase();
291 }
292 if (m_ExpectValue) {
293 WriteKeywordValue("null");
294 }
295 }
296
WriteAnyContentObject(const CAnyContentObject & obj)297 void CObjectOStreamJson::WriteAnyContentObject(const CAnyContentObject& obj)
298 {
299 string obj_name = obj.GetName();
300 if (obj_name.empty()) {
301 if (!StackIsEmpty() && TopFrame().HasMemberId()) {
302 obj_name = TopFrame().GetMemberId().GetName();
303 }
304 if (obj_name.empty()) {
305 ThrowError(fInvalidData, "AnyContent object must have name");
306 }
307 }
308 WriteKey(obj_name);
309 const vector<CSerialAttribInfoItem>& attlist = obj.GetAttributes();
310 if (attlist.empty()) {
311 WriteValue(obj.GetValue(),eStringTypeUTF8);
312 return;
313 }
314 StartBlock();
315 vector<CSerialAttribInfoItem>::const_iterator it;
316 for ( it = attlist.begin(); it != attlist.end(); ++it) {
317 NextElement();
318 WriteKey(it->GetName());
319 WriteValue(it->GetValue(),eStringTypeUTF8);
320 }
321 m_SkippedMemberId = obj_name;
322 WriteValue(obj.GetValue(),eStringTypeUTF8);
323 EndBlock();
324 }
325
CopyAnyContentObject(CObjectIStream & in)326 void CObjectOStreamJson::CopyAnyContentObject(CObjectIStream& in)
327 {
328 CAnyContentObject obj;
329 in.ReadAnyContentObject(obj);
330 WriteAnyContentObject(obj);
331 }
332
333
WriteBitString(const CBitString & obj)334 void CObjectOStreamJson::WriteBitString(const CBitString& obj)
335 {
336 m_Output.PutChar('\"');
337 #if BITSTRING_AS_VECTOR
338 static const char ToHex[] = "0123456789ABCDEF";
339 Uint1 data, mask;
340 bool done = false;
341 for ( CBitString::const_iterator i = obj.begin(); !done; ) {
342 for (data=0, mask=0x8; !done && mask!=0; mask = Uint1(mask >> 1)) {
343 if (*i) {
344 data |= mask;
345 }
346 done = (++i == obj.end());
347 }
348 m_Output.PutChar(ToHex[data]);
349 }
350 #else
351 if (IsCompressed()) {
352 bm::word_t* tmp_block = (bm::word_t*)bm::aligned_new_malloc(bm::set_block_alloc_size);
353 CBitString::statistics st;
354 obj.calc_stat(&st);
355 char* buf = (char*)malloc(st.max_serialize_mem);
356 size_t len = bm::serialize(obj, (unsigned char*)buf, tmp_block);
357 WriteBytes(buf,len);
358 free(buf);
359 bm::aligned_free(tmp_block);
360 } else {
361 CBitString::size_type i=0;
362 CBitString::size_type ilast = obj.size();
363 CBitString::enumerator e = obj.first();
364 for (; i < ilast; ++i) {
365 m_Output.PutChar( (i == *e) ? '1' : '0');
366 if (i == *e) {
367 ++e;
368 }
369 }
370 }
371 #endif
372 m_Output.PutString("B\"");
373 }
374
CopyBitString(CObjectIStream &)375 void CObjectOStreamJson::CopyBitString(CObjectIStream& /*in*/)
376 {
377 ThrowError(fNotImplemented, "Not Implemented");
378 }
379
WriteEnum(const CEnumeratedTypeValues & values,TEnumValueType value)380 void CObjectOStreamJson::WriteEnum(const CEnumeratedTypeValues& values,
381 TEnumValueType value)
382 {
383 string value_str;
384 if (values.IsInteger()) {
385 value_str = NStr::IntToString(value);
386 const string& name = values.FindNameEx(value, values.IsInteger());
387 if (name.empty() || GetWriteNamedIntegersByValue()) {
388 WriteKeywordValue(value_str);
389 } else {
390 WriteValue(name);
391 }
392 } else {
393 value_str = values.FindNameEx(value, values.IsInteger());
394 WriteValue(value_str);
395 }
396 }
397
CopyEnum(const CEnumeratedTypeValues & values,CObjectIStream & in)398 void CObjectOStreamJson::CopyEnum(const CEnumeratedTypeValues& values,
399 CObjectIStream& in)
400 {
401 TEnumValueType value = in.ReadEnum(values);
402 WriteEnum(values, value);
403 }
404
WriteClassMember(const CMemberId & memberId,TTypeInfo memberType,TConstObjectPtr memberPtr)405 void CObjectOStreamJson::WriteClassMember(const CMemberId& memberId,
406 TTypeInfo memberType,
407 TConstObjectPtr memberPtr)
408 {
409 CObjectOStream::WriteClassMember(memberId,memberType,memberPtr);
410 }
411
WriteClassMember(const CMemberId & memberId,const CDelayBuffer & buffer)412 bool CObjectOStreamJson::WriteClassMember(const CMemberId& memberId,
413 const CDelayBuffer& buffer)
414 {
415 return CObjectOStream::WriteClassMember(memberId,buffer);
416 }
417
WriteClassMemberSpecialCase(const CMemberId & memberId,TTypeInfo memberType,TConstObjectPtr memberPtr,ESpecialCaseWrite how)418 void CObjectOStreamJson::WriteClassMemberSpecialCase(
419 const CMemberId& memberId, TTypeInfo memberType,
420 TConstObjectPtr memberPtr, ESpecialCaseWrite how)
421 {
422 if (how == eWriteAsNil) {
423 BeginClassMember(memberId);
424 WriteKeywordValue("null");
425 EndClassMember();
426 }
427 }
428
BeginNamedType(TTypeInfo namedTypeInfo)429 void CObjectOStreamJson::BeginNamedType(TTypeInfo namedTypeInfo)
430 {
431 CObjectOStream::BeginNamedType(namedTypeInfo);
432 }
433
EndNamedType(void)434 void CObjectOStreamJson::EndNamedType(void)
435 {
436 CObjectOStream::EndNamedType();
437 }
438
439
BeginContainer(const CContainerTypeInfo * containerType)440 void CObjectOStreamJson::BeginContainer(const CContainerTypeInfo* containerType)
441 {
442 CObjectTypeInfo type(GetRealTypeInfo(containerType->GetElementType()));
443 if (type.GetTypeFamily() == eTypeFamilyPrimitive && type.GetPrimitiveValueType() == ePrimitiveValueAny) {
444 TopFrame().SetNotag();
445 m_BlockStart = true;
446 m_ExpectValue = false;
447 return;
448 }
449 BeginArray();
450 }
451
EndContainer(void)452 void CObjectOStreamJson::EndContainer(void)
453 {
454 if (TopFrame().GetNotag()) {
455 TopFrame().SetNotag(false);
456 return;
457 }
458 EndArray();
459 }
460
BeginContainerElement(TTypeInfo)461 void CObjectOStreamJson::BeginContainerElement(TTypeInfo /*elementType*/)
462 {
463 NextElement();
464 }
465
EndContainerElement(void)466 void CObjectOStreamJson::EndContainerElement(void)
467 {
468 }
469
470
BeginClass(const CClassTypeInfo *)471 void CObjectOStreamJson::BeginClass(const CClassTypeInfo* /*classInfo*/)
472 {
473 if (GetStackDepth() > 1 && FetchFrameFromTop(1).GetNotag()) {
474 return;
475 }
476 StartBlock();
477 }
478
479
EndClass(void)480 void CObjectOStreamJson::EndClass(void)
481 {
482 if (GetStackDepth() > 1 && FetchFrameFromTop(1).GetNotag()) {
483 return;
484 }
485 EndBlock();
486 }
487
BeginClassMember(const CMemberId & id)488 void CObjectOStreamJson::BeginClassMember(const CMemberId& id)
489 {
490 if (m_ExpectValue) {
491 return;
492 }
493 if (id.HasNotag() || id.IsAttlist()) {
494 TopFrame().SetNotag();
495 if (id.HasAnyContent()) {
496 #if 1
497 if ( m_BlockStart ) {
498 m_BlockStart = false;
499 } else {
500 m_Output.PutChar(',');
501 }
502 #else
503 NextElement();
504 #endif
505 } else {
506 auto tn = [this]()->const string& {
507 const string& r(m_TypeAlias->GetName());
508 m_TypeAlias = nullptr;
509 return r;
510 };
511 m_SkippedMemberId = (m_TypeAlias && id.HasNotag()) ? tn() : id.GetName();
512 }
513 return;
514 }
515 if (id.HasAnyContent()) {
516 return;
517 }
518 NextElement();
519 WriteMemberId(id);
520 }
521
EndClassMember(void)522 void CObjectOStreamJson::EndClassMember(void)
523 {
524 if (TopFrame().GetNotag()) {
525 TopFrame().SetNotag(false);
526 }
527 m_ExpectValue = false;
528 }
529
530
BeginChoice(const CChoiceTypeInfo *)531 void CObjectOStreamJson::BeginChoice(const CChoiceTypeInfo* /*choiceType*/)
532 {
533 if (GetStackDepth() > 1 && FetchFrameFromTop(1).GetNotag()) {
534 return;
535 }
536 StartBlock();
537 }
538
EndChoice(void)539 void CObjectOStreamJson::EndChoice(void)
540 {
541 if (GetStackDepth() > 1 && FetchFrameFromTop(1).GetNotag()) {
542 return;
543 }
544 EndBlock();
545 }
546
BeginChoiceVariant(const CChoiceTypeInfo *,const CMemberId & id)547 void CObjectOStreamJson::BeginChoiceVariant(const CChoiceTypeInfo* /*choiceType*/,
548 const CMemberId& id)
549 {
550 if (id.HasNotag() || id.IsAttlist()) {
551 m_SkippedMemberId = id.GetName();
552 TopFrame().SetNotag();
553 return;
554 }
555 NextElement();
556 WriteMemberId(id);
557 }
558
EndChoiceVariant(void)559 void CObjectOStreamJson::EndChoiceVariant(void)
560 {
561 if (TopFrame().GetNotag()) {
562 TopFrame().SetNotag(false);
563 }
564 m_ExpectValue = false;
565 }
566
567
568 static const char* const HEX = "0123456789ABCDEF";
569
BeginBytes(const ByteBlock &)570 void CObjectOStreamJson::BeginBytes(const ByteBlock& )
571 {
572 if (m_BinaryFormat == eArray_Bool ||
573 m_BinaryFormat == eArray_01 ||
574 m_BinaryFormat == eArray_Uint) {
575 m_Output.PutChar('[');
576 m_WrapAt = 78;
577 } else {
578 m_Output.PutChar('\"');
579 m_WrapAt = 0;
580 }
581 }
582
WriteBytes(const ByteBlock &,const char * bytes,size_t length)583 void CObjectOStreamJson::WriteBytes(const ByteBlock& /*block*/,
584 const char* bytes, size_t length)
585 {
586 if (m_BinaryFormat != CObjectOStreamJson::eDefault) {
587 WriteCustomBytes(bytes,length);
588 return;
589 }
590 if (IsCompressed()) {
591 WriteBase64Bytes(bytes,length);
592 return;
593 }
594 WriteBytes(bytes,length);
595 }
596
EndBytes(const ByteBlock &)597 void CObjectOStreamJson::EndBytes(const ByteBlock& )
598 {
599 if (m_BinaryFormat == eArray_Bool ||
600 m_BinaryFormat == eArray_01 ||
601 m_BinaryFormat == eArray_Uint) {
602 m_Output.BackChar(',');
603 m_Output.PutEol();
604 m_Output.PutChar(']');
605 } else {
606 if (m_BinaryFormat == eString_01B) {
607 m_Output.PutChar('B');
608 }
609 m_Output.PutChar('\"');
610 }
611 }
612
WriteBase64Bytes(const char * bytes,size_t length)613 void CObjectOStreamJson::WriteBase64Bytes(const char* bytes, size_t length)
614 {
615 const size_t chunk_in = 57;
616 const size_t chunk_out = 80;
617 if (length > chunk_in && m_WrapAt != 0) {
618 m_Output.PutEol(false);
619 }
620 char dst_buf[chunk_out];
621 size_t bytes_left = length;
622 size_t src_read=0, dst_written=0, line_len=0;
623 while (bytes_left > 0 && bytes_left <= length) {
624 BASE64_Encode(bytes, min(bytes_left,chunk_in), &src_read,
625 dst_buf, chunk_out, &dst_written, &line_len);
626 m_Output.PutString(dst_buf,dst_written);
627 bytes_left -= src_read;
628 bytes += src_read;
629 if (bytes_left > 0 && m_WrapAt != 0) {
630 m_Output.PutEol(false);
631 }
632 }
633 if (length > chunk_in && m_WrapAt != 0) {
634 m_Output.PutEol(false);
635 }
636 }
637
WriteBytes(const char * bytes,size_t length)638 void CObjectOStreamJson::WriteBytes(const char* bytes, size_t length)
639 {
640 while ( length-- > 0 ) {
641 char c = *bytes++;
642 m_Output.PutChar(HEX[(c >> 4) & 0xf]);
643 m_Output.PutChar(HEX[c & 0xf]);
644 }
645 }
646
WriteCustomBytes(const char * bytes,size_t length)647 void CObjectOStreamJson::WriteCustomBytes(const char* bytes, size_t length)
648 {
649 if (m_BinaryFormat == eString_Base64) {
650 WriteBase64Bytes(bytes, length);
651 return;
652 } else if (m_BinaryFormat == eString_Hex) {
653 WriteBytes(bytes, length);
654 return;
655 }
656 if (m_WrapAt != 0 &&
657 m_BinaryFormat != eString_Hex &&
658 m_BinaryFormat != eString_01 &&
659 m_BinaryFormat != eString_01B) {
660 m_Output.PutEol(false);
661 }
662 while ( length-- > 0 ) {
663 Uint1 c = *bytes++;
664 Uint1 mask=0x80;
665 switch (m_BinaryFormat) {
666 case eArray_Bool:
667 for (; mask!=0; mask = Uint1(mask >> 1)) {
668 if (m_WrapAt != 0) {
669 m_Output.WrapAt(m_WrapAt, false);
670 }
671 m_Output.PutString( (mask & c) ? "true" : "false");
672 m_Output.PutChar(',');
673 }
674 break;
675 case eArray_01:
676 for (; mask!=0; mask = Uint1(mask >> 1)) {
677 if (m_WrapAt != 0) {
678 m_Output.WrapAt(m_WrapAt, false);
679 }
680 m_Output.PutChar( (mask & c) ? '1' : '0');
681 m_Output.PutChar(',');
682 }
683 break;
684 default:
685 case eArray_Uint:
686 if (m_WrapAt != 0) {
687 m_Output.WrapAt(m_WrapAt, false);
688 }
689 m_Output.PutString( NStr::UIntToString((unsigned int)c));
690 m_Output.PutChar(',');
691 break;
692 case eString_01:
693 case eString_01B:
694 for (; mask!=0; mask = Uint1(mask >> 1)) {
695 m_Output.PutChar( (mask & c) ? '1' : '0');
696 }
697 break;
698 }
699 }
700 }
701
WriteChars(const CharBlock &,const char *,size_t)702 void CObjectOStreamJson::WriteChars(const CharBlock& /*block*/,
703 const char* /*chars*/, size_t /*length*/)
704 {
705 ThrowError(fNotImplemented, "Not Implemented");
706 }
707
708
WriteSeparator(void)709 void CObjectOStreamJson::WriteSeparator(void)
710 {
711 }
712
WriteMemberId(const CMemberId & id)713 void CObjectOStreamJson::WriteMemberId(const CMemberId& id)
714 {
715 WriteKey(id.GetName());
716 m_SkippedMemberId.erase();
717 }
718
WriteSkippedMember(void)719 void CObjectOStreamJson::WriteSkippedMember(void)
720 {
721 string name("#");
722 name += m_SkippedMemberId;
723 NextElement();
724 WriteKey(name);
725 m_SkippedMemberId.erase();
726 }
727
728
WriteEscapedChar(char c,EEncoding enc_in)729 void CObjectOStreamJson::WriteEscapedChar(char c, EEncoding enc_in)
730 {
731 switch ( c ) {
732 case '"':
733 m_Output.PutString("\\\"");
734 break;
735 case '\\':
736 m_Output.PutString("\\\\");
737 break;
738 default:
739 if ( (unsigned int)c < 0x20 ||
740 ((unsigned int)c >= 0x80 && enc_in != eEncoding_UTF8) ) {
741 m_Output.PutString("\\u00");
742 Uint1 ch = c;
743 unsigned hi = ch >> 4;
744 unsigned lo = ch & 0xF;
745 m_Output.PutChar(HEX[hi]);
746 m_Output.PutChar(HEX[lo]);
747 } else {
748 m_Output.PutChar(c);
749 }
750 break;
751 }
752 }
753
WriteEncodedChar(const char * & src,EStringType type)754 void CObjectOStreamJson::WriteEncodedChar(const char*& src, EStringType type)
755 {
756 EEncoding enc_in( type == eStringTypeUTF8 ? eEncoding_UTF8 : m_StringEncoding);
757 EEncoding enc_out(eEncoding_UTF8);
758
759 if (enc_in == enc_out || enc_in == eEncoding_Unknown || (*src & 0x80) == 0) {
760 WriteEscapedChar(*src, enc_in);
761 } else {
762 CStringUTF8 tmp( CUtf8::AsUTF8( CTempString(src,1),enc_in));
763 for ( string::const_iterator t = tmp.begin(); t != tmp.end(); ++t ) {
764 m_Output.PutChar(*t);
765 }
766 }
767 }
768
x_WriteString(const string & value,EStringType type)769 void CObjectOStreamJson::x_WriteString(const string& value, EStringType type)
770 {
771 m_Output.PutChar('\"');
772 for (const char* src = value.c_str(); *src; ++src) {
773 WriteEncodedChar(src,type);
774 }
775 m_Output.PutChar('\"');
776 }
777
WriteKey(const string & key)778 void CObjectOStreamJson::WriteKey(const string& key)
779 {
780 string s(key);
781 NStr::ReplaceInPlace(s,"-","_");
782 x_WriteString(s);
783 NameSeparator();
784 }
785
BeginValue(void)786 void CObjectOStreamJson::BeginValue(void)
787 {
788 if (!m_ExpectValue && !m_SkippedMemberId.empty()) {
789 WriteSkippedMember();
790 }
791 }
792
WriteValue(const string & value,EStringType type)793 void CObjectOStreamJson::WriteValue(const string& value, EStringType type)
794 {
795 BeginValue();
796 x_WriteString(value,type);
797 m_ExpectValue = false;
798 }
799
WriteKeywordValue(const string & value)800 void CObjectOStreamJson::WriteKeywordValue(const string& value)
801 {
802 BeginValue();
803 m_Output.PutString(value);
804 m_ExpectValue = false;
805 }
806
StartBlock(void)807 void CObjectOStreamJson::StartBlock(void)
808 {
809 BeginValue();
810 m_Output.PutChar('{');
811 m_Output.IncIndentLevel();
812 m_BlockStart = true;
813 m_ExpectValue = false;
814 }
815
EndBlock(void)816 void CObjectOStreamJson::EndBlock(void)
817 {
818 m_Output.DecIndentLevel();
819 m_Output.PutEol();
820 m_Output.PutChar('}');
821 m_BlockStart = false;
822 m_ExpectValue = false;
823 }
824
NextElement(void)825 void CObjectOStreamJson::NextElement(void)
826 {
827 if ( m_BlockStart ) {
828 m_BlockStart = false;
829 } else {
830 m_Output.PutChar(',');
831 }
832 m_Output.PutEol();
833 m_ExpectValue = true;
834 }
835
BeginArray(void)836 void CObjectOStreamJson::BeginArray(void)
837 {
838 BeginValue();
839 m_Output.PutChar('[');
840 m_Output.IncIndentLevel();
841 m_BlockStart = true;
842 m_ExpectValue = false;
843 }
844
EndArray(void)845 void CObjectOStreamJson::EndArray(void)
846 {
847 m_Output.DecIndentLevel();
848 m_Output.PutEol();
849 m_Output.PutChar(']');
850 m_BlockStart = false;
851 m_ExpectValue = false;
852 }
853
NameSeparator(void)854 void CObjectOStreamJson::NameSeparator(void)
855 {
856 m_Output.PutChar(':');
857 if (m_Output.GetUseIndentation()) {
858 m_Output.PutChar(' ');
859 }
860 m_ExpectValue = true;
861 }
862
863 END_NCBI_SCOPE
864