1 /* $Id: objostrxml.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 * XML object output stream
30 *
31 */
32
33 #include <ncbi_pch.hpp>
34 #include <corelib/ncbistd.hpp>
35 #include <corelib/ncbi_limits.h>
36
37 #include <serial/objostrxml.hpp>
38 #include <serial/objistr.hpp>
39 #include <serial/objcopy.hpp>
40 #include <serial/impl/memberid.hpp>
41 #include <serial/impl/memberlist.hpp>
42 #include <serial/enumvalues.hpp>
43 #include <serial/objhook.hpp>
44 #include <serial/impl/classinfo.hpp>
45 #include <serial/impl/choice.hpp>
46 #include <serial/impl/continfo.hpp>
47 #include <serial/impl/aliasinfo.hpp>
48 #include <serial/delaybuf.hpp>
49 #include <serial/impl/ptrinfo.hpp>
50 #include <serial/error_codes.hpp>
51
52 #include <stdio.h>
53 #include <math.h>
54
55
56 #define NCBI_USE_ERRCODE_X Serial_OStream
57
58 BEGIN_NCBI_SCOPE
59
OpenObjectOStreamXml(CNcbiOstream & out,EOwnership deleteOut)60 CObjectOStream* CObjectOStream::OpenObjectOStreamXml(CNcbiOstream& out,
61 EOwnership deleteOut)
62 {
63 return new CObjectOStreamXml(out, deleteOut);
64 }
65
66
67 string CObjectOStreamXml::sm_DefaultDTDFilePrefix = "";
68 const char* sm_DefaultNamespacePrefix = "ns";
69 const char* sm_DefaultSchemaNamespace = "http://www.ncbi.nlm.nih.gov";
70 static
71 const char* s_SchemaInstanceNamespace = "http://www.w3.org/2001/XMLSchema-instance";
72
73
CObjectOStreamXml(CNcbiOstream & out,bool deleteOut)74 CObjectOStreamXml::CObjectOStreamXml(CNcbiOstream& out, bool deleteOut)
75 : CObjectOStream(eSerial_Xml, out, deleteOut ? eTakeOwnership : eNoOwnership),
76 m_LastTagAction(eTagClose), m_SpecRef(eSpecRefNotSet), m_EndTag(true),
77 m_UseDefaultDTDFilePrefix( true),
78 m_UsePublicId( true),
79 m_Attlist( false), m_StdXml( false), m_EnforcedStdXml( false),
80 m_RealFmt( eRealScientificFormat ),
81 m_Encoding( eEncoding_Unknown ), m_StringEncoding( eEncoding_UTF8 ),
82 m_UseXmlDecl( true ), m_UseSchemaLoc( true ),
83 m_DefaultSchemaNamespace( sm_DefaultSchemaNamespace ),
84 m_SkipIndent( false ), m_SkipNextTag( false )
85 {
86 m_Output.SetBackLimit(1);
87 }
88
CObjectOStreamXml(CNcbiOstream & out,EOwnership deleteOut)89 CObjectOStreamXml::CObjectOStreamXml(CNcbiOstream& out, EOwnership deleteOut)
90 : CObjectOStream(eSerial_Xml, out, deleteOut),
91 m_LastTagAction(eTagClose), m_SpecRef(eSpecRefNotSet), m_EndTag(true),
92 m_UseDefaultDTDFilePrefix( true),
93 m_UsePublicId( true),
94 m_Attlist( false), m_StdXml( false), m_EnforcedStdXml( false),
95 m_RealFmt( eRealScientificFormat ),
96 m_Encoding( eEncoding_Unknown ), m_StringEncoding( eEncoding_UTF8 ),
97 m_UseXmlDecl( true ), m_UseSchemaLoc( true ),
98 m_DefaultSchemaNamespace( sm_DefaultSchemaNamespace ),
99 m_SkipIndent( false ), m_SkipNextTag( false )
100 {
101 m_Output.SetBackLimit(1);
102 }
103
~CObjectOStreamXml(void)104 CObjectOStreamXml::~CObjectOStreamXml(void)
105 {
106 }
107
SetEncoding(EEncoding enc)108 void CObjectOStreamXml::SetEncoding(EEncoding enc)
109 {
110 m_Encoding = enc;
111 }
112
GetEncoding(void) const113 EEncoding CObjectOStreamXml::GetEncoding(void) const
114 {
115 return m_Encoding;
116 }
117
SetDefaultStringEncoding(EEncoding enc)118 void CObjectOStreamXml::SetDefaultStringEncoding(EEncoding enc)
119 {
120 m_StringEncoding = enc;
121 }
122
GetDefaultStringEncoding(void) const123 EEncoding CObjectOStreamXml::GetDefaultStringEncoding(void) const
124 {
125 return m_StringEncoding;
126 }
127
SetReferenceSchema(bool use_schema)128 void CObjectOStreamXml::SetReferenceSchema(bool use_schema)
129 {
130 m_SpecRef = use_schema ? eSpecRefSchema : eSpecRefNone;
131 }
GetReferenceSchema(void) const132 bool CObjectOStreamXml::GetReferenceSchema(void) const
133 {
134 return m_SpecRef == eSpecRefSchema;
135 }
SetReferenceDTD(bool use_dtd)136 void CObjectOStreamXml::SetReferenceDTD(bool use_dtd)
137 {
138 m_SpecRef = use_dtd ? eSpecRefDTD : eSpecRefNone;
139 }
GetReferenceDTD(void) const140 bool CObjectOStreamXml::GetReferenceDTD(void) const
141 {
142 return m_SpecRef == eSpecRefDTD;
143 }
144
SetUseSchemaLocation(bool use_loc)145 void CObjectOStreamXml::SetUseSchemaLocation(bool use_loc)
146 {
147 m_UseSchemaLoc = use_loc;
148 }
GetUseSchemaLocation(void) const149 bool CObjectOStreamXml::GetUseSchemaLocation(void) const
150 {
151 return m_UseSchemaLoc;
152 }
153
154
155 CObjectOStreamXml::ERealValueFormat
GetRealValueFormat(void) const156 CObjectOStreamXml::GetRealValueFormat(void) const
157 {
158 return m_RealFmt;
159 }
SetRealValueFormat(CObjectOStreamXml::ERealValueFormat fmt)160 void CObjectOStreamXml::SetRealValueFormat(
161 CObjectOStreamXml::ERealValueFormat fmt)
162 {
163 m_RealFmt = fmt;
164 }
165
SetEnforcedStdXml(bool set)166 void CObjectOStreamXml::SetEnforcedStdXml(bool set)
167 {
168 m_EnforcedStdXml = set;
169 if (m_EnforcedStdXml) {
170 m_StdXml = false;
171 }
172 }
173
SetFormattingFlags(TSerial_Format_Flags flags)174 void CObjectOStreamXml::SetFormattingFlags(TSerial_Format_Flags flags)
175 {
176 TSerial_Format_Flags accepted =
177 fSerial_Xml_NoIndentation | fSerial_Xml_NoEol |
178 fSerial_Xml_NoXmlDecl | fSerial_Xml_NoRefDTD |
179 fSerial_Xml_RefSchema | fSerial_Xml_NoSchemaLoc;
180 if (flags & ~accepted) {
181 ERR_POST_X_ONCE(12, Warning <<
182 "CObjectOStreamXml::SetFormattingFlags: ignoring unknown formatting flags");
183 }
184 m_UseXmlDecl = (flags & fSerial_Xml_NoXmlDecl) == 0;
185 if ((flags & fSerial_Xml_NoRefDTD) != 0) {m_SpecRef = eSpecRefNone;}
186 if ((flags & fSerial_Xml_RefSchema) != 0) {m_SpecRef = eSpecRefSchema;}
187 m_UseSchemaLoc = (flags & fSerial_Xml_NoSchemaLoc) == 0;
188
189 CObjectOStream::SetFormattingFlags(
190 flags & (fSerial_Xml_NoIndentation | fSerial_Xml_NoEol));
191 }
192
193
GetPosition(void) const194 string CObjectOStreamXml::GetPosition(void) const
195 {
196 return "line "+NStr::SizetToString(m_Output.GetLine());
197 }
198
GetPublicModuleName(TTypeInfo type)199 static string GetPublicModuleName(TTypeInfo type)
200 {
201 const string& s = type->GetModuleName();
202 string name;
203 for ( string::const_iterator i = s.begin(); i != s.end(); ++i ) {
204 char c = *i;
205 if ( !isalnum((unsigned char) c) )
206 name += ' ';
207 else
208 name += c;
209 }
210 return name;
211 }
212
GetModuleName(TTypeInfo type)213 string CObjectOStreamXml::GetModuleName(TTypeInfo type)
214 {
215 string name;
216 if( !m_DTDFileName.empty() ) {
217 name = m_DTDFileName;
218 }
219 else {
220 const string& s = type->GetModuleName();
221 for ( string::const_iterator i = s.begin(); i != s.end(); ++i ) {
222 char c = *i;
223 if ( c == '-' )
224 name += '_';
225 else
226 name += c;
227 }
228 }
229 return name;
230 }
231
WriteFileHeader(TTypeInfo type)232 void CObjectOStreamXml::WriteFileHeader(TTypeInfo type)
233 {
234 if (m_UseXmlDecl) {
235 m_Output.PutString("<?xml version=\"1.0");
236 switch (m_Encoding) {
237 default:
238 break;
239 case eEncoding_UTF8:
240 m_Output.PutString("\" encoding=\"UTF-8");
241 break;
242 case eEncoding_ISO8859_1:
243 m_Output.PutString("\" encoding=\"ISO-8859-1");
244 break;
245 case eEncoding_Windows_1252:
246 m_Output.PutString("\" encoding=\"Windows-1252");
247 break;
248 }
249 m_Output.PutString("\"?>");
250 }
251
252 if (m_SpecRef == eSpecRefNotSet) {
253 CheckStdXml(type);
254 m_SpecRef = (type->GetDataSpec() == EDataSpec::eDTD || !x_IsStdXml()) ? eSpecRefDTD : eSpecRefSchema;
255 }
256 if (GetReferenceDTD()) {
257 if (m_UseXmlDecl) {
258 m_Output.PutEol();
259 }
260 m_Output.PutString("<!DOCTYPE ");
261 m_Output.PutString(type->GetName());
262
263 if (m_UsePublicId) {
264 m_Output.PutString(" PUBLIC \"");
265 if (m_PublicId.empty()) {
266 m_Output.PutString("-//NCBI//");
267 m_Output.PutString(GetPublicModuleName(type));
268 m_Output.PutString("/EN");
269 } else {
270 m_Output.PutString(m_PublicId);
271 }
272 m_Output.PutString("\"");
273 } else {
274 m_Output.PutString(" SYSTEM");
275 }
276 m_Output.PutString(" \"");
277 m_Output.PutString(GetDTDFilePrefix() + GetModuleName(type));
278 m_Output.PutString(".dtd\">");
279 } else if (!m_UseXmlDecl) {
280 m_SkipIndent = true;
281 }
282 m_LastTagAction = eTagClose;
283 m_NsNameToPrefix.clear();
284 m_NsPrefixToName.clear();
285 }
286
EndOfWrite(void)287 void CObjectOStreamXml::EndOfWrite(void)
288 {
289 m_Output.PutEol(false);
290 CObjectOStream::EndOfWrite();
291 }
292
x_WriteClassNamespace(TTypeInfo type)293 void CObjectOStreamXml::x_WriteClassNamespace(TTypeInfo type)
294 {
295 if (type->GetName().find(':') != string::npos) {
296 return;
297 }
298 if (!m_Attlist) {
299 OpenTagEndBack();
300 }
301
302 string ns_name( m_NsPrefixToName[m_CurrNsPrefix]);
303 if (ns_name.empty()) {
304 ns_name = GetDefaultSchemaNamespace();
305 }
306 if (type->HasNamespaceName() || ((type->GetDataSpec() != EDataSpec::eXSD) &&
307 m_NsNameToPrefix.find(ns_name) == m_NsNameToPrefix.end())) {
308 if (m_Attlist) {
309 m_Output.PutString(" xmlns");
310 } else {
311 m_Output.PutEol();
312 m_Output.PutString(" xmlns");
313 }
314 if (!m_CurrNsPrefix.empty()) {
315 m_Output.PutChar(':');
316 m_Output.PutString(m_CurrNsPrefix);
317 }
318 m_Output.PutString("=\"");
319 m_Output.PutString(ns_name + "\"");
320 m_NsPrefixToName[m_CurrNsPrefix] = ns_name;
321 m_NsNameToPrefix[ns_name] = m_CurrNsPrefix;
322 }
323
324 if (m_UseSchemaLoc) {
325 string xs_name(s_SchemaInstanceNamespace);
326 string xs_prefix("xs");
327 if (m_NsNameToPrefix.find(xs_name) == m_NsNameToPrefix.end()) {
328 for (char a='a';
329 m_NsPrefixToName.find(xs_prefix) != m_NsPrefixToName.end(); ++a) {
330 xs_prefix += a;
331 }
332 m_NsPrefixToName[xs_prefix] = xs_name;
333 m_NsNameToPrefix[xs_name] = xs_prefix;
334 m_Output.PutEol();
335 m_Output.PutString(" xmlns:");
336 m_Output.PutString(xs_prefix + "=\"");
337 m_Output.PutString(xs_name + "\"");
338 m_Output.PutEol();
339 m_Output.PutString(" ");
340 m_Output.PutString(xs_prefix);
341 m_Output.PutString(":schemaLocation=\"");
342 m_Output.PutString(ns_name + " ");
343 m_Output.PutString(GetDTDFilePrefix() + GetModuleName(type));
344 m_Output.PutString(".xsd\"");
345 m_Output.PutEol();
346 }
347 }
348 if (!m_Attlist) {
349 OpenTagEnd();
350 }
351 }
352
x_ProcessTypeNamespace(TTypeInfo type)353 bool CObjectOStreamXml::x_ProcessTypeNamespace(TTypeInfo type)
354 {
355 if (GetReferenceSchema()) {
356 if (type->HasNamespaceName()) {
357 string prefix(type->GetNamespacePrefix());
358 if (prefix.empty() && (type->IsNsQualified() == eNSUnqualified || (m_Attlist && type->IsNsQualified() == eNSQualified))) {
359 prefix = sm_DefaultNamespacePrefix;
360 }
361 return x_BeginNamespace(type->GetNamespaceName(),prefix);
362 }
363 return true;
364 }
365 return false;
366 }
367
x_EndTypeNamespace(void)368 void CObjectOStreamXml::x_EndTypeNamespace(void)
369 {
370 if (GetReferenceSchema()) {
371 if (TopFrame().HasTypeInfo()) {
372 TTypeInfo type = TopFrame().GetTypeInfo();
373 if (type->HasNamespaceName()) {
374 x_EndNamespace(type->GetNamespaceName());
375 }
376 }
377 }
378 }
379
x_BeginNamespace(const string & ns_name,const string & ns_prefix)380 bool CObjectOStreamXml::x_BeginNamespace(const string& ns_name,
381 const string& ns_prefix)
382 {
383 if (!GetReferenceSchema() || ns_name.empty()) {
384 return false;
385 }
386 string nsPrefix(ns_prefix);
387 if (m_Attlist || m_NsNameToPrefix.find(ns_name) == m_NsNameToPrefix.end()) {
388 for (char a='a';
389 m_NsPrefixToName.find(nsPrefix) != m_NsPrefixToName.end(); ++a) {
390 nsPrefix += a;
391 }
392 if (m_Attlist && m_NsNameToPrefix.find(ns_name) != m_NsNameToPrefix.end()) {
393 if (!m_NsNameToPrefix.at(ns_name).empty()) {
394 m_CurrNsPrefix = m_NsNameToPrefix.at(ns_name);
395 m_NsPrefixes.push_back(m_CurrNsPrefix);
396 return false;
397 }
398 }
399 m_CurrNsPrefix = nsPrefix;
400 if (!m_Attlist) {
401 m_NsNameToPrefix[ns_name] = nsPrefix;
402 }
403 m_NsPrefixToName[nsPrefix] = ns_name;
404 m_NsPrefixes.push_back(nsPrefix);
405 return true;
406 } else {
407 m_CurrNsPrefix = m_NsNameToPrefix[ns_name];
408 m_NsPrefixes.push_back(m_CurrNsPrefix);
409 }
410 return false;
411 }
412
x_EndNamespace(const string & ns_name)413 void CObjectOStreamXml::x_EndNamespace(const string& ns_name)
414 {
415 if (!GetReferenceSchema() || ns_name.empty()) {
416 return;
417 }
418 string nsPrefix = m_CurrNsPrefix;
419 // we should erase them according to Namespace Scoping rules
420 // http://www.w3.org/TR/REC-xml-names/#scoping
421 m_NsPrefixes.pop_back();
422 if (find(m_NsPrefixes.begin(), m_NsPrefixes.end(), nsPrefix)
423 == m_NsPrefixes.end()) {
424 if (!m_Attlist) {
425 m_NsNameToPrefix.erase(ns_name);
426 }
427 m_NsPrefixToName.erase(nsPrefix);
428 }
429 m_CurrNsPrefix = m_NsPrefixes.empty() ? kEmptyStr : m_NsPrefixes.back();
430 if (!m_Attlist && GetStackDepth() <= 2) {
431 m_NsNameToPrefix.clear();
432 m_NsPrefixToName.clear();
433 }
434 }
435
WriteEnum(const CEnumeratedTypeValues & values,TEnumValueType value,const string & valueName)436 void CObjectOStreamXml::WriteEnum(const CEnumeratedTypeValues& values,
437 TEnumValueType value,
438 const string& valueName)
439 {
440 bool skipname = valueName.empty() ||
441 (m_WriteNamedIntegersByValue && values.IsInteger());
442 bool valueonly = m_StdXml;
443 if (valueonly) {
444 if ( values.IsInteger() ) {
445 m_Output.PutInt4(value);
446 } else {
447 m_Output.PutString(valueName);
448 }
449 return;
450 }
451 if ( !m_SkipNextTag && !values.GetName().empty() ) {
452 OpenTagStart();
453 m_Output.PutString(values.GetName());
454 if ( !skipname ) {
455 m_Output.PutString(" value=\"");
456 m_Output.PutString(valueName);
457 m_Output.PutChar('\"');
458 }
459 if ( values.IsInteger() ) {
460 OpenTagEnd();
461 m_Output.PutInt4(value);
462 CloseTagStart();
463 m_Output.PutString(values.GetName());
464 CloseTagEnd();
465 }
466 else {
467 _ASSERT(!valueName.empty());
468 SelfCloseTagEnd();
469 m_LastTagAction = eTagClose;
470 }
471 }
472 else {
473 // local enum (member, variant or element)
474 if ( skipname ) {
475 _ASSERT(values.IsInteger());
476 m_Output.PutInt4(value);
477 }
478 else {
479 if (m_LastTagAction == eAttlistTag) {
480 m_Output.PutString(valueName);
481 } else {
482 OpenTagEndBack();
483 m_Output.PutString(" value=\"");
484 m_Output.PutString(valueName);
485 m_Output.PutChar('"');
486 if ( values.IsInteger() ) {
487 OpenTagEnd();
488 m_Output.PutInt4(value);
489 }
490 else {
491 SelfCloseTagEnd();
492 }
493 }
494 }
495 }
496 }
497
WriteEnum(const CEnumeratedTypeValues & values,TEnumValueType value)498 void CObjectOStreamXml::WriteEnum(const CEnumeratedTypeValues& values,
499 TEnumValueType value)
500 {
501 WriteEnum(values, value, values.FindNameEx(value, values.IsInteger()));
502 }
503
CopyEnum(const CEnumeratedTypeValues & values,CObjectIStream & in)504 void CObjectOStreamXml::CopyEnum(const CEnumeratedTypeValues& values,
505 CObjectIStream& in)
506 {
507 TEnumValueType value = in.ReadEnum(values);
508 WriteEnum(values, value, values.FindNameEx(value, values.IsInteger()));
509 }
510
WriteEscapedChar(char c)511 void CObjectOStreamXml::WriteEscapedChar(char c)
512 {
513 // http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char
514 switch ( c ) {
515 case '&':
516 m_Output.PutString("&");
517 break;
518 case '<':
519 m_Output.PutString("<");
520 break;
521 case '>':
522 m_Output.PutString(">");
523 break;
524 case '\'':
525 m_Output.PutString("'");
526 break;
527 case '"':
528 m_Output.PutString(""");
529 break;
530 default:
531 if ((unsigned int)c < 0x20) {
532 m_Output.PutString("&#x");
533 Uint1 ch = c;
534 unsigned hi = ch >> 4;
535 unsigned lo = ch & 0xF;
536 if ( hi ) {
537 m_Output.PutChar("0123456789abcdef"[hi]);
538 }
539 m_Output.PutChar("0123456789abcdef"[lo]);
540 m_Output.PutChar(';');
541 } else {
542 m_Output.PutChar(c);
543 }
544 break;
545 }
546 }
547
548 /*
549 In XML 1.1, almost all chars are allowed:
550 http://www.w3.org/TR/xml11/#NT-Char
551 BUT, we declare this as xml 1.0:
552 CObjectOStreamXml::WriteFileHeader
553 Once so, some chars are not allowed
554 http://www.w3.org/TR/xml/#charsets
555
556 */
BAD_CHAR(char x)557 inline bool BAD_CHAR(char x) {
558 return (x < 0x20 && x > 0x0 && x != 0x9 && x != 0xA && x != 0xD);
559 }
x_VerifyChar(char x)560 inline char CObjectOStreamXml::x_VerifyChar(char x) {
561 return BAD_CHAR(x) ?
562 ReplaceVisibleChar(x, x_FixCharsMethod(), this, kEmptyStr, x_FixCharsSubst()) : x;
563 }
564
WriteEncodedChar(const char * & src,EStringType type)565 void CObjectOStreamXml::WriteEncodedChar(const char*& src, EStringType type)
566 {
567 EEncoding enc_in( type == eStringTypeUTF8 ? eEncoding_UTF8 : m_StringEncoding);
568 EEncoding enc_out(m_Encoding == eEncoding_Unknown ? eEncoding_UTF8 : m_Encoding);
569
570 if (enc_in == enc_out || enc_in == eEncoding_Unknown || (*src & 0x80) == 0) {
571 char s = x_VerifyChar(*src);
572 if (s != '\0') {
573 WriteEscapedChar(s);
574 }
575 } else if (enc_out != eEncoding_UTF8) {
576 TUnicodeSymbol chU = (enc_in == eEncoding_UTF8) ?
577 CUtf8::Decode(src) : CUtf8::CharToSymbol( *src, enc_in);
578 char s = x_VerifyChar( CUtf8::SymbolToChar( chU, enc_out));
579 if (s != '\0') {
580 WriteEscapedChar(s);
581 }
582 } else {
583 CStringUTF8 tmp( CUtf8::AsUTF8( CTempString(src,1),enc_in));
584 for ( string::const_iterator t = tmp.begin(); t != tmp.end(); ++t ) {
585 char s = x_VerifyChar(*t);
586 if (s != '\0') {
587 WriteEscapedChar(s);
588 }
589 }
590 }
591 }
592
x_SpecialCaseWrite(void)593 bool CObjectOStreamXml::x_SpecialCaseWrite(void)
594 {
595 if (m_SpecialCaseWrite == eWriteAsDefault) {
596 OpenTagEndBack();
597 SelfCloseTagEnd();
598 return true;
599 }
600 else if (m_SpecialCaseWrite == eWriteAsNil) {
601 OpenTagEndBack();
602 m_Output.PutChar(' ');
603 if (GetReferenceSchema()) {
604 m_Output.PutString("xs:");
605 }
606 m_Output.PutString("nil=\"true\"");
607 SelfCloseTagEnd();
608 return true;
609 }
610 return false;
611 }
612
WriteBool(bool data)613 void CObjectOStreamXml::WriteBool(bool data)
614 {
615 if (m_SpecialCaseWrite && x_SpecialCaseWrite()) {
616 return;
617 }
618 if ( !x_IsStdXml() ) {
619 OpenTagEndBack();
620 if ( data )
621 m_Output.PutString(" value=\"true\"");
622 else
623 m_Output.PutString(" value=\"false\"");
624 SelfCloseTagEnd();
625 } else {
626 if ( data )
627 m_Output.PutString("true");
628 else
629 m_Output.PutString("false");
630 }
631 }
632
WriteChar(char data)633 void CObjectOStreamXml::WriteChar(char data)
634 {
635 WriteEscapedChar(data);
636 }
637
WriteInt4(Int4 data)638 void CObjectOStreamXml::WriteInt4(Int4 data)
639 {
640 if (m_SpecialCaseWrite && x_SpecialCaseWrite()) {
641 return;
642 }
643 m_Output.PutInt4(data);
644 }
645
WriteUint4(Uint4 data)646 void CObjectOStreamXml::WriteUint4(Uint4 data)
647 {
648 if (m_SpecialCaseWrite && x_SpecialCaseWrite()) {
649 return;
650 }
651 m_Output.PutUint4(data);
652 }
653
WriteInt8(Int8 data)654 void CObjectOStreamXml::WriteInt8(Int8 data)
655 {
656 if (m_SpecialCaseWrite && x_SpecialCaseWrite()) {
657 return;
658 }
659 m_Output.PutInt8(data);
660 }
661
WriteUint8(Uint8 data)662 void CObjectOStreamXml::WriteUint8(Uint8 data)
663 {
664 if (m_SpecialCaseWrite && x_SpecialCaseWrite()) {
665 return;
666 }
667 m_Output.PutUint8(data);
668 }
669
WriteDouble2(double data,unsigned digits)670 void CObjectOStreamXml::WriteDouble2(double data, unsigned digits)
671 {
672 if (m_SpecialCaseWrite && x_SpecialCaseWrite()) {
673 return;
674 }
675 if (isnan(data)) {
676 m_Output.PutString("NaN", 3);
677 return;
678 }
679 if (!finite(data)) {
680 if (data < 0) {
681 m_Output.PutChar('-');
682 }
683 m_Output.PutString("INF", 3);
684 return;
685 }
686 char buffer[512];
687 SIZE_TYPE width;
688 if (m_RealFmt == eRealFixedFormat) {
689 int shift = int(ceil(log10(fabs(data))));
690 int precision = int(digits - shift);
691 if ( precision < 0 )
692 precision = 0;
693 if ( precision > 64 ) // limit precision of data
694 precision = 64;
695 width = NStr::DoubleToString(data, (unsigned int)precision,
696 buffer, sizeof(buffer), NStr::fDoublePosix);
697 if (precision != 0) {
698 while (buffer[width-1] == '0') {
699 --width;
700 }
701 if (buffer[width-1] == '.') {
702 --width;
703 }
704 }
705 } else {
706 if (m_FastWriteDouble) {
707 width = NStr::DoubleToStringPosix(data, digits, buffer, sizeof(buffer));
708 } else {
709 width = sprintf(buffer, "%.*g", (int)digits, data);
710 char* dot = strchr(buffer,',');
711 if (dot) {
712 *dot = '.'; // enforce C locale
713 }
714 }
715 }
716 m_Output.PutString(buffer, width);
717 }
718
WriteDouble(double data)719 void CObjectOStreamXml::WriteDouble(double data)
720 {
721 WriteDouble2(data, DBL_DIG);
722 }
723
WriteFloat(float data)724 void CObjectOStreamXml::WriteFloat(float data)
725 {
726 WriteDouble2(data, FLT_DIG);
727 }
728
WriteNull(void)729 void CObjectOStreamXml::WriteNull(void)
730 {
731 OpenTagEndBack();
732 SelfCloseTagEnd();
733 }
734
WriteAnyContentObject(const CAnyContentObject & obj)735 void CObjectOStreamXml::WriteAnyContentObject(const CAnyContentObject& obj)
736 {
737 string ns_name(obj.GetNamespaceName());
738 bool needNs = x_BeginNamespace(ns_name,obj.GetNamespacePrefix());
739 string obj_name = obj.GetName();
740 if (obj_name.empty()) {
741 if (!StackIsEmpty() && TopFrame().HasMemberId()) {
742 obj_name = TopFrame().GetMemberId().GetName();
743 }
744 }
745 if (obj_name.empty()) {
746 ThrowError(fInvalidData, "AnyContent object must have name");
747 }
748 OpenTag(obj_name);
749
750 if (GetReferenceSchema()) {
751 OpenTagEndBack();
752 if (needNs) {
753 m_Output.PutEol();
754 m_Output.PutString(" xmlns");
755 if (!m_CurrNsPrefix.empty()) {
756 m_Output.PutChar(':');
757 m_Output.PutString(m_CurrNsPrefix);
758 }
759 m_Output.PutString("=\"");
760 m_Output.PutString(ns_name);
761 m_Output.PutChar('\"');
762 }
763
764 const vector<CSerialAttribInfoItem>& attlist = obj.GetAttributes();
765 if (!attlist.empty()) {
766 m_Attlist = true;
767 vector<CSerialAttribInfoItem>::const_iterator it;
768 for ( it = attlist.begin(); it != attlist.end(); ++it) {
769 string ns(it->GetNamespaceName());
770 string ns_prefix;
771 if (x_BeginNamespace(ns,kEmptyStr)) {
772 m_Output.PutEol();
773 m_Output.PutString(" xmlns");
774 ns_prefix = m_NsNameToPrefix[ns];
775 if (!ns_prefix.empty()) {
776 m_Output.PutChar(':');
777 m_Output.PutString(ns_prefix);
778 }
779 m_Output.PutString("=\"");
780 m_Output.PutString(ns);
781 m_Output.PutChar('\"');
782 }
783 ns_prefix = m_NsNameToPrefix[ns];
784
785 m_Output.PutEol();
786 m_Output.PutString(" ");
787 if (!ns_prefix.empty()) {
788 m_Output.PutString(ns_prefix);
789 m_Output.PutChar(':');
790 }
791 m_Output.PutString(it->GetName());
792 m_Output.PutString("=\"");
793 WriteString(it->GetValue(),eStringTypeUTF8);
794 m_Output.PutChar('\"');
795 x_EndNamespace(ns);
796 }
797 m_Attlist = false;
798 }
799 OpenTagEnd();
800 }
801
802 // value
803 // no verification on write!
804 const string& value = obj.GetValue();
805 if (value.empty()) {
806 OpenTagEndBack();
807 SelfCloseTagEnd();
808 m_LastTagAction = eTagClose;
809 x_EndNamespace(ns_name);
810 return;
811 }
812 bool was_open = true, was_close=true;
813 bool is_tag = false;
814 char attr_close ='\0';
815 for (const char* is = value.c_str(); *is; ++is) {
816 if (*is == '/' && *(is+1) == '>') {
817 m_Output.DecIndentLevel();
818 was_open = false;
819 }
820 if (*is == '<') {
821 if (*(is+1) == '/') {
822 m_Output.DecIndentLevel();
823 if (!was_open && was_close) {
824 m_Output.PutEol();
825 }
826 is_tag = was_open = false;
827 } else {
828 if (was_close) {
829 m_Output.PutEol();
830 }
831 m_Output.IncIndentLevel();
832 is_tag = was_open = true;
833 }
834 }
835 if (*is != '>' && *is != '<' && *is != attr_close) {
836 WriteEncodedChar(is,eStringTypeUTF8);
837 } else {
838 m_Output.PutChar(*is);
839 }
840 if (*is == '<') {
841 if (*(is+1) == '/') {
842 m_Output.PutChar(*(++is));
843 }
844 if (GetReferenceSchema() && !m_CurrNsPrefix.empty()) {
845 m_Output.PutString(m_CurrNsPrefix);
846 m_Output.PutChar(':');
847 }
848 }
849 if (*is == '>') {
850 was_close = true;
851 is_tag = false;
852 attr_close = '\0';
853 } else {
854 was_close = false;
855 }
856 if (is_tag && *is == '=' && (*(is+1) == '\"' || *(is+1) == '\'')) {
857 attr_close = *(is+1);
858 }
859 }
860
861 // close tag
862 if (!was_open) {
863 m_EndTag = true;
864 }
865 m_SkipIndent = !was_close;
866 CloseTag(obj_name);
867 x_EndNamespace(ns_name);
868 }
869
CopyAnyContentObject(CObjectIStream & in)870 void CObjectOStreamXml::CopyAnyContentObject(CObjectIStream& in)
871 {
872 CAnyContentObject obj;
873 in.ReadAnyContentObject(obj);
874 WriteAnyContentObject(obj);
875 }
876
WriteBitString(const CBitString & obj)877 void CObjectOStreamXml::WriteBitString(const CBitString& obj)
878 {
879 #if BITSTRING_AS_VECTOR
880 static const char ToHex[] = "0123456789ABCDEF";
881 Uint1 data, mask;
882 bool done = false;
883 for ( CBitString::const_iterator i = obj.begin(); !done; ) {
884 for (data=0, mask=0x8; !done && mask!=0; mask >>= 1) {
885 if (*i) {
886 data |= mask;
887 }
888 done = (++i == obj.end());
889 }
890 m_Output.PutChar(ToHex[data]);
891 }
892 #else
893 if (IsCompressed()) {
894 bm::word_t* tmp_block = (bm::word_t*)bm::aligned_new_malloc(bm::set_block_alloc_size);
895 CBitString::statistics st;
896 obj.calc_stat(&st);
897 char* buf = (char*)malloc(st.max_serialize_mem);
898 size_t len = bm::serialize(obj, (unsigned char*)buf, tmp_block);
899 WriteBytes(buf,len);
900 free(buf);
901 bm::aligned_free(tmp_block);
902 return;
903 }
904 CBitString::size_type i=0;
905 CBitString::size_type ilast = obj.size();
906 CBitString::enumerator e = obj.first();
907 for (; i < ilast; ++i) {
908 m_Output.PutChar( (i == *e) ? '1' : '0');
909 if (i == *e) {
910 ++e;
911 }
912 }
913 #endif
914 }
915
CopyBitString(CObjectIStream & in)916 void CObjectOStreamXml::CopyBitString(CObjectIStream& in)
917 {
918 CBitString obj;
919 in.ReadBitString(obj);
920 WriteBitString(obj);
921 }
922
WriteCString(const char * str)923 void CObjectOStreamXml::WriteCString(const char* str)
924 {
925 if ( str == 0 ) {
926 OpenTagEndBack();
927 SelfCloseTagEnd();
928 }
929 else {
930 for ( ; *str; ++str) {
931 WriteEncodedChar(str);
932 }
933 }
934 }
935
WriteString(const string & str,EStringType type)936 void CObjectOStreamXml::WriteString(const string& str, EStringType type)
937 {
938 if (m_SpecialCaseWrite && x_SpecialCaseWrite()) {
939 return;
940 }
941 for ( const char* src = str.c_str(); *src; ++src ) {
942 WriteEncodedChar(src,type);
943 }
944 }
945
WriteStringStore(const string & str)946 void CObjectOStreamXml::WriteStringStore(const string& str)
947 {
948 for ( string::const_iterator i = str.begin(); i != str.end(); ++i ) {
949 WriteEscapedChar(*i);
950 }
951 }
952
CopyString(CObjectIStream & in,EStringType type)953 void CObjectOStreamXml::CopyString(CObjectIStream& in,
954 EStringType type)
955 {
956 string str;
957 in.ReadString(str, type);
958 SetSpecialCaseWrite( (CObjectOStream::ESpecialCaseWrite)in.GetSpecialCaseUsed());
959 in.SetSpecialCaseUsed(CObjectIStream::eReadAsNormal);
960 WriteString(str, type);
961 SetSpecialCaseWrite(CObjectOStream::eWriteAsNormal);
962 }
963
CopyStringStore(CObjectIStream & in)964 void CObjectOStreamXml::CopyStringStore(CObjectIStream& in)
965 {
966 string str;
967 in.ReadStringStore(str);
968 for ( string::const_iterator i = str.begin(); i != str.end(); ++i ) {
969 WriteEscapedChar(*i);
970 }
971 }
972
WriteNullPointer(void)973 void CObjectOStreamXml::WriteNullPointer(void)
974 {
975 bool notag = TopFrame().HasMemberId() && TopFrame().GetMemberId().HasNotag();
976 bool nillable = TopFrame().HasMemberId() && TopFrame().GetMemberId().IsNillable();
977 if (TopFrame().GetNotag() && !notag) {
978 if (m_LastTagAction == eTagClose) {
979 OpenStackTag(0);
980 m_SpecialCaseWrite = eWriteAsNil;
981 x_SpecialCaseWrite();
982 m_SpecialCaseWrite = eWriteAsNormal;
983 CloseStackTag(0);
984 }
985 return;
986 }
987 m_SpecialCaseWrite = nillable ? eWriteAsNil : eWriteAsDefault;
988 x_SpecialCaseWrite();
989 m_SpecialCaseWrite = eWriteAsNormal;
990 }
991
WriteObjectReference(TObjectIndex index)992 void CObjectOStreamXml::WriteObjectReference(TObjectIndex index)
993 {
994 m_Output.PutString("<object index=");
995 if ( sizeof(TObjectIndex) == sizeof(Int4) )
996 m_Output.PutInt4(Int4(index));
997 else if ( sizeof(TObjectIndex) == sizeof(Int8) )
998 m_Output.PutInt8(index);
999 else
1000 ThrowError(fIllegalCall, "invalid size of TObjectIndex"
1001 "must be either sizeof(Int4) or sizeof(Int8)");
1002 m_Output.PutString("/>");
1003 m_EndTag = true;
1004 }
1005
WriteTag(const string & name)1006 void CObjectOStreamXml::WriteTag(const string& name)
1007 {
1008 if (!m_CurrNsPrefix.empty() && IsNsQualified()) {
1009 m_Output.PutString(m_CurrNsPrefix);
1010 m_Output.PutChar(':');
1011 }
1012 m_Output.PutString(name);
1013 }
1014
OpenTagStart(void)1015 void CObjectOStreamXml::OpenTagStart(void)
1016 {
1017 if (m_Attlist) {
1018 if ( m_LastTagAction == eTagOpen ) {
1019 m_Output.PutChar(' ');
1020 m_LastTagAction = eAttlistTag;
1021 }
1022 } else {
1023 if (m_SkipIndent) {
1024 m_SkipIndent = false;
1025 } else {
1026 m_Output.PutEol(false);
1027 m_Output.PutIndent();
1028 }
1029 m_Output.PutChar('<');
1030 m_LastTagAction = eTagOpen;
1031 }
1032 m_EndTag = false;
1033 }
1034
OpenTagEnd(void)1035 void CObjectOStreamXml::OpenTagEnd(void)
1036 {
1037 if (m_Attlist) {
1038 if ( m_LastTagAction == eAttlistTag ) {
1039 m_Output.PutString("=\"");
1040 }
1041 } else {
1042 if ( m_LastTagAction == eTagOpen ) {
1043 m_Output.PutChar('>');
1044 m_Output.IncIndentLevel();
1045 m_LastTagAction = eTagClose;
1046 }
1047 }
1048 }
1049
OpenTagEndBack(void)1050 void CObjectOStreamXml::OpenTagEndBack(void)
1051 {
1052 _ASSERT(m_LastTagAction == eTagClose);
1053 m_LastTagAction = eTagOpen;
1054 m_Output.BackChar('>');
1055 m_Output.DecIndentLevel();
1056 }
1057
SelfCloseTagEnd(void)1058 void CObjectOStreamXml::SelfCloseTagEnd(void)
1059 {
1060 _ASSERT(m_LastTagAction == eTagOpen);
1061 m_Output.PutString("/>");
1062 m_LastTagAction = eTagSelfClosed;
1063 m_EndTag = true;
1064 m_SkipIndent = false;
1065 }
1066
EolIfEmptyTag(void)1067 void CObjectOStreamXml::EolIfEmptyTag(void)
1068 {
1069 _ASSERT(m_LastTagAction != eTagSelfClosed);
1070 if ( m_LastTagAction == eTagOpen ) {
1071 m_LastTagAction = eTagClose;
1072 }
1073 }
1074
CloseTagStart(void)1075 void CObjectOStreamXml::CloseTagStart(void)
1076 {
1077 _ASSERT(m_LastTagAction != eTagSelfClosed);
1078 m_Output.DecIndentLevel();
1079 if (m_EndTag && !m_SkipIndent) {
1080 m_Output.PutEol(false);
1081 m_Output.PutIndent();
1082 }
1083 m_Output.PutString("</");
1084 m_LastTagAction = eTagOpen;
1085 }
1086
CloseTagEnd(void)1087 void CObjectOStreamXml::CloseTagEnd(void)
1088 {
1089 m_Output.PutChar('>');
1090 m_LastTagAction = eTagClose;
1091 m_EndTag = true;
1092 m_SkipIndent = false;
1093 }
1094
PrintTagName(size_t level)1095 void CObjectOStreamXml::PrintTagName(size_t level)
1096 {
1097 const TFrame& frame = FetchFrameFromTop(level);
1098 switch ( frame.GetFrameType() ) {
1099 case TFrame::eFrameNamed:
1100 case TFrame::eFrameArray:
1101 case TFrame::eFrameClass:
1102 case TFrame::eFrameChoice:
1103 {
1104 _ASSERT(frame.GetTypeInfo());
1105 const string& name = frame.GetTypeInfo()->GetName();
1106 if ( !name.empty() ) {
1107 WriteTag(name);
1108 #if defined(NCBI_SERIAL_IO_TRACE)
1109 TraceTag(name);
1110 #endif
1111 } else {
1112 PrintTagName(level + 1);
1113 }
1114 return;
1115 }
1116 case TFrame::eFrameClassMember:
1117 case TFrame::eFrameChoiceVariant:
1118 {
1119 bool attlist = m_Attlist;
1120 if (!x_IsStdXml()) {
1121 PrintTagName(level + 1);
1122 m_Output.PutChar('_');
1123 m_Attlist = true;
1124 }
1125 WriteTag(frame.GetMemberId().GetName());
1126 m_Attlist = attlist;
1127 #if defined(NCBI_SERIAL_IO_TRACE)
1128 TraceTag(frame.GetMemberId().GetName());
1129 #endif
1130 return;
1131 }
1132 case TFrame::eFrameArrayElement:
1133 {
1134 PrintTagName(level + 1);
1135 if (!x_IsStdXml()) {
1136 m_Output.PutString("_E");
1137 }
1138 return;
1139 }
1140 default:
1141 break;
1142 }
1143 ThrowError(fIllegalCall, "illegal frame type");
1144 }
1145
WriteOtherBegin(TTypeInfo typeInfo)1146 void CObjectOStreamXml::WriteOtherBegin(TTypeInfo typeInfo)
1147 {
1148 OpenTag(typeInfo);
1149 }
1150
WriteOtherEnd(TTypeInfo typeInfo)1151 void CObjectOStreamXml::WriteOtherEnd(TTypeInfo typeInfo)
1152 {
1153 CloseTag(typeInfo);
1154 }
1155
WriteOther(TConstObjectPtr object,TTypeInfo typeInfo)1156 void CObjectOStreamXml::WriteOther(TConstObjectPtr object,
1157 TTypeInfo typeInfo)
1158 {
1159 OpenTag(typeInfo);
1160 WriteObject(object, typeInfo);
1161 CloseTag(typeInfo);
1162 }
1163
BeginContainer(const CContainerTypeInfo * containerType)1164 void CObjectOStreamXml::BeginContainer(const CContainerTypeInfo* containerType)
1165 {
1166 bool needNs = x_ProcessTypeNamespace(containerType);
1167 if (!m_StdXml) {
1168 if (TopFrame().GetFrameType() == CObjectStackFrame::eFrameArray &&
1169 FetchFrameFromTop(1).GetFrameType() == CObjectStackFrame::eFrameNamed) {
1170 const CClassTypeInfo* clType =
1171 dynamic_cast<const CClassTypeInfo*>(FetchFrameFromTop(1).GetTypeInfo());
1172 if (clType && clType->Implicit()) {
1173 TopFrame().SetNotag();
1174 return;
1175 }
1176 }
1177 OpenTagIfNamed(containerType);
1178 }
1179 if (needNs) {
1180 x_WriteClassNamespace(containerType);
1181 }
1182 }
1183
EndContainer(void)1184 void CObjectOStreamXml::EndContainer(void)
1185 {
1186 if (!m_StdXml && !TopFrame().GetNotag()) {
1187 CloseTagIfNamed(TopFrame().GetTypeInfo());
1188 }
1189 x_EndTypeNamespace();
1190 }
1191
WillHaveName(TTypeInfo elementType)1192 bool CObjectOStreamXml::WillHaveName(TTypeInfo elementType)
1193 {
1194 while ( elementType->GetName().empty() ) {
1195 if ( elementType->GetTypeFamily() != eTypeFamilyPointer )
1196 return false;
1197 elementType = CTypeConverter<CPointerTypeInfo>::SafeCast(elementType)->GetPointedType();
1198 }
1199 // found named type
1200 return true;
1201 }
1202
BeginContainerElement(TTypeInfo elementType)1203 void CObjectOStreamXml::BeginContainerElement(TTypeInfo elementType)
1204 {
1205 if ( !WillHaveName(elementType) ) {
1206 BeginArrayElement(elementType);
1207 }
1208 }
1209
EndContainerElement(void)1210 void CObjectOStreamXml::EndContainerElement(void)
1211 {
1212 if ( !WillHaveName(TopFrame().GetTypeInfo()) ) {
1213 EndArrayElement();
1214 }
1215 }
1216
1217 #ifdef VIRTUAL_MID_LEVEL_IO
WriteContainer(const CContainerTypeInfo * cType,TConstObjectPtr containerPtr)1218 void CObjectOStreamXml::WriteContainer(const CContainerTypeInfo* cType,
1219 TConstObjectPtr containerPtr)
1220 {
1221 if ( !cType->GetName().empty() ) {
1222 BEGIN_OBJECT_FRAME2(eFrameArray, cType);
1223 OpenTag(cType);
1224
1225 WriteContainerContents(cType, containerPtr);
1226
1227 EolIfEmptyTag();
1228 CloseTag(cType);
1229 END_OBJECT_FRAME();
1230 }
1231 else {
1232 WriteContainerContents(cType, containerPtr);
1233 }
1234 }
1235 #endif
BeginArrayElement(TTypeInfo elementType)1236 void CObjectOStreamXml::BeginArrayElement(TTypeInfo elementType)
1237 {
1238 if (x_IsStdXml()) {
1239 CObjectTypeInfo type(GetRealTypeInfo(elementType));
1240 if (type.GetTypeFamily() != eTypeFamilyPrimitive ||
1241 type.GetPrimitiveValueType() == ePrimitiveValueAny) {
1242 TopFrame().SetNotag();
1243 return;
1244 }
1245 if (m_SkipNextTag && type.GetTypeFamily() == eTypeFamilyPrimitive) {
1246 m_Output.PutChar(' ');
1247 TopFrame().SetNotag();
1248 return;
1249 }
1250 }
1251 OpenStackTag(0);
1252 }
1253
EndArrayElement(void)1254 void CObjectOStreamXml::EndArrayElement(void)
1255 {
1256 if (TopFrame().GetNotag()) {
1257 TopFrame().SetNotag(false);
1258 } else {
1259 CloseStackTag(0);
1260 }
1261 }
1262
WriteContainerContents(const CContainerTypeInfo * cType,TConstObjectPtr containerPtr)1263 void CObjectOStreamXml::WriteContainerContents(const CContainerTypeInfo* cType,
1264 TConstObjectPtr containerPtr)
1265 {
1266 TTypeInfo elementType = cType->GetElementType();
1267 CContainerTypeInfo::CConstIterator i;
1268 if ( WillHaveName(elementType) ) {
1269 if ( cType->InitIterator(i, containerPtr) ) {
1270
1271 const CPointerTypeInfo* pointerType =
1272 dynamic_cast<const CPointerTypeInfo*>(elementType);
1273 do {
1274 TConstObjectPtr elementPtr = cType->GetElementPtr(i);
1275 if ( pointerType &&
1276 !pointerType->GetObjectPointer(elementPtr) ) {
1277 if ( GetVerifyData() == eSerialVerifyData_Yes ) {
1278 ThrowError(fUnassigned,
1279 "NULL element while writing container "+
1280 cType->GetName());
1281 }
1282 continue;
1283 }
1284
1285 WriteObject(elementPtr, elementType);
1286
1287 } while ( cType->NextElement(i) );
1288 }
1289 }
1290 else {
1291 BEGIN_OBJECT_FRAME2(eFrameArrayElement, elementType);
1292
1293 if ( cType->InitIterator(i, containerPtr) ) {
1294
1295 const CPointerTypeInfo* pointerType =
1296 dynamic_cast<const CPointerTypeInfo*>(elementType);
1297 do {
1298 TConstObjectPtr elementPtr = cType->GetElementPtr(i);
1299 if ( pointerType &&
1300 !pointerType->GetObjectPointer(elementPtr) ) {
1301 if ( GetVerifyData() == eSerialVerifyData_Yes ) {
1302 ThrowError(fUnassigned,
1303 "NULL element while writing container "+
1304 cType->GetName());
1305 }
1306 continue;
1307 }
1308
1309 BeginArrayElement(elementType);
1310 WriteObject(elementPtr, elementType);
1311 EndArrayElement();
1312 } while ( cType->NextElement(i) );
1313 } else {
1314 const TFrame& frame = FetchFrameFromTop(1);
1315 if (frame.GetFrameType() == CObjectStackFrame::eFrameNamed) {
1316 const CClassTypeInfo* clType =
1317 dynamic_cast<const CClassTypeInfo*>(frame.GetTypeInfo());
1318 if (clType && clType->Implicit() && clType->IsImplicitNonEmpty()) {
1319 ThrowError(fInvalidData, "container is empty");
1320 }
1321 }
1322 }
1323
1324 END_OBJECT_FRAME();
1325 }
1326 }
1327
BeginNamedType(TTypeInfo namedTypeInfo)1328 void CObjectOStreamXml::BeginNamedType(TTypeInfo namedTypeInfo)
1329 {
1330 CheckStdXml(namedTypeInfo);
1331 if (m_SkipNextTag || namedTypeInfo->GetName().empty()) {
1332 TopFrame().SetNotag();
1333 m_SkipNextTag = false;
1334 } else {
1335 TTypeInfo realtype = GetRealTypeInfo(namedTypeInfo);
1336 if (realtype->GetTypeFamily() == eTypeFamilyPrimitive &&
1337 GetStackDepth() > 2 && m_StdXml) {
1338 TopFrame().SetNotag();
1339 m_SkipNextTag = false;
1340 return;
1341 }
1342 bool needNs = x_ProcessTypeNamespace(namedTypeInfo);
1343 OpenTag(namedTypeInfo);
1344 if (needNs) {
1345 x_WriteClassNamespace(namedTypeInfo);
1346 }
1347 }
1348 const CAliasTypeInfo* aliasType =
1349 dynamic_cast<const CAliasTypeInfo*>(namedTypeInfo);
1350 if (aliasType) {
1351 m_SkipNextTag = aliasType->IsFullAlias();
1352 }
1353 else if (m_StdXml) {
1354 const CClassTypeInfo* classType = dynamic_cast<const CClassTypeInfo*>(namedTypeInfo);
1355 m_SkipNextTag = (classType && classType->Implicit());
1356 }
1357 }
1358
EndNamedType(void)1359 void CObjectOStreamXml::EndNamedType(void)
1360 {
1361 m_SkipNextTag = false;
1362 if (TopFrame().GetNotag()) {
1363 TopFrame().SetNotag(false);
1364 return;
1365 }
1366 CloseTag(TopFrame().GetTypeInfo());
1367 x_EndTypeNamespace();
1368 }
1369
1370 #ifdef VIRTUAL_MID_LEVEL_IO
1371
WriteNamedType(TTypeInfo namedTypeInfo,TTypeInfo typeInfo,TConstObjectPtr object)1372 void CObjectOStreamXml::WriteNamedType(TTypeInfo namedTypeInfo,
1373 TTypeInfo typeInfo,
1374 TConstObjectPtr object)
1375 {
1376 BEGIN_OBJECT_FRAME2(eFrameNamed, namedTypeInfo);
1377
1378 BeginNamedType(namedTypeInfo);
1379 WriteObject(object, typeInfo);
1380 EndNamedType();
1381
1382 END_OBJECT_FRAME();
1383 }
1384
CopyNamedType(TTypeInfo namedTypeInfo,TTypeInfo objectType,CObjectStreamCopier & copier)1385 void CObjectOStreamXml::CopyNamedType(TTypeInfo namedTypeInfo,
1386 TTypeInfo objectType,
1387 CObjectStreamCopier& copier)
1388 {
1389 BEGIN_OBJECT_2FRAMES_OF2(copier, eFrameNamed, namedTypeInfo);
1390 copier.In().BeginNamedType(namedTypeInfo);
1391 BeginNamedType(namedTypeInfo);
1392 CopyObject(objectType, copier);
1393 EndNamedType();
1394 copier.In().EndNamedType();
1395 END_OBJECT_2FRAMES_OF(copier);
1396 }
1397 #endif
1398
CheckStdXml(TTypeInfo typeinfo)1399 void CObjectOStreamXml::CheckStdXml(TTypeInfo typeinfo)
1400 {
1401 if (typeinfo->GetCodeVersion() > 21600) {
1402 m_StdXml = typeinfo->GetDataSpec() != EDataSpec::eASN;
1403 } else {
1404 const CClassTypeInfo* classType =
1405 dynamic_cast<const CClassTypeInfo*>(typeinfo);
1406 if (classType) {
1407 TMemberIndex first = classType->GetItems().FirstIndex();
1408 m_StdXml = classType->GetItems().GetItemInfo(first)->GetId().HaveNoPrefix();
1409 }
1410 }
1411 }
1412
BeginClass(const CClassTypeInfo * classInfo)1413 void CObjectOStreamXml::BeginClass(const CClassTypeInfo* classInfo)
1414 {
1415 CheckStdXml(classInfo);
1416 if (m_SkipNextTag) {
1417 TopFrame().SetNotag();
1418 m_SkipNextTag = false;
1419 return;
1420 }
1421 bool needNs = x_ProcessTypeNamespace(classInfo);
1422 OpenTagIfNamed(classInfo);
1423 if (needNs) {
1424 x_WriteClassNamespace(classInfo);
1425 }
1426 }
1427
EndClass(void)1428 void CObjectOStreamXml::EndClass(void)
1429 {
1430 if (TopFrame().GetNotag()) {
1431 TopFrame().SetNotag(false);
1432 return;
1433 }
1434 if (!m_Attlist && m_LastTagAction != eTagSelfClosed) {
1435 EolIfEmptyTag();
1436 }
1437 if (m_LastTagAction == eTagSelfClosed) {
1438 m_LastTagAction = eTagClose;
1439 } else {
1440 CloseTagIfNamed(TopFrame().GetTypeInfo());
1441 }
1442 x_EndTypeNamespace();
1443 }
1444
BeginClassMember(const CMemberId & id)1445 void CObjectOStreamXml::BeginClassMember(const CMemberId& id)
1446 {
1447 const CClassTypeInfoBase* classType = dynamic_cast<const CClassTypeInfoBase*>
1448 (FetchFrameFromTop(1).GetTypeInfo());
1449 _ASSERT(classType);
1450 BeginClassMember(classType->GetItemInfo(id.GetName())->GetTypeInfo(),id);
1451 }
1452
BeginClassMember(TTypeInfo memberType,const CMemberId & id)1453 void CObjectOStreamXml::BeginClassMember(TTypeInfo memberType,
1454 const CMemberId& id)
1455 {
1456 if (x_IsStdXml()) {
1457 if(id.IsAttlist()) {
1458 if(m_LastTagAction == eTagClose) {
1459 OpenTagEndBack();
1460 }
1461 m_Attlist = true;
1462 TopFrame().SetNotag();
1463 } else {
1464 ETypeFamily type = GetRealTypeFamily(memberType);
1465 bool needTag = true;
1466 if (GetEnforcedStdXml()) {
1467 if (type == eTypeFamilyContainer) {
1468 TTypeInfo mem_type = GetRealTypeInfo(memberType);
1469 TTypeInfo elem_type = GetContainerElementTypeInfo(mem_type);
1470 needTag = (elem_type->GetTypeFamily() != eTypeFamilyPrimitive ||
1471 elem_type->GetName() != mem_type->GetName());
1472 }
1473 } else {
1474 needTag = !id.HasNotag() && !id.HasAnyContent() && type != eTypeFamilyContainer;
1475 m_SkipNextTag = type != eTypeFamilyPrimitive && type != eTypeFamilyContainer;
1476 }
1477 if (needTag) {
1478 OpenStackTag(0);
1479 } else {
1480 TopFrame().SetNotag();
1481 }
1482 if (type == eTypeFamilyPrimitive) {
1483 m_SkipIndent = id.HasNotag();
1484 }
1485 }
1486 } else {
1487 OpenStackTag(0);
1488 }
1489 }
1490
EndClassMember(void)1491 void CObjectOStreamXml::EndClassMember(void)
1492 {
1493 m_SkipNextTag = false;
1494 if (TopFrame().GetNotag()) {
1495 TopFrame().SetNotag(false);
1496 m_Attlist = false;
1497 if(m_LastTagAction == eTagOpen) {
1498 OpenTagEnd();
1499 }
1500 } else {
1501 CloseStackTag(0);
1502 }
1503 }
1504
1505
1506 #ifdef VIRTUAL_MID_LEVEL_IO
1507
WriteClass(const CClassTypeInfo * classType,TConstObjectPtr classPtr)1508 void CObjectOStreamXml::WriteClass(const CClassTypeInfo* classType,
1509 TConstObjectPtr classPtr)
1510 {
1511 if ( (m_Attlist && classType->IsNsQualified() == eNSQualified) || !classType->GetName().empty() ) {
1512 BEGIN_OBJECT_FRAME2(eFrameClass, classType);
1513
1514 BeginClass(classType);
1515 for ( CClassTypeInfo::CIterator i(classType); i.Valid(); ++i ) {
1516 classType->GetMemberInfo(i)->WriteMember(*this, classPtr);
1517 }
1518 EndClass();
1519
1520 END_OBJECT_FRAME();
1521 }
1522 else {
1523 for ( CClassTypeInfo::CIterator i(classType); i.Valid(); ++i ) {
1524 classType->GetMemberInfo(i)->WriteMember(*this, classPtr);
1525 }
1526 }
1527 }
1528
WriteClassMember(const CMemberId & memberId,TTypeInfo memberType,TConstObjectPtr memberPtr)1529 void CObjectOStreamXml::WriteClassMember(const CMemberId& memberId,
1530 TTypeInfo memberType,
1531 TConstObjectPtr memberPtr)
1532 {
1533 BEGIN_OBJECT_FRAME2(eFrameClassMember,memberId);
1534
1535 BeginClassMember(memberType,memberId);
1536 WriteObject(memberPtr, memberType);
1537 EndClassMember();
1538
1539 END_OBJECT_FRAME();
1540 }
1541
WriteClassMember(const CMemberId & memberId,const CDelayBuffer & buffer)1542 bool CObjectOStreamXml::WriteClassMember(const CMemberId& memberId,
1543 const CDelayBuffer& buffer)
1544 {
1545 if ( !buffer.HaveFormat(eSerial_Xml) )
1546 return false;
1547
1548 BEGIN_OBJECT_FRAME2(eFrameClassMember, memberId);
1549 OpenStackTag(0);
1550
1551 Write(buffer.GetSource());
1552
1553 CloseStackTag(0);
1554 END_OBJECT_FRAME();
1555
1556 return true;
1557 }
1558
WriteClassMemberSpecialCase(const CMemberId & memberId,TTypeInfo,TConstObjectPtr,ESpecialCaseWrite how)1559 void CObjectOStreamXml::WriteClassMemberSpecialCase(const CMemberId& memberId,
1560 TTypeInfo /*memberType*/, TConstObjectPtr /*memberPtr*/, ESpecialCaseWrite how)
1561 {
1562 if (m_Attlist) {
1563 return;
1564 }
1565 m_SpecialCaseWrite = how;
1566 if (memberId.HasNotag() || m_SkipNextTag) {
1567 x_SpecialCaseWrite();
1568 } else {
1569 BEGIN_OBJECT_FRAME2(eFrameClassMember, memberId);
1570 OpenStackTag(0);
1571 x_SpecialCaseWrite();
1572 m_SpecialCaseWrite = eWriteAsNormal;
1573 CloseStackTag(0);
1574 END_OBJECT_FRAME();
1575 }
1576 m_SpecialCaseWrite = eWriteAsNormal;
1577 }
1578 #endif
1579
BeginChoice(const CChoiceTypeInfo * choiceType)1580 void CObjectOStreamXml::BeginChoice(const CChoiceTypeInfo* choiceType)
1581 {
1582 CheckStdXml(choiceType);
1583 if (m_SkipNextTag) {
1584 TopFrame().SetNotag();
1585 m_SkipNextTag = false;
1586 return;
1587 }
1588 bool needNs = x_ProcessTypeNamespace(choiceType);
1589 OpenTagIfNamed(choiceType);
1590 if (needNs) {
1591 x_WriteClassNamespace(choiceType);
1592 }
1593 }
1594
EndChoice(void)1595 void CObjectOStreamXml::EndChoice(void)
1596 {
1597 if (TopFrame().GetNotag()) {
1598 TopFrame().SetNotag(false);
1599 return;
1600 }
1601 CloseTagIfNamed(TopFrame().GetTypeInfo());
1602 x_EndTypeNamespace();
1603 }
1604
BeginChoiceVariant(const CChoiceTypeInfo * choiceType,const CMemberId & id)1605 void CObjectOStreamXml::BeginChoiceVariant(const CChoiceTypeInfo* choiceType,
1606 const CMemberId& id)
1607 {
1608 if (x_IsStdXml()) {
1609 const CVariantInfo* var_info = choiceType->GetVariantInfo(id.GetName());
1610 ETypeFamily type = GetRealTypeFamily(var_info->GetTypeInfo());
1611 bool needTag = true;
1612 if (GetEnforcedStdXml()) {
1613 if (type == eTypeFamilyContainer) {
1614 TTypeInfo var_type = GetRealTypeInfo(var_info->GetTypeInfo());
1615 TTypeInfo elem_type = GetContainerElementTypeInfo(var_type);
1616 needTag = (elem_type->GetTypeFamily() != eTypeFamilyPrimitive ||
1617 elem_type->GetName() != var_type->GetName());
1618 }
1619 } else {
1620 needTag = !id.HasNotag() && !id.HasAnyContent() && type != eTypeFamilyContainer;
1621 m_SkipNextTag = type != eTypeFamilyPrimitive && type != eTypeFamilyContainer;
1622 }
1623 if (needTag) {
1624 OpenStackTag(0);
1625 } else {
1626 TopFrame().SetNotag();
1627 }
1628 if (type == eTypeFamilyPrimitive) {
1629 m_SkipIndent = id.HasNotag();
1630 }
1631 } else {
1632 OpenStackTag(0);
1633 }
1634 }
1635
EndChoiceVariant(void)1636 void CObjectOStreamXml::EndChoiceVariant(void)
1637 {
1638 m_SkipNextTag = false;
1639 if (TopFrame().GetNotag()) {
1640 TopFrame().SetNotag(false);
1641 } else {
1642 CloseStackTag(0);
1643 }
1644 }
1645
WriteChoiceContents(const CChoiceTypeInfo * choiceType,TConstObjectPtr choicePtr)1646 void CObjectOStreamXml::WriteChoiceContents(const CChoiceTypeInfo* choiceType,
1647 TConstObjectPtr choicePtr)
1648 {
1649 TMemberIndex index = choiceType->GetIndex(choicePtr);
1650 const CVariantInfo* variantInfo = choiceType->GetVariantInfo(index);
1651 BEGIN_OBJECT_FRAME2(eFrameChoiceVariant, variantInfo->GetId());
1652 OpenStackTag(0);
1653
1654 variantInfo->WriteVariant(*this, choicePtr);
1655
1656 CloseStackTag(0);
1657 END_OBJECT_FRAME();
1658 }
1659
1660 static const char* const HEX = "0123456789ABCDEF";
1661
WriteBytes(const ByteBlock &,const char * bytes,size_t length)1662 void CObjectOStreamXml::WriteBytes(const ByteBlock& ,
1663 const char* bytes, size_t length)
1664 {
1665 if (IsCompressed()) {
1666 WriteBase64Bytes(bytes,length);
1667 return;
1668 }
1669 WriteBytes(bytes,length);
1670 }
1671
WriteBase64Bytes(const char * bytes,size_t length)1672 void CObjectOStreamXml::WriteBase64Bytes(const char* bytes, size_t length)
1673 {
1674 const size_t chunk_in = 57;
1675 const size_t chunk_out = 80;
1676 if (length > chunk_in) {
1677 m_Output.PutEol(false);
1678 }
1679 char dst_buf[chunk_out];
1680 size_t bytes_left = length;
1681 size_t src_read=0, dst_written=0, line_len=0;
1682 while (bytes_left > 0 && bytes_left <= length) {
1683 BASE64_Encode(bytes, min(bytes_left,chunk_in), &src_read,
1684 dst_buf, chunk_out, &dst_written, &line_len);
1685 m_Output.PutString(dst_buf,dst_written);
1686 bytes_left -= src_read;
1687 bytes += src_read;
1688 if (bytes_left > 0) {
1689 m_Output.PutEol(false);
1690 }
1691 }
1692 if (length > chunk_in) {
1693 m_Output.PutEol(false);
1694 }
1695 }
1696
WriteBytes(const char * bytes,size_t length)1697 void CObjectOStreamXml::WriteBytes(const char* bytes, size_t length)
1698 {
1699 while ( length-- > 0 ) {
1700 char c = *bytes++;
1701 m_Output.PutChar(HEX[(c >> 4) & 0xf]);
1702 m_Output.PutChar(HEX[c & 0xf]);
1703 }
1704 }
1705
WriteChars(const CharBlock &,const char * chars,size_t length)1706 void CObjectOStreamXml::WriteChars(const CharBlock& ,
1707 const char* chars, size_t length)
1708 {
1709 while ( length-- > 0 ) {
1710 char c = *chars++;
1711 WriteEscapedChar(c);
1712 }
1713 }
1714
1715
WriteSeparator(void)1716 void CObjectOStreamXml::WriteSeparator(void)
1717 {
1718 m_Output.PutString(GetSeparator());
1719 FlushBuffer();
1720 }
1721
1722 #if defined(NCBI_SERIAL_IO_TRACE)
1723
TraceTag(const string & name)1724 void CObjectOStreamXml::TraceTag(const string& name)
1725 {
1726 cout << ", Tag=" << name;
1727 }
1728
1729 #endif
1730
1731 END_NCBI_SCOPE
1732