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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: strbuffer.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 19:40:32  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.42
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: strbuffer.cpp,v 1000.3 2004/06/01 19:40:32 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. *   Input buffer
  38. *
  39. * ---------------------------------------------------------------------------
  40. * $Log: strbuffer.cpp,v $
  41. * Revision 1000.3  2004/06/01 19:40:32  gouriano
  42. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.42
  43. *
  44. * Revision 1.42  2004/05/24 18:13:01  gouriano
  45. * In text output files make indentation optional
  46. *
  47. * Revision 1.41  2004/05/17 21:06:02  gorelenk
  48. * Added include of PCH ncbi_pch.hpp
  49. *
  50. * Revision 1.40  2004/05/10 14:51:13  gouriano
  51. * Work with unsigned number (division/modulus ops) when writing an integer
  52. *
  53. * Revision 1.39  2003/12/31 20:51:33  gouriano
  54. * added possibility to seek (when possible) in CByteSourceReader
  55. *
  56. * Revision 1.38  2003/11/19 15:41:11  vasilche
  57. * Pushback unused data in destructor of CIStreamBuffer.
  58. *
  59. * Revision 1.37  2003/09/25 12:49:14  kuznets
  60. * Change to allowed more than one subsource collector
  61. *
  62. * Revision 1.36  2003/03/21 17:15:36  vasilche
  63. * Avoid unnecessary buffer growth in GetChars().
  64. *
  65. * Revision 1.35  2003/02/26 21:32:00  gouriano
  66. * modify C++ exceptions thrown by this library
  67. *
  68. * Revision 1.34  2002/11/18 19:49:37  grichenk
  69. * More details in error messages
  70. *
  71. * Revision 1.33  2002/11/04 21:29:22  grichenk
  72. * Fixed usage of const CRef<> and CRef<> constructor
  73. *
  74. * Revision 1.32  2002/10/22 20:22:55  gouriano
  75. * undo the prev change
  76. *
  77. * Revision 1.31  2002/10/22 19:01:36  gouriano
  78. * replaced THROW0_TRACE by throw in CIStreamBuffer::FillBuffer
  79. *
  80. * Revision 1.30  2002/01/29 16:01:21  grichenk
  81. * COStreamBuffer destructor fixed - no exceptions thrown
  82. *
  83. * Revision 1.29  2001/08/08 18:35:55  grichenk
  84. * CIStreamBuffer::FindChar() -- fixed bug with buffer pointers
  85. *
  86. * Revision 1.28  2001/06/20 17:36:19  grichenk
  87. * Updated FillBuffer() to work with GCC 3.0
  88. *
  89. * Revision 1.27  2001/06/06 15:50:01  grichenk
  90. * Fixed auto-wrapping of long lines
  91. *
  92. * Revision 1.26  2001/05/17 15:07:15  lavr
  93. * Typos corrected
  94. *
  95. * Revision 1.25  2001/05/11 13:58:52  grichenk
  96. * Removed "while" reading loop in CIStreamBuffer::FillBuffer()
  97. *
  98. * Revision 1.24  2001/04/17 21:47:29  vakatov
  99. * COStreamBuffer::Flush() -- try to flush the underlying output stream
  100. * regardless of its state (clear the state temporarily before flushing,
  101. * restore it afterwards).
  102. *
  103. * Revision 1.23  2001/03/14 17:59:26  vakatov
  104. * COStreamBuffer::  renamed GetFreeSpace() -> GetAvailableSpace()
  105. * to avoid clash with MS-Win system headers' #define
  106. *
  107. * Revision 1.22  2001/01/05 20:09:05  vasilche
  108. * Added util directory for various algorithms and utility classes.
  109. *
  110. * Revision 1.21  2000/12/15 15:38:46  vasilche
  111. * Added support of Int8 and long double.
  112. * Enum values now have type Int4 instead of long.
  113. *
  114. * Revision 1.20  2000/10/20 15:51:44  vasilche
  115. * Fixed data error processing.
  116. * Added interface for constructing container objects directly into output stream.
  117. * object.hpp, object.inl and object.cpp were split to
  118. * objectinfo.*, objecttype.*, objectiter.* and objectio.*.
  119. *
  120. * Revision 1.19  2000/10/13 20:59:21  vasilche
  121. * Avoid using of ssize_t absent on some compilers.
  122. *
  123. * Revision 1.18  2000/10/13 20:22:57  vasilche
  124. * Fixed warnings on 64 bit compilers.
  125. * Fixed missing typename in templates.
  126. *
  127. * Revision 1.17  2000/08/15 19:44:51  vasilche
  128. * Added Read/Write hooks:
  129. * CReadObjectHook/CWriteObjectHook for objects of specified type.
  130. * CReadClassMemberHook/CWriteClassMemberHook for specified members.
  131. * CReadChoiceVariantHook/CWriteChoiceVariant for specified choice variants.
  132. * CReadContainerElementHook/CWriteContainerElementsHook for containers.
  133. *
  134. * Revision 1.16  2000/07/03 18:42:47  vasilche
  135. * Added interface to typeinfo via CObjectInfo and CConstObjectInfo.
  136. * Reduced header dependency.
  137. *
  138. * Revision 1.15  2000/06/16 20:01:26  vasilche
  139. * Avoid use of unexpected_exception() which is unimplemented on Mac.
  140. *
  141. * Revision 1.14  2000/06/01 19:07:05  vasilche
  142. * Added parsing of XML data.
  143. *
  144. * Revision 1.13  2000/05/24 20:08:50  vasilche
  145. * Implemented XML dump.
  146. *
  147. * Revision 1.12  2000/05/03 14:38:14  vasilche
  148. * SERIAL: added support for delayed reading to generated classes.
  149. * DATATOOL: added code generation for delayed reading.
  150. *
  151. * Revision 1.11  2000/04/28 16:58:14  vasilche
  152. * Added classes CByteSource and CByteSourceReader for generic reading.
  153. * Added delayed reading of choice variants.
  154. *
  155. * Revision 1.10  2000/04/13 14:50:28  vasilche
  156. * Added CObjectIStream::Open() and CObjectOStream::Open() for easier use.
  157. *
  158. * Revision 1.9  2000/04/06 16:11:01  vasilche
  159. * Fixed bug with iterators in choices.
  160. * Removed unneeded calls to ReadExternalObject/WriteExternalObject.
  161. * Added output buffering to text ASN.1 data.
  162. *
  163. * Revision 1.8  2000/03/29 15:55:29  vasilche
  164. * Added two versions of object info - CObjectInfo and CConstObjectInfo.
  165. * Added generic iterators by class -
  166. *  CTypeIterator<class>, CTypeConstIterator<class>,
  167. *  CStdTypeIterator<type>, CStdTypeConstIterator<type>,
  168. *  CObjectsIterator and CObjectsConstIterator.
  169. *
  170. * Revision 1.7  2000/03/10 21:16:47  vasilche
  171. * Removed EOF workaround code.
  172. *
  173. * Revision 1.6  2000/03/10 17:59:21  vasilche
  174. * Fixed error reporting.
  175. * Added EOF bug workaround on MIPSpro compiler (not finished).
  176. *
  177. * Revision 1.5  2000/03/07 14:06:24  vasilche
  178. * Added stream buffering to ASN.1 binary input.
  179. * Optimized class loading/storing.
  180. * Fixed bugs in processing OPTIONAL fields.
  181. * Added generation of reference counted objects.
  182. *
  183. * Revision 1.4  2000/02/17 20:02:45  vasilche
  184. * Added some standard serialization exceptions.
  185. * Optimized text/binary ASN.1 reading.
  186. * Fixed wrong encoding of StringStore in ASN.1 binary format.
  187. * Optimized logic of object collection.
  188. *
  189. * Revision 1.3  2000/02/11 17:10:25  vasilche
  190. * Optimized text parsing.
  191. *
  192. * Revision 1.2  2000/02/02 19:07:41  vasilche
  193. * Added THROWS_NONE to constructor/destructor of exception.
  194. *
  195. * Revision 1.1  2000/02/01 21:47:23  vasilche
  196. * Added CGeneratedChoiceTypeInfo for generated choice classes.
  197. * Added buffering to CObjectIStreamAsn.
  198. * Removed CMemberInfo subclasses.
  199. * Added support for DEFAULT/OPTIONAL members.
  200. *
  201. *
  202. * ===========================================================================
  203. */
  204. #include <ncbi_pch.hpp>
  205. #include <corelib/ncbistre.hpp>
  206. #include <corelib/ncbi_limits.hpp>
  207. #include <util/strbuffer.hpp>
  208. #include <util/bytesrc.hpp>
  209. #include <algorithm>
  210. BEGIN_NCBI_SCOPE
  211. static const size_t KInitialBufferSize = 4096;
  212. static inline
  213. size_t BiggerBufferSize(size_t size) THROWS1_NONE
  214. {
  215.     return size * 2;
  216. }
  217. CIStreamBuffer::CIStreamBuffer(void)
  218.     THROWS1((bad_alloc))
  219.     : m_Error(0), m_BufferOffset(0),
  220.       m_BufferSize(KInitialBufferSize), m_Buffer(new char[KInitialBufferSize]),
  221.       m_CurrentPos(m_Buffer), m_DataEndPos(m_Buffer),
  222.       m_Line(1),
  223.       m_CollectPos(0)
  224. {
  225. }
  226. CIStreamBuffer::~CIStreamBuffer(void)
  227. {
  228.     try {
  229.         Close();
  230.     }
  231.     catch ( exception& exc ) {
  232.         ERR_POST(Warning <<
  233.                  "~CIStreamBuffer: exception while closing: " << exc.what());
  234.     }
  235.     delete[] m_Buffer;
  236.     
  237. }
  238. void CIStreamBuffer::Open(CByteSourceReader& reader)
  239. {
  240.     Close();
  241.     m_Input = &reader;
  242.     m_Error = 0;
  243. }
  244. void CIStreamBuffer::Close(void)
  245. {
  246.     if ( m_Input ) {
  247.         size_t unused = m_DataEndPos - m_CurrentPos;
  248.         if ( unused ) {
  249.             m_Input->Pushback(m_CurrentPos, unused);
  250.         }
  251.         m_Input.Reset();
  252.     }
  253.     m_BufferOffset = 0;
  254.     m_CurrentPos = m_Buffer;
  255.     m_DataEndPos = m_Buffer;
  256.     m_Line = 1;
  257.     m_Error = 0;
  258. }
  259. void CIStreamBuffer::StartSubSource(void)
  260. {
  261.     _ASSERT(!m_CollectPos);
  262.     m_CollectPos = m_CurrentPos;
  263.     m_Collector = m_Input->SubSource(m_DataEndPos - m_CurrentPos, m_Collector);
  264. }
  265. CRef<CByteSource> CIStreamBuffer::EndSubSource(void)
  266. {
  267.     _ASSERT(m_Collector);
  268.     _ASSERT(m_CollectPos);
  269.     _ASSERT(m_CollectPos <= m_CurrentPos);
  270.     if ( m_CurrentPos != m_CollectPos )
  271.         m_Collector->AddChunk(m_CollectPos, m_CurrentPos - m_CollectPos);
  272.     CRef<CByteSource> source = m_Collector->GetSource();
  273.     m_CollectPos = 0;
  274.     m_Collector.Reset();
  275.     return source;
  276. }
  277. // this method is highly optimized
  278. char CIStreamBuffer::SkipSpaces(void)
  279.     THROWS1((CIOException))
  280. {
  281.     // cache pointers
  282.     char* pos = m_CurrentPos;
  283.     char* end = m_DataEndPos;
  284.     // make sure thire is at least one char in buffer
  285.     if ( pos == end ) {
  286.         // fill buffer
  287.         pos = FillBuffer(pos);
  288.         // cache m_DataEndPos
  289.         end = m_DataEndPos;
  290.     }
  291.     // main cycle
  292.     // at the beginning:
  293.     //     pos == m_CurrentPos
  294.     //     end == m_DataEndPos
  295.     //     pos < end
  296.     for (;;) {
  297.         // we use do{}while() cycle because
  298.         // condition is true at the beginning ( pos < end )
  299.         do {
  300.             // cache current char
  301.             char c = *pos;
  302.             if ( c != ' ' ) { // it's not space (' ')
  303.                 // point m_CurrentPos to first non space char
  304.                 m_CurrentPos = pos;
  305.                 // return char value
  306.                 return c;
  307.             }
  308.             // skip space char
  309.         } while ( ++pos < end );
  310.         // here pos == end == m_DataEndPos
  311.         // point m_CurrentPos to end of buffer
  312.         m_CurrentPos = pos;
  313.         // fill next portion
  314.         pos = FillBuffer(pos);
  315.         // cache m_DataEndPos
  316.         end = m_DataEndPos;
  317.     }
  318. }
  319. // this method is highly optimized
  320. void CIStreamBuffer::FindChar(char c)
  321.     THROWS1((CIOException))
  322. {
  323.     // cache pointers
  324.     char* pos = m_CurrentPos;
  325.     char* end = m_DataEndPos;
  326.     // make sure thire is at least one char in buffer
  327.     if ( pos == end ) {
  328.         // fill buffer
  329.         pos = FillBuffer(pos);
  330.         // cache m_DataEndPos
  331.         end = m_DataEndPos;
  332.     }
  333.     // main cycle
  334.     // at the beginning:
  335.     //     pos == m_CurrentPos
  336.     //     end == m_DataEndPos
  337.     //     pos < end
  338.     for (;;) {
  339.         char* found = static_cast<char*>(memchr(pos, c, end - pos));
  340.         if ( found ) {
  341.             m_CurrentPos = found;
  342.             return;
  343.         }
  344.         // point m_CurrentPos to end of buffer
  345.         m_CurrentPos = end;
  346.         // fill next portion
  347.         pos = FillBuffer(end);
  348.         // cache m_DataEndPos
  349.         end = m_DataEndPos;
  350.     }
  351. }
  352. // this method is highly optimized
  353. size_t CIStreamBuffer::PeekFindChar(char c, size_t limit)
  354.     THROWS1((CIOException))
  355. {
  356.     _ASSERT(limit > 0);
  357.     PeekCharNoEOF(limit - 1);
  358.     // cache pointers
  359.     char* pos = m_CurrentPos;
  360.     size_t bufferSize = m_DataEndPos - pos;
  361.     if ( bufferSize != 0 ) {
  362.         char* found =
  363.             static_cast<char*>(memchr(pos, c, min(limit, bufferSize)));
  364.         if ( found )
  365.             return found - pos;
  366.     }
  367.     return limit;
  368. }
  369. char* CIStreamBuffer::FillBuffer(char* pos, bool noEOF)
  370.     THROWS1((CIOException, bad_alloc))
  371. {
  372.     _ASSERT(pos >= m_DataEndPos);
  373.     // remove unused portion of buffer at the beginning
  374.     _ASSERT(m_CurrentPos >= m_Buffer);
  375.     size_t erase = m_CurrentPos - m_Buffer;
  376.     if ( erase > 0 ) {
  377.         char* newPos = m_CurrentPos - erase;
  378.         if ( m_Collector ) {
  379.             _ASSERT(m_CollectPos);
  380.             size_t count = m_CurrentPos - m_CollectPos;
  381.             if ( count > 0 )
  382.                 m_Collector->AddChunk(m_CollectPos, count);
  383.             m_CollectPos = newPos;
  384.         }
  385.         size_t copy_count = m_DataEndPos - m_CurrentPos;
  386.         if ( copy_count )
  387.             memmove(newPos, m_CurrentPos, copy_count);
  388.         m_CurrentPos = newPos;
  389.         m_DataEndPos -= erase;
  390.         m_BufferOffset += erase;
  391.         pos -= erase;
  392.     }
  393.     size_t dataSize = m_DataEndPos - m_Buffer;
  394.     size_t newPosOffset = pos - m_Buffer;
  395.     if ( newPosOffset >= m_BufferSize ) {
  396.         // reallocate buffer
  397.         size_t newSize = BiggerBufferSize(m_BufferSize);
  398.         while ( newPosOffset >= newSize ) {
  399.             newSize = BiggerBufferSize(newSize);
  400.         }
  401.         char* newBuffer = new char[newSize];
  402.         memcpy(newBuffer, m_Buffer, dataSize);
  403.         m_CurrentPos = newBuffer + (m_CurrentPos - m_Buffer);
  404.         if ( m_CollectPos )
  405.             m_CollectPos = newBuffer + (m_CollectPos - m_Buffer);
  406.         pos = newBuffer + newPosOffset;
  407.         m_DataEndPos = newBuffer + dataSize;
  408.         delete[] m_Buffer;
  409.         m_Buffer = newBuffer;
  410.         m_BufferSize = newSize;
  411.     }
  412.     size_t load = m_BufferSize - dataSize;
  413.     while ( load > 0  &&  pos >= m_DataEndPos ) {
  414.         size_t count = m_Input->Read(m_DataEndPos, load);
  415.         if ( count == 0 ) {
  416.             if ( pos < m_DataEndPos )
  417.                 return pos;
  418.             if ( m_Input->EndOfData() ) {
  419.                 if ( noEOF ) {
  420.                     // ignore EOF
  421.                     _ASSERT(m_Buffer <= m_CurrentPos);
  422.                     _ASSERT(m_CurrentPos <= pos);
  423.                     _ASSERT(m_DataEndPos <= m_Buffer + m_BufferSize);
  424.                     _ASSERT(!m_CollectPos ||
  425.                             (m_CollectPos>=m_Buffer &&
  426.                              m_CollectPos<=m_CurrentPos));
  427.                     return pos;
  428.                 }
  429.                 m_Error = "end of file";
  430. //                THROW0_TRACE(CEofException());
  431.                 NCBI_THROW(CEofException,eEof,m_Error);
  432.             }
  433.             else {
  434.                 m_Error = "read fault";
  435. //                THROW1_TRACE(CIOException, "read fault");
  436.                 NCBI_THROW(CIOException,eRead,m_Error);
  437.             }
  438.         }
  439.         m_DataEndPos += count;
  440.         load -= count;
  441.     }
  442.     _ASSERT(m_Buffer <= m_CurrentPos);
  443.     _ASSERT(m_CurrentPos <= pos);
  444.     _ASSERT(pos < m_DataEndPos);
  445.     _ASSERT(m_DataEndPos <= m_Buffer + m_BufferSize);
  446.     _ASSERT(!m_CollectPos || (m_CollectPos>=m_Buffer && m_CollectPos<=m_CurrentPos));
  447.     return pos;
  448. }
  449. char CIStreamBuffer::FillBufferNoEOF(char* pos)
  450.     THROWS1((CIOException, bad_alloc))
  451. {
  452.     pos = FillBuffer(pos, true);
  453.     if ( pos >= m_DataEndPos )
  454.         return 0;
  455.     else
  456.         return *pos;
  457. }
  458. void CIStreamBuffer::GetChars(char* buffer, size_t count)
  459.     THROWS1((CIOException))
  460. {
  461.     // cache pos
  462.     char* pos = m_CurrentPos;
  463.     for ( ;; ) {
  464.         size_t c = m_DataEndPos - pos;
  465.         if ( c >= count ) {
  466.             // all data is already in buffer -> copy it
  467.             memcpy(buffer, pos, count);
  468.             m_CurrentPos = pos + count;
  469.             return;
  470.         }
  471.         else {
  472.             memcpy(buffer, pos, c);
  473.             buffer += c;
  474.             count -= c;
  475.             m_CurrentPos = pos += c;
  476.             pos = FillBuffer(pos);
  477.         }
  478.     }
  479. }
  480. void CIStreamBuffer::GetChars(size_t count)
  481.     THROWS1((CIOException))
  482. {
  483.     // cache pos
  484.     char* pos = m_CurrentPos;
  485.     for ( ;; ) {
  486.         size_t c = m_DataEndPos - pos;
  487.         if ( c >= count ) {
  488.             // all data is already in buffer -> skip it
  489.             m_CurrentPos = pos + count;
  490.             return;
  491.         }
  492.         else {
  493.             count -= c;
  494.             m_CurrentPos = pos += c;
  495.             pos = FillBuffer(pos);
  496.         }
  497.     }
  498. }
  499. void CIStreamBuffer::SkipEndOfLine(char lastChar)
  500.     THROWS1((CIOException))
  501. {
  502.     _ASSERT(lastChar == 'n' || lastChar == 'r');
  503.     _ASSERT(m_CurrentPos > m_Buffer && m_CurrentPos[-1] == lastChar);
  504.     m_Line++;
  505.     char nextChar;
  506.     try {
  507.         nextChar = PeekChar();
  508.     }
  509.     catch ( CEofException& /* ignored */ ) {
  510.         return;
  511.     }
  512.     // lastChar either 'r' or n'
  513.     // if nextChar is compliment, skip it
  514.     if ( (lastChar + nextChar) == ('r' + 'n') )
  515.         SkipChar();
  516. }
  517. size_t CIStreamBuffer::ReadLine(char* buff, size_t size)
  518.     THROWS1((CIOException))
  519. {
  520.     size_t count = 0;
  521.     try {
  522.         while ( size > 0 ) {
  523.             char c = *buff++ = GetChar();
  524.             count++;
  525.             size--;
  526.             switch ( c ) {
  527.             case 'r':
  528.                 // replace leading 'r' by 'n'
  529.                 buff[-1] = 'n';
  530.                 if ( PeekChar() == 'n' )
  531.                     SkipChar();
  532.                 return count;
  533.             case 'n':
  534.                 if ( PeekChar() == 'r' )
  535.                     SkipChar();
  536.                 return count;
  537.             }
  538.         }
  539.         return count;
  540.     }
  541.     catch ( CEofException& /*ignored*/ ) {
  542.         return count;
  543.     }
  544. }
  545. void CIStreamBuffer::BadNumber(void)
  546. {
  547.     m_Error = "bad number";
  548. //    THROW1_TRACE(runtime_error, "bad number in line " + NStr::UIntToString(GetLine()));
  549.     NCBI_THROW(CIOException,eRead,
  550.         "bad number in line " + NStr::UIntToString(GetLine()));
  551. }
  552. void CIStreamBuffer::SetStreamOffset(size_t pos)
  553. {
  554.     m_Input->Seekg(pos);
  555.     m_BufferOffset = pos;
  556.     m_DataEndPos = m_Buffer;
  557.     m_CurrentPos = m_Buffer;
  558.     m_Line = 1;
  559. }
  560. Int4 CIStreamBuffer::GetInt4(void)
  561. {
  562.     bool sign;
  563.     char c = GetChar();
  564.     switch ( c ) {
  565.     case '-':
  566.         sign = true;
  567.         c = GetChar();
  568.         break;
  569.     case '+':
  570.         sign = false;
  571.         c = GetChar();
  572.         break;
  573.     default:
  574.         sign = false;
  575.         break;
  576.     }
  577.     if ( c < '0' || c > '9' )
  578.         BadNumber();
  579.     Int4 n = c - '0';
  580.     for ( ;; ) {
  581.         c = PeekCharNoEOF();
  582.         if  ( c < '0' || c > '9' )
  583.             break;
  584.         SkipChar();
  585.         // TODO: check overflow
  586.         n = n * 10 + (c - '0');
  587.     }
  588.     if ( sign )
  589.         return -n;
  590.     else
  591.         return n;
  592. }
  593. Uint4 CIStreamBuffer::GetUint4(void)
  594. {
  595.     char c = GetChar();
  596.     if ( c == '+' )
  597.         c = GetChar();
  598.     if ( c < '0' || c > '9' )
  599.         BadNumber();
  600.     Uint4 n = c - '0';
  601.     for ( ;; ) {
  602.         c = PeekCharNoEOF();
  603.         if  ( c < '0' || c > '9' )
  604.             break;
  605.         SkipChar();
  606.         // TODO: check overflow
  607.         n = n * 10 + (c - '0');
  608.     }
  609.     return n;
  610. }
  611. Int8 CIStreamBuffer::GetInt8(void)
  612.     THROWS1((CIOException))
  613. {
  614.     bool sign;
  615.     char c = GetChar();
  616.     switch ( c ) {
  617.     case '-':
  618.         sign = true;
  619.         c = GetChar();
  620.         break;
  621.     case '+':
  622.         sign = false;
  623.         c = GetChar();
  624.         break;
  625.     default:
  626.         sign = false;
  627.         break;
  628.     }
  629.     if ( c < '0' || c > '9' )
  630.         BadNumber();
  631.     Int8 n = c - '0';
  632.     for ( ;; ) {
  633.         c = PeekCharNoEOF();
  634.         if  ( c < '0' || c > '9' )
  635.             break;
  636.         SkipChar();
  637.         // TODO: check overflow
  638.         n = n * 10 + (c - '0');
  639.     }
  640.     if ( sign )
  641.         return -n;
  642.     else
  643.         return n;
  644. }
  645. Uint8 CIStreamBuffer::GetUint8(void)
  646.     THROWS1((CIOException))
  647. {
  648.     char c = GetChar();
  649.     if ( c == '+' )
  650.         c = GetChar();
  651.     if ( c < '0' || c > '9' )
  652.         BadNumber();
  653.     Uint8 n = c - '0';
  654.     for ( ;; ) {
  655.         c = PeekCharNoEOF();
  656.         if  ( c < '0' || c > '9' )
  657.             break;
  658.         SkipChar();
  659.         // TODO: check overflow
  660.         n = n * 10 + (c - '0');
  661.     }
  662.     return n;
  663. }
  664. COStreamBuffer::COStreamBuffer(CNcbiOstream& out, bool deleteOut)
  665.     THROWS1((bad_alloc))
  666.     : m_Output(out), m_DeleteOutput(deleteOut), m_Error(0),
  667.       m_IndentLevel(0), m_BufferOffset(0),
  668.       m_Buffer(new char[KInitialBufferSize]),
  669.       m_CurrentPos(m_Buffer),
  670.       m_BufferEnd(m_Buffer + KInitialBufferSize),
  671.       m_Line(1), m_LineLength(0),
  672.       m_BackLimit(0), m_UseIndentation(true)
  673. {
  674. }
  675. COStreamBuffer::~COStreamBuffer(void)
  676. {
  677.     try {
  678.         Close();
  679.     }
  680.     catch ( exception& exc ) {
  681.         ERR_POST(Warning <<
  682.                  "~COStreamBuffer: exception while closing: " << exc.what());
  683.     }
  684.     delete[] m_Buffer;
  685. }
  686. void COStreamBuffer::Close(void)
  687. {
  688.     if ( m_Output ) {
  689.         Flush();
  690.         if ( m_DeleteOutput )
  691.             delete &m_Output;
  692.         m_DeleteOutput = false;
  693.     }
  694.     m_Error = 0;
  695.     m_IndentLevel = 0;
  696.     m_CurrentPos = m_Buffer;
  697.     m_Line = 1;
  698.     m_LineLength = 0;
  699. }
  700. void COStreamBuffer::FlushBuffer(bool fullBuffer)
  701.     THROWS1((CIOException))
  702. {
  703.     size_t used = GetUsedSpace();
  704.     size_t count;
  705.     size_t leave;
  706.     if ( fullBuffer ) {
  707.         count = used;
  708.         leave = 0;
  709.     }
  710.     else {
  711.         leave = m_BackLimit;
  712.         if ( used < leave )
  713.             return; // none to flush
  714.         count = used - leave;
  715.     }
  716.     if ( count != 0 ) {
  717.         if ( !m_Output.write(m_Buffer, count) ) {
  718.             m_Error = "write fault";
  719. //            THROW1_TRACE(CIOException, "write fault");
  720.             NCBI_THROW(CIOException,eWrite,m_Error);
  721.         }
  722.         if ( leave != 0 ) {
  723.             memmove(m_Buffer, m_Buffer + count, leave);
  724.             m_CurrentPos -= count;
  725.         }
  726.         else {
  727.             m_CurrentPos = m_Buffer;
  728.         }
  729.         m_BufferOffset += count;
  730.     }
  731. }
  732. void COStreamBuffer::Flush(void)
  733.     THROWS1((CIOException))
  734. {
  735.     FlushBuffer();
  736.     IOS_BASE::iostate state = m_Output.rdstate();
  737.     m_Output.clear();
  738.     try {
  739.         if ( !m_Output.flush() ) {
  740.             NCBI_THROW(CIOException,eFlush,"COStreamBuffer::Flush: failed");
  741.         }
  742.     }
  743.     catch (...) {
  744.         m_Output.clear(state);
  745.         throw;
  746.     }
  747.     m_Output.clear(state);
  748. }
  749. char* COStreamBuffer::DoReserve(size_t count)
  750.     THROWS1((CIOException, bad_alloc))
  751. {
  752.     FlushBuffer(false);
  753.     size_t usedSize = m_CurrentPos - m_Buffer;
  754.     size_t needSize = usedSize + count;
  755.     size_t bufferSize = m_BufferEnd - m_Buffer;
  756.     if ( bufferSize < needSize ) {
  757.         // realloc too small buffer
  758.         do {
  759.             bufferSize = BiggerBufferSize(bufferSize);
  760.         } while ( bufferSize < needSize );
  761.         if ( usedSize == 0 ) {
  762.             delete[] m_Buffer;
  763.             m_CurrentPos = m_Buffer = new char[bufferSize];
  764.             m_BufferEnd = m_Buffer + bufferSize;
  765.         }
  766.         else {
  767.             char* oldBuffer = m_Buffer;
  768.             m_Buffer = new char[bufferSize];
  769.             m_BufferEnd = m_Buffer + bufferSize;
  770.             memcpy(m_Buffer, oldBuffer, usedSize);
  771.             delete[] oldBuffer;
  772.             m_CurrentPos = m_Buffer + usedSize;
  773.         }
  774.     }
  775.     return m_CurrentPos;
  776. }
  777. void COStreamBuffer::PutInt4(Int4 v)
  778.     THROWS1((CIOException, bad_alloc))
  779. {
  780.     const size_t BSIZE = (sizeof(v)*CHAR_BIT) / 3 + 2;
  781.     char b[BSIZE];
  782.     char* pos = b + BSIZE;
  783.     if ( v == 0 ) {
  784.         *--pos = '0';
  785.     }
  786.     else {
  787.         Uint4 uv = v;
  788.         bool sign = v < 0;
  789.         if ( sign )
  790.             uv = -v;
  791.         
  792.         do {
  793.             *--pos = char('0' + (uv % 10));
  794.             uv /= 10;
  795.         } while ( uv );
  796.         
  797.         if ( sign )
  798.             *--pos = '-';
  799.     }
  800.     PutString(pos, b + BSIZE - pos);
  801. }
  802. void COStreamBuffer::PutUint4(Uint4 v)
  803.     THROWS1((CIOException, bad_alloc))
  804. {
  805.     const size_t BSIZE = (sizeof(v)*CHAR_BIT) / 3 + 2;
  806.     char b[BSIZE];
  807.     char* pos = b + BSIZE;
  808.     if ( v == 0 ) {
  809.         *--pos = '0';
  810.     }
  811.     else {
  812.         do {
  813.             *--pos = char('0' + (v % 10));
  814.             v /= 10;
  815.         } while ( v );
  816.     }
  817.     PutString(pos, b + BSIZE - pos);
  818. }
  819. void COStreamBuffer::PutInt8(Int8 v)
  820.     THROWS1((CIOException, bad_alloc))
  821. {
  822.     const size_t BSIZE = (sizeof(v)*CHAR_BIT) / 3 + 2;
  823.     char b[BSIZE];
  824.     char* pos = b + BSIZE;
  825.     if ( v == 0 ) {
  826.         *--pos = '0';
  827.     }
  828.     else {
  829.         bool sign = v < 0;
  830.         if ( sign )
  831.             v = -v;
  832.         
  833.         do {
  834.             *--pos = char('0' + (v % 10));
  835.             v /= 10;
  836.         } while ( v );
  837.         
  838.         if ( sign )
  839.             *--pos = '-';
  840.     }
  841.     PutString(pos, b + BSIZE - pos);
  842. }
  843. void COStreamBuffer::PutUint8(Uint8 v)
  844.     THROWS1((CIOException, bad_alloc))
  845. {
  846.     const size_t BSIZE = (sizeof(v)*CHAR_BIT) / 3 + 2;
  847.     char b[BSIZE];
  848.     char* pos = b + BSIZE;
  849.     if ( v == 0 ) {
  850.         *--pos = '0';
  851.     }
  852.     else {
  853.         do {
  854.             *--pos = char('0' + (v % 10));
  855.             v /= 10;
  856.         } while ( v );
  857.     }
  858.     PutString(pos, b + BSIZE - pos);
  859. }
  860. void COStreamBuffer::PutEolAtWordEnd(size_t lineLength)
  861.     THROWS1((CIOException, bad_alloc))
  862. {
  863.     Reserve(1);
  864.     size_t linePos = m_LineLength;
  865.     char* pos = m_CurrentPos;
  866.     bool goodPlace = false;
  867.     while ( pos > m_Buffer && linePos > 0 ) {
  868.         --pos;
  869.         --linePos;
  870.         if ( linePos <= lineLength && (isspace(*pos) || *pos == ''') ) {
  871.             goodPlace = true;
  872.             break;
  873.         }
  874.         else if ( *pos == 'n' || *pos == '"' ) {
  875.             // no suitable space found
  876.             break;
  877.         }
  878.     }
  879.     // Prevent insertion of more than one 'n'
  880.     if (pos > m_Buffer  &&  *(pos-1) == 'n') {
  881.         goodPlace = false;
  882.     }
  883.     if ( !goodPlace ) {
  884.         // no suitable space found
  885.         if ( linePos < lineLength ) {
  886.             pos += lineLength - linePos;
  887.             linePos = lineLength;
  888.         }
  889.         // assure we will not break double ""
  890.         while ( pos > m_Buffer && *(pos - 1) == '"' ) {
  891.             --pos;
  892.             --linePos;
  893.         }
  894.         if ( pos == m_Buffer ) {
  895.             // it's possible that we already put some " before...
  896.             while ( pos < m_CurrentPos && *pos == '"' ) {
  897.                 ++pos;
  898.                 ++linePos;
  899.             }
  900.         }
  901.     }
  902.     // split there
  903.     // insert 'n'
  904.     size_t count = m_CurrentPos - pos;
  905.     memmove(pos + 1, pos, count);
  906.     m_LineLength = count;
  907.     ++m_CurrentPos;
  908.     *pos = 'n';
  909.     ++m_Line;
  910. }
  911. void COStreamBuffer::Write(const char* data, size_t dataLength)
  912.     THROWS1((CIOException, bad_alloc))
  913. {
  914.     while ( dataLength > 0 ) {
  915.         size_t available = GetAvailableSpace();
  916.         if ( available == 0 ) {
  917.             FlushBuffer(false);
  918.             available = GetAvailableSpace();
  919.         }
  920.         if ( available >= dataLength )
  921.             break; // current chunk will fit in buffer
  922.         memcpy(m_CurrentPos, data, available);
  923.         m_CurrentPos += available;
  924.         data += available;
  925.         dataLength -= available;
  926.     }
  927.     memcpy(m_CurrentPos, data, dataLength);
  928.     m_CurrentPos += dataLength;
  929. }
  930. void COStreamBuffer::Write(CByteSourceReader& reader)
  931.     THROWS1((CIOException, bad_alloc))
  932. {
  933.     for ( ;; ) {
  934.         size_t available = GetAvailableSpace();
  935.         if ( available == 0 ) {
  936.             FlushBuffer(false);
  937.             available = GetAvailableSpace();
  938.         }
  939.         size_t count = reader.Read(m_CurrentPos, available);
  940.         if ( count == 0 ) {
  941.             if ( reader.EndOfData() )
  942.                 return;
  943.             else
  944. //                THROW1_TRACE(CIOException, "buffer read fault");
  945.                 NCBI_THROW(CIOException,eRead,"buffer read fault");
  946.         }
  947.         m_CurrentPos += count;
  948.     }
  949. }
  950. END_NCBI_SCOPE