objostrxml.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:46k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: objostrxml.cpp,v $
  4.  * PRODUCTION Revision 1000.5  2004/06/01 19:41:18  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.73
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: objostrxml.cpp,v 1000.5 2004/06/01 19:41:18 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Author: Eugene Vasilchenko
  35. *
  36. * File Description:
  37. *   XML object output stream
  38. *
  39. * ---------------------------------------------------------------------------
  40. * $Log: objostrxml.cpp,v $
  41. * Revision 1000.5  2004/06/01 19:41:18  gouriano
  42. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.73
  43. *
  44. * Revision 1.73  2004/05/19 17:26:19  gouriano
  45. * Corrected serialization of containers when the code was generated by DTD
  46. *
  47. * Revision 1.72  2004/05/17 21:03:03  gorelenk
  48. * Added include of PCH ncbi_pch.hpp
  49. *
  50. * Revision 1.71  2004/05/04 17:04:43  gouriano
  51. * Check double for being finite
  52. *
  53. * Revision 1.70  2004/01/29 20:43:04  gouriano
  54. * Corrected writing of AnyContent objects in case it has attributes
  55. * with previously undefined namespaces, or tags with empty content
  56. *
  57. * Revision 1.69  2004/01/22 20:48:38  gouriano
  58. * corrected writing of namespace prefixes
  59. *
  60. * Revision 1.68  2004/01/08 17:42:00  gouriano
  61. * Added encoding Windows-1252.
  62. * Made it possible to omit document type declaration
  63. *
  64. * Revision 1.67  2003/11/26 19:59:41  vasilche
  65. * GetPosition() and GetDataFormat() methods now are implemented
  66. * in parent classes CObjectIStream and CObjectOStream to avoid
  67. * pure virtual method call in destructors.
  68. *
  69. * Revision 1.66  2003/11/21 16:16:48  vasilche
  70. * More efficient writing of hex numbers.
  71. *
  72. * Revision 1.65  2003/10/31 17:39:40  grichenk
  73. * Allow empty containers
  74. *
  75. * Revision 1.64  2003/09/25 19:44:08  gouriano
  76. * Corrected serialization of AnyContent object's attributes
  77. *
  78. * Revision 1.63  2003/09/22 20:55:23  gouriano
  79. * Corrected writing of AnyContent objects in case of no schema reference
  80. *
  81. * Revision 1.62  2003/09/16 14:48:36  gouriano
  82. * Enhanced AnyContent objects to support XML namespaces and attribute info items.
  83. *
  84. * Revision 1.61  2003/08/25 15:59:09  gouriano
  85. * added possibility to use namespaces in XML i/o streams
  86. *
  87. * Revision 1.60  2003/08/13 18:23:54  gouriano
  88. * corrected XML schema namespace name
  89. *
  90. * Revision 1.59  2003/08/13 15:47:45  gouriano
  91. * implemented serialization of AnyContent objects
  92. *
  93. * Revision 1.58  2003/07/02 13:01:29  gouriano
  94. * added ability to read/write XML files with reference to schema
  95. *
  96. * Revision 1.57  2003/06/30 15:39:48  gouriano
  97. * added encoding (utf-8 or iso-8859-1)
  98. *
  99. * Revision 1.56  2003/06/24 20:57:36  gouriano
  100. * corrected code generation and serialization of non-empty unnamed containers (XML)
  101. *
  102. * Revision 1.55  2003/05/22 20:10:02  gouriano
  103. * added UTF8 strings
  104. *
  105. * Revision 1.54  2003/05/16 18:02:18  gouriano
  106. * revised exception error messages
  107. *
  108. * Revision 1.53  2003/04/29 18:30:37  gouriano
  109. * object data member initialization verification
  110. *
  111. * Revision 1.52  2003/03/26 16:14:23  vasilche
  112. * Removed TAB symbols. Some formatting.
  113. *
  114. * Revision 1.51  2003/02/07 16:09:22  gouriano
  115. * correction of GetContainerElementTypeFamily for the case of copying objects
  116. *
  117. * Revision 1.50  2003/02/05 17:08:00  gouriano
  118. * added possibility to read/write objects generated from an ASN.1 spec as "standard" XML - without scope prefixes
  119. *
  120. * Revision 1.49  2003/02/04 17:06:25  gouriano
  121. * added check for NaN in WriteDouble
  122. *
  123. * Revision 1.48  2003/01/22 21:03:16  gouriano
  124. * remove trailing zeros when writing a float value
  125. *
  126. * Revision 1.47  2003/01/22 20:53:09  gouriano
  127. * more control on how a float value is to be written
  128. *
  129. * Revision 1.46  2003/01/21 19:32:26  gouriano
  130. * corrected reading containers of primitive types
  131. *
  132. * Revision 1.45  2003/01/10 17:48:41  gouriano
  133. * added check for empty container
  134. *
  135. * Revision 1.44  2003/01/10 16:54:10  gouriano
  136. * fixed a bug with optional class members
  137. *
  138. * Revision 1.43  2002/12/26 21:35:45  gouriano
  139. * corrected handling choice's XML attributes
  140. *
  141. * Revision 1.42  2002/12/26 19:32:34  gouriano
  142. * changed XML I/O streams to properly handle object copying
  143. *
  144. * Revision 1.41  2002/12/17 19:04:32  gouriano
  145. * corrected reading/writing of character references
  146. *
  147. * Revision 1.40  2002/12/12 21:08:07  gouriano
  148. * implemented handling of complex XML containers
  149. *
  150. * Revision 1.39  2002/11/26 22:10:31  gouriano
  151. * added unnamed lists of sequences (choices) as container elements
  152. *
  153. * Revision 1.38  2002/11/20 21:22:51  gouriano
  154. * corrected processing of unnamed sequences as choice variants
  155. *
  156. * Revision 1.37  2002/11/19 19:48:51  gouriano
  157. * added support of XML attributes of choice variants
  158. *
  159. * Revision 1.36  2002/11/14 21:00:18  gouriano
  160. * added support of XML attribute lists
  161. *
  162. * Revision 1.35  2002/10/25 14:49:27  vasilche
  163. * NCBI C Toolkit compatibility code extracted to libxcser library.
  164. * Serial streams flags names were renamed to fXxx.
  165. *
  166. * Names of flags
  167. *
  168. * Revision 1.34  2002/10/18 14:27:09  gouriano
  169. * added possibility to enable/disable/set public identifier
  170. *
  171. * Revision 1.33  2002/10/15 13:47:59  gouriano
  172. * modified to handle "standard" (generated from DTD) XML i/o
  173. *
  174. * Revision 1.32  2002/10/08 18:59:38  grichenk
  175. * Check for null pointers in containers (assert in debug mode,
  176. * warning in release).
  177. *
  178. * Revision 1.31  2002/09/25 19:37:36  gouriano
  179. * added the possibility of having no tag prefix in XML I/O streams
  180. *
  181. * Revision 1.30  2002/03/07 22:02:02  grichenk
  182. * Added "Separator" modifier for CObjectOStream
  183. *
  184. * Revision 1.29  2001/11/09 19:07:58  grichenk
  185. * Fixed DTDFilePrefix functions
  186. *
  187. * Revision 1.28  2001/10/17 20:41:26  grichenk
  188. * Added CObjectOStream::CharBlock class
  189. *
  190. * Revision 1.27  2001/10/17 18:18:30  grichenk
  191. * Added CObjectOStreamXml::xxxFilePrefix() and
  192. * CObjectOStreamXml::xxxFileName()
  193. *
  194. * Revision 1.26  2001/05/17 15:07:08  lavr
  195. * Typos corrected
  196. *
  197. * Revision 1.25  2001/04/25 20:41:53  vakatov
  198. * <limits.h>, <float.h>  --->  <corelib/ncbi_limits.h>
  199. *
  200. * Revision 1.24  2001/04/13 14:57:15  kholodov
  201. * Added: SetDTDFileName function to set DTD module name in XML header
  202. *
  203. * Revision 1.23  2000/12/26 22:24:14  vasilche
  204. * Fixed errors of compilation on Mac.
  205. *
  206. * Revision 1.22  2000/12/15 15:38:45  vasilche
  207. * Added support of Int8 and long double.
  208. * Enum values now have type Int4 instead of long.
  209. *
  210. * Revision 1.21  2000/12/04 19:02:41  beloslyu
  211. * changes for FreeBSD
  212. *
  213. * Revision 1.20  2000/11/07 17:25:41  vasilche
  214. * Fixed encoding of XML:
  215. *     removed unnecessary apostrophes in OCTET STRING
  216. *     removed unnecessary content in NULL
  217. * Added module names to CTypeInfo and CEnumeratedTypeValues
  218. *
  219. * Revision 1.19  2000/10/20 15:51:43  vasilche
  220. * Fixed data error processing.
  221. * Added interface for constructing container objects directly into output stream.
  222. * object.hpp, object.inl and object.cpp were split to
  223. * objectinfo.*, objecttype.*, objectiter.* and objectio.*.
  224. *
  225. * Revision 1.18  2000/10/17 18:45:35  vasilche
  226. * Added possibility to turn off object cross reference detection in
  227. * CObjectIStream and CObjectOStream.
  228. *
  229. * Revision 1.17  2000/10/13 20:22:56  vasilche
  230. * Fixed warnings on 64 bit compilers.
  231. * Fixed missing typename in templates.
  232. *
  233. * Revision 1.16  2000/10/13 16:28:40  vasilche
  234. * Reduced header dependency.
  235. * Avoid use of templates with virtual methods.
  236. * Reduced amount of different maps used.
  237. * All this lead to smaller compiled code size (libraries and programs).
  238. *
  239. * Revision 1.15  2000/10/05 15:52:51  vasilche
  240. * Avoid using snprintf because it's missing on osf1_gcc
  241. *
  242. * Revision 1.14  2000/10/05 13:17:17  vasilche
  243. * Added missing #include <stdio.h>
  244. *
  245. * Revision 1.13  2000/10/04 19:19:00  vasilche
  246. * Fixed processing floating point data.
  247. *
  248. * Revision 1.12  2000/10/03 17:22:45  vasilche
  249. * Reduced header dependency.
  250. * Reduced size of debug libraries on WorkShop by 3 times.
  251. * Fixed tag allocation for parent classes.
  252. * Fixed CObject allocation/deallocation in streams.
  253. * Moved instantiation of several templates in separate source file.
  254. *
  255. * Revision 1.11  2000/09/29 16:18:24  vasilche
  256. * Fixed binary format encoding/decoding on 64 bit compulers.
  257. * Implemented CWeakMap<> for automatic cleaning map entries.
  258. * Added cleaning local hooks via CWeakMap<>.
  259. * Renamed ReadTypeName -> ReadFileHeader, ENoTypeName -> ENoFileHeader.
  260. * Added some user interface methods to CObjectIStream, CObjectOStream and
  261. * CObjectStreamCopier.
  262. *
  263. * Revision 1.10  2000/09/26 17:38:22  vasilche
  264. * Fixed incomplete choiceptr implementation.
  265. * Removed temporary comments.
  266. *
  267. * Revision 1.9  2000/09/18 20:00:25  vasilche
  268. * Separated CVariantInfo and CMemberInfo.
  269. * Implemented copy hooks.
  270. * All hooks now are stored in CTypeInfo/CMemberInfo/CVariantInfo.
  271. * Most type specific functions now are implemented via function pointers instead of virtual functions.
  272. *
  273. * Revision 1.8  2000/09/01 13:16:20  vasilche
  274. * Implemented class/container/choice iterators.
  275. * Implemented CObjectStreamCopier for copying data without loading into memory.
  276. *
  277. * Revision 1.7  2000/08/15 19:44:50  vasilche
  278. * Added Read/Write hooks:
  279. * CReadObjectHook/CWriteObjectHook for objects of specified type.
  280. * CReadClassMemberHook/CWriteClassMemberHook for specified members.
  281. * CReadChoiceVariantHook/CWriteChoiceVariant for specified choice variants.
  282. * CReadContainerElementHook/CWriteContainerElementsHook for containers.
  283. *
  284. * Revision 1.6  2000/07/03 18:42:46  vasilche
  285. * Added interface to typeinfo via CObjectInfo and CConstObjectInfo.
  286. * Reduced header dependency.
  287. *
  288. * Revision 1.5  2000/06/16 19:24:22  vasilche
  289. * Updated MSVC project.
  290. * Fixed error on MSVC with static const class member.
  291. *
  292. * Revision 1.4  2000/06/16 16:31:22  vasilche
  293. * Changed implementation of choices and classes info to allow use of the same classes in generated and user written classes.
  294. *
  295. * Revision 1.3  2000/06/07 19:46:00  vasilche
  296. * Some code cleaning.
  297. * Macros renaming in more clear way.
  298. * BEGIN_NAMED_*_INFO, ADD_*_MEMBER, ADD_NAMED_*_MEMBER.
  299. *
  300. * Revision 1.2  2000/06/01 19:07:05  vasilche
  301. * Added parsing of XML data.
  302. *
  303. * Revision 1.1  2000/05/24 20:08:49  vasilche
  304. * Implemented XML dump.
  305. *
  306. * ===========================================================================
  307. */
  308. #include <ncbi_pch.hpp>
  309. #include <corelib/ncbistd.hpp>
  310. #include <corelib/ncbi_limits.h>
  311. #include <serial/objostrxml.hpp>
  312. #include <serial/objistr.hpp>
  313. #include <serial/objcopy.hpp>
  314. #include <serial/memberid.hpp>
  315. #include <serial/memberlist.hpp>
  316. #include <serial/enumvalues.hpp>
  317. #include <serial/objhook.hpp>
  318. #include <serial/classinfo.hpp>
  319. #include <serial/choice.hpp>
  320. #include <serial/continfo.hpp>
  321. #include <serial/delaybuf.hpp>
  322. #include <serial/ptrinfo.hpp>
  323. #include <stdio.h>
  324. #include <math.h>
  325. BEGIN_NCBI_SCOPE
  326. CObjectOStream* CObjectOStream::OpenObjectOStreamXml(CNcbiOstream& out,
  327.                                                      bool deleteOut)
  328. {
  329.     return new CObjectOStreamXml(out, deleteOut);
  330. }
  331. string CObjectOStreamXml::sm_DefaultDTDFilePrefix = "";
  332. string CObjectOStreamXml::sm_DefaultSchemaNamespace = "http://www.ncbi.nlm.nih.gov";
  333. CObjectOStreamXml::CObjectOStreamXml(CNcbiOstream& out, bool deleteOut)
  334.     : CObjectOStream(eSerial_Xml, out, deleteOut),
  335.       m_LastTagAction(eTagClose), m_EndTag(true),
  336.       m_UseDefaultDTDFilePrefix( true),
  337.       m_UsePublicId( true),
  338.       m_Attlist( false), m_StdXml( false), m_EnforcedStdXml( false),
  339.       m_RealFmt( eRealScientificFormat ), m_Encoding( eEncoding_Unknown ),
  340.       m_UseSchemaRef( false ), m_UseSchemaLoc( true ), m_UseDTDRef( true )
  341. {
  342.     m_Output.SetBackLimit(1);
  343. }
  344. CObjectOStreamXml::~CObjectOStreamXml(void)
  345. {
  346. }
  347. void CObjectOStreamXml::SetEncoding(EEncoding enc)
  348. {
  349.     m_Encoding = enc;
  350. }
  351. CObjectOStreamXml::EEncoding CObjectOStreamXml::GetEncoding(void) const
  352. {
  353.     return m_Encoding;
  354. }
  355. void CObjectOStreamXml::SetReferenceSchema(bool use_schema)
  356. {
  357.     m_UseSchemaRef = use_schema;
  358. }
  359. bool CObjectOStreamXml::GetReferenceSchema(void) const
  360. {
  361.     return m_UseSchemaRef;
  362. }
  363. void CObjectOStreamXml::SetReferenceDTD(bool use_dtd)
  364. {
  365.     m_UseDTDRef = use_dtd;
  366. }
  367. bool CObjectOStreamXml::GetReferenceDTD(void) const
  368. {
  369.     return m_UseDTDRef;
  370. }
  371. void CObjectOStreamXml::SetUseSchemaLocation(bool use_loc)
  372. {
  373.     m_UseSchemaLoc = use_loc;
  374. }
  375. bool CObjectOStreamXml::GetUseSchemaLocation(void) const
  376. {
  377.     return m_UseSchemaLoc;
  378. }
  379. CObjectOStreamXml::ERealValueFormat
  380.     CObjectOStreamXml::GetRealValueFormat(void) const
  381. {
  382.     return m_RealFmt;
  383. }
  384. void CObjectOStreamXml::SetRealValueFormat(
  385.     CObjectOStreamXml::ERealValueFormat fmt)
  386. {
  387.     m_RealFmt = fmt;
  388. }
  389. void CObjectOStreamXml::SetEnforcedStdXml(bool set)
  390. {
  391.     m_EnforcedStdXml = set;
  392.     if (m_EnforcedStdXml) {
  393.         m_StdXml = false;
  394.     }
  395. }
  396. string CObjectOStreamXml::GetPosition(void) const
  397. {
  398.     return "line "+NStr::UIntToString(m_Output.GetLine());
  399. }
  400. static string GetPublicModuleName(TTypeInfo type)
  401. {
  402.     const string& s = type->GetModuleName();
  403.     string name;
  404.     for ( string::const_iterator i = s.begin(); i != s.end(); ++i ) {
  405.         char c = *i;
  406.         if ( !isalnum(c) )
  407.             name += ' ';
  408.         else
  409.             name += c;
  410.     }
  411.     return name;
  412. }
  413. string CObjectOStreamXml::GetModuleName(TTypeInfo type)
  414. {
  415.     string name;
  416.     if( !m_DTDFileName.empty() ) {
  417.         name = m_DTDFileName;
  418.     }
  419.     else {
  420.         const string& s = type->GetModuleName();
  421.         for ( string::const_iterator i = s.begin(); i != s.end(); ++i ) {
  422.             char c = *i;
  423.             if ( c == '-' )
  424.                 name += '_';
  425.             else
  426.                 name += c;
  427.         }
  428.     }
  429.     return name;
  430. }
  431. void CObjectOStreamXml::WriteFileHeader(TTypeInfo type)
  432. {
  433.     m_Output.PutString("<?xml version="1.0");
  434.     switch (m_Encoding) {
  435.     default:
  436.         break;
  437.     case eEncoding_UTF8:
  438.         m_Output.PutString("" encoding="UTF-8");
  439.         break;
  440.     case eEncoding_ISO8859_1:
  441.         m_Output.PutString("" encoding="ISO-8859-1");   
  442.         break;
  443.     case eEncoding_Windows_1252:
  444.         m_Output.PutString("" encoding="Windows-1252");   
  445.         break;
  446.     }
  447.     m_Output.PutString(""?>");
  448.     m_Output.PutEol();
  449.     if (!m_UseSchemaRef && m_UseDTDRef) {
  450.         m_Output.PutString("<!DOCTYPE ");
  451.         m_Output.PutString(type->GetName());
  452.     
  453.         if (m_UsePublicId) {
  454.             m_Output.PutString(" PUBLIC "");
  455.             if (m_PublicId.empty()) {
  456.                 m_Output.PutString("-//NCBI//");
  457.                 m_Output.PutString(GetPublicModuleName(type));
  458.                 m_Output.PutString("/EN");
  459.             } else {
  460.                 m_Output.PutString(m_PublicId);
  461.             }
  462.             m_Output.PutString(""");
  463.         } else {
  464.             m_Output.PutString(" SYSTEM");
  465.         }
  466.         m_Output.PutString(" "");
  467.         m_Output.PutString(GetDTDFilePrefix() + GetModuleName(type));
  468.         m_Output.PutString(".dtd">");
  469.         m_Output.PutEol();
  470.     }
  471.     m_LastTagAction = eTagClose;
  472. }
  473. void CObjectOStreamXml::x_WriteClassNamespace(TTypeInfo type)
  474. {
  475.     OpenTagEndBack();
  476.     if (m_UseSchemaLoc) {
  477.         m_Output.PutEol();
  478.         m_Output.PutString("   ");
  479.     }
  480.     m_Output.PutString(" xmlns");
  481.     if (!m_CurrNsPrefix.empty()) {
  482.        m_Output.PutChar(':');
  483.        m_Output.PutString(m_CurrNsPrefix);
  484.     }
  485.     m_Output.PutString("="");
  486.     string ns_name( m_NsPrefixToName[m_CurrNsPrefix]);
  487.     if (ns_name.empty()) {
  488.         ns_name = GetDefaultSchemaNamespace();
  489.     }
  490.     m_Output.PutString(ns_name + """);
  491.     if (m_UseSchemaLoc) {
  492.         m_Output.PutEol();
  493.         string xs_name("http://www.w3.org/2001/XMLSchema-instance");
  494.         string xs_prefix("xs");
  495.         if (m_NsNameToPrefix.find(xs_name) == m_NsNameToPrefix.end()) {
  496.             for (char a='a';
  497.                 m_NsPrefixToName.find(xs_prefix) != m_NsPrefixToName.end(); ++a) {
  498.                 xs_prefix += a;
  499.             }
  500.             m_NsPrefixToName[xs_prefix] = xs_name;
  501.             m_NsNameToPrefix[xs_name] = xs_prefix;
  502.             m_Output.PutString("    xmlns:");
  503.             m_Output.PutString(xs_prefix + "="");
  504.             m_Output.PutString(xs_name + """);
  505.             m_Output.PutEol();
  506.             m_Output.PutString("    ");
  507.             m_Output.PutString(xs_prefix);
  508.             m_Output.PutString(":schemaLocation="");
  509.             m_Output.PutString(ns_name + " ");
  510.             m_Output.PutString(GetDTDFilePrefix() + GetModuleName(type));
  511.             m_Output.PutString(".xsd"");
  512.             m_Output.PutEol();
  513.         }
  514.     }
  515.     OpenTagEnd();
  516. }
  517. bool CObjectOStreamXml::x_ProcessTypeNamespace(TTypeInfo type)
  518. {
  519.     if (m_UseSchemaRef) {
  520.         string nsName;
  521.         if (type->HasNamespaceName()) {
  522.             nsName = type->GetNamespaceName();
  523.         } else if (m_NsPrefixes.empty()) {
  524.             nsName = GetDefaultSchemaNamespace();
  525.         }
  526.         return x_BeginNamespace(nsName,type->GetNamespacePrefix());
  527.     }
  528.     return false;
  529. }
  530. void CObjectOStreamXml::x_EndTypeNamespace(void)
  531. {
  532.     if (m_UseSchemaRef) {
  533.         if (TopFrame().HasTypeInfo()) {
  534.             TTypeInfo type = TopFrame().GetTypeInfo();
  535.             if (type->HasNamespaceName()) {
  536.                 x_EndNamespace(type->GetNamespaceName());
  537.             }
  538.         }
  539.     }
  540. }
  541. bool CObjectOStreamXml::x_BeginNamespace(const string& ns_name,
  542.                                          const string& ns_prefix)
  543. {
  544.     if (!m_UseSchemaRef || ns_name.empty()) {
  545.         return false;
  546.     }
  547.     string nsPrefix(ns_prefix);
  548.     if (m_NsNameToPrefix.find(ns_name) == m_NsNameToPrefix.end()) {
  549.         for (char a='a';
  550.             m_NsPrefixToName.find(nsPrefix) != m_NsPrefixToName.end(); ++a) {
  551.             nsPrefix += a;
  552.         }
  553.         m_CurrNsPrefix = nsPrefix;
  554.         m_NsNameToPrefix[ns_name] = nsPrefix;
  555.         m_NsPrefixToName[nsPrefix] = ns_name;
  556.         m_NsPrefixes.push(nsPrefix);
  557.         return true;
  558.     } else {
  559.         m_CurrNsPrefix = m_NsNameToPrefix[ns_name];
  560.         m_NsPrefixes.push(m_CurrNsPrefix);
  561.     }
  562.     return false;
  563. }
  564. void CObjectOStreamXml::x_EndNamespace(const string& ns_name)
  565. {
  566.     if (!m_UseSchemaRef || ns_name.empty()) {
  567.         return;
  568.     }
  569.     string nsPrefix = m_NsNameToPrefix[ns_name];
  570. // not sure about it - should we erase them or not?
  571. //    m_NsNameToPrefix.erase(ns_name);
  572. //    m_NsPrefixToName.erase(nsPrefix);
  573.     m_NsPrefixes.pop();
  574.     m_CurrNsPrefix = m_NsPrefixes.empty() ? kEmptyStr : m_NsPrefixes.top();
  575.     if (!m_Attlist && GetStackDepth() <= 2) {
  576.         m_NsNameToPrefix.clear();
  577.         m_NsPrefixToName.clear();
  578.     }
  579. }
  580. void CObjectOStreamXml::WriteEnum(const CEnumeratedTypeValues& values,
  581.                                   TEnumValueType value,
  582.                                   const string& valueName)
  583. {
  584.     if ( !values.GetName().empty() ) {
  585.         // global enum
  586.         OpenTagStart();
  587.         m_Output.PutString(values.GetName());
  588.         if ( !valueName.empty() ) {
  589.             m_Output.PutString(" value="");
  590.             m_Output.PutString(valueName);
  591.             m_Output.PutChar('"');
  592.         }
  593.         if ( values.IsInteger() ) {
  594.             OpenTagEnd();
  595.             m_Output.PutInt4(value);
  596.             CloseTagStart();
  597.             m_Output.PutString(values.GetName());
  598.             CloseTagEnd();
  599.         }
  600.         else {
  601.             _ASSERT(!valueName.empty());
  602.             SelfCloseTagEnd();
  603.             m_LastTagAction = eTagClose;
  604.         }
  605.     }
  606.     else {
  607.         // local enum (member, variant or element)
  608.         if ( valueName.empty() ) {
  609.             _ASSERT(values.IsInteger());
  610.             m_Output.PutInt4(value);
  611.         }
  612.         else {
  613.             if (m_LastTagAction == eAttlistTag) {
  614.                 m_Output.PutString(valueName);
  615.             } else {
  616.                 OpenTagEndBack();
  617.                 m_Output.PutString(" value="");
  618.                 m_Output.PutString(valueName);
  619.                 m_Output.PutChar('"');
  620.                 if ( values.IsInteger() ) {
  621.                     OpenTagEnd();
  622.                     m_Output.PutInt4(value);
  623.                 }
  624.                 else {
  625.                     SelfCloseTagEnd();
  626.                 }
  627.             }
  628.         }
  629.     }
  630. }
  631. void CObjectOStreamXml::WriteEnum(const CEnumeratedTypeValues& values,
  632.                                   TEnumValueType value)
  633. {
  634.     WriteEnum(values, value, values.FindName(value, values.IsInteger()));
  635. }
  636. void CObjectOStreamXml::CopyEnum(const CEnumeratedTypeValues& values,
  637.                                  CObjectIStream& in)
  638. {
  639.     TEnumValueType value = in.ReadEnum(values);
  640.     WriteEnum(values, value, values.FindName(value, values.IsInteger()));
  641. }
  642. void CObjectOStreamXml::WriteEscapedChar(char c)
  643. {
  644. //  http://www.w3.org/TR/2000/REC-xml-20001006#NT-Char
  645.     switch ( c ) {
  646.     case '&':
  647.         m_Output.PutString("&amp;");
  648.         break;
  649.     case '<':
  650.         m_Output.PutString("&lt;");
  651.         break;
  652.     case '>':
  653.         m_Output.PutString("&gt;");
  654.         break;
  655.     case ''':
  656.         m_Output.PutString("&apos;");
  657.         break;
  658.     case '"':
  659.         m_Output.PutString("&quot;");
  660.         break;
  661.     default:
  662.         if ((unsigned int)c < 0x20) {
  663.             m_Output.PutString("&#x");
  664.             Uint1 ch = c;
  665.             unsigned hi = ch >> 4;
  666.             unsigned lo = ch & 0xF;
  667.             if ( hi ) {
  668.                 m_Output.PutChar("0123456789abcdef"[hi]);
  669.             }
  670.             m_Output.PutChar("0123456789abcdef"[lo]);
  671.             m_Output.PutChar(';');
  672.         } else if ((unsigned int)c >= 0x80) {
  673.             if ( m_Encoding == eEncoding_UTF8 ||
  674.                  m_Encoding == eEncoding_Unknown ) {
  675.                 Uint1 ch = c;
  676.                 m_Output.PutChar((ch >> 6) | 0xC0);
  677.                 m_Output.PutChar((ch & 0x3F) | 0x80);
  678.             } else {
  679.                 m_Output.PutChar(c);
  680.             }
  681.         } else {
  682.             m_Output.PutChar(c);
  683.         }
  684.         break;
  685.     }
  686. }
  687. void CObjectOStreamXml::WriteBool(bool data)
  688. {
  689.     OpenTagEndBack();
  690.     if ( data )
  691.         m_Output.PutString(" value="true"");
  692.     else
  693.         m_Output.PutString(" value="false"");
  694.     SelfCloseTagEnd();
  695. }
  696. void CObjectOStreamXml::WriteChar(char data)
  697. {
  698.     WriteEscapedChar(data);
  699. }
  700. void CObjectOStreamXml::WriteInt4(Int4 data)
  701. {
  702.     m_Output.PutInt4(data);
  703. }
  704. void CObjectOStreamXml::WriteUint4(Uint4 data)
  705. {
  706.     m_Output.PutUint4(data);
  707. }
  708. void CObjectOStreamXml::WriteInt8(Int8 data)
  709. {
  710.     m_Output.PutInt8(data);
  711. }
  712. void CObjectOStreamXml::WriteUint8(Uint8 data)
  713. {
  714.     m_Output.PutUint8(data);
  715. }
  716. void CObjectOStreamXml::WriteDouble2(double data, size_t digits)
  717. {
  718.     if (isnan(data)) {
  719.         ThrowError(fInvalidData, "invalid double: not a number");
  720.     }
  721.     if (!finite(data)) {
  722.         ThrowError(fInvalidData, "invalid double: infinite");
  723.     }
  724.     char buffer[512];
  725.     SIZE_TYPE width;
  726.     if (m_RealFmt == eRealFixedFormat) {
  727.         int shift = int(ceil(log10(fabs(data))));
  728.         int precision = int(digits - shift);
  729.         if ( precision < 0 )
  730.             precision = 0;
  731.         if ( precision > 64 ) // limit precision of data
  732.             precision = 64;
  733.         width = NStr::DoubleToString(data, (unsigned int)precision,
  734.                                     buffer, sizeof(buffer));
  735.         if (precision != 0) {
  736.             while (buffer[width-1] == '0') {
  737.                 --width;
  738.             }
  739.             if (buffer[width-1] == '.') {
  740.                 --width;
  741.             }
  742.         }
  743.     } else {
  744.         width = sprintf(buffer, "%.*g", digits, data);
  745.     }
  746.     m_Output.PutString(buffer, width);
  747. }
  748. void CObjectOStreamXml::WriteDouble(double data)
  749. {
  750.     WriteDouble2(data, DBL_DIG);
  751. }
  752. void CObjectOStreamXml::WriteFloat(float data)
  753. {
  754.     WriteDouble2(data, FLT_DIG);
  755. }
  756. void CObjectOStreamXml::WriteNull(void)
  757. {
  758.     OpenTagEndBack();
  759.     SelfCloseTagEnd();
  760. }
  761. void CObjectOStreamXml::WriteAnyContentObject(const CAnyContentObject& obj)
  762. {
  763.     if (obj.GetName().empty()) {
  764.         return;
  765.     }
  766.     string ns_name(obj.GetNamespaceName());
  767.     bool needNs = x_BeginNamespace(ns_name,obj.GetNamespacePrefix());
  768.     OpenTag(obj.GetName());
  769.     if (m_UseSchemaRef) {
  770.         OpenTagEndBack();
  771.         if (needNs) {
  772.             m_Output.PutEol();
  773.             m_Output.PutString("    xmlns");
  774.             if (!m_CurrNsPrefix.empty()) {
  775.                 m_Output.PutChar(':');
  776.                 m_Output.PutString(m_CurrNsPrefix);
  777.             }
  778.             m_Output.PutString("="");
  779.             m_Output.PutString(ns_name);
  780.             m_Output.PutChar('"');
  781.         }
  782.         const vector<CSerialAttribInfoItem>& attlist = obj.GetAttributes();
  783.         if (!attlist.empty()) {
  784.             m_Attlist = true;
  785.             vector<CSerialAttribInfoItem>::const_iterator it;
  786.             for ( it = attlist.begin(); it != attlist.end(); ++it) {
  787.                 string ns(it->GetNamespaceName());
  788.                 string ns_prefix;
  789.                 if (x_BeginNamespace(ns,kEmptyStr)) {
  790.                     m_Output.PutEol();
  791.                     m_Output.PutString("    xmlns");
  792.                     ns_prefix = m_NsNameToPrefix[ns];
  793.                     if (!ns_prefix.empty()) {
  794.                         m_Output.PutChar(':');
  795.                         m_Output.PutString(ns_prefix);
  796.                     }
  797.                     m_Output.PutString("="");
  798.                     m_Output.PutString(ns);
  799.                     m_Output.PutChar('"');
  800.                 }
  801.                 ns_prefix = m_NsNameToPrefix[ns];
  802.                 m_Output.PutEol();
  803.                 m_Output.PutString("    ");
  804.                 if (!ns_prefix.empty()) {
  805.                     m_Output.PutString(ns_prefix);
  806.                     m_Output.PutChar(':');
  807.                 }
  808.                 m_Output.PutString(it->GetName());
  809.                 m_Output.PutString("="");
  810.                 m_Output.PutString(it->GetValue());
  811.                 m_Output.PutChar('"');
  812.                 x_EndNamespace(ns);
  813.             }
  814.             m_Attlist = false;
  815.         }
  816.         OpenTagEnd();
  817.     }
  818. // value
  819. // no verification on write!
  820.     const string& value = obj.GetValue();
  821.     bool was_open = true;
  822.     for (string::const_iterator is=value.begin(); is != value.end(); ++is) {
  823.         if (*is == '/' && *(is+1) == '>') {
  824.             m_Output.DecIndentLevel();
  825.             was_open = false;
  826.         }
  827.         if (*is == '<') {
  828.             if (*(is+1) == '/') {
  829.                 m_Output.DecIndentLevel();
  830.                 if (!was_open) {
  831.                     m_Output.PutEol();
  832.                 }
  833.                 was_open = false;
  834.             } else {
  835.                 m_Output.PutEol();
  836.                 m_Output.IncIndentLevel();
  837.                 was_open = true;
  838.             }
  839.         }
  840.         m_Output.PutChar(*is);
  841.         if (*is == '<') {
  842.             if (*(is+1) == '/') {
  843.                 m_Output.PutChar(*(++is));
  844.             }
  845.             if (m_UseSchemaRef && !m_CurrNsPrefix.empty()) {
  846.                 m_Output.PutString(m_CurrNsPrefix);
  847.                 m_Output.PutChar(':');
  848.             }
  849.         }
  850.     }
  851. // close tag
  852.     if (!was_open) {
  853.         m_Output.PutEol(false);
  854.         m_EndTag = true;
  855.     }
  856.     CloseTag(obj.GetName());
  857.     x_EndNamespace(ns_name);
  858. }
  859. void CObjectOStreamXml::CopyAnyContentObject(CObjectIStream& in)
  860. {
  861.     NCBI_THROW(CSerialException,eNotImplemented,"not yet");
  862. }
  863. void CObjectOStreamXml::WriteCString(const char* str)
  864. {
  865.     if ( str == 0 ) {
  866.         OpenTagEndBack();
  867.         SelfCloseTagEnd();
  868.     }
  869.     else {
  870.         while ( *str ) {
  871.             WriteEscapedChar(*str++);
  872.         }
  873.     }
  874. }
  875. void CObjectOStreamXml::WriteString(const string& str, EStringType type)
  876. {
  877.     EEncoding enc = m_Encoding;
  878.     if (type == eStringTypeUTF8) {
  879.         if (m_Encoding == eEncoding_UTF8 || m_Encoding == eEncoding_Unknown) {
  880.             m_Encoding = eEncoding_ISO8859_1;
  881.         } else {
  882.             string tmp = (static_cast<const CStringUTF8&>(str)).AsAscii();
  883.             WriteString( tmp, eStringTypeVisible);
  884.             return;
  885.         }
  886.     }
  887.     for ( string::const_iterator i = str.begin(); i != str.end(); ++i ) {
  888.         WriteEscapedChar(*i);
  889.     }
  890.     m_Encoding = enc;
  891. }
  892. void CObjectOStreamXml::WriteStringStore(const string& str)
  893. {
  894.     for ( string::const_iterator i = str.begin(); i != str.end(); ++i ) {
  895.         WriteEscapedChar(*i);
  896.     }
  897. }
  898. void CObjectOStreamXml::CopyString(CObjectIStream& in)
  899. {
  900.     string str;
  901.     in.ReadStd(str);
  902.     for ( string::const_iterator i = str.begin(); i != str.end(); ++i ) {
  903.         WriteEscapedChar(*i);
  904.     }
  905. }
  906. void CObjectOStreamXml::CopyStringStore(CObjectIStream& in)
  907. {
  908.     string str;
  909.     in.ReadStringStore(str);
  910.     for ( string::const_iterator i = str.begin(); i != str.end(); ++i ) {
  911.         WriteEscapedChar(*i);
  912.     }
  913. }
  914. void CObjectOStreamXml::WriteNullPointer(void)
  915. {
  916.     OpenTagEndBack();
  917.     SelfCloseTagEnd();
  918. }
  919. void CObjectOStreamXml::WriteObjectReference(TObjectIndex index)
  920. {
  921.     m_Output.PutString("<object index=");
  922.     if ( sizeof(TObjectIndex) == sizeof(Int4) )
  923.         m_Output.PutInt4(Int4(index));
  924.     else if ( sizeof(TObjectIndex) == sizeof(Int8) )
  925.         m_Output.PutInt8(index);
  926.     else
  927.         ThrowError(fIllegalCall, "invalid size of TObjectIndex"
  928.             "must be either sizeof(Int4) or sizeof(Int8)");
  929.     m_Output.PutString("/>");
  930.     m_EndTag = true;
  931. }
  932. void CObjectOStreamXml::WriteTag(const string& name)
  933. {
  934.     if (!m_Attlist && !m_CurrNsPrefix.empty()) {
  935.         m_Output.PutString(m_CurrNsPrefix);
  936.         m_Output.PutChar(':');
  937.     }
  938.     m_Output.PutString(name);
  939. }
  940. void CObjectOStreamXml::OpenTagStart(void)
  941. {
  942.     if (m_Attlist) {
  943.         if ( m_LastTagAction == eTagOpen ) {
  944.             m_Output.PutChar(' ');
  945.             m_LastTagAction = eAttlistTag;
  946.         }
  947.     } else {
  948.         if (!m_EndTag)
  949.             m_Output.PutEol(false);
  950.         m_Output.PutIndent();
  951.         m_Output.PutChar('<');
  952.         m_LastTagAction = eTagOpen;
  953.     }
  954.     m_EndTag = false;
  955. }
  956. void CObjectOStreamXml::OpenTagEnd(void)
  957. {
  958.     if (m_Attlist) {
  959.         if ( m_LastTagAction == eAttlistTag ) {
  960.             m_Output.PutString("="");
  961.         }
  962.     } else {
  963.         if ( m_LastTagAction == eTagOpen ) {
  964.             m_Output.PutChar('>');
  965.             m_Output.IncIndentLevel();
  966.             m_LastTagAction = eTagClose;
  967.         }
  968.     }
  969. }
  970. void CObjectOStreamXml::OpenTagEndBack(void)
  971. {
  972.     _ASSERT(m_LastTagAction == eTagClose);
  973.     m_LastTagAction = eTagOpen;
  974.     m_Output.BackChar('>');
  975.     m_Output.DecIndentLevel();
  976. }
  977. void CObjectOStreamXml::SelfCloseTagEnd(void)
  978. {
  979.     _ASSERT(m_LastTagAction == eTagOpen);
  980.     m_Output.PutString("/>");
  981.     m_Output.PutEol(false);
  982.     m_LastTagAction = eTagSelfClosed;
  983.     m_EndTag = true;
  984. }
  985. void CObjectOStreamXml::EolIfEmptyTag(void)
  986. {
  987.     _ASSERT(m_LastTagAction != eTagSelfClosed);
  988.     if ( m_LastTagAction == eTagOpen ) {
  989.         m_Output.PutEol(false);
  990.         m_LastTagAction = eTagClose;
  991.     }
  992. }
  993. void CObjectOStreamXml::CloseTagStart(void)
  994. {
  995.     _ASSERT(m_LastTagAction != eTagSelfClosed);
  996.     m_Output.DecIndentLevel();
  997.     if (m_EndTag)
  998.         m_Output.PutIndent();
  999.     m_Output.PutString("</");
  1000.     m_LastTagAction = eTagOpen;
  1001. }
  1002. void CObjectOStreamXml::CloseTagEnd(void)
  1003. {
  1004.     m_Output.PutChar('>');
  1005.     m_Output.PutEol(false);
  1006.     m_LastTagAction = eTagClose;
  1007.     m_EndTag = true;
  1008. }
  1009. void CObjectOStreamXml::PrintTagName(size_t level)
  1010. {
  1011.     const TFrame& frame = FetchFrameFromTop(level);
  1012.     switch ( frame.GetFrameType() ) {
  1013.     case TFrame::eFrameNamed:
  1014.     case TFrame::eFrameArray:
  1015.     case TFrame::eFrameClass:
  1016.     case TFrame::eFrameChoice:
  1017.         {
  1018.             _ASSERT(frame.GetTypeInfo());
  1019.             const string& name = frame.GetTypeInfo()->GetName();
  1020.             if ( !name.empty() ) {
  1021.                 WriteTag(name);
  1022. #if defined(NCBI_SERIAL_IO_TRACE)
  1023.     TraceTag(name);
  1024. #endif
  1025.             } else {
  1026.                 PrintTagName(level + 1);
  1027.             }
  1028.             return;
  1029.         }
  1030.     case TFrame::eFrameClassMember:
  1031.     case TFrame::eFrameChoiceVariant:
  1032.         {
  1033.             bool attlist = m_Attlist;
  1034.             if (!x_IsStdXml()) {
  1035.                 PrintTagName(level + 1);
  1036.                 m_Output.PutChar('_');
  1037.                 m_Attlist = true;
  1038.             }
  1039.             WriteTag(frame.GetMemberId().GetName());
  1040.             m_Attlist = attlist;
  1041. #if defined(NCBI_SERIAL_IO_TRACE)
  1042.     TraceTag(frame.GetMemberId().GetName());
  1043. #endif
  1044.             return;
  1045.         }
  1046.     case TFrame::eFrameArrayElement:
  1047.         {
  1048.             PrintTagName(level + 1);
  1049.             if (!x_IsStdXml()) {
  1050.                 m_Output.PutString("_E");
  1051.             }
  1052.             return;
  1053.         }
  1054.     default:
  1055.         break;
  1056.     }
  1057.     ThrowError(fIllegalCall, "illegal frame type");
  1058. }
  1059. void CObjectOStreamXml::WriteOtherBegin(TTypeInfo typeInfo)
  1060. {
  1061.     OpenTag(typeInfo);
  1062. }
  1063. void CObjectOStreamXml::WriteOtherEnd(TTypeInfo typeInfo)
  1064. {
  1065.     CloseTag(typeInfo);
  1066. }
  1067. void CObjectOStreamXml::WriteOther(TConstObjectPtr object,
  1068.                                    TTypeInfo typeInfo)
  1069. {
  1070.     OpenTag(typeInfo);
  1071.     WriteObject(object, typeInfo);
  1072.     CloseTag(typeInfo);
  1073. }
  1074. void CObjectOStreamXml::BeginContainer(const CContainerTypeInfo* containerType)
  1075. {
  1076.     if (!x_IsStdXml()) {
  1077.         OpenTagIfNamed(containerType);
  1078.     }
  1079. }
  1080. void CObjectOStreamXml::EndContainer(void)
  1081. {
  1082.     if (!x_IsStdXml()) {
  1083.         CloseTagIfNamed(TopFrame().GetTypeInfo());
  1084.     }
  1085. }
  1086. bool CObjectOStreamXml::WillHaveName(TTypeInfo elementType)
  1087. {
  1088.     while ( elementType->GetName().empty() ) {
  1089.         if ( elementType->GetTypeFamily() != eTypeFamilyPointer )
  1090.             return false;
  1091.         elementType = CTypeConverter<CPointerTypeInfo>::SafeCast(elementType)->GetPointedType();
  1092.     }
  1093.     // found named type
  1094.     return true;
  1095. }
  1096. void CObjectOStreamXml::BeginContainerElement(TTypeInfo elementType)
  1097. {
  1098.     if ( !WillHaveName(elementType) ) {
  1099.         BeginArrayElement(elementType);
  1100.     }
  1101. }
  1102. void CObjectOStreamXml::EndContainerElement(void)
  1103. {
  1104.     if ( !WillHaveName(TopFrame().GetTypeInfo()) ) {
  1105.         EndArrayElement();
  1106.     }
  1107. }
  1108. #ifdef VIRTUAL_MID_LEVEL_IO
  1109. void CObjectOStreamXml::WriteContainer(const CContainerTypeInfo* cType,
  1110.                                        TConstObjectPtr containerPtr)
  1111. {
  1112.     if ( !cType->GetName().empty() ) {
  1113.         BEGIN_OBJECT_FRAME2(eFrameArray, cType);
  1114.         OpenTag(cType);
  1115.         WriteContainerContents(cType, containerPtr);
  1116.         EolIfEmptyTag();
  1117.         CloseTag(cType);
  1118.         END_OBJECT_FRAME();
  1119.     }
  1120.     else {
  1121.         WriteContainerContents(cType, containerPtr);
  1122.     }
  1123. }
  1124. void CObjectOStreamXml::BeginArrayElement(TTypeInfo elementType)
  1125. {
  1126.     if (x_IsStdXml() && GetRealTypeFamily(elementType) != eTypeFamilyPrimitive) {
  1127.         TopFrame().SetNotag();
  1128.     } else {
  1129.         OpenStackTag(0);
  1130.     }
  1131. }
  1132. void CObjectOStreamXml::EndArrayElement(void)
  1133. {
  1134.     if (TopFrame().GetNotag()) {
  1135.         TopFrame().SetNotag(false);
  1136.     } else {
  1137.         CloseStackTag(0);
  1138.     }
  1139. }
  1140. void CObjectOStreamXml::WriteContainerContents(const CContainerTypeInfo* cType,
  1141.                                                TConstObjectPtr containerPtr)
  1142. {
  1143.     TTypeInfo elementType = cType->GetElementType();
  1144.     CContainerTypeInfo::CConstIterator i;
  1145.     if ( WillHaveName(elementType) ) {
  1146.         if ( cType->InitIterator(i, containerPtr) ) {
  1147.             do {
  1148.                 if (elementType->GetTypeFamily() == eTypeFamilyPointer) {
  1149.                     const CPointerTypeInfo* pointerType =
  1150.                         CTypeConverter<CPointerTypeInfo>::SafeCast(elementType);
  1151.                     _ASSERT(pointerType->GetObjectPointer(cType->GetElementPtr(i)));
  1152.                     if ( !pointerType->GetObjectPointer(cType->GetElementPtr(i)) ) {
  1153.                         ERR_POST(Warning << " NULL pointer found in container: skipping");
  1154.                         continue;
  1155.                     }
  1156.                 }
  1157.                 WriteObject(cType->GetElementPtr(i), elementType);
  1158.             } while ( cType->NextElement(i) );
  1159.         }
  1160.     }
  1161.     else {
  1162.         BEGIN_OBJECT_FRAME2(eFrameArrayElement, elementType);
  1163.         if ( cType->InitIterator(i, containerPtr) ) {
  1164.             do {
  1165.                 BeginArrayElement(elementType);
  1166.                 WriteObject(cType->GetElementPtr(i), elementType);
  1167.                 EndArrayElement();
  1168.             } while ( cType->NextElement(i) );
  1169.         } else {
  1170.             const TFrame& frame = FetchFrameFromTop(1);
  1171.             if (frame.GetFrameType() == CObjectStackFrame::eFrameNamed) {
  1172.                 const CClassTypeInfo* clType =
  1173.                     dynamic_cast<const CClassTypeInfo*>(frame.GetTypeInfo());
  1174.                 if (clType && clType->Implicit() && clType->IsImplicitNonEmpty()) {
  1175.                     ThrowError(fInvalidData, "container is empty");
  1176.                 }
  1177.             }
  1178.         }
  1179.         END_OBJECT_FRAME();
  1180.     }
  1181. }
  1182. #endif
  1183. void CObjectOStreamXml::BeginNamedType(TTypeInfo namedTypeInfo)
  1184. {
  1185.     const CClassTypeInfo* classType =
  1186.         dynamic_cast<const CClassTypeInfo*>(namedTypeInfo);
  1187.     if (classType) {
  1188.         CheckStdXml(classType);
  1189.     }
  1190.     OpenTag(namedTypeInfo);
  1191. }
  1192. void CObjectOStreamXml::EndNamedType(void)
  1193. {
  1194.     CloseTag(TopFrame().GetTypeInfo());
  1195. }
  1196. #ifdef VIRTUAL_MID_LEVEL_IO
  1197. void CObjectOStreamXml::WriteNamedType(TTypeInfo namedTypeInfo,
  1198.                                        TTypeInfo typeInfo,
  1199.                                        TConstObjectPtr object)
  1200. {
  1201.     BEGIN_OBJECT_FRAME2(eFrameNamed, namedTypeInfo);
  1202.     
  1203.     BeginNamedType(namedTypeInfo);
  1204.     WriteObject(object, typeInfo);
  1205.     EndNamedType();
  1206.     END_OBJECT_FRAME();
  1207. }
  1208. void CObjectOStreamXml::CopyNamedType(TTypeInfo namedTypeInfo,
  1209.                                       TTypeInfo objectType,
  1210.                                       CObjectStreamCopier& copier)
  1211. {
  1212.     BEGIN_OBJECT_2FRAMES_OF2(copier, eFrameNamed, namedTypeInfo);
  1213.     copier.In().BeginNamedType(namedTypeInfo);
  1214.     BeginNamedType(namedTypeInfo);
  1215.     CopyObject(objectType, copier);
  1216.     EndNamedType();
  1217.     copier.In().EndNamedType();
  1218.     END_OBJECT_2FRAMES_OF(copier);
  1219. }
  1220. #endif
  1221. void CObjectOStreamXml::CheckStdXml(const CClassTypeInfoBase* classType)
  1222. {
  1223.     if (m_EnforcedStdXml) {
  1224.         m_StdXml = false;
  1225.         return;
  1226.     }
  1227.     TMemberIndex first = classType->GetItems().FirstIndex();
  1228.     m_StdXml = classType->GetItems().GetItemInfo(first)->GetId().HaveNoPrefix();
  1229. }
  1230. ETypeFamily CObjectOStreamXml::GetRealTypeFamily(TTypeInfo typeInfo)
  1231. {
  1232.     ETypeFamily type = typeInfo->GetTypeFamily();
  1233.     if (type == eTypeFamilyPointer) {
  1234.         const CPointerTypeInfo* ptr =
  1235.             dynamic_cast<const CPointerTypeInfo*>(typeInfo);
  1236.         if (ptr) {
  1237.             type = ptr->GetPointedType()->GetTypeFamily();
  1238.         }
  1239.     }
  1240.     return type;
  1241. }
  1242. ETypeFamily CObjectOStreamXml::GetContainerElementTypeFamily(TTypeInfo typeInfo)
  1243. {
  1244.     if (typeInfo->GetTypeFamily() == eTypeFamilyPointer) {
  1245.         const CPointerTypeInfo* ptr =
  1246.             dynamic_cast<const CPointerTypeInfo*>(typeInfo);
  1247.         if (ptr) {
  1248.             typeInfo = ptr->GetPointedType();
  1249.         }
  1250.     }
  1251.     _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer);
  1252.     const CContainerTypeInfo* ptr =
  1253.         dynamic_cast<const CContainerTypeInfo*>(typeInfo);
  1254.     return GetRealTypeFamily(ptr->GetElementType());
  1255. }
  1256. void CObjectOStreamXml::BeginClass(const CClassTypeInfo* classInfo)
  1257. {
  1258.     CheckStdXml(classInfo);
  1259.     bool needNs = x_ProcessTypeNamespace(classInfo);
  1260.     OpenTagIfNamed(classInfo);
  1261.     if (needNs) {
  1262.         x_WriteClassNamespace(classInfo);
  1263.     }
  1264. }
  1265. void CObjectOStreamXml::EndClass(void)
  1266. {
  1267.     if (!m_Attlist && m_LastTagAction != eTagSelfClosed) {
  1268.         EolIfEmptyTag();
  1269.     }
  1270.     CloseTagIfNamed(TopFrame().GetTypeInfo());
  1271.     x_EndTypeNamespace();
  1272. }
  1273. void CObjectOStreamXml::BeginClassMember(const CMemberId& id)
  1274. {
  1275.     const CClassTypeInfoBase* classType = dynamic_cast<const CClassTypeInfoBase*>
  1276.         (FetchFrameFromTop(1).GetTypeInfo());
  1277.     _ASSERT(classType);
  1278.     BeginClassMember(classType->GetItemInfo(id.GetName())->GetTypeInfo(),id);
  1279. }
  1280. void CObjectOStreamXml::BeginClassMember(TTypeInfo memberType,
  1281.                                          const CMemberId& id)
  1282. {
  1283.     if (x_IsStdXml()) {
  1284.         if(id.IsAttlist()) {
  1285.             if(m_LastTagAction == eTagClose) {
  1286.                 OpenTagEndBack();
  1287.             }
  1288.             m_Attlist = true;
  1289.             TopFrame().SetNotag();
  1290.         } else {
  1291.             ETypeFamily type = GetRealTypeFamily(memberType);
  1292.             bool needTag = true;
  1293.             if (GetEnforcedStdXml()) {
  1294.                 if (type == eTypeFamilyContainer) {
  1295.                     needTag = (GetContainerElementTypeFamily(memberType) !=
  1296.                                eTypeFamilyPrimitive);
  1297.                 }
  1298.             } else {
  1299.                 needTag = (type == eTypeFamilyPrimitive && !id.HasNotag());
  1300.             }
  1301.             if (needTag) {
  1302.                 OpenStackTag(0);
  1303.             } else {
  1304.                 TopFrame().SetNotag();
  1305.             }
  1306.         }
  1307.     } else {
  1308.         OpenStackTag(0);
  1309.     }
  1310. }
  1311. void CObjectOStreamXml::EndClassMember(void)
  1312. {
  1313.     if (TopFrame().GetNotag()) {
  1314.         TopFrame().SetNotag(false);
  1315.         m_Attlist = false;
  1316.         if(m_LastTagAction == eTagOpen) {
  1317.             OpenTagEnd();
  1318.         }
  1319.     } else {
  1320.         CloseStackTag(0);
  1321.     }
  1322. }
  1323. #ifdef VIRTUAL_MID_LEVEL_IO
  1324. void CObjectOStreamXml::WriteClass(const CClassTypeInfo* classType,
  1325.                                    TConstObjectPtr classPtr)
  1326. {
  1327.     if ( !classType->GetName().empty() ) {
  1328.         BEGIN_OBJECT_FRAME2(eFrameClass, classType);
  1329.         BeginClass(classType);
  1330.         for ( CClassTypeInfo::CIterator i(classType); i.Valid(); ++i ) {
  1331.             classType->GetMemberInfo(i)->WriteMember(*this, classPtr);
  1332.         }
  1333.         EndClass();
  1334.         END_OBJECT_FRAME();
  1335.     }
  1336.     else {
  1337.         for ( CClassTypeInfo::CIterator i(classType); i.Valid(); ++i ) {
  1338.             classType->GetMemberInfo(i)->WriteMember(*this, classPtr);
  1339.         }
  1340.     }
  1341. }
  1342. void CObjectOStreamXml::WriteClassMember(const CMemberId& memberId,
  1343.                                          TTypeInfo memberType,
  1344.                                          TConstObjectPtr memberPtr)
  1345. {
  1346.     BEGIN_OBJECT_FRAME2(eFrameClassMember,memberId);
  1347.     BeginClassMember(memberType,memberId);
  1348.     WriteObject(memberPtr, memberType);
  1349.     EndClassMember();
  1350.     END_OBJECT_FRAME();
  1351. }
  1352. bool CObjectOStreamXml::WriteClassMember(const CMemberId& memberId,
  1353.                                          const CDelayBuffer& buffer)
  1354. {
  1355.     if ( !buffer.HaveFormat(eSerial_Xml) )
  1356.         return false;
  1357.     BEGIN_OBJECT_FRAME2(eFrameClassMember, memberId);
  1358.     OpenStackTag(0);
  1359.     
  1360.     Write(buffer.GetSource());
  1361.     
  1362.     CloseStackTag(0);
  1363.     END_OBJECT_FRAME();
  1364.     return true;
  1365. }
  1366. #endif
  1367. void CObjectOStreamXml::BeginChoice(const CChoiceTypeInfo* choiceType)
  1368. {
  1369.     CheckStdXml(choiceType);
  1370.     bool needNs = x_ProcessTypeNamespace(choiceType);
  1371.     OpenTagIfNamed(choiceType);
  1372.     if (needNs) {
  1373.         x_WriteClassNamespace(choiceType);
  1374.     }
  1375. }
  1376. void CObjectOStreamXml::EndChoice(void)
  1377. {
  1378.     CloseTagIfNamed(TopFrame().GetTypeInfo());
  1379.     x_EndTypeNamespace();
  1380. }
  1381. void CObjectOStreamXml::BeginChoiceVariant(const CChoiceTypeInfo* choiceType,
  1382.                                            const CMemberId& id)
  1383. {
  1384.     if (x_IsStdXml()) {
  1385.         const CVariantInfo* var_info = choiceType->GetVariantInfo(id.GetName());
  1386.         ETypeFamily type = GetRealTypeFamily(var_info->GetTypeInfo());
  1387.         bool needTag = true;
  1388.         if (GetEnforcedStdXml()) {
  1389.             if (type == eTypeFamilyContainer) {
  1390.                 needTag = (GetContainerElementTypeFamily(
  1391.                     var_info->GetTypeInfo()) != eTypeFamilyPrimitive);
  1392.             }
  1393.         } else {
  1394.             needTag = (type == eTypeFamilyPrimitive && !id.HasNotag());
  1395.         }
  1396.         if (needTag) {
  1397.             OpenStackTag(0);
  1398.         } else {
  1399.             TopFrame().SetNotag();
  1400.         }
  1401.     } else {
  1402.         OpenStackTag(0);
  1403.     }
  1404. }
  1405. void CObjectOStreamXml::EndChoiceVariant(void)
  1406. {
  1407.     if (TopFrame().GetNotag()) {
  1408.         TopFrame().SetNotag(false);
  1409.     } else {
  1410.         CloseStackTag(0);
  1411.     }
  1412. }
  1413. #ifdef VIRTUAL_MID_LEVEL_IO
  1414. void CObjectOStreamXml::WriteChoice(const CChoiceTypeInfo* choiceType,
  1415.                                     TConstObjectPtr choicePtr)
  1416. {
  1417.     if ( !choiceType->GetName().empty() ) {
  1418.         BEGIN_OBJECT_FRAME2(eFrameChoice, choiceType);
  1419.         OpenTag(choiceType);
  1420.         WriteChoiceContents(choiceType, choicePtr);
  1421.         CloseTag(choiceType);
  1422.         END_OBJECT_FRAME();
  1423.     }
  1424.     else {
  1425.         WriteChoiceContents(choiceType, choicePtr);
  1426.     }
  1427. }
  1428. void CObjectOStreamXml::WriteChoiceContents(const CChoiceTypeInfo* choiceType,
  1429.                                             TConstObjectPtr choicePtr)
  1430. {
  1431.     TMemberIndex index = choiceType->GetIndex(choicePtr);
  1432.     const CVariantInfo* variantInfo = choiceType->GetVariantInfo(index);
  1433.     BEGIN_OBJECT_FRAME2(eFrameChoiceVariant, variantInfo->GetId());
  1434.     OpenStackTag(0);
  1435.     
  1436.     variantInfo->WriteVariant(*this, choicePtr);
  1437.     
  1438.     CloseStackTag(0);
  1439.     END_OBJECT_FRAME();
  1440. }
  1441. #endif
  1442. static const char* const HEX = "0123456789ABCDEF";
  1443. void CObjectOStreamXml::WriteBytes(const ByteBlock& ,
  1444.                                    const char* bytes, size_t length)
  1445. {
  1446.     while ( length-- > 0 ) {
  1447.         char c = *bytes++;
  1448.         m_Output.PutChar(HEX[(c >> 4) & 0xf]);
  1449.         m_Output.PutChar(HEX[c & 0xf]);
  1450.     }
  1451. }
  1452. void CObjectOStreamXml::WriteChars(const CharBlock& ,
  1453.                                    const char* chars, size_t length)
  1454. {
  1455.     while ( length-- > 0 ) {
  1456.         char c = *chars++;
  1457.         WriteEscapedChar(c);
  1458.     }
  1459. }
  1460. void CObjectOStreamXml::WriteSeparator(void)
  1461. {
  1462.     m_Output.PutString(GetSeparator());
  1463. }
  1464. #if defined(NCBI_SERIAL_IO_TRACE)
  1465. void CObjectOStreamXml::TraceTag(const string& name)
  1466. {
  1467.     cout << ", Tag=" << name;
  1468. }
  1469. #endif
  1470. END_NCBI_SCOPE