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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: asn2asn.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 18:27:12  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.46
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: asn2asn.cpp,v 1000.1 2004/06/01 18:27:12 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. *   asn2asn test program
  38. *
  39. * ---------------------------------------------------------------------------
  40. * $Log: asn2asn.cpp,v $
  41. * Revision 1000.1  2004/06/01 18:27:12  gouriano
  42. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.46
  43. *
  44. * Revision 1.46  2004/05/21 21:41:38  gorelenk
  45. * Added PCH ncbi_pch.hpp
  46. *
  47. * Revision 1.45  2003/03/11 15:30:29  kuznets
  48. * iterate -> ITERATE
  49. *
  50. * Revision 1.44  2002/09/19 20:05:44  vasilche
  51. * Safe initialization of static mutexes
  52. *
  53. * Revision 1.43  2002/09/17 22:27:09  grichenk
  54. * Type<> -> CType<>
  55. *
  56. * Revision 1.42  2002/09/05 21:23:22  vasilche
  57. * Added mutex for arguments
  58. *
  59. * Revision 1.41  2002/08/30 16:22:47  vasilche
  60. * Added MT mode to asn2asn
  61. *
  62. * Revision 1.40  2001/08/31 20:05:44  ucko
  63. * Fix ICC build.
  64. *
  65. * Revision 1.39  2001/05/17 15:05:45  lavr
  66. * Typos corrected
  67. *
  68. * Revision 1.38  2001/02/01 19:53:17  vasilche
  69. * Reading program arguments from file moved to CNcbiApplication::AppMain.
  70. *
  71. * Revision 1.37  2001/01/30 21:42:29  vasilche
  72. * Added passing arguments via file.
  73. *
  74. * Revision 1.36  2001/01/23 00:12:02  vakatov
  75. * Added comments and usage directions
  76. *
  77. * Revision 1.35  2000/12/24 00:14:16  vakatov
  78. * Minor fix due to the changed NCBIARGS API
  79. *
  80. * Revision 1.34  2000/12/12 14:28:31  vasilche
  81. * Changed the way arguments are processed.
  82. *
  83. * Revision 1.33  2000/11/17 22:04:33  vakatov
  84. * CArgDescriptions::  Switch the order of optional args in methods
  85. * AddOptionalKey() and AddPlain(). Also, enforce the default value to
  86. * match arg. description (and constraints, if any) at all times.
  87. *
  88. * Revision 1.32  2000/11/14 21:40:08  vasilche
  89. * New NCBIArgs API.
  90. *
  91. * Revision 1.31  2000/11/01 20:38:28  vasilche
  92. * Removed ECanDelete enum and related constructors.
  93. *
  94. * Revision 1.30  2000/10/27 14:42:59  ostell
  95. * removed extra CreateArguments call so that usage shows properly
  96. *
  97. * Revision 1.29  2000/10/20 19:29:52  vasilche
  98. * Adapted for MSVC which doesn't like explicit operator templates.
  99. *
  100. * Revision 1.28  2000/10/20 15:51:52  vasilche
  101. * Fixed data error processing.
  102. * Added interface for constructing container objects directly into output stream.
  103. * object.hpp, object.inl and object.cpp were split to
  104. * objectinfo.*, objecttype.*, objectiter.* and objectio.*.
  105. *
  106. * Revision 1.27  2000/10/18 13:07:17  ostell
  107. * added proper program name to usage
  108. *
  109. * Revision 1.26  2000/10/17 18:46:25  vasilche
  110. * Added print usage to asn2asn
  111. * Remove unnecessary warning about missing config file.
  112. *
  113. * Revision 1.25  2000/10/13 16:29:40  vasilche
  114. * Fixed processing of optional -o argument.
  115. *
  116. * Revision 1.24  2000/10/03 17:23:50  vasilche
  117. * Added code for CSeq_entry as choice pointer.
  118. *
  119. * Revision 1.23  2000/09/29 14:38:54  vasilche
  120. * Updated for changes in library.
  121. *
  122. * Revision 1.22  2000/09/26 19:29:17  vasilche
  123. * Removed experimental choice pointer stuff.
  124. *
  125. * Revision 1.21  2000/09/26 17:39:02  vasilche
  126. * Updated hooks implementation.
  127. *
  128. * Revision 1.20  2000/09/18 20:47:27  vasilche
  129. * Updated to new headers.
  130. *
  131. * Revision 1.19  2000/09/01 13:16:41  vasilche
  132. * Implemented class/container/choice iterators.
  133. * Implemented CObjectStreamCopier for copying data without loading into memory.
  134. *
  135. * Revision 1.18  2000/08/15 19:46:57  vasilche
  136. * Added Read/Write hooks.
  137. *
  138. * Revision 1.17  2000/06/16 16:32:06  vasilche
  139. * Fixed 'unused variable' warnings.
  140. *
  141. * Revision 1.16  2000/06/01 19:07:08  vasilche
  142. * Added parsing of XML data.
  143. *
  144. * Revision 1.15  2000/05/24 20:09:54  vasilche
  145. * Implemented XML dump.
  146. *
  147. * Revision 1.14  2000/04/28 16:59:39  vasilche
  148. * Fixed call to CObjectIStream::Open().
  149. *
  150. * Revision 1.13  2000/04/13 14:50:59  vasilche
  151. * Added CObjectIStream::Open() and CObjectOStream::Open() for easier use.
  152. *
  153. * Revision 1.12  2000/04/07 19:27:34  vasilche
  154. * Generated objects now are placed in NCBI_NS_NCBI::objects namespace.
  155. *
  156. * Revision 1.11  2000/04/06 16:12:14  vasilche
  157. * Added -c option.
  158. *
  159. * Revision 1.10  2000/03/17 16:47:48  vasilche
  160. * Added copyright message to generated files.
  161. * All objects pointers in choices now share the only CObject pointer.
  162. *
  163. * Revision 1.9  2000/03/07 14:10:52  vasilche
  164. * Fixed for reference counting.
  165. *
  166. * Revision 1.8  2000/02/17 20:07:18  vasilche
  167. * Generated class names now have 'C' prefix.
  168. *
  169. * Revision 1.7  2000/02/04 18:09:57  vasilche
  170. * Added binary option to files.
  171. *
  172. * Revision 1.6  2000/02/04 17:57:45  vasilche
  173. * Fixed for new generated classes interface.
  174. *
  175. * Revision 1.5  2000/01/20 21:51:28  vakatov
  176. * Fixed to follow changes of the "CNcbiApplication" interface
  177. *
  178. * Revision 1.4  2000/01/10 19:47:20  vasilche
  179. * Member type typedef now generated in _Base class.
  180. *
  181. * Revision 1.3  2000/01/10 14:17:47  vasilche
  182. * Fixed usage of different types in ?: statement.
  183. *
  184. * Revision 1.2  2000/01/06 21:28:04  vasilche
  185. * Fixed for variable scope.
  186. *
  187. * Revision 1.1  2000/01/05 19:46:58  vasilche
  188. * Added asn2asn test application.
  189. *
  190. * ===========================================================================
  191. */
  192. #include <ncbi_pch.hpp>
  193. #include <corelib/ncbistd.hpp>
  194. #include <corelib/ncbienv.hpp>
  195. #include <corelib/ncbithr.hpp>
  196. #include <objects/seqset/Seq_entry.hpp>
  197. #include <objects/seqset/Bioseq_set.hpp>
  198. #include <memory>
  199. BEGIN_NCBI_SCOPE
  200. // CSEQ_ENTRY_REF_CHOICE macro to switch implementation of CSeq_entry choice
  201. // as choice class or virtual base class.
  202. // 0 -> generated choice class
  203. // 1 -> virtual base class
  204. #define CSEQ_ENTRY_REF_CHOICE 0
  205. #if CSEQ_ENTRY_REF_CHOICE
  206. template<typename T> const CTypeInfo* (*GetTypeRef(const T* object))(void);
  207. template<typename T> pair<void*, const CTypeInfo*> ObjectInfo(T& object);
  208. template<typename T> pair<const void*, const CTypeInfo*> ConstObjectInfo(const T& object);
  209. EMPTY_TEMPLATE
  210. inline
  211. const CTypeInfo* (*GetTypeRef< CRef<NCBI_NS_NCBI::objects::CSeq_entry> >(const CRef<NCBI_NS_NCBI::objects::CSeq_entry>* object))(void)
  212. {
  213.     return &NCBI_NS_NCBI::objects::CSeq_entry::GetRefChoiceTypeInfo;
  214. }
  215. EMPTY_TEMPLATE
  216. inline
  217. pair<void*, const CTypeInfo*> ObjectInfo< CRef<NCBI_NS_NCBI::objects::CSeq_entry> >(CRef<NCBI_NS_NCBI::objects::CSeq_entry>& object)
  218. {
  219.     return make_pair((void*)&object, GetTypeRef(&object)());
  220. }
  221. EMPTY_TEMPLATE
  222. inline
  223. pair<const void*, const CTypeInfo*> ConstObjectInfo< CRef<NCBI_NS_NCBI::objects::CSeq_entry> >(const CRef<NCBI_NS_NCBI::objects::CSeq_entry>& object)
  224. {
  225.     return make_pair((const void*)&object, GetTypeRef(&object)());
  226. }
  227. #endif
  228. END_NCBI_SCOPE
  229. #include "asn2asn.hpp"
  230. #include <corelib/ncbiutil.hpp>
  231. #include <corelib/ncbiargs.hpp>
  232. #include <objects/seq/Bioseq.hpp>
  233. #include <serial/object.hpp>
  234. #include <serial/objistr.hpp>
  235. #include <serial/objostr.hpp>
  236. #include <serial/objcopy.hpp>
  237. #include <serial/serial.hpp>
  238. #include <serial/objhook.hpp>
  239. #include <serial/iterator.hpp>
  240. USING_NCBI_SCOPE;
  241. using namespace NCBI_NS_NCBI::objects;
  242. #if CSEQ_ENTRY_REF_CHOICE
  243. typedef CRef<CSeq_entry> TSeqEntry;
  244. #else
  245. typedef CSeq_entry TSeqEntry;
  246. #endif
  247. int main(int argc, char** argv)
  248. {
  249.     return CAsn2Asn().AppMain(argc, argv, 0, eDS_Default, 0, "asn2asn");
  250. }
  251. static
  252. void SeqEntryProcess(CSeq_entry& entry);  /* dummy function */
  253. #if CSEQ_ENTRY_REF_CHOICE
  254. static
  255. void SeqEntryProcess(CRef<CSeq_entry>& entry)
  256. {
  257.     SeqEntryProcess(*entry);
  258. }
  259. #endif
  260. class CCounter
  261. {
  262. public:
  263.     CCounter(void)
  264.         : m_Counter(0)
  265.         {
  266.         }
  267.     ~CCounter(void)
  268.         {
  269.             _ASSERT(m_Counter == 0);
  270.         }
  271.     operator int(void) const
  272.         {
  273.             return m_Counter;
  274.         }
  275. private:
  276.     friend class CInc;
  277.     int m_Counter;
  278. };
  279. class CInc
  280. {
  281. public:
  282.     CInc(CCounter& counter)
  283.         : m_Counter(counter)
  284.         {
  285.             ++counter.m_Counter;
  286.         }
  287.     ~CInc(void)
  288.         {
  289.             --m_Counter.m_Counter;
  290.         }
  291. private:
  292.     CCounter& m_Counter;
  293. };
  294. class CReadSeqSetHook : public CReadClassMemberHook
  295. {
  296. public:
  297.     void ReadClassMember(CObjectIStream& in,
  298.                          const CObjectInfo::CMemberIterator& member);
  299.     CCounter m_Level;
  300. };
  301. class CWriteSeqSetHook : public CWriteClassMemberHook
  302. {
  303. public:
  304.     void WriteClassMember(CObjectOStream& out,
  305.                           const CConstObjectInfo::CMemberIterator& member);
  306.     CCounter m_Level;
  307. };
  308. class CWriteSeqEntryHook : public CWriteObjectHook
  309. {
  310. public:
  311.     void WriteObject(CObjectOStream& out, const CConstObjectInfo& object);
  312.     CCounter m_Level;
  313. };
  314. /*****************************************************************************
  315. *
  316. *   Main program loop to read, process, write SeqEntrys
  317. *
  318. *****************************************************************************/
  319. void CAsn2Asn::Init(void)
  320. {
  321.     auto_ptr<CArgDescriptions> d(new CArgDescriptions);
  322.     d->SetUsageContext("asn2asn", "convert Seq-entry or Bioseq-set data");
  323.     d->AddKey("i", "inputFile",
  324.               "input data file",
  325.               CArgDescriptions::eInputFile);
  326.     d->AddOptionalKey("o", "outputFile",
  327.                       "output data file",
  328.                       CArgDescriptions::eOutputFile);
  329.     d->AddFlag("e",
  330.                "treat data as Seq-entry");
  331.     d->AddFlag("b",
  332.                "binary ASN.1 input format");
  333.     d->AddFlag("X",
  334.                "XML input format");
  335.     d->AddFlag("s",
  336.                "binary ASN.1 output format");
  337.     d->AddFlag("x",
  338.                "XML output format");
  339.     d->AddFlag("C",
  340.                "Convert data without reading in memory");
  341.     d->AddFlag("S",
  342.                "Skip data without reading in memory");
  343.     d->AddOptionalKey("l", "logFile",
  344.                       "log errors to <logFile>",
  345.                       CArgDescriptions::eOutputFile);
  346.     d->AddDefaultKey("c", "count",
  347.                       "perform command <count> times",
  348.                       CArgDescriptions::eInteger, "1");
  349.     d->AddDefaultKey("tc", "threadCount",
  350.                       "perform command in <threadCount> thread",
  351.                       CArgDescriptions::eInteger, "1");
  352.     
  353.     d->AddFlag("ih",
  354.                "Use read hooks");
  355.     d->AddFlag("oh",
  356.                "Use write hooks");
  357.     d->AddFlag("q",
  358.                "Quiet execution");
  359.     SetupArgDescriptions(d.release());
  360. }
  361. class CAsn2AsnThread : public CThread
  362. {
  363. public:
  364.     CAsn2AsnThread(int index, CAsn2Asn* asn2asn)
  365.         : m_Index(index), m_Asn2Asn(asn2asn), m_DoneOk(false)
  366.     {
  367.     }
  368.     void* Main()
  369.     {
  370.         string suffix = '.'+NStr::IntToString(m_Index);
  371.         try {
  372.             m_Asn2Asn->RunAsn2Asn(suffix);
  373.         }
  374.         catch (exception& e) {
  375.             CNcbiDiag() << Error << "[asn2asn thread " << m_Index << "]" <<
  376.                 "Exception: " << e.what();
  377.             return 0;
  378.         }
  379.         m_DoneOk = true;
  380.         return 0;
  381.     }
  382.     bool DoneOk() const
  383.     {
  384.         return m_DoneOk;
  385.     }
  386. private:
  387.     int m_Index;
  388.     CAsn2Asn* m_Asn2Asn;
  389.     bool m_DoneOk;
  390. };
  391. int CAsn2Asn::Run(void)
  392. {
  393. SetDiagPostLevel(eDiag_Error);
  394.     const CArgs& args = GetArgs();
  395.     if ( const CArgValue& l = args["l"] )
  396.         SetDiagStream(&l.AsOutputFile());
  397.     size_t threadCount = args["tc"].AsInteger();
  398.     vector< CRef<CAsn2AsnThread> > threads(threadCount);
  399.     for ( size_t i = 1; i < threadCount; ++i ) {
  400.         threads[i] = new CAsn2AsnThread(i, this);
  401.         threads[i]->Run();
  402.     }
  403.     
  404.     try {
  405.       RunAsn2Asn("");
  406.     }
  407.     catch (exception& e) {
  408.         CNcbiDiag() << Error << "[asn2asn]" << "Exception: " << e.what();
  409.         return 1;
  410.     }
  411.     for ( size_t i = 1; i < threadCount; ++i ) {
  412.         threads[i]->Join();
  413.         if ( !threads[i]->DoneOk() ) {
  414.             NcbiCerr << "Error in thread: " << i << NcbiEndl;
  415.             return 1;
  416.         }
  417.     }
  418.     return 0;
  419. }
  420. DEFINE_STATIC_FAST_MUTEX(s_ArgsMutex);
  421. void CAsn2Asn::RunAsn2Asn(const string& outFileSuffix)
  422. {
  423.     CFastMutexGuard GUARD(s_ArgsMutex);
  424.     const CArgs& args = GetArgs();
  425.     string inFile = args["i"].AsString();
  426.     ESerialDataFormat inFormat = eSerial_AsnText;
  427.     if ( args["b"] )
  428.         inFormat = eSerial_AsnBinary;
  429.     else if ( args["X"] )
  430.         inFormat = eSerial_Xml;
  431.     const CArgValue& o = args["o"];
  432.     bool haveOutput = o;
  433.     string outFile;
  434.     ESerialDataFormat outFormat = eSerial_AsnText;
  435.     if ( haveOutput ) {
  436.         outFile = o.AsString();
  437.         if ( args["s"] )
  438.             outFormat = eSerial_AsnBinary;
  439.         else if ( args["x"] )
  440.             outFormat = eSerial_Xml;
  441.     }
  442.     outFile += outFileSuffix;
  443.     bool inSeqEntry = args["e"];
  444.     bool skip = args["S"];
  445.     bool convert = args["C"];
  446.     bool readHook = args["ih"];
  447.     bool writeHook = args["oh"];
  448.     bool quiet = args["q"];
  449.     size_t count = args["c"].AsInteger();
  450.     GUARD.Release();
  451.     
  452.     for ( size_t i = 1; i <= count; ++i ) {
  453.         bool displayMessages = count != 1 && !quiet;
  454.         if ( displayMessages )
  455.             NcbiCerr << "Step " << i << ':' << NcbiEndl;
  456.         auto_ptr<CObjectIStream> in(CObjectIStream::Open(inFormat, inFile,
  457.                                                          eSerial_StdWhenAny));
  458.         auto_ptr<CObjectOStream> out(!haveOutput? 0:
  459.                                      CObjectOStream::Open(outFormat, outFile,
  460.                                                           eSerial_StdWhenAny));
  461.         if ( inSeqEntry ) { /* read one Seq-entry */
  462.             if ( skip ) {
  463.                 if ( displayMessages )
  464.                     NcbiCerr << "Skipping Seq-entry..." << NcbiEndl;
  465.                 in->Skip(CType<CSeq_entry>());
  466.             }
  467.             else if ( convert && haveOutput ) {
  468.                 if ( displayMessages )
  469.                     NcbiCerr << "Copying Seq-entry..." << NcbiEndl;
  470.                 CObjectStreamCopier copier(*in, *out);
  471.                 copier.Copy(CType<CSeq_entry>());
  472.             }
  473.             else {
  474.                 TSeqEntry entry;
  475.                 //entry.DoNotDeleteThisObject();
  476.                 if ( displayMessages )
  477.                     NcbiCerr << "Reading Seq-entry..." << NcbiEndl;
  478.                 *in >> entry;
  479.                 SeqEntryProcess(entry);     /* do any processing */
  480.                 if ( haveOutput ) {
  481.                     if ( displayMessages )
  482.                         NcbiCerr << "Writing Seq-entry..." << NcbiEndl;
  483.                     *out << entry;
  484.                 }
  485.             }
  486.         }
  487.         else {              /* read Seq-entry's from a Bioseq-set */
  488.             if ( skip ) {
  489.                 if ( displayMessages )
  490.                     NcbiCerr << "Skipping Bioseq-set..." << NcbiEndl;
  491.                 in->Skip(CType<CBioseq_set>());
  492.             }
  493.             else if ( convert && haveOutput ) {
  494.                 if ( displayMessages )
  495.                     NcbiCerr << "Copying Bioseq-set..." << NcbiEndl;
  496.                 CObjectStreamCopier copier(*in, *out);
  497.                 copier.Copy(CType<CBioseq_set>());
  498.             }
  499.             else {
  500.                 CBioseq_set entries;
  501.                 //entries.DoNotDeleteThisObject();
  502.                 if ( displayMessages )
  503.                     NcbiCerr << "Reading Bioseq-set..." << NcbiEndl;
  504.                 if ( readHook ) {
  505.                     CObjectTypeInfo bioseqSetType = CType<CBioseq_set>();
  506.                     bioseqSetType.FindMember("seq-set")
  507.                         .SetLocalReadHook(*in, new CReadSeqSetHook);
  508.                     *in >> entries;
  509.                 }
  510.                 else {
  511.                     *in >> entries;
  512.                     NON_CONST_ITERATE ( CBioseq_set::TSeq_set, seqi,
  513.                                         entries.SetSeq_set() ) {
  514.                         SeqEntryProcess(**seqi);     /* do any processing */
  515.                     }
  516.                 }
  517.                 if ( haveOutput ) {
  518.                     if ( displayMessages )
  519.                         NcbiCerr << "Writing Bioseq-set..." << NcbiEndl;
  520.                     if ( writeHook ) {
  521. #if 0
  522.                         CObjectTypeInfo bioseqSetType = CType<CBioseq_set>();
  523.                         bioseqSetType.FindMember("seq-set")
  524.                             .SetLocalWriteHook(*out, new CWriteSeqSetHook);
  525. #else
  526.                         CObjectTypeInfo seqEntryType = CType<CSeq_entry>();
  527.                         seqEntryType
  528.                             .SetLocalWriteHook(*out, new CWriteSeqEntryHook);
  529. #endif
  530.                         *out << entries;
  531.                     }
  532.                     else {
  533.                         *out << entries;
  534.                     }
  535.                 }
  536.             }
  537.         }
  538.     }
  539. }
  540. /*****************************************************************************
  541. *
  542. *   void SeqEntryProcess (sep)
  543. *      just a dummy routine that does nothing
  544. *
  545. *****************************************************************************/
  546. static
  547. void SeqEntryProcess(CSeq_entry& /* seqEntry */)
  548. {
  549. }
  550. void CReadSeqSetHook::ReadClassMember(CObjectIStream& in,
  551.                                       const CObjectInfo::CMemberIterator& member)
  552. {
  553.     CInc inc(m_Level);
  554.     if ( m_Level == 1 ) {
  555.         // (do not have to read member open/close tag, it's done by this time)
  556.         // Read each element separately to a local TSeqEntry,
  557.         // process it somehow, and... not store it in the container.
  558.         for ( CIStreamContainerIterator i(in, member); i; ++i ) {
  559.             TSeqEntry entry;
  560.             //entry.DoNotDeleteThisObject();
  561.             i >> entry;
  562.             SeqEntryProcess(entry);
  563.         }
  564.         // MemberIterators are DANGEROUS!  -- do not use the following
  565.         // unless...
  566.         // The same trick can be done with CIStreamClassMember -- to traverse
  567.         // through the class members rather than container elements.
  568.         // CObjectInfo object = member;
  569.         // for ( CIStreamClassMemberIterator i(in, object); i; ++i ) {
  570.         //    // CObjectTypeInfo::CMemberIterator nextMember = *i;
  571.         //    in.ReadObject(object.GetMember(*i));
  572.         // }
  573.     }
  574.     else {
  575.         // standard read
  576.         in.ReadClassMember(member);
  577.     }
  578. }
  579. void CWriteSeqEntryHook::WriteObject(CObjectOStream& out,
  580.                                      const CConstObjectInfo& object)
  581. {
  582.     CInc inc(m_Level);
  583.     if ( m_Level == 1 ) {
  584.         NcbiCerr << "entry" << NcbiEndl;
  585.         // const CSeq_entry& entry = *CType<CSeq_entry>::Get(object);
  586.         object.GetTypeInfo()->DefaultWriteData(out, object.GetObjectPtr());
  587.     }
  588.     else {
  589.         // const CSeq_entry& entry = *CType<CSeq_entry>::Get(object);
  590.         object.GetTypeInfo()->DefaultWriteData(out, object.GetObjectPtr());
  591.     }
  592. }
  593. void CWriteSeqSetHook::WriteClassMember(CObjectOStream& out,
  594.                                         const CConstObjectInfo::CMemberIterator& member)
  595. {
  596.     // keep track of the level of write recursion
  597.     CInc inc(m_Level);
  598.     // just for fun -- do the hook only on the first level of write recursion,
  599.     if ( m_Level == 1 ) {
  600.         // provide opening and closing(automagic, in destr) tags for the member
  601.         COStreamClassMember m(out, member);
  602.         // out.WriteObject(*member);  or, with just the same effect:
  603.         // provide opening and closing(automagic) tags for the container
  604.         COStreamContainer o(out, member);
  605.         typedef CBioseq_set::TSeq_set TSeq_set;
  606.         // const TSeq_set& cnt = *CType<TSeq_set>::Get(*member);
  607.         // but as soon as we know for sure that it *is* TSeq_set, so:
  608.         const TSeq_set& cnt = *CType<TSeq_set>::GetUnchecked(*member);
  609.         // write elem-by-elem
  610.         for ( TSeq_set::const_iterator i = cnt.begin(); i != cnt.end(); ++i ) {
  611.             const TSeqEntry& entry = **i;
  612.             // COStreamContainer is smart enough to automagically put
  613.             // open/close tags for each element written
  614.             o << entry;
  615.             // here, we could e.g. write each elem twice:
  616.             // o << entry;  o << entry;
  617.             // we cannot change the element content as everything is const in
  618.             // the write hooks.
  619.         }
  620.     }
  621.     else {
  622.         // on all other levels -- use standard write func for this member
  623.         out.WriteClassMember(member);
  624.     }
  625. }