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