1 /*  $Id: objostrasnb.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: Eugene Vasilchenko
27 *
28 * File Description:
29 *   ASN.1 binary object output stream.
30 */
31 
32 #include <ncbi_pch.hpp>
33 #include <corelib/ncbistd.hpp>
34 #include <corelib/ncbi_limits.hpp>
35 #include <corelib/ncbi_param.hpp>
36 
37 #include <serial/objostrasnb.hpp>
38 #include <serial/objistr.hpp>
39 #include <serial/objcopy.hpp>
40 #include <serial/objistrasnb.hpp>
41 #include <serial/impl/memberid.hpp>
42 #include <serial/enumvalues.hpp>
43 #include <serial/impl/memberlist.hpp>
44 #include <serial/objhook.hpp>
45 #include <serial/impl/classinfo.hpp>
46 #include <serial/impl/choice.hpp>
47 #include <serial/impl/continfo.hpp>
48 #include <serial/delaybuf.hpp>
49 #include <serial/error_codes.hpp>
50 
51 #include <stdio.h>
52 #include <math.h>
53 
54 #undef _TRACE
55 #define _TRACE(arg) ((void)0)
56 
57 #define NCBI_USE_ERRCODE_X   Serial_OStream
58 
59 #define USE_OLD_TAGS 0
60 // this is backward compatibility check
61 #define USE_VERIFY_TAGGING 1
62 
63 BEGIN_NCBI_SCOPE
64 
65 
OpenObjectOStreamAsnBinary(CNcbiOstream & out,EOwnership deleteOut)66 CObjectOStream* CObjectOStream::OpenObjectOStreamAsnBinary(CNcbiOstream& out,
67                                                            EOwnership deleteOut)
68 {
69     return new CObjectOStreamAsnBinary(out, deleteOut);
70 }
71 
CObjectOStreamAsnBinary(CNcbiOstream & out,EFixNonPrint how)72 CObjectOStreamAsnBinary::CObjectOStreamAsnBinary(CNcbiOstream& out,
73                                                  EFixNonPrint how)
74     : CObjectOStream(eSerial_AsnBinary, out),
75       m_CStyleBigInt(false), m_SkipNextTag(false), m_AutomaticTagging(true)
76 {
77     FixNonPrint(how);
78 #if CHECK_OUTSTREAM_INTEGRITY
79     m_CurrentPosition = 0;
80     m_CurrentTagState = eTagStart;
81     m_CurrentTagLimit = 0;
82 #endif
83 }
84 
CObjectOStreamAsnBinary(CNcbiOstream & out,bool deleteOut,EFixNonPrint how)85 CObjectOStreamAsnBinary::CObjectOStreamAsnBinary(CNcbiOstream& out,
86                                                  bool deleteOut,
87                                                  EFixNonPrint how)
88     : CObjectOStream(eSerial_AsnBinary, out, deleteOut ? eTakeOwnership : eNoOwnership),
89       m_CStyleBigInt(false), m_SkipNextTag(false), m_AutomaticTagging(true)
90 {
91     FixNonPrint(how);
92 #if CHECK_OUTSTREAM_INTEGRITY
93     m_CurrentPosition = 0;
94     m_CurrentTagState = eTagStart;
95     m_CurrentTagLimit = 0;
96 #endif
97 }
98 
CObjectOStreamAsnBinary(CNcbiOstream & out,EOwnership deleteOut,EFixNonPrint how)99 CObjectOStreamAsnBinary::CObjectOStreamAsnBinary(CNcbiOstream& out,
100                                                  EOwnership deleteOut,
101                                                  EFixNonPrint how)
102     : CObjectOStream(eSerial_AsnBinary, out, deleteOut),
103       m_CStyleBigInt(false), m_SkipNextTag(false), m_AutomaticTagging(true)
104 {
105     FixNonPrint(how);
106 #if CHECK_OUTSTREAM_INTEGRITY
107     m_CurrentPosition = 0;
108     m_CurrentTagState = eTagStart;
109     m_CurrentTagLimit = 0;
110 #endif
111 }
112 
~CObjectOStreamAsnBinary(void)113 CObjectOStreamAsnBinary::~CObjectOStreamAsnBinary(void)
114 {
115 #if CHECK_OUTSTREAM_INTEGRITY
116     if ( !m_Limits.empty() || m_CurrentTagState != eTagStart )
117         ERR_POST_X(9, "CObjectOStreamAsnBinary not finished");
118 #endif
119 }
120 
121 #if CHECK_OUTSTREAM_INTEGRITY
122 inline
StartTag(Uint1 code)123 void CObjectOStreamAsnBinary::StartTag(Uint1 code)
124 {
125     m_Limits.push(m_CurrentTagLimit);
126     m_CurrentTagCode = code;
127     m_CurrentTagPosition = m_CurrentPosition;
128     m_CurrentTagState = GetTagValue(code) == eLongTag? eTagValue: eLengthStart;
129 }
130 
131 inline
EndTag(void)132 void CObjectOStreamAsnBinary::EndTag(void)
133 {
134     if ( m_Limits.empty() )
135         ThrowError(fIllegalCall, "too many tag ends");
136     m_CurrentTagState = eTagStart;
137     m_CurrentTagLimit = m_Limits.top();
138     m_Limits.pop();
139 }
140 
141 inline
SetTagLength(size_t length)142 void CObjectOStreamAsnBinary::SetTagLength(size_t length)
143 {
144     Int8 limit = m_CurrentPosition + 1 + length;
145     if ( limit <= m_CurrentPosition ||
146         (m_CurrentTagLimit != 0 && limit > m_CurrentTagLimit) )
147         ThrowError(fIllegalCall, "tag will overflow enclosing tag");
148     m_CurrentTagLimit = limit;
149     if ( IsTagConstructed(m_CurrentTagCode) ) // constructed
150         m_CurrentTagState = eTagStart;
151     else
152         m_CurrentTagState = eData;
153     if ( length == 0 )
154         EndTag();
155 }
156 #endif
157 
158 #if !CHECK_OUTSTREAM_INTEGRITY
159 inline
160 #endif
WriteByte(Uint1 byte)161 void CObjectOStreamAsnBinary::WriteByte(Uint1 byte)
162 {
163 #if CHECK_OUTSTREAM_INTEGRITY
164     //_TRACE("WriteByte: " << NStr::PtrToString(byte));
165     if ( m_CurrentTagLimit != 0 &&
166          m_CurrentPosition >= m_CurrentTagLimit )
167         ThrowError(fOverflow, "tag size overflow");
168     switch ( m_CurrentTagState ) {
169     case eTagStart:
170         StartTag(byte);
171         break;
172     case eTagValue:
173         if ( (byte & 0x80) == 0)
174             m_CurrentTagState = eLengthStart;
175         break;
176     case eLengthStart:
177         if ( byte == 0 ) {
178             SetTagLength(0);
179             if ( m_CurrentTagCode == 0 )
180                 EndTag();
181         }
182         else if ( byte == 0x80 ) {
183             if ( !IsTagConstructed(m_CurrentTagCode) ) {
184                 ThrowError(fIllegalCall,
185                            "cannot use indefinite form for primitive tag");
186             }
187             m_CurrentTagState = eTagStart;
188         }
189         else if ( byte < 0x80 ) {
190             SetTagLength(byte);
191         }
192         else {
193             m_CurrentTagLengthSize = byte - 0x80;
194             if ( m_CurrentTagLengthSize > sizeof(size_t) )
195                 ThrowError(fOverflow, "tag length is too big");
196             m_CurrentTagState = eLengthValueFirst;
197         }
198         break;
199     case eLengthValueFirst:
200         if ( byte == 0 )
201             ThrowError(fInvalidData, "first byte of length is zero");
202         if ( --m_CurrentTagLengthSize == 0 ) {
203             SetTagLength(byte);
204         }
205         else {
206             m_CurrentTagLength = byte;
207             m_CurrentTagState = eLengthValue;
208         }
209         break;
210         // fall down to next case (no break needed)
211     case eLengthValue:
212         m_CurrentTagLength = (m_CurrentTagLength << 8) | byte;
213         if ( --m_CurrentTagLengthSize == 0 )
214             SetTagLength(m_CurrentTagLength);
215         break;
216     case eData:
217         _ASSERT( m_CurrentTagLimit != 0);
218         if ( m_CurrentPosition + 1 == m_CurrentTagLimit )
219             EndTag();
220         break;
221     }
222     m_CurrentPosition += 1;
223 #endif
224     m_Output.PutChar(byte);
225 }
226 
227 #if !CHECK_OUTSTREAM_INTEGRITY
228 inline
229 #endif
WriteBytes(const char * bytes,size_t size)230 void CObjectOStreamAsnBinary::WriteBytes(const char* bytes, size_t size)
231 {
232     if ( size == 0 )
233         return;
234 #if CHECK_OUTSTREAM_INTEGRITY
235     //_TRACE("WriteBytes: " << size);
236     if ( m_CurrentTagState != eData )
237         ThrowError(fIllegalCall, "WriteBytes only allowed in DATA");
238     Int8 new_pos = m_CurrentPosition + size;
239     if ( new_pos < m_CurrentPosition ||
240         (m_CurrentTagLimit != 0 && new_pos > m_CurrentTagLimit) )
241         ThrowError(fOverflow, "tag DATA overflow");
242     m_CurrentPosition = new_pos;
243     if ( new_pos == m_CurrentTagLimit )
244         EndTag();
245 #endif
246     m_Output.PutString(bytes, size);
247 }
248 
249 template<typename T>
250 inline
WriteBytesOf(const T & value,size_t count)251 void CObjectOStreamAsnBinary::WriteBytesOf(const T& value, size_t count)
252 {
253     for ( size_t shift = (count - 1) * 8; shift > 0; shift -= 8 ) {
254         WriteByte(Uint1(value >> shift));
255     }
256     WriteByte(Uint1(value));
257 }
258 
259 inline
WriteShortTag(ETagClass tag_class,ETagConstructed tag_constructed,ETagValue tag_value)260 void CObjectOStreamAsnBinary::WriteShortTag(ETagClass tag_class,
261                                             ETagConstructed tag_constructed,
262                                             ETagValue tag_value)
263 {
264     if (m_SkipNextTag) {
265         m_SkipNextTag = false;
266         return;
267     }
268     WriteByte(MakeTagByte(tag_class, tag_constructed, tag_value));
269 }
270 
271 inline
WriteSysTag(ETagValue tag_value)272 void CObjectOStreamAsnBinary::WriteSysTag(ETagValue tag_value)
273 {
274     if (m_SkipNextTag) {
275         m_SkipNextTag = false;
276         return;
277     }
278     WriteShortTag(eUniversal, ePrimitive, tag_value);
279 }
280 
281 NCBI_PARAM_DECL(bool, SERIAL, WRITE_UTF8STRING_TAG);
282 NCBI_PARAM_DEF_EX(bool, SERIAL, WRITE_UTF8STRING_TAG, false,
283                   eParam_NoThread, SERIAL_WRITE_UTF8STRING_TAG);
284 
MakeUTF8StringTag(void)285 CObjectOStreamAsnBinary::TByte CObjectOStreamAsnBinary::MakeUTF8StringTag(void)
286 {
287     static CSafeStatic<NCBI_PARAM_TYPE(SERIAL, WRITE_UTF8STRING_TAG)> s_WriteUTF8StringTag;
288     ETagValue value = s_WriteUTF8StringTag->Get() ? eUTF8String: eVisibleString;
289     return MakeTagByte(eUniversal, ePrimitive, value);
290 }
291 
292 inline
GetUTF8StringTag(void)293 CObjectOStreamAsnBinary::TByte CObjectOStreamAsnBinary::GetUTF8StringTag(void)
294 {
295     static TByte s_UTF8StringTag = 0;
296     if ( !s_UTF8StringTag ) {
297         s_UTF8StringTag = MakeUTF8StringTag();
298     }
299     return s_UTF8StringTag;
300 }
301 
302 inline
WriteStringTag(EStringType type)303 void CObjectOStreamAsnBinary::WriteStringTag(EStringType type)
304 {
305     if (m_SkipNextTag) {
306         m_SkipNextTag = false;
307         return;
308     }
309     WriteByte(type == eStringTypeUTF8?
310               GetUTF8StringTag():
311               MakeTagByte(eUniversal, ePrimitive, eVisibleString));
312 }
313 
WriteLongTag(ETagClass tag_class,ETagConstructed tag_constructed,TLongTag tag_value)314 void CObjectOStreamAsnBinary::WriteLongTag(ETagClass tag_class,
315                                            ETagConstructed tag_constructed,
316                                            TLongTag tag_value)
317 {
318     if ( tag_value <= 0 )
319         ThrowError(fInvalidData, "negative tag number");
320 
321     // long form
322     WriteShortTag(tag_class, tag_constructed, eLongTag);
323     // calculate largest shift enough for TTag to fit
324     size_t shift = (sizeof(TLongTag) * 8 - 1) / 7 * 7;
325     Uint1 bits;
326     // find first non zero 7bits
327     while ( (bits = (tag_value >> shift) & 0x7f) == 0 ) {
328         shift -= 7;
329     }
330 
331     // beginning of tag
332     while ( shift != 0 ) {
333         shift -= 7;
334         WriteByte(Uint1(tag_value >> shift) | 0x80);
335     }
336     // write remaining bits
337     WriteByte(tag_value & 0x7f);
338 }
339 
340 inline
WriteTag(ETagClass tag_class,ETagConstructed tag_constructed,TLongTag tag_value)341 void CObjectOStreamAsnBinary::WriteTag(ETagClass tag_class,
342                                        ETagConstructed tag_constructed,
343                                        TLongTag tag_value)
344 {
345     if (m_SkipNextTag) {
346         m_SkipNextTag = false;
347         return;
348     }
349     if ( tag_value >= 0 && tag_value < eLongTag )
350         WriteShortTag(tag_class, tag_constructed, ETagValue(tag_value));
351     else
352         WriteLongTag(tag_class, tag_constructed, tag_value);
353 }
354 
WriteClassTag(TTypeInfo typeInfo)355 void CObjectOStreamAsnBinary::WriteClassTag(TTypeInfo typeInfo)
356 {
357     if (m_SkipNextTag) {
358         m_SkipNextTag = false;
359         return;
360     }
361     const string& tag = typeInfo->GetName();
362     if ( tag.empty() )
363         ThrowError(fInvalidData, "empty tag string");
364 
365     _ASSERT( tag[0] > eLongTag );
366 
367     // long form
368     WriteShortTag(eApplication, eConstructed, eLongTag);
369     SIZE_TYPE last = tag.size() - 1;
370     for ( SIZE_TYPE i = 0; i <= last; ++i ) {
371         char c = tag[i];
372         _ASSERT( (c & 0x80) == 0 );
373         if ( i != last )
374             c |= (char)0x80;
375         WriteByte(c);
376     }
377 }
378 
379 inline
WriteIndefiniteLength(void)380 void CObjectOStreamAsnBinary::WriteIndefiniteLength(void)
381 {
382     WriteByte(eIndefiniteLengthByte);
383 }
384 
385 inline
WriteShortLength(size_t length)386 void CObjectOStreamAsnBinary::WriteShortLength(size_t length)
387 {
388     WriteByte(TByte(length));
389 }
390 
WriteLongLength(size_t length)391 void CObjectOStreamAsnBinary::WriteLongLength(size_t length)
392 {
393     // long form
394     size_t count;
395     if ( length <= 0xffU )
396         count = 1;
397     else if ( length <= 0xffffU )
398         count = 2;
399     else if ( length <= 0xffffffU )
400         count = 3;
401     else {
402         count = sizeof(length);
403         if ( sizeof(length) > 4 ) {
404             for ( size_t shift = (count-1)*8;
405                   count > 0; --count, shift -= 8 ) {
406                 if ( Uint1(length >> shift) != 0 )
407                     break;
408             }
409         }
410     }
411     WriteByte(TByte(0x80 + count));
412     WriteBytesOf(length, count);
413 }
414 
415 inline
WriteLength(size_t length)416 void CObjectOStreamAsnBinary::WriteLength(size_t length)
417 {
418     if ( length <= 127 )
419         WriteShortLength(length);
420     else
421         WriteLongLength(length);
422 }
423 
424 inline
WriteEndOfContent(void)425 void CObjectOStreamAsnBinary::WriteEndOfContent(void)
426 {
427     WriteSysTag(eNone);
428     WriteShortLength(0);
429 }
430 
WriteNull(void)431 void CObjectOStreamAsnBinary::WriteNull(void)
432 {
433     WriteSysTag(eNull);
434     WriteShortLength(0);
435 }
436 
WriteAnyContentObject(const CAnyContentObject &)437 void CObjectOStreamAsnBinary::WriteAnyContentObject(const CAnyContentObject& )
438 {
439     ThrowError(fNotImplemented,
440         "CObjectOStreamAsnBinary::WriteAnyContentObject: "
441         "unable to write AnyContent object in ASN");
442 }
443 
CopyAnyContentObject(CObjectIStream &)444 void CObjectOStreamAsnBinary::CopyAnyContentObject(CObjectIStream& )
445 {
446     ThrowError(fNotImplemented,
447         "CObjectOStreamAsnBinary::CopyAnyContentObject: "
448         "unable to copy AnyContent object in ASN");
449 }
450 
WriteBitString(const CBitString & obj)451 void CObjectOStreamAsnBinary::WriteBitString(const CBitString& obj)
452 {
453 #if BITSTRING_AS_VECTOR
454     bool compressed = false;
455 #else
456     bool compressed = IsCompressed();
457 #endif
458     char* buf=0;
459     size_t len = obj.size();
460     if (compressed) {
461         CBitString::statistics st;
462         obj.calc_stat(&st);
463         buf = (char*)malloc(st.max_serialize_mem);
464         bm::word_t* tmp_block = (bm::word_t*)bm::aligned_new_malloc(bm::set_block_alloc_size);
465         len = 8*bm::serialize(obj, (unsigned char*)buf, tmp_block);
466         bm::aligned_free(tmp_block);
467     }
468 
469     WriteSysTag(compressed ? eOctetString : eBitString);
470     if (len == 0) {
471         WriteLength(0);
472         return;
473     }
474     WriteLength((len+7)/8+(compressed ? 0 : 1));
475     if (!compressed) {
476         WriteByte(TByte(len%8 ? 8-len%8 : 0));
477     }
478     const size_t reserve=128;
479     char bytes[reserve];
480     size_t b=0;
481     Uint1 data, mask;
482     bool done=false;
483 
484 #if BITSTRING_AS_VECTOR
485     for ( CBitString::const_iterator i = obj.begin(); !done; ) {
486         for (data=0, mask=0x80; mask != 0 && !done; mask = Uint1(mask >> 1)) {
487             if (*i) {
488                 data |= mask;
489             }
490             done = (++i == obj.end());
491         }
492         bytes[b++] = data;
493         if (b==reserve || done) {
494             WriteBytes(bytes,b);
495             b=0;
496         }
497     }
498 #else
499     if (compressed) {
500         WriteBytes(buf,len/8);
501         free(buf);
502         return;
503     }
504     CBitString::size_type i=0;
505     CBitString::size_type ilast = obj.size();
506     CBitString::enumerator e = obj.first();
507     while (!done) {
508         for (data=0, mask=0x80; !done && mask!=0; mask = Uint1(mask >> 1)) {
509             if (i == *e) {
510                 data |= mask;
511                 ++e;
512             }
513             done = (++i == ilast);
514         }
515         bytes[b++] = data;
516         if (b==reserve || done) {
517             WriteBytes(bytes,b);
518             b = 0;
519         }
520     }
521 #endif
522 }
523 
CopyBitString(CObjectIStream & in)524 void CObjectOStreamAsnBinary::CopyBitString(CObjectIStream& in)
525 {
526     CBitString obj;
527     in.ReadBitString(obj);
528     WriteBitString(obj);
529 }
530 
WriteNumberValue(Int4 data)531 void CObjectOStreamAsnBinary::WriteNumberValue(Int4 data)
532 {
533     size_t length;
534     if ( data >= Int4(-0x80) && data <= Int4(0x7f) ) {
535         // one byte
536         length = 1;
537     }
538     else if ( data >= Int4(-0x8000) && data <= Int4(0x7fff) ) {
539         // two bytes
540         length = 2;
541     }
542     else if ( data >= Int4(-0x800000) && data <= Int4(0x7fffff) ) {
543         // three bytes
544         length = 3;
545     }
546     else {
547         // full length signed
548         length = sizeof(data);
549     }
550     WriteShortLength(length);
551     WriteBytesOf(data, length);
552 }
553 
WriteNumberValue(Int8 data)554 void CObjectOStreamAsnBinary::WriteNumberValue(Int8 data)
555 {
556     size_t length;
557     if ( data >= -Int8(0x80) && data <= Int8(0x7f) ) {
558         // one byte
559         length = 1;
560     }
561     else if ( data >= Int8(-0x8000) && data <= Int8(0x7fff) ) {
562         // two bytes
563         length = 2;
564     }
565     else if ( data >= Int8(-0x800000) && data <= Int8(0x7fffff) ) {
566         // three bytes
567         length = 3;
568     }
569     else if ( data >= NCBI_CONST_INT8(-0x80000000) &&
570               data <= NCBI_CONST_INT8( 0x7fffffff) ) {
571         // four bytes
572         length = 4;
573     }
574     else if ( data >= NCBI_CONST_INT8(-0x8000000000) &&
575               data <= NCBI_CONST_INT8( 0x7fffffffff) ) {
576         // four bytes
577         length = 5;
578     }
579     else if ( data >= NCBI_CONST_INT8(-0x800000000000) &&
580               data <= NCBI_CONST_INT8( 0x7fffffffffff) ) {
581         // four bytes
582         length = 6;
583     }
584     else if ( data >= NCBI_CONST_INT8(-0x80000000000000) &&
585               data <= NCBI_CONST_INT8( 0x7fffffffffffff) ) {
586         // four bytes
587         length = 7;
588     }
589     else {
590         // full length signed
591         length = sizeof(data);
592     }
593     WriteShortLength(length);
594     WriteBytesOf(data, length);
595 }
596 
WriteNumberValue(Uint4 data)597 void CObjectOStreamAsnBinary::WriteNumberValue(Uint4 data)
598 {
599     size_t length;
600     if ( data <= 0x7fU ) {
601         length = 1;
602     }
603     else if ( data <= 0x7fffU ) {
604         // two bytes
605         length = 2;
606     }
607     else if ( data <= 0x7fffffU ) {
608         // three bytes
609         length = 3;
610     }
611     else if ( data <= 0x7fffffffU ) {
612         // four bytes
613         length = 4;
614     }
615     else {
616         // check for high bit to avoid storing unsigned data as negative
617         if ( (data & (Uint4(1) << (sizeof(data) * 8 - 1))) != 0 ) {
618             // full length unsigned - and doesn't fit in signed place
619             WriteShortLength(sizeof(data) + 1);
620             WriteByte(0);
621             WriteBytesOf(data, sizeof(data));
622             return;
623         }
624         else {
625             // full length
626             length = sizeof(data);
627         }
628     }
629     WriteShortLength(length);
630     WriteBytesOf(data, length);
631 }
632 
WriteNumberValue(Uint8 data)633 void CObjectOStreamAsnBinary::WriteNumberValue(Uint8 data)
634 {
635     size_t length;
636     if ( data <= 0x7fUL ) {
637         length = 1;
638     }
639     else if ( data <= 0x7fffUL ) {
640         // two bytes
641         length = 2;
642     }
643     else if ( data <= 0x7fffffUL ) {
644         // three bytes
645         length = 3;
646     }
647     else if ( data <= 0x7fffffffUL ) {
648         // four bytes
649         length = 4;
650     }
651     else if ( data <= NCBI_CONST_UINT8(0x7fffffffff) ) {
652         length = 5;
653     }
654     else if ( data <= NCBI_CONST_UINT8(0x7fffffffffff) ) {
655         length = 6;
656     }
657     else if ( data <= NCBI_CONST_UINT8(0x7fffffffffffff) ) {
658         length = 7;
659     }
660     else if ( data <= NCBI_CONST_UINT8(0x7fffffffffffffff) ) {
661         length = 8;
662     }
663     else {
664         // check for high bit to avoid storing unsigned data as negative
665         if ( (data & (Uint8(1) << (sizeof(data) * 8 - 1))) != 0 ) {
666             // full length unsigned - and doesn't fit in signed place
667             WriteShortLength(sizeof(data) + 1);
668             WriteByte(0);
669             WriteBytesOf(data, sizeof(data));
670             return;
671         }
672         else {
673             // full length
674             length = sizeof(data);
675         }
676     }
677     WriteShortLength(length);
678     WriteBytesOf(data, length);
679 }
680 
WriteBool(bool data)681 void CObjectOStreamAsnBinary::WriteBool(bool data)
682 {
683     WriteSysTag(eBoolean);
684     WriteShortLength(1);
685     WriteByte(data);
686 }
687 
WriteChar(char data)688 void CObjectOStreamAsnBinary::WriteChar(char data)
689 {
690     WriteSysTag(eGeneralString);
691     WriteShortLength(1);
692     WriteByte(data);
693 }
694 
WriteInt4(Int4 data)695 void CObjectOStreamAsnBinary::WriteInt4(Int4 data)
696 {
697     WriteSysTag(eInteger);
698     WriteNumberValue(data);
699 }
700 
WriteUint4(Uint4 data)701 void CObjectOStreamAsnBinary::WriteUint4(Uint4 data)
702 {
703     WriteSysTag(eInteger);
704     WriteNumberValue(data);
705 }
706 
707 static inline
s_IsOldStyleInt8(const CObjectOStreamAsnBinary * os)708 bool s_IsOldStyleInt8(const CObjectOStreamAsnBinary* os)
709 {
710     TTypeInfo type = os->GetRecentTypeInfo();
711     return type != nullptr && type->GetCodeVersion() < 21600;
712 }
713 
WriteInt8(Int8 data)714 void CObjectOStreamAsnBinary::WriteInt8(Int8 data)
715 {
716     if ( m_CStyleBigInt && (m_SpecialCaseWrite == eWriteAsBigInt || s_IsOldStyleInt8(this))) {
717         WriteShortTag(eApplication, ePrimitive, eInteger);
718     } else {
719         WriteSysTag(eInteger);
720     }
721     WriteNumberValue(data);
722 }
723 
WriteUint8(Uint8 data)724 void CObjectOStreamAsnBinary::WriteUint8(Uint8 data)
725 {
726     if ( m_CStyleBigInt && (m_SpecialCaseWrite == eWriteAsBigInt || s_IsOldStyleInt8(this))) {
727         WriteShortTag(eApplication, ePrimitive, eInteger);
728     } else {
729         WriteSysTag(eInteger);
730     }
731     WriteNumberValue(data);
732 }
733 
734 static const size_t kMaxDoubleLength = 64;
735 
WriteDouble2(double data,unsigned digits)736 void CObjectOStreamAsnBinary::WriteDouble2(double data, unsigned digits)
737 {
738     char buffer[kMaxDoubleLength + 16];
739     int width = 0;
740     Uint1 type = eDecimal;
741     WriteSysTag(eReal);
742 
743 #if 0
744     if (isnan(data)) {
745         ThrowError(fInvalidData, "invalid double: not a number");
746     }
747     if (!finite(data)) {
748         ThrowError(fInvalidData, "invalid double: infinite");
749     }
750 #else
751 // CXX-5248
752 // for backward compatibility, this stays disabled
753 #if 0
754     if (data == 0.) {
755         double zero = 0.;
756         if (memcmp(&data, &zero, sizeof(double)) == 0) {
757             WriteLength(0);
758             return;
759         }
760         type = eNegativeZero;
761     } else
762 #endif
763     if (isnan(data)) {
764         type = eNotANumber;
765     } else if (!finite(data)) {
766         if (data > 0) {
767             type = ePositiveInfinity;
768         } else {
769             type = eNegativeInfinity;
770         }
771     }
772     else
773 #endif
774     if (m_FastWriteDouble) {
775         width = (int)NStr::DoubleToStringPosix(data, digits, buffer, sizeof(buffer));
776     } else {
777         int shift = 0;
778         int precision = int(digits - shift);
779         if ( precision < 0 )
780             precision = 0;
781         else if ( size_t(precision) > kMaxDoubleLength ) // limit precision of data
782             precision = int(kMaxDoubleLength);
783 
784         // ensure buffer is large enough to fit result
785         // (additional bytes are for sign, dot and exponent)
786         width = sprintf(buffer, "%.*g", precision, data);
787         if ( width <= 0 || width >= int(sizeof(buffer) - 1) )
788             ThrowError(fOverflow, "buffer overflow");
789         _ASSERT(strlen(buffer) == size_t(width));
790         char* dot = strchr(buffer,',');
791         if (dot) {
792             *dot = '.'; // enforce C locale
793         }
794     }
795 
796     WriteLength(width + 1);
797     if (width) {
798 // CXX-5248
799 // for backward compatibility, this stays disabled
800 #if 0
801         type = eDecimal_NR1;
802         for (const char* p = buffer + width - 1;  p >= buffer;  --p) {
803             if (*p == '.') {
804                 type = eDecimal_NR2;
805                 break;
806             } else if (*p == 'e'  ||  *p == 'E') {
807                 type = eDecimal_NR3;
808                 break;
809             }
810         }
811 #endif
812         WriteByte(type);
813         WriteBytes(buffer, width);
814     } else {
815         WriteByte(type);
816     }
817 }
818 
WriteDouble(double data)819 void CObjectOStreamAsnBinary::WriteDouble(double data)
820 {
821     WriteDouble2(data, DBL_DIG);
822 }
823 
WriteFloat(float data)824 void CObjectOStreamAsnBinary::WriteFloat(float data)
825 {
826     WriteDouble2(data, FLT_DIG);
827 }
828 
WriteString(const string & str,EStringType type)829 void CObjectOStreamAsnBinary::WriteString(const string& str, EStringType type)
830 {
831     size_t length = str.size(), fixed = 0;
832     WriteStringTag(type);
833     if ( type == eStringTypeVisible && x_FixCharsMethod() == eFNP_Skip ) {
834         for ( size_t i = 0; i < length; ++i ) {
835             if ( !GoodVisibleChar(str[i]) ) {
836                 ++fixed;
837             }
838         }
839     }
840     WriteLength(length - fixed);
841     if ( type == eStringTypeVisible && x_FixCharsMethod() != eFNP_Allow ) {
842         size_t done = 0;
843         for ( size_t i = 0; i < length; ++i ) {
844             char c = str[i];
845             if ( !GoodVisibleChar(c) ) {
846 #if SERIAL_ALLOW_UTF8_IN_VISIBLESTRING_ON_WRITING
847                 size_t valid = CUtf8::EvaluateSymbolLength(CTempString(str.data()+i,length-done-i));
848                 if (valid != 0) {
849                     i += valid-1;
850                     continue;
851                 }
852 #endif
853                 if ( i > done ) {
854                     WriteBytes(str.data() + done, i - done);
855                 }
856                 c = ReplaceVisibleChar(c, x_FixCharsMethod(), this, str, x_FixCharsSubst());
857                 if (c != 0) {
858                     WriteByte(c);
859                 }
860                 done = i + 1;
861             }
862         }
863         if ( done < length ) {
864             WriteBytes(str.data() + done, length - done);
865         }
866     }
867     else {
868         WriteBytes(str.data(), length);
869     }
870 }
871 
WriteStringStore(const string & str)872 void CObjectOStreamAsnBinary::WriteStringStore(const string& str)
873 {
874     WriteShortTag(eApplication, ePrimitive, eStringStore);
875     size_t length = str.size();
876     WriteLength(length);
877     WriteBytes(str.data(), length);
878 }
879 
CopyStringValue(CObjectIStreamAsnBinary & in,bool)880 void CObjectOStreamAsnBinary::CopyStringValue(CObjectIStreamAsnBinary& in,
881                                               bool /*checkVisible*/)
882 {
883     size_t length = in.ReadLength();
884     WriteLength(length);
885     while ( length > 0 ) {
886         char buffer[1024];
887         size_t c = min(length, sizeof(buffer));
888         in.ReadBytes(buffer, c);
889 #if 0
890         if ( checkVisible ) {
891             // Check the string for non-printable characters
892             for (size_t i = 0; i < c; i++) {
893                 if ( !GoodVisibleChar(buffer[i]) ) {
894                     FixVisibleChar(buffer[i], x_FixCharsMethod(), this, string(buffer,c));
895                 }
896             }
897         }
898 #endif
899         WriteBytes(buffer, c);
900         length -= c;
901     }
902     in.EndOfTag();
903 }
904 
CopyString(CObjectIStream & in,EStringType type)905 void CObjectOStreamAsnBinary::CopyString(CObjectIStream& in,
906                                          EStringType type)
907 {
908     // do we need to check symbols while copying?
909     // x_FixCharsMethod() != eFNP_Allow, type == eStringTypeVisible
910     const bool checkVisible = false;
911     WriteStringTag(type);
912     if ( in.GetDataFormat() == eSerial_AsnBinary ) {
913         CObjectIStreamAsnBinary& bIn =
914             *CTypeConverter<CObjectIStreamAsnBinary>::SafeCast(&in);
915         bIn.ExpectStringTag(type);
916         CopyStringValue(bIn, checkVisible);
917     }
918     else {
919         string str;
920         in.ReadString(str, type);
921         size_t length = str.size();
922 #if 0
923         if ( checkVisible ) {
924             // Check the string for non-printable characters
925             NON_CONST_ITERATE(string, i, str) {
926                 if ( !GoodVisibleChar(*i) ) {
927                     FixVisibleChar(*i, x_FixCharsMethod(), this, str);
928                 }
929             }
930         }
931 #endif
932         WriteLength(length);
933         WriteBytes(str.data(), length);
934     }
935 }
936 
CopyStringStore(CObjectIStream & in)937 void CObjectOStreamAsnBinary::CopyStringStore(CObjectIStream& in)
938 {
939     WriteShortTag(eApplication, ePrimitive, eStringStore);
940     if ( in.GetDataFormat() == eSerial_AsnBinary ) {
941         CObjectIStreamAsnBinary& bIn =
942             *CTypeConverter<CObjectIStreamAsnBinary>::SafeCast(&in);
943         bIn.ExpectSysTag(eApplication, ePrimitive, eStringStore);
944         CopyStringValue(bIn);
945     }
946     else {
947         string str;
948         in.ReadStringStore(str);
949         size_t length = str.size();
950         WriteLength(length);
951         WriteBytes(str.data(), length);
952     }
953 }
954 
WriteCString(const char * str)955 void CObjectOStreamAsnBinary::WriteCString(const char* str)
956 {
957     if ( str == 0 ) {
958         WriteSysTag(eNull);
959         WriteShortLength(0);
960     }
961     else {
962         size_t length = strlen(str), fixed = 0;
963         CTempString original(str, length);
964         WriteSysTag(eVisibleString);
965         WriteLength(length);
966         if ( x_FixCharsMethod() != eFNP_Allow ) {
967             size_t done = 0;
968             for ( size_t i = 0; i < length; ++i ) {
969                 char c = str[i];
970                 if ( !GoodVisibleChar(c) ) {
971 #if SERIAL_ALLOW_UTF8_IN_VISIBLESTRING_ON_WRITING
972                     size_t valid = CUtf8::EvaluateSymbolLength(CTempString(str+i,length-done-i));
973                     if (valid != 0) {
974                         i += valid-1;
975                         continue;
976                     }
977 #endif
978                     if ( i > done ) {
979                         WriteBytes(str + done, i - done);
980                     }
981                     c = ReplaceVisibleChar(c, x_FixCharsMethod(), this, original, x_FixCharsSubst());
982                     WriteByte(c);
983                     if (c != 0) {
984                         WriteByte(c);
985                     } else {
986                         ++fixed;
987                     }
988                     done = i + 1;
989                 }
990             }
991             if ( done < length ) {
992                 WriteBytes(str + done, length - done);
993             }
994             while (fixed--) {
995                 WriteByte(0);
996             }
997         }
998         else {
999             WriteBytes(str, length);
1000         }
1001     }
1002 }
1003 
WriteEnum(const CEnumeratedTypeValues & values,TEnumValueType value)1004 void CObjectOStreamAsnBinary::WriteEnum(const CEnumeratedTypeValues& values,
1005                                         TEnumValueType value)
1006 {
1007     if ( values.IsInteger() ) {
1008         WriteSysTag(eInteger);
1009     }
1010     else {
1011         values.FindName(value, false); // check value
1012         WriteSysTag(eEnumerated);
1013     }
1014     WriteNumberValue(value);
1015 }
1016 
CopyEnum(const CEnumeratedTypeValues & values,CObjectIStream & in)1017 void CObjectOStreamAsnBinary::CopyEnum(const CEnumeratedTypeValues& values,
1018                                        CObjectIStream& in)
1019 {
1020     TEnumValueType value = in.ReadEnum(values);
1021     if ( values.IsInteger() )
1022         WriteSysTag(eInteger);
1023     else
1024         WriteSysTag(eEnumerated);
1025     WriteNumberValue(value);
1026 }
1027 
WriteObjectReference(TObjectIndex index)1028 void CObjectOStreamAsnBinary::WriteObjectReference(TObjectIndex index)
1029 {
1030     WriteTag(eApplication, ePrimitive, eObjectReference);
1031     if ( sizeof(TObjectIndex) == sizeof(Int4) )
1032         WriteNumberValue(Int4(index));
1033     else if ( sizeof(TObjectIndex) == sizeof(Int8) )
1034         WriteNumberValue(Int8(index));
1035     else
1036         ThrowError(fIllegalCall, "invalid size of TObjectIndex"
1037             "must be either sizeof(Int4) or sizeof(Int8)");
1038 }
1039 
WriteNullPointer(void)1040 void CObjectOStreamAsnBinary::WriteNullPointer(void)
1041 {
1042     WriteSysTag(eNull);
1043     WriteShortLength(0);
1044 }
1045 
WriteOtherBegin(TTypeInfo typeInfo)1046 void CObjectOStreamAsnBinary::WriteOtherBegin(TTypeInfo typeInfo)
1047 {
1048     WriteClassTag(typeInfo);
1049     WriteIndefiniteLength();
1050 }
1051 
WriteOtherEnd(TTypeInfo)1052 void CObjectOStreamAsnBinary::WriteOtherEnd(TTypeInfo /*typeInfo*/)
1053 {
1054     WriteEndOfContent();
1055 }
1056 
WriteOther(TConstObjectPtr object,TTypeInfo typeInfo)1057 void CObjectOStreamAsnBinary::WriteOther(TConstObjectPtr object,
1058                                          TTypeInfo typeInfo)
1059 {
1060     WriteClassTag(typeInfo);
1061     WriteIndefiniteLength();
1062     WriteObject(object, typeInfo);
1063     WriteEndOfContent();
1064 }
1065 
1066 
1067 #ifdef VIRTUAL_MID_LEVEL_IO
1068 
BeginNamedType(TTypeInfo namedTypeInfo)1069 void CObjectOStreamAsnBinary::BeginNamedType(TTypeInfo namedTypeInfo)
1070 {
1071 #if !USE_OLD_TAGS
1072     bool need_eoc = false;
1073 #if USE_VERIFY_TAGGING
1074     m_AutomaticTagging = namedTypeInfo->GetTagType() == CAsnBinaryDefs::eAutomatic;
1075 #endif
1076     if (namedTypeInfo->HasTag()) {
1077 #if USE_VERIFY_TAGGING
1078         if (m_AutomaticTagging) {
1079             ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1080         }
1081 #endif
1082         if (!m_SkipNextTag) {
1083             need_eoc = namedTypeInfo->IsTagConstructed();
1084             WriteTag(namedTypeInfo->GetTagClass(),
1085                      namedTypeInfo->GetTagConstructed(),
1086                      namedTypeInfo->GetTag());
1087             if (need_eoc) {
1088                 WriteIndefiniteLength();
1089             }
1090         }
1091         m_SkipNextTag = namedTypeInfo->IsTagImplicit();
1092     }
1093     TopFrame().SetNoEOC(!need_eoc);
1094 #endif
1095 }
1096 
EndNamedType(void)1097 void CObjectOStreamAsnBinary::EndNamedType(void)
1098 {
1099 #if !USE_OLD_TAGS
1100     m_SkipNextTag = false;
1101     if (!TopFrame().GetNoEOC()) {
1102         WriteEndOfContent();
1103     }
1104 #endif
1105 }
1106 
WriteNamedType(TTypeInfo namedTypeInfo,TTypeInfo objectType,TConstObjectPtr objectPtr)1107 void CObjectOStreamAsnBinary::WriteNamedType(
1108     TTypeInfo namedTypeInfo,TTypeInfo objectType, TConstObjectPtr objectPtr)
1109 {
1110 
1111 #if USE_OLD_TAGS
1112 #ifndef VIRTUAL_MID_LEVEL_IO
1113     BEGIN_OBJECT_FRAME2(eFrameNamed, namedTypeInfo);
1114     BeginNamedType(namedTypeInfo);
1115 #endif
1116     WriteObject(objectPtr, objectType);
1117 #ifndef VIRTUAL_MID_LEVEL_IO
1118     EndNamedType();
1119     END_OBJECT_FRAME();
1120 #endif
1121 #else //USE_OLD_TAGS
1122 
1123     bool need_eoc = false;
1124 #if USE_VERIFY_TAGGING
1125     m_AutomaticTagging = namedTypeInfo->GetTagType() == CAsnBinaryDefs::eAutomatic;
1126 #endif
1127     if (namedTypeInfo->HasTag()) {
1128 #if USE_VERIFY_TAGGING
1129         if (m_AutomaticTagging) {
1130             ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1131         }
1132 #endif
1133         if (!m_SkipNextTag) {
1134             need_eoc = namedTypeInfo->IsTagConstructed();
1135             WriteTag(namedTypeInfo->GetTagClass(),
1136                      namedTypeInfo->GetTagConstructed(),
1137                      namedTypeInfo->GetTag());
1138             if (need_eoc) {
1139                 WriteIndefiniteLength();
1140             }
1141         }
1142         m_SkipNextTag = namedTypeInfo->IsTagImplicit();
1143     }
1144     WriteObject(objectPtr, objectType);
1145     if (need_eoc) {
1146         WriteEndOfContent();
1147     }
1148 #endif // USE_OLD_TAGS
1149 }
1150 
CopyNamedType(TTypeInfo namedTypeInfo,TTypeInfo objectType,CObjectStreamCopier & copier)1151 void CObjectOStreamAsnBinary::CopyNamedType(
1152     TTypeInfo namedTypeInfo,TTypeInfo objectType,CObjectStreamCopier& copier)
1153 {
1154     BEGIN_OBJECT_2FRAMES_OF2(copier, eFrameNamed, namedTypeInfo);
1155     copier.In().BeginNamedType(namedTypeInfo);
1156     BeginNamedType(namedTypeInfo);
1157 
1158     CopyObject(objectType, copier);
1159 
1160     EndNamedType();
1161     copier.In().EndNamedType();
1162     END_OBJECT_2FRAMES_OF(copier);
1163 }
1164 
1165 
BeginContainer(const CContainerTypeInfo * cType)1166 void CObjectOStreamAsnBinary::BeginContainer(const CContainerTypeInfo* cType)
1167 {
1168 #if USE_OLD_TAGS
1169     WriteByte(MakeContainerTagByte(cType->RandomElementsOrder()));
1170     WriteIndefiniteLength();
1171 #else
1172     _ASSERT(cType->HasTag());
1173     _ASSERT(cType->IsTagConstructed());
1174 #if 0 //USE_VERIFY_TAGGING
1175     m_AutomaticTagging = cType->GetTagType() == CAsnBinaryDefs::eAutomatic;
1176 #endif
1177     bool need_eoc = !m_SkipNextTag;
1178     if (!m_SkipNextTag) {
1179         WriteTag(cType->GetTagClass(), eConstructed, cType->GetTag());
1180         WriteIndefiniteLength();
1181     }
1182 #if USE_VERIFY_TAGGING
1183     else if (m_AutomaticTagging) {
1184         ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1185     }
1186 #endif
1187     m_SkipNextTag = cType->IsTagImplicit();
1188     TopFrame().SetNoEOC(!need_eoc);
1189 #endif
1190 }
1191 
EndContainer(void)1192 void CObjectOStreamAsnBinary::EndContainer(void)
1193 {
1194 #if USE_OLD_TAGS
1195     WriteEndOfContent();
1196 #else
1197     m_SkipNextTag = false;
1198     if (!TopFrame().GetNoEOC()) {
1199         WriteEndOfContent();
1200     }
1201 #endif
1202 }
1203 
WriteContainer(const CContainerTypeInfo * cType,TConstObjectPtr containerPtr)1204 void CObjectOStreamAsnBinary::WriteContainer(const CContainerTypeInfo* cType,
1205                                              TConstObjectPtr containerPtr)
1206 {
1207 #if USE_OLD_TAGS
1208     WriteByte(MakeContainerTagByte(cType->RandomElementsOrder()));
1209     WriteIndefiniteLength();
1210 #else
1211     BEGIN_OBJECT_FRAME2(eFrameArray, cType);
1212     _ASSERT(cType->HasTag());
1213     _ASSERT(cType->IsTagConstructed());
1214 #if 0 //USE_VERIFY_TAGGING
1215     m_AutomaticTagging = cType->GetTagType() == CAsnBinaryDefs::eAutomatic;
1216 #endif
1217     bool need_eoc = !m_SkipNextTag;
1218     if (!m_SkipNextTag) {
1219         WriteTag(cType->GetTagClass(), eConstructed, cType->GetTag());
1220         WriteIndefiniteLength();
1221     }
1222 #if USE_VERIFY_TAGGING
1223     else if (m_AutomaticTagging) {
1224         ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1225     }
1226 #endif
1227     m_SkipNextTag = cType->IsTagImplicit();
1228 #endif
1229 
1230     CContainerTypeInfo::CConstIterator i;
1231     if ( cType->InitIterator(i, containerPtr) ) {
1232         TTypeInfo elementType = cType->GetElementType();
1233         BEGIN_OBJECT_FRAME2(eFrameArrayElement, elementType);
1234 
1235         const CPointerTypeInfo* pointerType =
1236             dynamic_cast<const CPointerTypeInfo*>(elementType);
1237         do {
1238             TConstObjectPtr elementPtr = cType->GetElementPtr(i);
1239             if ( pointerType &&
1240                  !pointerType->GetObjectPointer(elementPtr) ) {
1241                 if ( GetVerifyData() == eSerialVerifyData_Yes ) {
1242                     ThrowError(fUnassigned,
1243                                "NULL element while writing container "+
1244                                cType->GetName());
1245                 }
1246                 continue;
1247             }
1248 
1249             WriteObject(elementPtr, elementType);
1250 
1251         } while ( cType->NextElement(i) );
1252 
1253         END_OBJECT_FRAME();
1254     }
1255 
1256 #if USE_OLD_TAGS
1257     WriteEndOfContent();
1258 #else
1259     if (need_eoc) {
1260         WriteEndOfContent();
1261     }
1262     END_OBJECT_FRAME();
1263 #endif
1264 }
1265 
CopyContainer(const CContainerTypeInfo * cType,CObjectStreamCopier & copier)1266 void CObjectOStreamAsnBinary::CopyContainer(const CContainerTypeInfo* cType,
1267                                             CObjectStreamCopier& copier)
1268 {
1269 #if USE_OLD_TAGS
1270     BEGIN_OBJECT_FRAME_OF2(copier.In(), eFrameArray, cType);
1271     copier.In().BeginContainer(cType);
1272     WriteByte(MakeContainerTagByte(cType->RandomElementsOrder()));
1273     WriteIndefiniteLength();
1274 #else
1275     BEGIN_OBJECT_2FRAMES_OF2(copier, eFrameArray, cType);
1276     copier.In().BeginContainer(cType);
1277     CObjectOStreamAsnBinary::BeginContainer(cType);
1278 #endif
1279 
1280     TTypeInfo elementType = cType->GetElementType();
1281     BEGIN_OBJECT_2FRAMES_OF2(copier, eFrameArrayElement, elementType);
1282 
1283     while ( copier.In().BeginContainerElement(elementType) ) {
1284 
1285         CopyObject(elementType, copier);
1286 
1287         copier.In().EndContainerElement();
1288     }
1289 
1290     END_OBJECT_2FRAMES_OF(copier);
1291 
1292 #if USE_OLD_TAGS
1293     WriteEndOfContent();
1294     copier.In().EndContainer();
1295     END_OBJECT_FRAME_OF(copier.In());
1296 #else
1297     CObjectOStreamAsnBinary::EndContainer();
1298     copier.In().EndContainer();
1299     END_OBJECT_2FRAMES_OF(copier);
1300 #endif
1301 
1302 }
1303 
1304 #endif
1305 
BeginClass(const CClassTypeInfo * classType)1306 void CObjectOStreamAsnBinary::BeginClass(const CClassTypeInfo* classType)
1307 {
1308 #if USE_OLD_TAGS
1309     WriteByte(MakeContainerTagByte(classType->RandomOrder()));
1310     WriteIndefiniteLength();
1311 #else
1312     _ASSERT(classType->HasTag());
1313     _ASSERT(classType->IsTagConstructed());
1314 #if USE_VERIFY_TAGGING
1315     m_AutomaticTagging = classType->GetTagType() == CAsnBinaryDefs::eAutomatic;
1316 #endif
1317     bool need_eoc = !m_SkipNextTag;
1318     if (!m_SkipNextTag) {
1319         WriteTag(classType->GetTagClass(), eConstructed, classType->GetTag());
1320         WriteIndefiniteLength();
1321     }
1322 #if USE_VERIFY_TAGGING
1323     else if (m_AutomaticTagging) {
1324         ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1325     }
1326 #endif
1327     m_SkipNextTag = classType->IsTagImplicit();
1328     TopFrame().SetNoEOC(!need_eoc);
1329 #endif
1330 }
1331 
EndClass(void)1332 void CObjectOStreamAsnBinary::EndClass(void)
1333 {
1334 #if USE_OLD_TAGS
1335     WriteEndOfContent();
1336 #else
1337     m_SkipNextTag = false;
1338     if (!TopFrame().GetNoEOC()) {
1339         WriteEndOfContent();
1340     }
1341 #endif
1342 }
1343 
BeginClassMember(const CMemberId & id)1344 void CObjectOStreamAsnBinary::BeginClassMember(const CMemberId& id)
1345 {
1346 #if USE_OLD_TAGS
1347     WriteTag(eContextSpecific, eConstructed, id.GetTag());
1348     WriteIndefiniteLength();
1349 #else
1350     if (id.HasTag()) {
1351         WriteTag(id.GetTagClass(), id.GetTagConstructed(), id.GetTag());
1352         if (id.IsTagConstructed()) {
1353             WriteIndefiniteLength();
1354         }
1355     }
1356 #if USE_VERIFY_TAGGING
1357     else if (m_AutomaticTagging) {
1358         ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1359     }
1360 #endif
1361     m_SkipNextTag = id.HasTag() && id.IsTagImplicit();
1362 #endif
1363 }
1364 
EndClassMember(void)1365 void CObjectOStreamAsnBinary::EndClassMember(void)
1366 {
1367 #if USE_OLD_TAGS
1368     WriteEndOfContent();
1369 #else
1370     m_SkipNextTag = false;
1371     const CMemberId& id = TopFrame().GetMemberId();
1372     if (id.HasTag() && id.IsTagConstructed()) {
1373         WriteEndOfContent();
1374     }
1375 #endif
1376 }
1377 
1378 #ifdef VIRTUAL_MID_LEVEL_IO
WriteClass(const CClassTypeInfo * classType,TConstObjectPtr classPtr)1379 void CObjectOStreamAsnBinary::WriteClass(const CClassTypeInfo* classType,
1380                                          TConstObjectPtr classPtr)
1381 {
1382 #if USE_OLD_TAGS
1383     WriteByte(MakeContainerTagByte(classType->RandomOrder()));
1384     WriteIndefiniteLength();
1385 #else
1386     BEGIN_OBJECT_FRAME2(eFrameClass, classType);
1387     _ASSERT(classType->HasTag());
1388     _ASSERT(classType->IsTagConstructed());
1389 #if USE_VERIFY_TAGGING
1390     m_AutomaticTagging = classType->GetTagType() == CAsnBinaryDefs::eAutomatic;
1391 #endif
1392     bool need_eoc = !m_SkipNextTag;
1393     if (!m_SkipNextTag) {
1394         WriteTag(classType->GetTagClass(), eConstructed, classType->GetTag());
1395         WriteIndefiniteLength();
1396     }
1397 #if USE_VERIFY_TAGGING
1398     else if (m_AutomaticTagging) {
1399         ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1400     }
1401 #endif
1402     m_SkipNextTag = classType->IsTagImplicit();
1403 #endif
1404 
1405     for ( CClassTypeInfo::CIterator i(classType); i.Valid(); ++i ) {
1406         classType->GetMemberInfo(i)->WriteMember(*this, classPtr);
1407     }
1408 
1409 #if USE_OLD_TAGS
1410     WriteEndOfContent();
1411 #else
1412     if (need_eoc) {
1413         WriteEndOfContent();
1414     }
1415     END_OBJECT_FRAME();
1416 #endif
1417 }
1418 
WriteClassMember(const CMemberId & memberId,TTypeInfo memberType,TConstObjectPtr memberPtr)1419 void CObjectOStreamAsnBinary::WriteClassMember(const CMemberId& memberId,
1420                                                TTypeInfo memberType,
1421                                                TConstObjectPtr memberPtr)
1422 {
1423     BEGIN_OBJECT_FRAME2(eFrameClassMember, memberId);
1424 #if USE_OLD_TAGS
1425     WriteTag(eContextSpecific, eConstructed, memberId.GetTag());
1426     WriteIndefiniteLength();
1427 #else
1428     bool need_eoc = false;
1429     if (memberId.HasTag()) {
1430         WriteTag(memberId.GetTagClass(), memberId.GetTagConstructed(), memberId.GetTag());
1431         need_eoc = memberId.IsTagConstructed();
1432         if (need_eoc) {
1433             WriteIndefiniteLength();
1434         }
1435     }
1436 #if USE_VERIFY_TAGGING
1437     else if (m_AutomaticTagging) {
1438         ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1439     }
1440 #endif
1441     m_SkipNextTag = memberId.HasTag() && memberId.IsTagImplicit();
1442 #endif
1443 
1444     WriteObject(memberPtr, memberType);
1445 
1446 #if USE_OLD_TAGS
1447     WriteEndOfContent();
1448 #else
1449     if (need_eoc) {
1450         WriteEndOfContent();
1451     }
1452 #endif
1453     END_OBJECT_FRAME();
1454 }
1455 
WriteClassMember(const CMemberId & memberId,const CDelayBuffer & buffer)1456 bool CObjectOStreamAsnBinary::WriteClassMember(const CMemberId& memberId,
1457                                                const CDelayBuffer& buffer)
1458 {
1459     if ( !buffer.HaveFormat(eSerial_AsnBinary) )
1460         return false;
1461 
1462     BEGIN_OBJECT_FRAME2(eFrameClassMember, memberId);
1463 #if USE_OLD_TAGS
1464     WriteTag(eContextSpecific, eConstructed, memberId.GetTag());
1465     WriteIndefiniteLength();
1466 #else
1467     bool need_eoc = false;
1468     if (memberId.HasTag()) {
1469         WriteTag(memberId.GetTagClass(), memberId.GetTagConstructed(), memberId.GetTag());
1470         need_eoc = memberId.IsTagConstructed();
1471         if (need_eoc) {
1472             WriteIndefiniteLength();
1473         }
1474     }
1475 #if USE_VERIFY_TAGGING
1476     else if (m_AutomaticTagging) {
1477         ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1478     }
1479 #endif
1480     m_SkipNextTag = memberId.HasTag() && memberId.IsTagImplicit();
1481 #endif
1482 
1483     Write(buffer.GetSource());
1484 
1485 #if USE_OLD_TAGS
1486     WriteEndOfContent();
1487 #else
1488     if (need_eoc) {
1489         WriteEndOfContent();
1490     }
1491 #endif
1492     END_OBJECT_FRAME();
1493 
1494     return true;
1495 }
1496 
CopyClassRandom(const CClassTypeInfo * classType,CObjectStreamCopier & copier)1497 void CObjectOStreamAsnBinary::CopyClassRandom(const CClassTypeInfo* classType,
1498                                               CObjectStreamCopier& copier)
1499 {
1500 #if USE_OLD_TAGS
1501     BEGIN_OBJECT_FRAME_OF2(copier.In(), eFrameClass, classType);
1502     copier.In().BeginClass(classType);
1503     WriteByte(MakeContainerTagByte(classType->RandomOrder()));
1504     WriteIndefiniteLength();
1505 #else
1506     BEGIN_OBJECT_2FRAMES_OF2(copier, eFrameClass, classType);
1507     copier.In().BeginClass(classType);
1508     CObjectOStreamAsnBinary::BeginClass(classType);
1509 #endif
1510 
1511     vector<Uint1> read(classType->GetMembers().LastIndex() + 1);
1512 
1513     BEGIN_OBJECT_2FRAMES_OF(copier, eFrameClassMember);
1514 
1515     TMemberIndex index;
1516     while ( (index = copier.In().BeginClassMember(classType)) !=
1517             kInvalidMember ) {
1518         const CMemberInfo* memberInfo = classType->GetMemberInfo(index);
1519         copier.In().SetTopMemberId(memberInfo->GetId());
1520         SetTopMemberId(memberInfo->GetId());
1521         copier.SetPathHooks(*this, true);
1522 
1523         if ( read[index] ) {
1524             copier.DuplicatedMember(memberInfo);
1525         }
1526         else {
1527             read[index] = true;
1528 
1529 #if USE_OLD_TAGS
1530             WriteTag(eContextSpecific,
1531                      eConstructed,
1532                      memberInfo->GetId().GetTag());
1533             WriteIndefiniteLength();
1534 #else
1535             CObjectOStreamAsnBinary::BeginClassMember(memberInfo->GetId());
1536 #endif
1537 
1538             memberInfo->CopyMember(copier);
1539 
1540 #if USE_OLD_TAGS
1541             WriteEndOfContent();
1542 #else
1543             CObjectOStreamAsnBinary::EndClassMember();
1544 #endif
1545         }
1546 
1547         copier.SetPathHooks(*this, false);
1548         copier.In().EndClassMember();
1549     }
1550 
1551     END_OBJECT_2FRAMES_OF(copier);
1552 
1553     // init all absent members
1554     for ( CClassTypeInfo::CIterator i(classType); i.Valid(); ++i ) {
1555         if ( !read[*i] ) {
1556             classType->GetMemberInfo(i)->CopyMissingMember(copier);
1557         }
1558     }
1559 
1560 #if USE_OLD_TAGS
1561     WriteEndOfContent();
1562     copier.In().EndClass();
1563     END_OBJECT_FRAME_OF(copier.In());
1564 #else
1565     CObjectOStreamAsnBinary::EndClass();
1566     copier.In().EndClass();
1567     END_OBJECT_2FRAMES_OF(copier);
1568 #endif
1569 }
1570 
CopyClassSequential(const CClassTypeInfo * classType,CObjectStreamCopier & copier)1571 void CObjectOStreamAsnBinary::CopyClassSequential(const CClassTypeInfo* classType,
1572                                                   CObjectStreamCopier& copier)
1573 {
1574 #if USE_OLD_TAGS
1575     BEGIN_OBJECT_FRAME_OF2(copier.In(), eFrameClass, classType);
1576     copier.In().BeginClass(classType);
1577     WriteByte(MakeContainerTagByte(classType->RandomOrder()));
1578     WriteIndefiniteLength();
1579 #else
1580     BEGIN_OBJECT_2FRAMES_OF2(copier, eFrameClass, classType);
1581     copier.In().BeginClass(classType);
1582     CObjectOStreamAsnBinary::BeginClass(classType);
1583 #endif
1584 
1585     CClassTypeInfo::CIterator pos(classType);
1586     BEGIN_OBJECT_2FRAMES_OF(copier, eFrameClassMember);
1587 
1588     TMemberIndex index;
1589     while ( (index = copier.In().BeginClassMember(classType, *pos)) !=
1590             kInvalidMember ) {
1591         const CMemberInfo* memberInfo = classType->GetMemberInfo(index);
1592         copier.In().SetTopMemberId(memberInfo->GetId());
1593         SetTopMemberId(memberInfo->GetId());
1594 
1595         for ( TMemberIndex i = *pos; i < index; ++i ) {
1596             // init missing member
1597             classType->GetMemberInfo(i)->CopyMissingMember(copier);
1598         }
1599         copier.SetPathHooks(*this, true);
1600 
1601 #if USE_OLD_TAGS
1602         WriteTag(eContextSpecific, eConstructed, memberInfo->GetId().GetTag());
1603         WriteIndefiniteLength();
1604 #else
1605             CObjectOStreamAsnBinary::BeginClassMember(memberInfo->GetId());
1606 #endif
1607 
1608         memberInfo->CopyMember(copier);
1609 
1610 #if USE_OLD_TAGS
1611         WriteEndOfContent();
1612 #else
1613         CObjectOStreamAsnBinary::EndClassMember();
1614 #endif
1615 
1616         pos.SetIndex(index + 1);
1617 
1618         copier.SetPathHooks(*this, false);
1619         copier.In().EndClassMember();
1620     }
1621 
1622     END_OBJECT_2FRAMES_OF(copier);
1623 
1624     // init all absent members
1625     for ( ; pos.Valid(); ++pos ) {
1626         classType->GetMemberInfo(pos)->CopyMissingMember(copier);
1627     }
1628 
1629 #if USE_OLD_TAGS
1630     WriteEndOfContent();
1631     copier.In().EndClass();
1632     END_OBJECT_FRAME_OF(copier.In());
1633 #else
1634     CObjectOStreamAsnBinary::EndClass();
1635     copier.In().EndClass();
1636     END_OBJECT_2FRAMES_OF(copier);
1637 #endif
1638 }
1639 #endif
1640 
BeginChoice(const CChoiceTypeInfo * choiceType)1641 void CObjectOStreamAsnBinary::BeginChoice(const CChoiceTypeInfo* choiceType)
1642 {
1643     if (choiceType->GetVariantInfo(kFirstMemberIndex)->GetId().IsAttlist()) {
1644         TopFrame().SetNotag();
1645         WriteByte(MakeContainerTagByte(false));
1646         WriteIndefiniteLength();
1647     }
1648 }
1649 
EndChoice(void)1650 void CObjectOStreamAsnBinary::EndChoice(void)
1651 {
1652     if (TopFrame().GetNotag()) {
1653         WriteEndOfContent();
1654     }
1655 }
1656 
BeginChoiceVariant(const CChoiceTypeInfo *,const CMemberId & id)1657 void CObjectOStreamAsnBinary::BeginChoiceVariant(const CChoiceTypeInfo* ,
1658                                                  const CMemberId& id)
1659 {
1660     if (FetchFrameFromTop(1).GetNotag()) {
1661         WriteTag(eContextSpecific, eConstructed, kFirstMemberIndex);
1662         WriteIndefiniteLength();
1663         WriteTag(eContextSpecific, eConstructed, id.GetTag()-1);
1664         WriteIndefiniteLength();
1665     } else {
1666 #if USE_OLD_TAGS
1667         WriteTag(eContextSpecific, eConstructed, id.GetTag());
1668         WriteIndefiniteLength();
1669 #else
1670         if (id.HasTag()) {
1671             WriteTag(id.GetTagClass(), id.GetTagConstructed(), id.GetTag());
1672             if (id.IsTagConstructed()) {
1673                 WriteIndefiniteLength();
1674             }
1675         }
1676 #if USE_VERIFY_TAGGING
1677         else if (m_AutomaticTagging) {
1678             ThrowError(fInvalidData, "ASN TAGGING ERROR. Report immediately!");
1679         }
1680 #endif
1681         m_SkipNextTag = id.HasTag() && id.IsTagImplicit();
1682 #endif
1683     }
1684 }
1685 
EndChoiceVariant(void)1686 void CObjectOStreamAsnBinary::EndChoiceVariant(void)
1687 {
1688     m_SkipNextTag = false;
1689     if (FetchFrameFromTop(1).GetNotag()) {
1690         WriteEndOfContent();
1691     }
1692 #if USE_OLD_TAGS
1693     WriteEndOfContent();
1694 #else
1695     const CMemberId& id = TopFrame().GetMemberId();
1696     if (id.HasTag() && id.IsTagConstructed()) {
1697         WriteEndOfContent();
1698     }
1699 #endif
1700 }
1701 
BeginBytes(const ByteBlock & block)1702 void CObjectOStreamAsnBinary::BeginBytes(const ByteBlock& block)
1703 {
1704     WriteSysTag(eOctetString);
1705     WriteLength(block.GetLength());
1706 }
1707 
WriteBytes(const ByteBlock &,const char * bytes,size_t length)1708 void CObjectOStreamAsnBinary::WriteBytes(const ByteBlock& ,
1709                                          const char* bytes, size_t length)
1710 {
1711     WriteBytes(bytes, length);
1712 }
1713 
BeginChars(const CharBlock & block)1714 void CObjectOStreamAsnBinary::BeginChars(const CharBlock& block)
1715 {
1716     if ( block.GetLength() == 0 ) {
1717         WriteSysTag(eNull);
1718         WriteShortLength(0);
1719         return;
1720     }
1721     WriteSysTag(eVisibleString);
1722     WriteLength(block.GetLength());
1723 }
1724 
1725 
WriteChars(const CharBlock &,const char * str,size_t length)1726 void CObjectOStreamAsnBinary::WriteChars(const CharBlock& ,
1727                                          const char* str, size_t length)
1728 {
1729     if ( x_FixCharsMethod() != eFNP_Allow ) {
1730         CTempString original(str, length);
1731         size_t done = 0, fixed = 0;
1732         for ( size_t i = 0; i < length; ++i ) {
1733             char c = str[i];
1734             if ( !GoodVisibleChar(c) ) {
1735 #if SERIAL_ALLOW_UTF8_IN_VISIBLESTRING_ON_WRITING
1736                 size_t valid = CUtf8::EvaluateSymbolLength(CTempString(str+i,length-done-i));
1737                 if (valid != 0) {
1738                     i += valid-1;
1739                     continue;
1740                 }
1741 #endif
1742                 if ( i > done ) {
1743                     WriteBytes(str + done, i - done);
1744                 }
1745                 c = ReplaceVisibleChar(c, x_FixCharsMethod(), this, original, x_FixCharsSubst());
1746                 if (c != 0) {
1747                     WriteByte(c);
1748                 } else {
1749                     ++fixed;
1750                 }
1751                 done = i + 1;
1752             }
1753         }
1754         if ( done < length ) {
1755             WriteBytes(str + done, length - done);
1756         }
1757         while (fixed--) {
1758             WriteByte(0);
1759         }
1760     }
1761     else {
1762         WriteBytes(str, length);
1763     }
1764 }
1765 
1766 
1767 END_NCBI_SCOPE
1768