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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: objistrxml.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 19:41:03  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.61
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: objistrxml.cpp,v 1000.3 2004/06/01 19:41:03 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. *   !!! PUT YOUR DESCRIPTION HERE !!!
  38. *
  39. * ---------------------------------------------------------------------------
  40. * $Log: objistrxml.cpp,v $
  41. * Revision 1000.3  2004/06/01 19:41:03  gouriano
  42. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.61
  43. *
  44. * Revision 1.61  2004/05/19 17:26:19  gouriano
  45. * Corrected serialization of containers when the code was generated by DTD
  46. *
  47. * Revision 1.60  2004/05/17 21:03:03  gorelenk
  48. * Added include of PCH ncbi_pch.hpp
  49. *
  50. * Revision 1.59  2004/04/28 19:24:29  gouriano
  51. * Corrected reading of containers
  52. *
  53. * Revision 1.58  2004/03/23 15:39:23  gouriano
  54. * Added setup options for skipping unknown data members
  55. *
  56. * Revision 1.57  2004/03/05 20:29:38  gouriano
  57. * make it possible to skip unknown data fields
  58. *
  59. * Revision 1.56  2004/01/30 20:29:56  gouriano
  60. * Corrected reading white spaces
  61. *
  62. * Revision 1.55  2004/01/29 20:48:07  gouriano
  63. * Corrected handling of white spaces in XML tags: preserve insignificant
  64. * white spaces inside the tag.
  65. * Corrected reading of AnyContent object attributes and tags with empty content
  66. *
  67. * Revision 1.54  2004/01/22 20:50:17  gouriano
  68. * corrected reading of undefined attributes, of boolean values, of tags with empty content
  69. *
  70. * Revision 1.53  2004/01/12 16:52:58  gouriano
  71. * Corrected reading EMPTY tag value. Added skipping undescribed class member attributes.
  72. *
  73. * Revision 1.52  2004/01/08 18:16:53  gouriano
  74. * correction when skipping end of line
  75. *
  76. * Revision 1.51  2004/01/08 17:40:53  gouriano
  77. * Added encoding Windows-1252.
  78. * Corrected reading of containers.
  79. * Made it possible to read a choice variant, which is am empty container.
  80. *
  81. * Revision 1.50  2003/11/26 19:59:40  vasilche
  82. * GetPosition() and GetDataFormat() methods now are implemented
  83. * in parent classes CObjectIStream and CObjectOStream to avoid
  84. * pure virtual method call in destructors.
  85. *
  86. * Revision 1.49  2003/09/25 19:44:08  gouriano
  87. * Corrected serialization of AnyContent object's attributes
  88. *
  89. * Revision 1.48  2003/09/16 14:48:36  gouriano
  90. * Enhanced AnyContent objects to support XML namespaces and attribute info items.
  91. *
  92. * Revision 1.47  2003/08/25 15:59:09  gouriano
  93. * added possibility to use namespaces in XML i/o streams
  94. *
  95. * Revision 1.46  2003/08/14 20:03:58  vasilche
  96. * Avoid memory reallocation when reading over preallocated object.
  97. * Simplified CContainerTypeInfo iterators interface.
  98. *
  99. * Revision 1.45  2003/08/13 15:47:45  gouriano
  100. * implemented serialization of AnyContent objects
  101. *
  102. * Revision 1.44  2003/07/02 13:01:29  gouriano
  103. * added ability to read/write XML files with reference to schema
  104. *
  105. * Revision 1.43  2003/06/30 15:39:48  gouriano
  106. * added encoding (utf-8 or iso-8859-1)
  107. *
  108. * Revision 1.42  2003/06/24 20:57:36  gouriano
  109. * corrected code generation and serialization of non-empty unnamed containers (XML)
  110. *
  111. * Revision 1.41  2003/05/22 20:10:02  gouriano
  112. * added UTF8 strings
  113. *
  114. * Revision 1.40  2003/05/16 18:02:18  gouriano
  115. * revised exception error messages
  116. *
  117. * Revision 1.39  2003/05/05 20:09:10  gouriano
  118. * fixed "skipping" an object
  119. *
  120. * Revision 1.38  2003/03/26 16:14:23  vasilche
  121. * Removed TAB symbols. Some formatting.
  122. *
  123. * Revision 1.37  2003/02/07 16:09:22  gouriano
  124. * correction of GetContainerElementTypeFamily for the case of copying objects
  125. *
  126. * Revision 1.36  2003/02/05 17:08:01  gouriano
  127. * added possibility to read/write objects generated from an ASN.1 spec as "standard" XML - without scope prefixes
  128. *
  129. * Revision 1.35  2003/01/21 19:32:27  gouriano
  130. * corrected reading containers of primitive types
  131. *
  132. * Revision 1.34  2002/12/26 19:32:33  gouriano
  133. * changed XML I/O streams to properly handle object copying
  134. *
  135. * Revision 1.33  2002/12/17 19:04:32  gouriano
  136. * corrected reading/writing of character references
  137. *
  138. * Revision 1.32  2002/12/13 21:50:42  gouriano
  139. * corrected reading of choices
  140. *
  141. * Revision 1.31  2002/12/12 21:08:07  gouriano
  142. * implemented handling of complex XML containers
  143. *
  144. * Revision 1.30  2002/11/26 22:09:02  gouriano
  145. * added HasMoreElements method,
  146. * added unnamed lists of sequences (choices) as container elements
  147. *
  148. * Revision 1.29  2002/11/20 21:22:51  gouriano
  149. * corrected processing of unnamed sequences as choice variants
  150. *
  151. * Revision 1.28  2002/11/19 19:48:52  gouriano
  152. * added support of XML attributes of choice variants
  153. *
  154. * Revision 1.27  2002/11/15 20:33:12  gouriano
  155. * support of XML attributes of empty elements
  156. *
  157. * Revision 1.26  2002/11/14 20:58:54  gouriano
  158. * added support of XML attribute lists
  159. *
  160. * Revision 1.25  2002/10/25 14:49:27  vasilche
  161. * NCBI C Toolkit compatibility code extracted to libxcser library.
  162. * Serial streams flags names were renamed to fXxx.
  163. *
  164. * Names of flags
  165. *
  166. * Revision 1.24  2002/10/15 13:47:59  gouriano
  167. * modified to handle "standard" (generated from DTD) XML i/o
  168. *
  169. * Revision 1.23  2002/09/26 18:11:01  gouriano
  170. * added more checks for MemberId
  171. *
  172. * Revision 1.22  2002/09/25 19:37:36  gouriano
  173. * added the possibility of having no tag prefix in XML I/O streams
  174. *
  175. * Revision 1.21  2001/11/13 20:53:36  grichenk
  176. * Fixed comments reading
  177. *
  178. * Revision 1.20  2001/10/17 20:41:24  grichenk
  179. * Added CObjectOStream::CharBlock class
  180. *
  181. * Revision 1.19  2001/08/08 18:35:09  grichenk
  182. * ReadTagData() -- added memory pre-allocation for long strings
  183. *
  184. * Revision 1.18  2001/05/17 15:07:08  lavr
  185. * Typos corrected
  186. *
  187. * Revision 1.17  2000/12/26 22:24:12  vasilche
  188. * Fixed errors of compilation on Mac.
  189. *
  190. * Revision 1.16  2000/12/15 15:38:44  vasilche
  191. * Added support of Int8 and long double.
  192. * Enum values now have type Int4 instead of long.
  193. *
  194. * Revision 1.15  2000/11/07 17:25:40  vasilche
  195. * Fixed encoding of XML:
  196. *     removed unnecessary apostrophes in OCTET STRING
  197. *     removed unnecessary content in NULL
  198. * Added module names to CTypeInfo and CEnumeratedTypeValues
  199. *
  200. * Revision 1.14  2000/10/20 15:51:41  vasilche
  201. * Fixed data error processing.
  202. * Added interface for constructing container objects directly into output stream.
  203. * object.hpp, object.inl and object.cpp were split to
  204. * objectinfo.*, objecttype.*, objectiter.* and objectio.*.
  205. *
  206. * Revision 1.13  2000/10/13 20:59:21  vasilche
  207. * Avoid using of ssize_t absent on some compilers.
  208. *
  209. * Revision 1.12  2000/10/13 20:22:55  vasilche
  210. * Fixed warnings on 64 bit compilers.
  211. * Fixed missing typename in templates.
  212. *
  213. * Revision 1.11  2000/10/03 17:22:44  vasilche
  214. * Reduced header dependency.
  215. * Reduced size of debug libraries on WorkShop by 3 times.
  216. * Fixed tag allocation for parent classes.
  217. * Fixed CObject allocation/deallocation in streams.
  218. * Moved instantiation of several templates in separate source file.
  219. *
  220. * Revision 1.10  2000/09/29 16:18:23  vasilche
  221. * Fixed binary format encoding/decoding on 64 bit compulers.
  222. * Implemented CWeakMap<> for automatic cleaning map entries.
  223. * Added cleaning local hooks via CWeakMap<>.
  224. * Renamed ReadTypeName -> ReadFileHeader, ENoTypeName -> ENoFileHeader.
  225. * Added some user interface methods to CObjectIStream, CObjectOStream and
  226. * CObjectStreamCopier.
  227. *
  228. * Revision 1.9  2000/09/18 20:00:24  vasilche
  229. * Separated CVariantInfo and CMemberInfo.
  230. * Implemented copy hooks.
  231. * All hooks now are stored in CTypeInfo/CMemberInfo/CVariantInfo.
  232. * Most type specific functions now are implemented via function pointers instead of virtual functions.
  233. *
  234. * Revision 1.8  2000/09/01 13:16:18  vasilche
  235. * Implemented class/container/choice iterators.
  236. * Implemented CObjectStreamCopier for copying data without loading into memory.
  237. *
  238. * Revision 1.7  2000/08/15 19:44:49  vasilche
  239. * Added Read/Write hooks:
  240. * CReadObjectHook/CWriteObjectHook for objects of specified type.
  241. * CReadClassMemberHook/CWriteClassMemberHook for specified members.
  242. * CReadChoiceVariantHook/CWriteChoiceVariant for specified choice variants.
  243. * CReadContainerElementHook/CWriteContainerElementsHook for containers.
  244. *
  245. * Revision 1.6  2000/07/03 20:47:23  vasilche
  246. * Removed unused variables/functions.
  247. *
  248. * Revision 1.5  2000/07/03 18:42:45  vasilche
  249. * Added interface to typeinfo via CObjectInfo and CConstObjectInfo.
  250. * Reduced header dependency.
  251. *
  252. * Revision 1.4  2000/06/16 19:24:22  vasilche
  253. * Updated MSVC project.
  254. * Fixed error on MSVC with static const class member.
  255. *
  256. * Revision 1.3  2000/06/16 16:31:20  vasilche
  257. * Changed implementation of choices and classes info to allow use of the same classes in generated and user written classes.
  258. *
  259. * Revision 1.2  2000/06/07 19:45:59  vasilche
  260. * Some code cleaning.
  261. * Macros renaming in more clear way.
  262. * BEGIN_NAMED_*_INFO, ADD_*_MEMBER, ADD_NAMED_*_MEMBER.
  263. *
  264. * Revision 1.1  2000/06/01 19:07:04  vasilche
  265. * Added parsing of XML data.
  266. *
  267. * ===========================================================================
  268. */
  269. #include <ncbi_pch.hpp>
  270. #include <corelib/ncbistd.hpp>
  271. #include <serial/objistrxml.hpp>
  272. #include <serial/enumvalues.hpp>
  273. #include <serial/objhook.hpp>
  274. #include <serial/classinfo.hpp>
  275. #include <serial/choice.hpp>
  276. #include <serial/ptrinfo.hpp>
  277. #include <serial/continfo.hpp>
  278. #include <serial/memberlist.hpp>
  279. #include <serial/memberid.hpp>
  280. BEGIN_NCBI_SCOPE
  281. CObjectIStream* CObjectIStream::CreateObjectIStreamXml()
  282. {
  283.     return new CObjectIStreamXml();
  284. }
  285. CObjectIStreamXml::CObjectIStreamXml(void)
  286.     : CObjectIStream(eSerial_Xml),
  287.       m_TagState(eTagOutside), m_Attlist(false),
  288.       m_StdXml(false), m_EnforcedStdXml(false),
  289.       m_Encoding( eEncoding_Unknown )
  290. {
  291. }
  292. CObjectIStreamXml::~CObjectIStreamXml(void)
  293. {
  294. }
  295. CObjectIStreamXml::EEncoding CObjectIStreamXml::GetEncoding(void) const
  296. {
  297.     return m_Encoding;
  298. }
  299. string CObjectIStreamXml::GetPosition(void) const
  300. {
  301.     return "line "+NStr::UIntToString(m_Input.GetLine());
  302. }
  303. void CObjectIStreamXml::SetEnforcedStdXml(bool set)
  304. {
  305.     m_EnforcedStdXml = set;
  306.     if (m_EnforcedStdXml) {
  307.         m_StdXml = false;
  308.     }
  309. }
  310. static inline
  311. bool IsBaseChar(char c)
  312. {
  313.     return
  314.         c >= 'A' && c <='Z' ||
  315.         c >= 'a' && c <= 'z' ||
  316.         c >= 'xC0' && c <= 'xD6' ||
  317.         c >= 'xD8' && c <= 'xF6' ||
  318.         c >= 'xF8' && c <= 'xFF';
  319. }
  320. static inline
  321. bool IsDigit(char c)
  322. {
  323.     return c >= '0' && c <= '9';
  324. }
  325. static inline
  326. bool IsIdeographic(char /*c*/)
  327. {
  328.     return false;
  329. }
  330. static inline
  331. bool IsLetter(char c)
  332. {
  333.     return IsBaseChar(c) || IsIdeographic(c);
  334. }
  335. static inline
  336. bool IsFirstNameChar(char c)
  337. {
  338.     return IsLetter(c) || c == '_' || c == ':';
  339. }
  340. static inline
  341. bool IsCombiningChar(char /*c*/)
  342. {
  343.     return false;
  344. }
  345. static inline
  346. bool IsExtender(char c)
  347. {
  348.     return c == 'xB7';
  349. }
  350. static inline
  351. bool IsNameChar(char c)
  352. {
  353.     return IsFirstNameChar(c) ||
  354.         IsDigit(c) || c == '.' || c == '-' ||
  355.         IsCombiningChar(c) || IsExtender(c);
  356. }
  357. static inline
  358. bool IsWhiteSpace(char c)
  359. {
  360.     return c == ' ' || c == 't' || c == 'n' || c == 'r';
  361. }
  362. static inline
  363. bool IsEndOfTagChar(char c)
  364. {
  365.     return c == '>' || c == '/';
  366. }
  367. char CObjectIStreamXml::SkipWS(void)
  368. {
  369.     _ASSERT(InsideTag());
  370.     for ( ;; ) {
  371.         char c = m_Input.SkipSpaces();
  372.         switch ( c ) {
  373.         case 't':
  374.             m_Input.SkipChar();
  375.             continue;
  376.         case 'r':
  377.         case 'n':
  378.             m_Input.SkipChar();
  379.             m_Input.SkipEndOfLine(c);
  380.             continue;
  381.         default:
  382.             return c;
  383.         }
  384.     }
  385. }
  386. char CObjectIStreamXml::SkipWSAndComments(void)
  387. {
  388.     _ASSERT(OutsideTag());
  389.     for ( ;; ) {
  390.         char c = m_Input.SkipSpaces();
  391.         switch ( c ) {
  392.         case 't':
  393.             m_Input.SkipChar();
  394.             continue;
  395.         case 'r':
  396.         case 'n':
  397.             m_Input.SkipChar();
  398.             m_Input.SkipEndOfLine(c);
  399.             continue;
  400.         case '<':
  401.             if ( m_Input.PeekChar(1) == '!' &&
  402.                  m_Input.PeekChar(2) == '-' &&
  403.                  m_Input.PeekChar(3) == '-' &&
  404.                  m_Input.PeekChar(4) != '-' ) {
  405.                 // start of comment
  406.                 m_Input.SkipChars(4);
  407.                 for ( ;; ) {
  408.                     m_Input.FindChar('-');
  409.                     if ( m_Input.PeekChar(1) == '-' ) {
  410.                         // --
  411.                         if ( m_Input.PeekChar(2) == '>' ) {
  412.                             // -->
  413.                             m_Input.SkipChars(3);
  414.                             break;
  415.                         }
  416.                         else {
  417.                             // --[^>]
  418.                             ThrowError(fFormatError,
  419.                                        "double dash '--' is not allowed in XML comments");
  420.                         }
  421.                     }
  422.                     else {
  423.                         // -[^-]
  424.                         m_Input.SkipChars(2);
  425.                     }
  426.                     
  427.                 }
  428.                 continue; // skip the next WS or comment
  429.             }
  430.             return '<';
  431.         default:
  432.             return c;
  433.         }
  434.     }
  435. }
  436. void CObjectIStreamXml::EndTag(void)
  437. {
  438.     char c = SkipWS();
  439.     if (m_Attlist) {
  440.         if (c == '=') {
  441.             m_Input.SkipChar();
  442.             c = SkipWS();
  443.             if (c == '"') {
  444.                 m_Input.SkipChar();
  445.                 return;
  446.             }
  447.         }
  448.         if (c == '"') {
  449.             m_Input.SkipChar();
  450.             m_TagState = eTagInsideOpening;
  451.             return;
  452.         }
  453.         if (c == '/' && m_Input.PeekChar(1) == '>' ) {
  454.             m_Input.SkipChars(2);
  455.             m_TagState = eTagInsideOpening;
  456.             Found_slash_gt();
  457.             return;
  458.         }
  459.     }
  460.     if ( c != '>' ) {
  461.         c = ReadUndefinedAttributes();
  462.         if ( c != '>' ) {
  463.             ThrowError(fFormatError, "'>' expected");
  464.         }
  465.     }
  466.     m_Input.SkipChar();
  467.     Found_gt();
  468. }
  469. bool CObjectIStreamXml::EndOpeningTagSelfClosed(void)
  470. {
  471.     if (TopFrame().GetNotag()) {
  472.         return SelfClosedTag();
  473.     }
  474.     _ASSERT(InsideOpeningTag());
  475.     char c = SkipWS();
  476.     if (m_Attlist) {
  477.         return false;
  478.     }
  479.     if ( c == '/' && m_Input.PeekChar(1) == '>' ) {
  480.         // end of self closed tag
  481.         m_Input.SkipChars(2);
  482.         Found_slash_gt();
  483.         return true;
  484.     }
  485.     if ( c != '>' ) {
  486.         c = ReadUndefinedAttributes();
  487.         if ( c == '/' && m_Input.PeekChar(1) == '>' ) {
  488.             // end of self closed tag
  489.             m_Input.SkipChars(2);
  490.             Found_slash_gt();
  491.             return true;
  492.         }
  493.         if ( c != '>' )
  494.             ThrowError(fFormatError, "end of tag expected");
  495.     }
  496.     // end of open tag
  497.     m_Input.SkipChar(); // '>'
  498.     Found_gt();
  499.     return false;
  500. }
  501. char CObjectIStreamXml::BeginOpeningTag(void)
  502. {
  503.     BeginData();
  504.     // find beginning '<'
  505.     char c = SkipWSAndComments();
  506.     if ( c != '<' )
  507.         ThrowError(fFormatError, "'<' expected");
  508.     c = m_Input.PeekChar(1);
  509.     if ( c == '/' )
  510.         ThrowError(fFormatError, "unexpected '</'");
  511.     m_Input.SkipChar();
  512.     Found_lt();
  513.     return c;
  514. }
  515. char CObjectIStreamXml::BeginClosingTag(void)
  516. {
  517.     BeginData();
  518.     // find beginning '<'
  519.     char c = SkipWSAndComments();
  520.     if ( c != '<' || m_Input.PeekChar(1) != '/' )
  521.         ThrowError(fFormatError, "'</' expected");
  522.     m_Input.SkipChars(2);
  523.     Found_lt_slash();
  524.     return m_Input.PeekChar();
  525. }
  526. CLightString CObjectIStreamXml::ReadName(char c)
  527. {
  528.     _ASSERT(InsideTag());
  529.     if ( !IsFirstNameChar(c) )
  530.         ThrowError(fFormatError,
  531.             "Name begins with an invalid character: #"
  532.             +NStr::UIntToString(c));
  533.     // find end of tag name
  534.     size_t i = 1, iColon = 0;
  535.     while ( IsNameChar(c = m_Input.PeekChar(i)) ) {
  536.         if (c == ':') {
  537.             iColon = i+1;
  538.         }
  539.         ++i;
  540.     }
  541.     // save beginning of tag name
  542.     const char* ptr = m_Input.GetCurrentPos();
  543.     // check end of tag name
  544.     m_Input.SkipChars(i);
  545.     if (c == 'n' || c == 'r') {
  546.         m_Input.SkipChar();
  547.         m_Input.SkipEndOfLine(c);
  548.     }
  549.     m_LastTag = CLightString(ptr+iColon, i-iColon);
  550.     if (iColon > 1) {
  551.         string ns_prefix( CLightString(ptr, iColon-1));
  552.         if (ns_prefix == "xmlns") {
  553.             string value;
  554.             ReadAttributeValue(value, true);
  555.             if (m_LastTag == m_CurrNsPrefix) {
  556.                 if (FetchFrameFromTop(1).HasTypeInfo()) {
  557.                     TTypeInfo type = FetchFrameFromTop(1).GetTypeInfo();
  558.                     type->SetNamespacePrefix(m_CurrNsPrefix);
  559.                     type->SetNamespaceName(value);
  560.                 }
  561.             }
  562.             m_NsPrefixToName[m_LastTag] = value;
  563.             m_NsNameToPrefix[value] = m_LastTag;
  564.             char ch = SkipWS();
  565.             return IsEndOfTagChar(ch) ? CLightString() : ReadName(ch);
  566.         } else if (ns_prefix == "xml") {
  567.             iColon = 0;
  568.         } else {
  569.             if (m_Attlist) {
  570.                 if (m_CurrNsPrefix != ns_prefix) {
  571.                     string value;
  572.                     ReadAttributeValue(value, true);
  573.                     char ch = SkipWS();
  574.                     return IsEndOfTagChar(ch) ? CLightString() : ReadName(ch);
  575.                 }
  576.             } else {
  577.                 m_CurrNsPrefix = ns_prefix;
  578.             }
  579.         }
  580.     } else {
  581.         m_CurrNsPrefix.erase();
  582.     }
  583. #if defined(NCBI_SERIAL_IO_TRACE)
  584.     cout << ", Read= " << m_LastTag;
  585. #endif
  586.     return CLightString(ptr+iColon, i-iColon);
  587. }
  588. CLightString CObjectIStreamXml::RejectedName(void)
  589. {
  590.     _ASSERT(!m_RejectedTag.empty());
  591.     m_LastTag = m_RejectedTag;
  592.     m_RejectedTag.erase();
  593.     m_TagState = eTagInsideOpening;
  594. #if defined(NCBI_SERIAL_IO_TRACE)
  595.     cout << ", Redo= " << m_LastTag;
  596. #endif
  597.     return m_LastTag;
  598. }
  599. void CObjectIStreamXml::SkipAttributeValue(char c)
  600. {
  601.     _ASSERT(InsideOpeningTag());
  602.     m_Input.SkipChar();
  603.     m_Input.FindChar(c);
  604.     m_Input.SkipChar();
  605. }
  606. void CObjectIStreamXml::SkipQDecl(void)
  607. {
  608.     _ASSERT(InsideOpeningTag());
  609.     m_Input.SkipChar();
  610.     CLightString tagName;
  611.     tagName = ReadName( SkipWS());
  612. //    _ASSERT(tagName == "xml");
  613.     for (;;) {
  614.         char ch = SkipWS();
  615.         if (ch == '?') {
  616.             break;
  617.         }
  618.         tagName = ReadName(ch);
  619.         string value;
  620.         ReadAttributeValue(value);
  621.         if (tagName == "encoding") {
  622.             if (value == "UTF-8") {
  623.                 m_Encoding = eEncoding_UTF8;
  624.             } else if (value == "ISO-8859-1") {
  625.                 m_Encoding = eEncoding_ISO8859_1;
  626.             } else if (value == "Windows-1252") {
  627.                 m_Encoding = eEncoding_Windows_1252;
  628.             } else {
  629.                 ThrowError(fFormatError, "unknown encoding: " + value);
  630.             }
  631.             break;
  632.         }
  633.     }
  634.     for ( ;; ) {
  635.         m_Input.FindChar('?');
  636.         if ( m_Input.PeekChar(1) == '>' ) {
  637.             // ?>
  638.             m_Input.SkipChars(2);
  639.             Found_gt();
  640.             return;
  641.         }
  642.         else
  643.             m_Input.SkipChar();
  644.     }
  645. }
  646. string CObjectIStreamXml::ReadFileHeader(void)
  647. {
  648.     for ( ;; ) {
  649.         switch ( BeginOpeningTag() ) {
  650.         case '?':
  651.             SkipQDecl();
  652.             break;
  653.         case '!':
  654.             {
  655.                 m_Input.SkipChar();
  656.                 CLightString tagName = ReadName(m_Input.PeekChar());
  657.                 if ( tagName == "DOCTYPE" ) {
  658.                     CLightString docType = ReadName(SkipWS());
  659.                     string typeName = docType;
  660.                     // skip the rest of !DOCTYPE
  661.                     for ( ;; ) {
  662.                         char c = SkipWS();
  663.                         if ( c == '>' ) {
  664.                             m_Input.SkipChar();
  665.                             Found_gt();
  666.                             return typeName;
  667.                         }
  668.                         else if ( c == '"' || c == ''' ) {
  669.                             SkipAttributeValue(c);
  670.                         }
  671.                         else {
  672.                             ReadName(c);
  673.                         }
  674.                     }
  675.                 }
  676.                 else {
  677.                     // unknown tag
  678.                     ThrowError(fFormatError,
  679.                         "unknown tag in file header: "+string(tagName));
  680.                 }
  681.             }
  682.         default:
  683.             {
  684.                 string typeName = ReadName(m_Input.PeekChar());
  685.                 UndoClassMember();
  686.                 return typeName;
  687.             }
  688. /*
  689.             m_Input.UngetChar('<');
  690.             Back_lt();
  691.             ThrowError(fFormatError, "unknown DOCTYPE");
  692. */
  693.         }
  694.     }
  695.     return NcbiEmptyString;
  696. }
  697. string CObjectIStreamXml::PeekNextTypeName(void)
  698. {
  699.     if (!m_RejectedTag.empty()) {
  700.         return m_RejectedTag;
  701.     }
  702.     string typeName = ReadName(BeginOpeningTag());
  703.     UndoClassMember();
  704.     return typeName;
  705. }
  706. void CObjectIStreamXml::x_EndTypeNamespace(void)
  707. {
  708.     if (x_IsStdXml()) {
  709.         if (TopFrame().HasTypeInfo()) {
  710.             TTypeInfo type = TopFrame().GetTypeInfo();
  711.             if (type->HasNamespaceName()) {
  712.                 string nsName = type->GetNamespaceName();
  713.                 string nsPrefix = m_NsNameToPrefix[nsName];
  714. // not sure about it - should we erase them or not?
  715. //                m_NsNameToPrefix.erase(nsName);
  716. //                m_NsPrefixToName.erase(nsPrefix);
  717.             }
  718.         }
  719.         if (GetStackDepth() <= 2) {
  720.             m_NsNameToPrefix.clear();
  721.             m_NsPrefixToName.clear();
  722.         }
  723.     }
  724. }
  725. int CObjectIStreamXml::ReadEscapedChar(char endingChar, bool* encoded)
  726. {
  727.     char c = m_Input.PeekChar();
  728.     if (encoded) {
  729.         *encoded = false;
  730.     }
  731.     if ( c == '&' ) {
  732.         if (encoded) {
  733.             *encoded = true;
  734.         }
  735.         m_Input.SkipChar();
  736.         const size_t limit = 32;
  737.         size_t offset = m_Input.PeekFindChar(';', limit);
  738.         if ( offset >= limit )
  739.             ThrowError(fFormatError, "entity reference is too long");
  740.         const char* p = m_Input.GetCurrentPos(); // save entity string pointer
  741.         m_Input.SkipChars(offset + 1); // skip it
  742.         if ( offset == 0 )
  743.             ThrowError(fFormatError, "invalid entity reference");
  744.         if ( *p == '#' ) {
  745.             const char* end = p + offset;
  746.             ++p;
  747.             // char ref
  748.             if ( p == end )
  749.                 ThrowError(fFormatError, "invalid char reference");
  750.             unsigned v = 0;
  751.             if ( *p == 'x' ) {
  752.                 // hex
  753.                 if ( ++p == end )
  754.                     ThrowError(fFormatError, "invalid char reference");
  755.                 do {
  756.                     c = *p++;
  757.                     if ( c >= '0' && c <= '9' )
  758.                         v = v * 16 + (c - '0');
  759.                     else if ( c >= 'A' && c <='F' )
  760.                         v = v * 16 + (c - 'A' + 0xA);
  761.                     else if ( c >= 'a' && c <='f' )
  762.                         v = v * 16 + (c - 'a' + 0xA);
  763.                     else
  764.                         ThrowError(fFormatError,
  765.                             "invalid symbol in char reference");
  766.                 } while ( p < end );
  767.             }
  768.             else {
  769.                 // dec
  770.                 if ( p == end )
  771.                     ThrowError(fFormatError, "invalid char reference");
  772.                 do {
  773.                     c = *p++;
  774.                     if ( c >= '0' && c <= '9' )
  775.                         v = v * 10 + (c - '0');
  776.                     else
  777.                         ThrowError(fFormatError,
  778.                             "invalid symbol in char reference");
  779.                 } while ( p < end );
  780.             }
  781.             return v & 0xFF;
  782.         }
  783.         else {
  784.             CLightString e(p, offset);
  785.             if ( e == "lt" )
  786.                 return '<';
  787.             if ( e == "gt" )
  788.                 return '>';
  789.             if ( e == "amp" )
  790.                 return '&';
  791.             if ( e == "apos" )
  792.                 return ''';
  793.             if ( e == "quot" )
  794.                 return '"';
  795.             ThrowError(fFormatError, "unknown entity name: " + string(e));
  796.         }
  797.     }
  798.     else if ( c == endingChar ) {
  799.         return -1;
  800.     }
  801.     if ((c & 0x80) != 0) {
  802.         if (m_Encoding == eEncoding_UTF8 || m_Encoding == eEncoding_Unknown) {
  803.             Uint1 ch = c;
  804.             Uint1 chRes = (ch & 0x1F);
  805.             m_Input.SkipChar();
  806.             ch = m_Input.PeekChar();
  807.             chRes = (chRes << 6) | (ch & 0x3F);
  808.             c = chRes;
  809.         }
  810.     }
  811.     m_Input.SkipChar();
  812.     return c & 0xFF;
  813. }
  814. CLightString CObjectIStreamXml::ReadAttributeName(void)
  815. {
  816.     if ( OutsideTag() )
  817.         ThrowError(fFormatError, "attribute expected");
  818.     return ReadName(SkipWS());
  819. }
  820. void CObjectIStreamXml::ReadAttributeValue(string& value, bool skipClosing)
  821. {
  822.     if ( SkipWS() != '=' )
  823.         ThrowError(fFormatError, "'=' expected");
  824.     m_Input.SkipChar(); // '='
  825.     char startChar = SkipWS();
  826.     if ( startChar != ''' && startChar != '"' )
  827.         ThrowError(fFormatError, "attribute value must start with ' or "");
  828.     m_Input.SkipChar();
  829.     for ( ;; ) {
  830.         int c = ReadEscapedChar(startChar);
  831.         if ( c < 0 )
  832.             break;
  833.         value += char(c);
  834.     }
  835.     if (!m_Attlist || skipClosing) {
  836.         m_Input.SkipChar();
  837.     }
  838. }
  839. char CObjectIStreamXml::ReadUndefinedAttributes(void)
  840. {
  841.     char c;
  842.     m_Attlist = true;
  843.     for (;;) {
  844.         c = SkipWS();
  845.         if (IsEndOfTagChar(c)) {
  846.             m_Attlist = false;
  847.             break;
  848.         }
  849.         CLightString tagName = ReadName(c);
  850.         if (tagName.GetLength()) {
  851.             string value;
  852.             ReadAttributeValue(value, true);
  853.         }
  854.     }
  855.     return c;
  856. }
  857. bool CObjectIStreamXml::ReadBool(void)
  858. {
  859.     CLightString attr;
  860.     while (HasAttlist()) {
  861.         attr = ReadAttributeName();
  862.         if ( attr == "value" ) {    
  863.             break;
  864.         }
  865.         string value;
  866.         ReadAttributeValue(value);
  867.     }
  868.     if ( attr != "value" ) {
  869.         EndOpeningTagSelfClosed();
  870.         ThrowError(fMissingValue,"attribute 'value' is missing");
  871.     }
  872.     string sValue;
  873.     ReadAttributeValue(sValue);
  874.     bool value;
  875.     if ( sValue == "true" )
  876.         value = true;
  877.     else {
  878.         if ( sValue != "false" ) {
  879.             ThrowError(fFormatError,
  880.                        "'true' or 'false' attrubute value expected: "+sValue);
  881.         }
  882.         value = false;
  883.     }
  884.     if ( !EndOpeningTagSelfClosed() && !NextTagIsClosing() )
  885.         ThrowError(fFormatError, "boolean tag must have empty contents");
  886.     return value;
  887. }
  888. char CObjectIStreamXml::ReadChar(void)
  889. {
  890.     BeginData();
  891.     int c = ReadEscapedChar('<');
  892.     if ( c < 0 || m_Input.PeekChar() != '<' )
  893.         ThrowError(fFormatError, "one char tag content expected");
  894.     return c;
  895. }
  896. Int4 CObjectIStreamXml::ReadInt4(void)
  897. {
  898.     BeginData();
  899.     return m_Input.GetInt4();
  900. }
  901. Uint4 CObjectIStreamXml::ReadUint4(void)
  902. {
  903.     BeginData();
  904.     return m_Input.GetUint4();
  905. }
  906. Int8 CObjectIStreamXml::ReadInt8(void)
  907. {
  908.     BeginData();
  909.     return m_Input.GetInt8();
  910. }
  911. Uint8 CObjectIStreamXml::ReadUint8(void)
  912. {
  913.     BeginData();
  914.     return m_Input.GetUint8();
  915. }
  916. double CObjectIStreamXml::ReadDouble(void)
  917. {
  918.     string s;
  919.     ReadTagData(s);
  920.     char* endptr;
  921.     double data = strtod(s.c_str(), &endptr);
  922.     if ( *endptr != 0 )
  923.         ThrowError(fFormatError, "invalid float number");
  924.     return data;
  925. }
  926. void CObjectIStreamXml::ReadNull(void)
  927. {
  928.     if ( !EndOpeningTagSelfClosed() && !NextTagIsClosing() )
  929.         ThrowError(fFormatError, "empty tag expected");
  930. }
  931. void CObjectIStreamXml::ReadAnyContentTo(
  932.     const string& ns_prefix, string& value, const CLightString& tagName)
  933. {
  934.     if (ThisTagIsSelfClosed()) {
  935.         EndSelfClosedTag();
  936.         return;
  937.     }
  938.     while (!NextTagIsClosing()) {
  939.         while (NextIsTag()) {
  940.             CLightString tagAny;
  941.             tagAny = ReadName(BeginOpeningTag());
  942.             value += '<';
  943.             value += tagAny;
  944.             while (HasAttlist()) {
  945.                 string attribName = ReadName(SkipWS());
  946.                 if (attribName.empty()) {
  947.                     break;
  948.                 }
  949.                 if (m_CurrNsPrefix.empty() || m_CurrNsPrefix == ns_prefix) {
  950.                     value += " ";
  951.                     value += attribName;
  952.                     value += "="";
  953.                     string attribValue;
  954.                     ReadAttributeValue(attribValue, true);
  955.                     value += attribValue;
  956.                     value += """;
  957.                 } else {
  958.                     // skip attrib from different namespaces
  959.                     string attribValue;
  960.                     ReadAttributeValue(attribValue, true);
  961.                 }
  962.             }
  963.             string value2;
  964.             ReadAnyContentTo(ns_prefix, value2,tagAny);
  965.             if (value2.empty()) {
  966.                 value += "/>";
  967.             } else {
  968.                 value += '>';
  969.                 value += value2;
  970.                 value += "</";
  971.                 value += tagAny;
  972.                 value += '>';
  973.             }
  974.         }
  975.         string data;
  976.         ReadTagData(data);
  977.         value += data;
  978.     }
  979.     CloseTag(tagName);
  980. }
  981. void CObjectIStreamXml::ReadAnyContentObject(CAnyContentObject& obj)
  982. {
  983.     BEGIN_OBJECT_FRAME(eFrameOther);
  984.     CLightString tagName;
  985.     if (m_RejectedTag.empty()) {
  986.         tagName = ReadName(BeginOpeningTag());
  987.     } else {
  988.         tagName = RejectedName();
  989.     }
  990.     obj.SetName( tagName);
  991.     string ns_prefix(m_CurrNsPrefix);
  992.     while (HasAttlist()) {
  993.         string attribName = ReadName(SkipWS());
  994.         if (attribName.empty()) {
  995.             break;
  996.         }
  997.         string value;
  998.         ReadAttributeValue(value, true);
  999.         obj.AddAttribute( attribName, m_NsPrefixToName[m_CurrNsPrefix],value);
  1000.     }
  1001.     obj.SetNamespacePrefix(ns_prefix);
  1002.     obj.SetNamespaceName(m_NsPrefixToName[ns_prefix]);
  1003.     string value;
  1004.     ReadAnyContentTo(ns_prefix,value,tagName);
  1005.     obj.SetValue(value);
  1006.     END_OBJECT_FRAME();
  1007. }
  1008. void CObjectIStreamXml::SkipAnyContentObject(void)
  1009. {
  1010.     CAnyContentObject obj;
  1011.     ReadAnyContentObject(obj);
  1012. }
  1013. void CObjectIStreamXml::ReadString(string& str, EStringType type)
  1014. {
  1015.     str.erase();
  1016.     if ( !EndOpeningTagSelfClosed() ) {
  1017.         EEncoding enc = m_Encoding;
  1018.         if (type == eStringTypeUTF8) {
  1019.             if (m_Encoding == eEncoding_UTF8 || m_Encoding == eEncoding_Unknown) {
  1020.                 m_Encoding = eEncoding_ISO8859_1;
  1021.             } else {
  1022.                 string tmp;
  1023.                 ReadTagData(tmp);
  1024.                 (static_cast<CStringUTF8&>(str)) = tmp;
  1025.                 return;
  1026.             }
  1027.         }
  1028.         ReadTagData(str);
  1029.         m_Encoding = enc;
  1030.     }
  1031. }
  1032. char* CObjectIStreamXml::ReadCString(void)
  1033. {
  1034.     if ( EndOpeningTagSelfClosed() ) {
  1035.         // null pointer string
  1036.         return 0;
  1037.     }
  1038.     string str;
  1039.     ReadTagData(str);
  1040.     return strdup(str.c_str());
  1041. }
  1042. void CObjectIStreamXml::ReadTagData(string& str)
  1043. {
  1044.     BeginData();
  1045.     bool skip_spaces = false;
  1046.     bool encoded = false;
  1047.     for ( ;; ) {
  1048.         int c = ReadEscapedChar(m_Attlist ? '"' : '<', &encoded);
  1049.         if ( c < 0 ) {
  1050.             break;
  1051.         }
  1052.         if (!encoded) {
  1053.             if (c == 'n' || c == 'r') {
  1054.                 skip_spaces = true;
  1055.                 continue;
  1056.             }
  1057.             if (skip_spaces) {
  1058.                 if (IsWhiteSpace(c)) {
  1059.                     continue;
  1060.                 } else {
  1061.                     skip_spaces = false;
  1062.                     str += ' ';
  1063.                 }
  1064.             }
  1065.         }
  1066.         str += char(c);
  1067.         // pre-allocate memory for long strings
  1068.         if ( str.size() > 128  &&  double(str.capacity())/(str.size()+1.0) < 1.1 ) {
  1069.             str.reserve(str.size()*2);
  1070.         }
  1071.     }
  1072.     str.reserve(str.size());
  1073. }
  1074. TEnumValueType CObjectIStreamXml::ReadEnum(const CEnumeratedTypeValues& values)
  1075. {
  1076.     const string& enumName = values.GetName();
  1077.     if ( !enumName.empty() ) {
  1078.         // global enum
  1079.         OpenTag(enumName);
  1080.         _ASSERT(InsideOpeningTag());
  1081.     }
  1082.     TEnumValueType value;
  1083.     if ( InsideOpeningTag() ) {
  1084.         // try to read attribute 'value'
  1085.         if ( IsEndOfTagChar( SkipWS()) ) {
  1086.             // no attribute
  1087.             if ( !values.IsInteger() )
  1088.                 ThrowError(fFormatError, "attribute 'value' expected");
  1089.             m_Input.SkipChar();
  1090.             Found_gt();
  1091.             BeginData();
  1092.             value = m_Input.GetInt4();
  1093.         }
  1094.         else {
  1095.             if (m_Attlist) {
  1096.                 string valueName;
  1097.                 ReadAttributeValue(valueName);
  1098.                 value = values.FindValue(valueName);
  1099.             } else {
  1100.                 CLightString attr;
  1101.                 while (HasAttlist()) {
  1102.                     attr = ReadAttributeName();
  1103.                     if ( attr == "value" ) {    
  1104.                         break;
  1105.                     }
  1106.                     string value;
  1107.                     ReadAttributeValue(value);
  1108.                 }
  1109.                 if ( attr != "value" ) {
  1110.                     EndOpeningTagSelfClosed();
  1111.                     ThrowError(fMissingValue,"attribute 'value' is missing");
  1112.                 }
  1113.                 string valueName;
  1114.                 ReadAttributeValue(valueName);
  1115.                 value = values.FindValue(valueName);
  1116.                 if ( !EndOpeningTagSelfClosed() && values.IsInteger() ) {
  1117.                     // read integer value
  1118.                     SkipWSAndComments();
  1119.                     if ( value != m_Input.GetInt4() )
  1120.                         ThrowError(fFormatError,
  1121.                                    "incompatible name and value of enum");
  1122.                 }
  1123.             }
  1124.         }
  1125.     }
  1126.     else {
  1127.         // outside of tag
  1128.         if ( !values.IsInteger() )
  1129.             ThrowError(fFormatError, "attribute 'value' expected");
  1130.         BeginData();
  1131.         value = m_Input.GetInt4();
  1132.     }
  1133.     if ( !enumName.empty() ) {
  1134.         // global enum
  1135.         CloseTag(enumName);
  1136.     }
  1137.     return value;
  1138. }
  1139. CObjectIStream::EPointerType CObjectIStreamXml::ReadPointerType(void)
  1140. {
  1141.     if ( !HasAttlist() && InsideOpeningTag() && EndOpeningTagSelfClosed() ) {
  1142.         // self closed tag
  1143.         return eNullPointer;
  1144.     }
  1145.     return eThisPointer;
  1146. }
  1147. CObjectIStreamXml::TObjectIndex CObjectIStreamXml::ReadObjectPointer(void)
  1148. {
  1149.     ThrowError(fIllegalCall, "unimplemented");
  1150.     return 0;
  1151. /*
  1152.     CLightString attr = ReadAttributeName();
  1153.     if ( attr != "index" )
  1154.         ThrowError(fIllegalCall, "attribute 'index' expected");
  1155.     string index;
  1156.     ReadAttributeValue(index);
  1157.     EndOpeningTagSelfClosed();
  1158.     return NStr::StringToInt(index);
  1159. */
  1160. }
  1161. string CObjectIStreamXml::ReadOtherPointer(void)
  1162. {
  1163.     ThrowError(fIllegalCall, "unimplemented");
  1164.     return NcbiEmptyString;
  1165. }
  1166. CLightString CObjectIStreamXml::SkipTagName(CLightString tag,
  1167.                                             const char* str, size_t length)
  1168. {
  1169.     if ( tag.GetLength() < length ||
  1170.          memcmp(tag.GetString(), str, length) != 0 )
  1171.         ThrowError(fFormatError, "invalid tag name: "+string(tag));
  1172.     return CLightString(tag.GetString() + length, tag.GetLength() - length);
  1173. }
  1174. CLightString CObjectIStreamXml::SkipStackTagName(CLightString tag,
  1175.                                                  size_t level)
  1176. {
  1177.     const TFrame& frame = FetchFrameFromTop(level);
  1178.     switch ( frame.GetFrameType() ) {
  1179.     case TFrame::eFrameNamed:
  1180.     case TFrame::eFrameArray:
  1181.     case TFrame::eFrameClass:
  1182.     case TFrame::eFrameChoice:
  1183.         {
  1184.             const string& name = frame.GetTypeInfo()->GetName();
  1185.             if ( !name.empty() )
  1186.                 return SkipTagName(tag, name);
  1187.             else
  1188.                 return SkipStackTagName(tag, level + 1);
  1189.         }
  1190.     case TFrame::eFrameClassMember:
  1191.     case TFrame::eFrameChoiceVariant:
  1192.         {
  1193.             tag = SkipStackTagName(tag, level + 1, '_');
  1194.             return SkipTagName(tag, frame.GetMemberId().GetName());
  1195.         }
  1196.     case TFrame::eFrameArrayElement:
  1197.         {
  1198.             tag = SkipStackTagName(tag, level + 1);
  1199.             return SkipTagName(tag, "_E");
  1200.         }
  1201.     default:
  1202.         break;
  1203.     }
  1204.     ThrowError(fIllegalCall, "illegal frame type");
  1205.     return tag;
  1206. }
  1207. CLightString CObjectIStreamXml::SkipStackTagName(CLightString tag,
  1208.                                                  size_t level, char c)
  1209. {
  1210.     tag = SkipStackTagName(tag, level);
  1211.     if ( tag.Empty() || *tag.GetString() != c )
  1212.         ThrowError(fFormatError, "invalid tag name: "+string(tag));
  1213.     return CLightString(tag.GetString() + 1, tag.GetLength() - 1);
  1214. }
  1215. void CObjectIStreamXml::OpenTag(const string& e)
  1216. {
  1217.     CLightString tagName;
  1218.     if (m_RejectedTag.empty()) {
  1219.         tagName = ReadName(BeginOpeningTag());
  1220.     } else {
  1221.         tagName = RejectedName();
  1222.     }
  1223.     if ( tagName != e )
  1224.         ThrowError(fFormatError, "tag '"+e+"' expected: "+string(tagName));
  1225. }
  1226. void CObjectIStreamXml::CloseTag(const string& e)
  1227. {
  1228.     if ( SelfClosedTag() ) {
  1229.         EndSelfClosedTag();
  1230.     }
  1231.     else {
  1232.         CLightString tagName = ReadName(BeginClosingTag());
  1233.         if ( tagName != e )
  1234.             ThrowError(fFormatError, "tag '"+e+"' expected: "+string(tagName));
  1235.         EndClosingTag();
  1236.     }
  1237. }
  1238. void CObjectIStreamXml::OpenStackTag(size_t level)
  1239. {
  1240.     CLightString tagName;
  1241.     if (m_RejectedTag.empty()) {
  1242.         tagName = ReadName(BeginOpeningTag());
  1243.         if (!x_IsStdXml()) {
  1244.             CLightString rest = SkipStackTagName(tagName, level);
  1245.             if ( !rest.Empty() )
  1246.                 ThrowError(fFormatError,
  1247.                     "unexpected tag: "+string(tagName)+string(rest));
  1248.         }
  1249.     } else {
  1250.         tagName = RejectedName();
  1251.     }
  1252. }
  1253. void CObjectIStreamXml::CloseStackTag(size_t level)
  1254. {
  1255.     if ( SelfClosedTag() ) {
  1256.         EndSelfClosedTag();
  1257.     }
  1258.     else {
  1259.         if (m_Attlist) {
  1260.             m_TagState = eTagInsideClosing;
  1261.         } else {
  1262.             CLightString tagName = ReadName(BeginClosingTag());
  1263.             if (!x_IsStdXml()) {
  1264.                 CLightString rest = SkipStackTagName(tagName, level);
  1265.                 if ( !rest.Empty() )
  1266.                     ThrowError(fFormatError,
  1267.                         "unexpected tag: "+string(tagName)+string(rest));
  1268.             }
  1269.         }
  1270.         EndClosingTag();
  1271.     }
  1272. }
  1273. void CObjectIStreamXml::OpenTagIfNamed(TTypeInfo type)
  1274. {
  1275.     if ( !type->GetName().empty() ) {
  1276.         OpenTag(type->GetName());
  1277.     }
  1278. }
  1279. void CObjectIStreamXml::CloseTagIfNamed(TTypeInfo type)
  1280. {
  1281.     if ( !type->GetName().empty() )
  1282.         CloseTag(type->GetName());
  1283. }
  1284. bool CObjectIStreamXml::WillHaveName(TTypeInfo elementType)
  1285. {
  1286.     while ( elementType->GetName().empty() ) {
  1287.         if ( elementType->GetTypeFamily() != eTypeFamilyPointer )
  1288.             return false;
  1289.         elementType = CTypeConverter<CPointerTypeInfo>::SafeCast(
  1290.             elementType)->GetPointedType();
  1291.     }
  1292.     // found named type
  1293.     return true;
  1294. }
  1295. bool CObjectIStreamXml::HasAttlist(void)
  1296. {
  1297.     if (InsideTag()) {
  1298.         return !IsEndOfTagChar( SkipWS() );
  1299.     }
  1300.     return false;
  1301. }
  1302. bool CObjectIStreamXml::NextIsTag(void)
  1303. {
  1304.     BeginData();
  1305.     return SkipWSAndComments() == '<' && m_Input.PeekChar(1) != '/';
  1306. }
  1307. bool CObjectIStreamXml::NextTagIsClosing(void)
  1308. {
  1309.     BeginData();
  1310.     return SkipWSAndComments() == '<' && m_Input.PeekChar(1) == '/';
  1311. }
  1312. bool CObjectIStreamXml::ThisTagIsSelfClosed(void)
  1313. {
  1314.     if (InsideOpeningTag()) {
  1315.         return EndOpeningTagSelfClosed();
  1316.     }
  1317.     return false;
  1318. }
  1319. void CObjectIStreamXml::BeginContainer(const CContainerTypeInfo* containerType)
  1320. {
  1321.     if (!x_IsStdXml()) {
  1322.         OpenTagIfNamed(containerType);
  1323.     }
  1324. }
  1325. void CObjectIStreamXml::EndContainer(void)
  1326. {
  1327.     if (!x_IsStdXml()) {
  1328.         CloseTagIfNamed(TopFrame().GetTypeInfo());
  1329.     }
  1330. }
  1331. bool CObjectIStreamXml::BeginContainerElement(TTypeInfo elementType)
  1332. {
  1333.     if (!HasMoreElements(elementType)) {
  1334.         return false;
  1335.     }
  1336.     if ( !WillHaveName(elementType) ) {
  1337.         BeginArrayElement(elementType);
  1338.     }
  1339.     return true;
  1340. }
  1341. void CObjectIStreamXml::EndContainerElement(void)
  1342. {
  1343.     if ( !WillHaveName(TopFrame().GetTypeInfo()) ) {
  1344.         EndArrayElement();
  1345.     }
  1346. }
  1347. #ifdef VIRTUAL_MID_LEVEL_IO
  1348. void CObjectIStreamXml::ReadContainer(const CContainerTypeInfo* containerType,
  1349.                                       TObjectPtr containerPtr)
  1350. {
  1351.     if ( containerType->GetName().empty() ) {
  1352.         ReadContainerContents(containerType, containerPtr);
  1353.     }
  1354.     else {
  1355.         BEGIN_OBJECT_FRAME2(eFrameArray, containerType);
  1356.         OpenTag(containerType);
  1357.         ReadContainerContents(containerType, containerPtr);
  1358.         CloseTag(containerType);
  1359.         END_OBJECT_FRAME();
  1360.     }
  1361. }
  1362. void CObjectIStreamXml::SkipContainer(const CContainerTypeInfo* containerType)
  1363. {
  1364.     if ( containerType->GetName().empty() ) {
  1365.         SkipContainerContents(containerType);
  1366.     }
  1367.     else {
  1368.         BEGIN_OBJECT_FRAME2(eFrameArray, containerType);
  1369.         OpenTag(containerType);
  1370.         SkipContainerContents(containerType);
  1371.         CloseTag(containerType);
  1372.         END_OBJECT_FRAME();
  1373.     }
  1374. }
  1375. bool CObjectIStreamXml::HasAnyContent(const CClassTypeInfoBase* classType)
  1376. {
  1377.     const CItemsInfo& items = classType->GetItems();
  1378.     if (items.Size() == 1) {
  1379.         const CItemInfo* itemInfo = items.GetItemInfo( items.FirstIndex());
  1380.         if (itemInfo->GetId().HasAnyContent()) {
  1381.             return true;
  1382.         }
  1383.     }
  1384.     return false;
  1385. }
  1386. bool CObjectIStreamXml::HasMoreElements(TTypeInfo elementType)
  1387. {
  1388.     if (ThisTagIsSelfClosed() || NextTagIsClosing()) {
  1389.         m_LastPrimitive.erase();
  1390.         return false;
  1391.     }
  1392.     if (x_IsStdXml()) {
  1393.         CLightString tagName;
  1394.         TTypeInfo type = elementType;
  1395.         // this is to handle STL containers of primitive types
  1396.         if (GetRealTypeFamily(type) == eTypeFamilyPrimitive) {
  1397.             if (!m_RejectedTag.empty()) {
  1398.                 m_LastPrimitive = m_RejectedTag;
  1399.                 return true;
  1400.             } else {
  1401.                 tagName = ReadName(BeginOpeningTag());
  1402.                 UndoClassMember();
  1403.                 bool res = (tagName == m_LastPrimitive);
  1404.                 if (!res) {
  1405.                     m_LastPrimitive.erase();
  1406.                 }
  1407.                 return res;
  1408.             }
  1409.         }
  1410.         if (type->GetTypeFamily() == eTypeFamilyPointer) {
  1411.             const CPointerTypeInfo* ptr =
  1412.                 dynamic_cast<const CPointerTypeInfo*>(type);
  1413.             if (ptr) {
  1414.                 type = ptr->GetPointedType();
  1415.             }
  1416.         }
  1417.         const CClassTypeInfoBase* classType =
  1418.             dynamic_cast<const CClassTypeInfoBase*>(type);
  1419.         if (classType) {
  1420.             if (m_RejectedTag.empty()) {
  1421.                 tagName = ReadName(BeginOpeningTag());
  1422.             } else {
  1423.                 tagName = RejectedName();
  1424.             }
  1425.             UndoClassMember();
  1426.             if (classType->GetName().empty()) {
  1427.                 return classType->GetItems().FindDeep(tagName) != kInvalidMember ||
  1428.                     HasAnyContent(classType);
  1429.             }
  1430.             return tagName == classType->GetName();
  1431.         }
  1432.     }
  1433.     return true;
  1434. }
  1435. TMemberIndex CObjectIStreamXml::FindDeep(TTypeInfo type,
  1436.                                          const CLightString& name) const
  1437. {
  1438.     for (;;) {
  1439.         if (type->GetTypeFamily() == eTypeFamilyContainer) {
  1440.             const CContainerTypeInfo* cont =
  1441.                 dynamic_cast<const CContainerTypeInfo*>(type);
  1442.             if (cont) {
  1443.                 type = cont->GetElementType();
  1444.             }
  1445.         } else if (type->GetTypeFamily() == eTypeFamilyPointer) {
  1446.             const CPointerTypeInfo* ptr =
  1447.                 dynamic_cast<const CPointerTypeInfo*>(type);
  1448.             if (ptr) {
  1449.                 type = ptr->GetPointedType();
  1450.             }
  1451.         } else {
  1452.             break;
  1453.         }
  1454.     }
  1455.     const CClassTypeInfoBase* classType =
  1456.         dynamic_cast<const CClassTypeInfoBase*>(type);
  1457.     if (classType) {
  1458.         TMemberIndex i = classType->GetItems().FindDeep(name);
  1459.         if (i != kInvalidMember) {
  1460.             return i;
  1461.         }
  1462.     }
  1463.     return kInvalidMember;
  1464. }
  1465. void CObjectIStreamXml::BeginArrayElement(TTypeInfo elementType)
  1466. {
  1467.     if (x_IsStdXml() && GetRealTypeFamily(elementType) != eTypeFamilyPrimitive) {
  1468.         TopFrame().SetNotag();
  1469.     } else {
  1470.         OpenStackTag(0);
  1471.     }
  1472. }
  1473. void CObjectIStreamXml::EndArrayElement(void)
  1474. {
  1475.     if (TopFrame().GetNotag()) {
  1476.         TopFrame().SetNotag(false);
  1477.     } else {
  1478.         CloseStackTag(0);
  1479.     }
  1480. }
  1481. void CObjectIStreamXml::ReadContainerContents(const CContainerTypeInfo* cType,
  1482.                                               TObjectPtr containerPtr)
  1483. {
  1484.     int count = 0;
  1485.     TTypeInfo elementType = cType->GetElementType();
  1486.     if ( !WillHaveName(elementType) ) {
  1487.         BEGIN_OBJECT_FRAME2(eFrameArrayElement, elementType);
  1488.         CContainerTypeInfo::CIterator iter;
  1489.         bool old_element = cType->InitIterator(iter, containerPtr);
  1490.         while ( HasMoreElements(elementType) ) {
  1491.             BeginArrayElement(elementType);
  1492.             do {
  1493.                 if ( old_element ) {
  1494.                     elementType->ReadData(*this, cType->GetElementPtr(iter));
  1495.                     old_element = cType->NextElement(iter);
  1496.                 }
  1497.                 else {
  1498.                     cType->AddElement(containerPtr, *this);
  1499.                 }
  1500.             } while (!m_RejectedTag.empty() &&
  1501.                      FindDeep(elementType,m_RejectedTag) != kInvalidMember);
  1502.             EndArrayElement();
  1503.             ++count;
  1504.         }
  1505.         if ( old_element ) {
  1506.             cType->EraseAllElements(iter);
  1507.         }
  1508.         END_OBJECT_FRAME();
  1509.     }
  1510.     else {
  1511.         CContainerTypeInfo::CIterator iter;
  1512.         bool old_element = cType->InitIterator(iter, containerPtr);
  1513.         while ( HasMoreElements(elementType) ) {
  1514.             if ( old_element ) {
  1515.                 elementType->ReadData(*this, cType->GetElementPtr(iter));
  1516.                 old_element = cType->NextElement(iter);
  1517.             }
  1518.             else {
  1519.                 cType->AddElement(containerPtr, *this);
  1520.             }
  1521.             ++count;
  1522.         }
  1523.         if ( old_element ) {
  1524.             cType->EraseAllElements(iter);
  1525.         }
  1526.     }
  1527.     if (count == 0) {
  1528.         const TFrame& frame = FetchFrameFromTop(0);
  1529.         if (frame.GetFrameType() == CObjectStackFrame::eFrameNamed) {
  1530.             const CClassTypeInfo* clType =
  1531.                 dynamic_cast<const CClassTypeInfo*>(frame.GetTypeInfo());
  1532.             if (clType && clType->Implicit() && clType->IsImplicitNonEmpty()) {
  1533.                 ThrowError(fFormatError, "container is empty");
  1534.             }
  1535.         }
  1536.     }
  1537. }
  1538. void CObjectIStreamXml::SkipContainerContents(const CContainerTypeInfo* cType)
  1539. {
  1540.     TTypeInfo elementType = cType->GetElementType();
  1541.     if ( !WillHaveName(elementType) ) {
  1542.         BEGIN_OBJECT_FRAME2(eFrameArrayElement, elementType);
  1543.         while ( HasMoreElements(elementType) ) {
  1544.             BeginArrayElement(elementType);
  1545.             SkipObject(elementType);
  1546.             EndArrayElement();
  1547.         }
  1548.         
  1549.         END_OBJECT_FRAME();
  1550.     }
  1551.     else {
  1552.         while ( HasMoreElements(elementType) ) {
  1553.             SkipObject(elementType);
  1554.         }
  1555.     }
  1556. }
  1557. #endif
  1558. void CObjectIStreamXml::BeginNamedType(TTypeInfo namedTypeInfo)
  1559. {
  1560.     const CClassTypeInfo* classType =
  1561.         dynamic_cast<const CClassTypeInfo*>(namedTypeInfo);
  1562.     if (classType) {
  1563.         CheckStdXml(classType);
  1564.     }
  1565.     OpenTag(namedTypeInfo);
  1566. }
  1567. void CObjectIStreamXml::EndNamedType(void)
  1568. {
  1569.     CloseTag(TopFrame().GetTypeInfo()->GetName());
  1570. }
  1571. #ifdef VIRTUAL_MID_LEVEL_IO
  1572. void CObjectIStreamXml::ReadNamedType(TTypeInfo namedTypeInfo,
  1573.                                       TTypeInfo typeInfo,
  1574.                                       TObjectPtr object)
  1575. {
  1576.     BEGIN_OBJECT_FRAME2(eFrameNamed, namedTypeInfo);
  1577.     BeginNamedType(namedTypeInfo);
  1578.     ReadObject(object, typeInfo);
  1579.     EndNamedType();
  1580.     END_OBJECT_FRAME();
  1581. }
  1582. #endif
  1583. void CObjectIStreamXml::CheckStdXml(const CClassTypeInfoBase* classType)
  1584. {
  1585.     if (m_EnforcedStdXml) {
  1586.         m_StdXml = false;
  1587.         return;
  1588.     }
  1589.     TMemberIndex first = classType->GetItems().FirstIndex();
  1590.     m_StdXml = classType->GetItems().GetItemInfo(first)->GetId().HaveNoPrefix();
  1591. }
  1592. ETypeFamily CObjectIStreamXml::GetRealTypeFamily(TTypeInfo typeInfo)
  1593. {
  1594.     ETypeFamily type = typeInfo->GetTypeFamily();
  1595.     if (type == eTypeFamilyPointer) {
  1596.         const CPointerTypeInfo* ptr =
  1597.             dynamic_cast<const CPointerTypeInfo*>(typeInfo);
  1598.         if (ptr) {
  1599.             type = ptr->GetPointedType()->GetTypeFamily();
  1600.         }
  1601.     }
  1602.     return type;
  1603. }
  1604. ETypeFamily CObjectIStreamXml::GetContainerElementTypeFamily(TTypeInfo typeInfo)
  1605. {
  1606.     if (typeInfo->GetTypeFamily() == eTypeFamilyPointer) {
  1607.         const CPointerTypeInfo* ptr =
  1608.             dynamic_cast<const CPointerTypeInfo*>(typeInfo);
  1609.         if (ptr) {
  1610.             typeInfo = ptr->GetPointedType();
  1611.         }
  1612.     }
  1613.     _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer);
  1614.     const CContainerTypeInfo* ptr =
  1615.         dynamic_cast<const CContainerTypeInfo*>(typeInfo);
  1616.     return GetRealTypeFamily(ptr->GetElementType());
  1617. }
  1618. void CObjectIStreamXml::BeginClass(const CClassTypeInfo* classInfo)
  1619. {
  1620.     CheckStdXml(classInfo);
  1621.     if (x_IsStdXml()) {
  1622.         if (m_Attlist || HasAttlist()) {
  1623.             TopFrame().SetNotag();
  1624.         } else {
  1625.             OpenTagIfNamed(classInfo);
  1626.         }
  1627.     } else {
  1628.         OpenTagIfNamed(classInfo);
  1629.     }
  1630. }
  1631. void CObjectIStreamXml::EndClass(void)
  1632. {
  1633.     if (TopFrame().GetNotag()) {
  1634.         TopFrame().SetNotag(false);
  1635.     } else {
  1636.         CloseTagIfNamed(TopFrame().GetTypeInfo());
  1637.     }
  1638.     x_EndTypeNamespace();
  1639. }
  1640. void CObjectIStreamXml::UnexpectedMember(const CLightString& id,
  1641.                                          const CItemsInfo& items)
  1642. {
  1643.     string message =
  1644.         """+string(id)+"": unexpected member, should be one of: ";
  1645.     for ( CItemsInfo::CIterator i(items); i.Valid(); ++i ) {
  1646.         message += '"' + items.GetItemInfo(i)->GetId().ToString() + "" ";
  1647.     }
  1648.     ThrowError(fFormatError, message);
  1649. }
  1650. TMemberIndex
  1651. CObjectIStreamXml::BeginClassMember(const CClassTypeInfo* classType)
  1652. {
  1653.     CLightString tagName;
  1654.     bool more;
  1655.     do {
  1656.         more = false;
  1657.         if (m_RejectedTag.empty()) {
  1658.             if (m_Attlist && InsideTag()) {
  1659.                 if (HasAttlist()) {
  1660.                     tagName = ReadName(SkipWS());
  1661.                 } else {
  1662.                     return kInvalidMember;
  1663.                 }
  1664.             } else {
  1665.                 if ( NextTagIsClosing() )
  1666.                     return kInvalidMember;
  1667.                 tagName = ReadName(BeginOpeningTag());
  1668.             }
  1669.         } else {
  1670.             tagName = RejectedName();
  1671.         }
  1672.         TMemberIndex ind = classType->GetMembers().Find(tagName);
  1673.         if ( ind != kInvalidMember ) {
  1674.             if (x_IsStdXml()) {
  1675.                 return ind;
  1676.             }
  1677.         }
  1678. // if it is an attribute list, but the tag is unrecognized - just skip it
  1679.         if (m_Attlist) {
  1680.             string value;
  1681.             ReadAttributeValue(value);
  1682.             m_Input.SkipChar();
  1683.             more = true;
  1684.         }
  1685.     } while (more);
  1686.     CLightString id = SkipStackTagName(tagName, 1, '_');
  1687.     TMemberIndex index = classType->GetMembers().Find(id);
  1688.     if ( index == kInvalidMember ) {
  1689.         if (GetSkipUnknownMembers() == eSerialSkipUnknown_Yes) {
  1690.             string value;
  1691.             ReadAnyContentTo(m_CurrNsPrefix,value, tagName);
  1692.             return BeginClassMember(classType);
  1693.         } else {
  1694.             UnexpectedMember(id, classType->GetMembers());
  1695.         }
  1696.     }
  1697.     return index;
  1698. }
  1699. TMemberIndex
  1700. CObjectIStreamXml::BeginClassMember(const CClassTypeInfo* classType,
  1701.                                     TMemberIndex pos)
  1702. {
  1703.     CLightString tagName;
  1704.     TMemberIndex first = classType->GetMembers().FirstIndex();
  1705.     if (m_RejectedTag.empty()) {
  1706.         if (m_Attlist && InsideTag()) {
  1707.             if (HasAttlist()) {
  1708.                 for (;;) {
  1709.                     char ch = SkipWS();
  1710.                     if (IsEndOfTagChar(ch)) {
  1711.                         return kInvalidMember;
  1712.                     }
  1713.                     tagName = ReadName(ch);
  1714.                     if (tagName.GetLength()) {
  1715.                         if (classType->GetMembers().Find(tagName) != kInvalidMember) {
  1716.                             break;
  1717.                         }
  1718.                         string value;
  1719.                         ReadAttributeValue(value, true);
  1720.                     }
  1721.                 }
  1722.             } else {
  1723.                 return kInvalidMember;
  1724.             }
  1725.         } else {
  1726.             if (!m_Attlist) {
  1727.                 if (pos == first) {
  1728.                     if (classType->GetMemberInfo(first)->GetId().IsAttlist()) {
  1729.                         m_Attlist = true;
  1730.                         if (m_TagState == eTagOutside) {
  1731.                             m_Input.UngetChar('>');
  1732.                             m_TagState = eTagInsideOpening;
  1733.                         }
  1734.                         return first;
  1735.                     }
  1736. // if class spec defines no attributes, but there are some - skip them
  1737.                     if (HasAttlist()) {
  1738.                         ReadUndefinedAttributes();
  1739.                     }
  1740.                 }
  1741.             }
  1742.             if (m_Attlist && !SelfClosedTag()) {
  1743.                 m_Attlist = false;
  1744.                 if ( NextTagIsClosing() )
  1745.                     return kInvalidMember;
  1746.                 if (!NextIsTag()) {
  1747.                     TMemberIndex ind = first+1;
  1748.                     if (classType->GetMemberInfo(ind)->GetId().HasNotag()) {
  1749.                         TopFrame().SetNotag();
  1750.                         return ind;
  1751.                     }
  1752.                 }
  1753.             }
  1754.             if ( SelfClosedTag()) {
  1755.                 TMemberIndex last = classType->GetMembers().LastIndex();
  1756.                 if (pos == last) {
  1757.                     if (classType->GetMemberInfo(pos)->GetId().HasNotag()) {
  1758.                         TopFrame().SetNotag();
  1759.                         return pos;
  1760.                     }
  1761.                 }
  1762.                 m_Attlist = false;
  1763.                 return kInvalidMember;
  1764.             }
  1765.             if ( NextTagIsClosing() )
  1766.                 return kInvalidMember;
  1767.             tagName = ReadName(BeginOpeningTag());
  1768.         }
  1769.     } else {
  1770.         tagName = RejectedName();
  1771.     }
  1772.     TMemberIndex ind = classType->GetMembers().Find(tagName);
  1773.     if (ind == kInvalidMember) {
  1774.         ind = classType->GetMembers().FindDeep(tagName);
  1775.         if (ind != kInvalidMember) {
  1776.             TopFrame().SetNotag();
  1777.             UndoClassMember();
  1778.             return ind;
  1779.         }
  1780.     } else {
  1781.         const CMemberInfo *mem_info = classType->GetMemberInfo(ind);
  1782.         if (x_IsStdXml()) {
  1783.             ETypeFamily type = GetRealTypeFamily(mem_info->GetTypeInfo());
  1784.             bool needUndo = false;
  1785.             if (GetEnforcedStdXml()) {
  1786.                 if (type == eTypeFamilyContainer) {
  1787.                     needUndo = (GetContainerElementTypeFamily(
  1788.                         mem_info->GetTypeInfo()) == eTypeFamilyPrimitive);
  1789.                 }
  1790.             } else {
  1791.                 needUndo = (type != eTypeFamilyPrimitive);
  1792.             }
  1793.             if (needUndo) {
  1794.                 TopFrame().SetNotag();
  1795.                 UndoClassMember();
  1796.             }
  1797.             return ind;
  1798.         }
  1799.     }
  1800.     if (x_IsStdXml()) {
  1801.         UndoClassMember();
  1802.         if (pos==first && HasAnyContent(classType)) {
  1803.             TopFrame().SetNotag();
  1804.             return first;
  1805.         }
  1806.         if (GetSkipUnknownMembers() == eSerialSkipUnknown_Yes &&
  1807.             pos <= classType->GetMembers().LastIndex()) {
  1808.             string value;
  1809.             ReadAnyContentTo(m_CurrNsPrefix,value, RejectedName());
  1810.             return BeginClassMember(classType, pos);
  1811.         }
  1812.         return kInvalidMember;
  1813.     }
  1814.     CLightString id = SkipStackTagName(tagName, 1, '_');
  1815.     TMemberIndex index = classType->GetMembers().Find(id, pos);
  1816.     if ( index == kInvalidMember ) {
  1817.         if (GetSkipUnknownMembers() == eSerialSkipUnknown_Yes) {
  1818.             string value;
  1819.             ReadAnyContentTo(m_CurrNsPrefix,value, tagName);
  1820.             return BeginClassMember(classType, pos);
  1821.         } else {
  1822.            UnexpectedMember(id, classType->GetMembers());
  1823.         }
  1824.     }
  1825.     return index;
  1826. }
  1827. void CObjectIStreamXml::EndClassMember(void)
  1828. {
  1829.     if (TopFrame().GetNotag()) {
  1830.         TopFrame().SetNotag(false);
  1831.     } else {
  1832.         CloseStackTag(0);
  1833.     }
  1834. }
  1835. void CObjectIStreamXml::UndoClassMember(void)
  1836. {
  1837.     if (InsideOpeningTag()) {
  1838.         m_RejectedTag = m_LastTag;
  1839.         m_TagState = eTagOutside;
  1840. #if defined(NCBI_SERIAL_IO_TRACE)
  1841.     cout << ", Undo= " << m_LastTag;
  1842. #endif
  1843.     }
  1844. }
  1845. void CObjectIStreamXml::BeginChoice(const CChoiceTypeInfo* choiceType)
  1846. {
  1847.     CheckStdXml(choiceType);
  1848.     OpenTagIfNamed(choiceType);
  1849. }
  1850. void CObjectIStreamXml::EndChoice(void)
  1851. {
  1852.     CloseTagIfNamed(TopFrame().GetTypeInfo());
  1853.     x_EndTypeNamespace();
  1854. }
  1855. TMemberIndex CObjectIStreamXml::BeginChoiceVariant(const CChoiceTypeInfo* choiceType)
  1856. {
  1857.     CLightString tagName;
  1858.     TMemberIndex first = choiceType->GetVariants().FirstIndex();
  1859.     if (m_RejectedTag.empty()) {
  1860.         if (!m_Attlist) {
  1861.             if (choiceType->GetVariantInfo(first)->GetId().IsAttlist()) {
  1862.                 m_Attlist = true;
  1863.                 if (m_TagState == eTagOutside) {
  1864.                     m_Input.UngetChar('>');
  1865.                     m_TagState = eTagInsideOpening;
  1866.                 }
  1867.                 return first;
  1868.             }
  1869. // if spec defines no attributes, but there are some - skip them
  1870.             if (HasAttlist()) {
  1871.                 ReadUndefinedAttributes();
  1872.             }
  1873.         }
  1874.         m_Attlist = false;
  1875.         if ( NextTagIsClosing() ) {
  1876.             TMemberIndex ind = choiceType->GetVariants().FindEmpty();
  1877.             if (ind != kInvalidMember) {
  1878.                 TopFrame().SetNotag();
  1879.             }
  1880.             return ind;
  1881.         }
  1882.         tagName = ReadName(BeginOpeningTag());
  1883.     } else {
  1884.         tagName = RejectedName();
  1885.     }
  1886.     TMemberIndex ind = choiceType->GetVariants().Find(tagName);
  1887.     if (ind == kInvalidMember) {
  1888.         ind = choiceType->GetVariants().FindDeep(tagName);
  1889.         if (ind != kInvalidMember) {
  1890.             TopFrame().SetNotag();
  1891.             UndoClassMember();
  1892.             return ind;
  1893.         }
  1894.     } else {
  1895.         const CVariantInfo *var_info = choiceType->GetVariantInfo(ind);
  1896.         if (x_IsStdXml()) {
  1897.             ETypeFamily type = GetRealTypeFamily(var_info->GetTypeInfo());
  1898.             bool needUndo = false;
  1899.             if (GetEnforcedStdXml()) {
  1900.                 if (type == eTypeFamilyContainer) {
  1901.                     needUndo = (GetContainerElementTypeFamily(
  1902.                         var_info->GetTypeInfo()) == eTypeFamilyPrimitive);
  1903.                 }
  1904.             } else {
  1905.                 needUndo = (type != eTypeFamilyPrimitive);
  1906.             }
  1907.             if (needUndo) {
  1908.                 TopFrame().SetNotag();
  1909.                 UndoClassMember();
  1910.             }
  1911.             return ind;
  1912.         }
  1913.     }
  1914.     if (x_IsStdXml()) {
  1915.         UndoClassMember();
  1916.         UnexpectedMember(tagName, choiceType->GetVariants());
  1917.     }
  1918.     CLightString id = SkipStackTagName(tagName, 1, '_');
  1919.     ind = choiceType->GetVariants().Find(id);
  1920.     if ( ind == kInvalidMember ) {
  1921.         UnexpectedMember(tagName, choiceType->GetVariants());
  1922.     }
  1923.     return ind;
  1924. }
  1925. void CObjectIStreamXml::EndChoiceVariant(void)
  1926. {
  1927.     if (TopFrame().GetNotag()) {
  1928.         TopFrame().SetNotag(false);
  1929.     } else {
  1930.         CloseStackTag(0);
  1931.     }
  1932. }
  1933. #ifdef VIRTUAL_MID_LEVEL_IO
  1934. void CObjectIStreamXml::ReadChoice(const CChoiceTypeInfo* choiceType,
  1935.                                    TObjectPtr choicePtr)
  1936. {
  1937.     if ( choiceType->GetName().empty() ) {
  1938.         ReadChoiceContents(choiceType, choicePtr);
  1939.     }
  1940.     else {
  1941.         BEGIN_OBJECT_FRAME2(eFrameChoice, choiceType);
  1942.         OpenTag(choiceType);
  1943.         ReadChoiceContents(choiceType, choicePtr);
  1944.         CloseTag(choiceType);
  1945.         END_OBJECT_FRAME();
  1946.     }
  1947. }
  1948. void CObjectIStreamXml::ReadChoiceContents(const CChoiceTypeInfo* choiceType,
  1949.                                            TObjectPtr choicePtr)
  1950. {
  1951.     CLightString tagName = ReadName(BeginOpeningTag());
  1952.     CLightString id = SkipStackTagName(tagName, 0, '_');
  1953.     TMemberIndex index = choiceType->GetVariants().Find(id);
  1954.     if ( index == kInvalidMember )
  1955.         UnexpectedMember(id, choiceType->GetVariants());
  1956.     const CVariantInfo* variantInfo = choiceType->GetVariantInfo(index);
  1957.     BEGIN_OBJECT_FRAME2(eFrameChoiceVariant, variantInfo->GetId());
  1958.     variantInfo->ReadVariant(*this, choicePtr);
  1959.     
  1960.     CloseStackTag(0);
  1961.     END_OBJECT_FRAME();
  1962. }
  1963. void CObjectIStreamXml::SkipChoice(const CChoiceTypeInfo* choiceType)
  1964. {
  1965.     if ( choiceType->GetName().empty() ) {
  1966.         SkipChoiceContents(choiceType);
  1967.     }
  1968.     else {
  1969.         BEGIN_OBJECT_FRAME2(eFrameChoice, choiceType);
  1970.         OpenTag(choiceType);
  1971.         SkipChoiceContents(choiceType);
  1972.         CloseTag(choiceType);
  1973.         END_OBJECT_FRAME();
  1974.     }
  1975. }
  1976. void CObjectIStreamXml::SkipChoiceContents(const CChoiceTypeInfo* choiceType)
  1977. {
  1978.     CLightString tagName = ReadName(BeginOpeningTag());
  1979.     CLightString id = SkipStackTagName(tagName, 0, '_');
  1980.     TMemberIndex index = choiceType->GetVariants().Find(id);
  1981.     if ( index == kInvalidMember )
  1982.         UnexpectedMember(id, choiceType->GetVariants());
  1983.     const CVariantInfo* variantInfo = choiceType->GetVariantInfo(index);
  1984.     BEGIN_OBJECT_FRAME2(eFrameChoiceVariant, variantInfo->GetId());
  1985.     variantInfo->SkipVariant(*this);
  1986.     
  1987.     CloseStackTag(0);
  1988.     END_OBJECT_FRAME();
  1989. }
  1990. #endif
  1991. void CObjectIStreamXml::BeginBytes(ByteBlock& )
  1992. {
  1993.     BeginData();
  1994. }
  1995. int CObjectIStreamXml::GetHexChar(void)
  1996. {
  1997.     char c = m_Input.GetChar();
  1998.     if ( c >= '0' && c <= '9' ) {
  1999.         return c - '0';
  2000.     }
  2001.     else if ( c >= 'A' && c <= 'Z' ) {
  2002.         return c - 'A' + 10;
  2003.     }
  2004.     else if ( c >= 'a' && c <= 'z' ) {
  2005.         return c - 'a' + 10;
  2006.     }
  2007.     else {
  2008.         m_Input.UngetChar(c);
  2009.         if ( c != '<' )
  2010.             ThrowError(fFormatError, "invalid char in octet string");
  2011.     }
  2012.     return -1;
  2013. }
  2014. size_t CObjectIStreamXml::ReadBytes(ByteBlock& block,
  2015.                                     char* dst, size_t length)
  2016. {
  2017.     size_t count = 0;
  2018.     while ( length-- > 0 ) {
  2019.         int c1 = GetHexChar();
  2020.         if ( c1 < 0 ) {
  2021.             block.EndOfBlock();
  2022.             return count;
  2023.         }
  2024.         int c2 = GetHexChar();
  2025.         if ( c2 < 0 ) {
  2026.             *dst++ = c1 << 4;
  2027.             count++;
  2028.             block.EndOfBlock();
  2029.             return count;
  2030.         }
  2031.         else {
  2032.             *dst++ = (c1 << 4) | c2;
  2033.             count++;
  2034.         }
  2035.     }
  2036.     return count;
  2037. }
  2038. void CObjectIStreamXml::BeginChars(CharBlock& )
  2039. {
  2040.     BeginData();
  2041. }
  2042. size_t CObjectIStreamXml::ReadChars(CharBlock& block,
  2043.                                     char* dst, size_t length)
  2044. {
  2045.     size_t count = 0;
  2046.     while ( length-- > 0 ) {
  2047.         char c = m_Input.GetChar();
  2048.         if (c == '<') {
  2049.             block.EndOfBlock();
  2050.             break;
  2051.         }
  2052.         *dst++ = c;
  2053.         count++;
  2054.     }
  2055.     return count;
  2056. }
  2057. void CObjectIStreamXml::SkipBool(void)
  2058. {
  2059.     ReadBool();
  2060. }
  2061. void CObjectIStreamXml::SkipChar(void)
  2062. {
  2063.     ReadChar();
  2064. }
  2065. void CObjectIStreamXml::SkipSNumber(void)
  2066. {
  2067.     BeginData();
  2068.     size_t i;
  2069.     char c = SkipWSAndComments();
  2070.     switch ( c ) {
  2071.     case '+':
  2072.     case '-':
  2073.         c = m_Input.PeekChar(1);
  2074.         // next char
  2075.         i = 2;
  2076.         break;
  2077.     default:
  2078.         // next char
  2079.         i = 1;
  2080.         break;
  2081.     }
  2082.     if ( c < '0' || c > '9' ) {
  2083.         ThrowError(fFormatError, "invalid symbol in number");
  2084.     }
  2085.     while ( (c = m_Input.PeekCharNoEOF(i)) >= '0' && c <= '9' ) {
  2086.         ++i;
  2087.     }
  2088.     m_Input.SkipChars(i);
  2089. }
  2090. void CObjectIStreamXml::SkipUNumber(void)
  2091. {
  2092.     BeginData();
  2093.     size_t i;
  2094.     char c = SkipWSAndComments();
  2095.     switch ( c ) {
  2096.     case '+':
  2097.         c = m_Input.PeekChar(1);
  2098.         // next char
  2099.         i = 2;
  2100.         break;
  2101.     default:
  2102.         // next char
  2103.         i = 1;
  2104.         break;
  2105.     }
  2106.     if ( c < '0' || c > '9' ) {
  2107.         ThrowError(fFormatError, "invalid symbol in number");
  2108.     }
  2109.     while ( (c = m_Input.PeekCharNoEOF(i)) >= '0' && c <= '9' ) {
  2110.         ++i;
  2111.     }
  2112.     m_Input.SkipChars(i);
  2113. }
  2114. void CObjectIStreamXml::SkipFNumber(void)
  2115. {
  2116.     ReadDouble();
  2117. }
  2118. void CObjectIStreamXml::SkipString(EStringType type)
  2119. {
  2120.     BeginData();
  2121.     EEncoding enc = m_Encoding;
  2122.     if (type == eStringTypeUTF8) {
  2123.         m_Encoding = eEncoding_ISO8859_1;
  2124.     }
  2125.     while ( ReadEscapedChar(m_Attlist ? '"' : '<') >= 0 )
  2126.         continue;
  2127.     m_Encoding = enc;
  2128. }
  2129. void CObjectIStreamXml::SkipNull(void)
  2130. {
  2131.     if ( !EndOpeningTagSelfClosed() )
  2132.         ThrowError(fFormatError, "empty tag expected");
  2133. }
  2134. void CObjectIStreamXml::SkipByteBlock(void)
  2135. {
  2136.     BeginData();
  2137.     if ( m_Input.PeekChar() != ''' )
  2138.         ThrowError(fFormatError, "' expected");
  2139.     m_Input.SkipChar();
  2140.     for ( ;; ) {
  2141.         char c = m_Input.GetChar();
  2142.         if ( c >= '0' && c <= '9' ) {
  2143.             continue;
  2144.         }
  2145.         else if ( c >= 'A' && c <= 'Z' ) {
  2146.             continue;
  2147.         }
  2148.         else if ( c >= 'a' && c <= 'z' ) {
  2149.             continue;
  2150.         }
  2151.         else if ( c == ''' ) {
  2152.             break;
  2153.         }
  2154.         else {
  2155.             m_Input.UngetChar(c);
  2156.             ThrowError(fFormatError, "invalid char in octet string");
  2157.         }
  2158.     }
  2159.     if ( m_Input.PeekChar() != 'H' )
  2160.         ThrowError(fFormatError, "'H' expected");
  2161.     m_Input.SkipChar();
  2162. }
  2163. END_NCBI_SCOPE