Claw  1.7.3
buffered_istream.tpp
1 /*
2  CLAW - a C++ Library Absolutely Wonderful
3 
4  CLAW is a free library without any particular aim but being useful to
5  anyone.
6 
7  Copyright (C) 2005-2011 Julien Jorge
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 
23  contact: julien.jorge@gamned.org
24 */
25 /**
26  * \file buffered_istream.tpp
27  * \brief Implementation of the claw::buffered_istream class.
28  * \author Julien Jorge
29  */
30 #include <cassert>
31 
32 /*----------------------------------------------------------------------------*/
33 /**
34  * \brief Constructor.
35  * \param f The file associated to the stream.
36  */
37 template<typename Stream>
38 claw::buffered_istream<Stream>::buffered_istream( stream_type& f )
39  : m_stream(f), m_begin(NULL), m_end(NULL), m_current(NULL),
40  m_buffer_size(1024)
41 {
42  m_begin = new char[m_buffer_size];
43  m_end = m_begin;
44  m_current = m_end;
45 } // buffered_istream::buffered_istream()
46 
47 /*----------------------------------------------------------------------------*/
48 /**
49  * \brief Destructor.
50  */
51 template<typename Stream>
52 claw::buffered_istream<Stream>::~buffered_istream()
53 {
54  close();
55 
56  if (m_begin)
57  delete[] m_begin;
58 } // buffered_istream::~buffered_istream()
59 
60 /*----------------------------------------------------------------------------*/
61 /**
62  * \brief Tell how many bytes are ready in the buffer.
63  */
64 template<typename Stream>
65 unsigned int claw::buffered_istream<Stream>::remaining() const
66 {
67  return m_end - m_current;
68 } // buffered_istream::remaining()
69 
70 /*----------------------------------------------------------------------------*/
71 /**
72  * \brief Increase the number of ready bytes to a given number.
73  * \param n The number of bytes you need.
74  * \remark This method reads n - remaining() bytes from the file.
75  */
76 template<typename Stream>
77 bool claw::buffered_istream<Stream>::read_more( unsigned int n )
78 {
79  if ( n <= remaining() )
80  return true;
81 
82  unsigned int r = remaining();
83 
84  // we'll reach the end of the buffer
85  if ( m_current + n > m_begin + m_buffer_size )
86  {
87  // try to avoid reallocation
88  if (n <= m_buffer_size)
89  std::copy(m_current, m_end, m_begin);
90  else // not enough space in the buffer
91  {
92  m_buffer_size = n;
93 
94  char* new_buffer = new char[m_buffer_size];
95 
96  std::copy(m_current, m_end, new_buffer);
97 
98  delete[] m_begin;
99 
100  m_begin = new_buffer;
101  }
102 
103  m_current = m_begin;
104  m_end = m_current + r;
105  }
106 
107  m_stream.read( m_end, n-r );
108  m_end += m_stream.gcount();
109 
110  return !!m_stream;
111 } // buffered_istream::read_more()
112 
113 /*----------------------------------------------------------------------------*/
114 /**
115  * \brief Get the input buffer.
116  */
117 template<typename Stream>
118 const char* claw::buffered_istream<Stream>::get_buffer() const
119 {
120  return m_current;
121 } // buffered_istream::get_buffer()
122 
123 /*----------------------------------------------------------------------------*/
124 /**
125  * \brief Get the next value in the buffer and move one byte forward.
126  */
127 template<typename Stream>
128 char claw::buffered_istream<Stream>::get_next()
129 {
130  assert( remaining() >= 1 );
131 
132  char result = *m_current;
133  ++m_current;
134 
135  return result;
136 } // buffered_istream::get_next()
137 
138 /*----------------------------------------------------------------------------*/
139 /**
140  * \brief Read a range of data.
141  * \param buf The buffer in which we write the read data.
142  * \param n The number of bytes to read.
143  */
144 template<typename Stream>
145 bool claw::buffered_istream<Stream>::read( char* buf, unsigned int n )
146 {
147  while ( (n != 0) && !!(*this) )
148  {
149  if ( n > remaining() )
150  read_more(m_buffer_size);
151 
152  unsigned int len = std::min(n, remaining());
153 
154  std::copy( m_current, m_current + len, buf );
155  buf += len;
156  n -= len;
157  m_current += len;
158  }
159 
160  return n==0;
161 } // buffered_istream::read()
162 
163 /*----------------------------------------------------------------------------*/
164 /**
165  * \brief Move some bytes forward.
166  * \param n The number of bytes to skip.
167  */
168 template<typename Stream>
169 void claw::buffered_istream<Stream>::move( unsigned int n )
170 {
171  assert( m_current + n <= m_end );
172  m_current += n;
173 } // buffered_istream::move()
174 
175 /*----------------------------------------------------------------------------*/
176 /**
177  * \brief Closes this buffer (not the stream).
178  *
179  * The cursor of the stream is repositioned according to the remaining data, and
180  * the buffer is cleared.
181  */
182 template<typename Stream>
183 void claw::buffered_istream<Stream>::close()
184 {
185  m_stream.seekg( m_current - m_end, std::ios_base::cur );
186  m_current = m_begin;
187  m_end = m_begin;
188 } // buffered_istream::close()
189 
190 /*----------------------------------------------------------------------------*/
191 /**
192  * \brief Tell if there is still datas in the buffer/stream.
193  */
194 template<typename Stream>
195 claw::buffered_istream<Stream>::operator bool() const
196 {
197  return m_stream || (remaining() > 0);
198 } // buffered_istream::operator bool()