comparison deps/Platinum/ThirdParty/Neptune/Source/Core/NptBufferedStreams.cpp @ 0:3425707ddbf6

Initial import (hopefully this mercurial stuff works...)
author fraserofthenight
date Mon, 06 Jul 2009 08:06:28 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:3425707ddbf6
1 /*****************************************************************
2 |
3 | Neptune - Buffered Streams
4 |
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
6 | All rights reserved.
7 |
8 | Redistribution and use in source and binary forms, with or without
9 | modification, are permitted provided that the following conditions are met:
10 | * Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 | * Redistributions in binary form must reproduce the above copyright
13 | notice, this list of conditions and the following disclaimer in the
14 | documentation and/or other materials provided with the distribution.
15 | * Neither the name of Axiomatic Systems nor the
16 | names of its contributors may be used to endorse or promote products
17 | derived from this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY
20 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
30 ****************************************************************/
31
32 /*----------------------------------------------------------------------
33 | includes
34 +---------------------------------------------------------------------*/
35 #include "NptTypes.h"
36 #include "NptInterfaces.h"
37 #include "NptConstants.h"
38 #include "NptBufferedStreams.h"
39 #include "NptUtils.h"
40
41 /*----------------------------------------------------------------------
42 | NPT_BufferedInputStream::NPT_BufferedInputStream
43 +---------------------------------------------------------------------*/
44 NPT_BufferedInputStream::NPT_BufferedInputStream(NPT_InputStreamReference& source, NPT_Size buffer_size) :
45 m_Source(source),
46 m_SkipNewline(false),
47 m_Eos(false)
48 {
49 // setup the read buffer
50 m_Buffer.data = NULL;
51 m_Buffer.offset = 0;
52 m_Buffer.valid = 0;
53 m_Buffer.size = buffer_size;
54 }
55
56 /*----------------------------------------------------------------------
57 | NPT_BufferedInputStream::~NPT_BufferedInputStream
58 +---------------------------------------------------------------------*/
59 NPT_BufferedInputStream::~NPT_BufferedInputStream()
60 {
61 // release the buffer
62 delete[] m_Buffer.data;
63 }
64
65 /*----------------------------------------------------------------------
66 | NPT_BufferedInputStream::SetBufferSize
67 +---------------------------------------------------------------------*/
68 NPT_Result
69 NPT_BufferedInputStream::SetBufferSize(NPT_Size size)
70 {
71 if (m_Buffer.data != NULL) {
72 // we already have a buffer
73 if (m_Buffer.size < size) {
74 // the current buffer is too small, reallocate
75 NPT_Byte* buffer = new NPT_Byte[size];
76 if (buffer == NULL) return NPT_ERROR_OUT_OF_MEMORY;
77
78 // copy existing data
79 NPT_Size need_to_copy = m_Buffer.valid - m_Buffer.offset;
80 if (need_to_copy) {
81 NPT_CopyMemory((void*)buffer,
82 m_Buffer.data+m_Buffer.offset,
83 need_to_copy);
84 }
85
86 // use the new buffer
87 delete[] m_Buffer.data;
88 m_Buffer.data = buffer;
89 m_Buffer.valid -= m_Buffer.offset;
90 m_Buffer.offset = 0;
91 }
92 }
93 m_Buffer.size = size;
94
95 return NPT_SUCCESS;
96 }
97
98 /*----------------------------------------------------------------------
99 | NPT_BufferedInputStream::FillBuffer
100 +---------------------------------------------------------------------*/
101 NPT_Result
102 NPT_BufferedInputStream::FillBuffer()
103 {
104 // shortcut
105 if (m_Eos) return NPT_ERROR_EOS;
106
107 // check that there is nothing left in the buffer and the buffer
108 // size is not 0
109 NPT_ASSERT(m_Buffer.valid == m_Buffer.offset);
110 NPT_ASSERT(m_Buffer.size != 0);
111
112 // allocate the read buffer if it has not been done yet
113 if (m_Buffer.data == NULL) {
114 m_Buffer.data = new NPT_Byte[m_Buffer.size];
115 if (m_Buffer.data == NULL) return NPT_ERROR_OUT_OF_MEMORY;
116 }
117
118 // refill the buffer
119 m_Buffer.offset = 0;
120 NPT_Result result = m_Source->Read(m_Buffer.data, m_Buffer.size, &m_Buffer.valid);
121 if (NPT_FAILED(result)) m_Buffer.valid = 0;
122 return result;
123 }
124
125 /*----------------------------------------------------------------------
126 | NPT_BufferedInputStream::ReleaseBuffer
127 +---------------------------------------------------------------------*/
128 NPT_Result
129 NPT_BufferedInputStream::ReleaseBuffer()
130 {
131 NPT_ASSERT(m_Buffer.size == 0);
132 NPT_ASSERT(m_Buffer.offset == m_Buffer.valid);
133
134 delete[] m_Buffer.data;
135 m_Buffer.data = NULL;
136 m_Buffer.offset = 0;
137 m_Buffer.valid = 0;
138
139 return NPT_SUCCESS;
140 }
141
142 /*----------------------------------------------------------------------
143 | NPT_BufferedInputStream::ReadLine
144 +---------------------------------------------------------------------*/
145 NPT_Result
146 NPT_BufferedInputStream::ReadLine(char* buffer,
147 NPT_Size size,
148 NPT_Size* chars_read,
149 bool break_on_cr)
150 {
151 NPT_Result result = NPT_SUCCESS;
152 char* buffer_start = buffer;
153 bool skip_newline = false;
154
155 // check parameters
156 if (buffer == NULL || size < 1) return NPT_ERROR_INVALID_PARAMETERS;
157
158 // read until EOF or newline
159 while (buffer-buffer_start < (long)(size-1)) {
160 while (m_Buffer.offset != m_Buffer.valid) {
161 // there is some data left in the buffer
162 NPT_Byte c = m_Buffer.data[m_Buffer.offset++];
163 if (c == '\r') {
164 if (break_on_cr) {
165 skip_newline = true;
166 goto done;
167 }
168 } else if (c == '\n') {
169 if (m_SkipNewline && (buffer == buffer_start)) {
170 continue;
171 }
172 goto done;
173 } else {
174 *buffer++ = c;
175 }
176 }
177
178 if (m_Buffer.size == 0 && !m_Eos) {
179 // unbuffered mode
180 if (m_Buffer.data != NULL) ReleaseBuffer();
181 while (NPT_SUCCEEDED(result = m_Source->Read(buffer, 1, NULL))) {
182 if (*buffer == '\r') {
183 if (break_on_cr) {
184 skip_newline = true;
185 goto done;
186 }
187 } else if (*buffer == '\n') {
188 goto done;
189 } else {
190 ++buffer;
191 }
192 }
193 } else {
194 // refill the buffer
195 result = FillBuffer();
196 }
197 if (NPT_FAILED(result)) goto done;
198 }
199
200 done:
201 // update the newline skipping state
202 m_SkipNewline = skip_newline;
203
204 // NULL-terminate the line
205 *buffer = '\0';
206
207 // return what we have
208 if (chars_read) *chars_read = (NPT_Size)(buffer-buffer_start);
209 if (result == NPT_ERROR_EOS) {
210 m_Eos = true;
211 if (buffer != buffer_start) {
212 // we have reached the end of the stream, but we have read
213 // some chars, so do not return EOS now
214 return NPT_SUCCESS;
215 }
216 }
217 return result;
218 }
219
220 /*----------------------------------------------------------------------
221 | NPT_BufferedInputStream::ReadLine
222 +---------------------------------------------------------------------*/
223 NPT_Result
224 NPT_BufferedInputStream::ReadLine(NPT_String& line,
225 NPT_Size max_chars,
226 bool break_on_cr)
227 {
228 // clear the line
229 line.SetLength(0);
230
231 // reserve space for the chars
232 line.Reserve(max_chars);
233
234 // read the line
235 NPT_Size chars_read = 0;
236 NPT_CHECK(ReadLine(line.UseChars(), max_chars, &chars_read, break_on_cr));
237
238 // adjust the length of the string object
239 line.SetLength(chars_read);
240
241 return NPT_SUCCESS;
242 }
243
244 /*----------------------------------------------------------------------
245 | NPT_BufferedInputStream::Read
246 +---------------------------------------------------------------------*/
247 NPT_Result
248 NPT_BufferedInputStream::Read(void* buffer,
249 NPT_Size bytes_to_read,
250 NPT_Size* bytes_read)
251 {
252 NPT_Result result = NPT_SUCCESS;
253 NPT_Size total_read = 0;
254 NPT_Size buffered;
255
256 // check for a possible shortcut
257 if (bytes_to_read == 0) return NPT_SUCCESS;
258
259 // skip a newline char if needed
260 if (m_SkipNewline) {
261 m_SkipNewline = false;
262 result = Read(buffer, 1, NULL);
263 if (NPT_FAILED(result)) goto done;
264 NPT_Byte c = *(NPT_Byte*)buffer;
265 if (c != '\n') {
266 buffer = (void*)((NPT_Byte*)buffer+1);
267 --bytes_to_read;
268 total_read = 1;
269 }
270 }
271
272 // compute how much is buffered
273 buffered = m_Buffer.valid-m_Buffer.offset;
274 if (bytes_to_read > buffered) {
275 // there is not enough in the buffer, take what's there
276 if (buffered) {
277 NPT_CopyMemory(buffer,
278 m_Buffer.data + m_Buffer.offset,
279 buffered);
280 buffer = (void*)((NPT_Byte*)buffer+buffered);
281 m_Buffer.offset += buffered;
282 bytes_to_read -= buffered;
283 total_read += buffered;
284 goto done;
285 }
286
287 // read the rest from the source
288 if (m_Buffer.size == 0) {
289 // unbuffered mode, read directly into the supplied buffer
290 if (m_Buffer.data != NULL) ReleaseBuffer(); // cleanup if necessary
291 NPT_Size local_read = 0;
292 result = m_Source->Read(buffer, bytes_to_read, &local_read);
293 if (NPT_SUCCEEDED(result)) {
294 total_read += local_read;
295 }
296 goto done;
297 } else {
298 // refill the buffer
299 result = FillBuffer();
300 if (NPT_FAILED(result)) goto done;
301 buffered = m_Buffer.valid;
302 if (bytes_to_read > buffered) bytes_to_read = buffered;
303 }
304 }
305
306 // get what we can from the buffer
307 if (bytes_to_read) {
308 NPT_CopyMemory(buffer,
309 m_Buffer.data + m_Buffer.offset,
310 bytes_to_read);
311 m_Buffer.offset += bytes_to_read;
312 total_read += bytes_to_read;
313 }
314
315 done:
316 if (bytes_read) *bytes_read = total_read;
317 if (result == NPT_ERROR_EOS) {
318 m_Eos = true;
319 if (total_read != 0) {
320 // we have reached the end of the stream, but we have read
321 // some chars, so do not return EOS now
322 return NPT_SUCCESS;
323 }
324 }
325 return result;
326 }
327
328 /*----------------------------------------------------------------------
329 | NPT_BufferedInputStream::Seek
330 +---------------------------------------------------------------------*/
331 NPT_Result
332 NPT_BufferedInputStream::Seek(NPT_Position /*offset*/)
333 {
334 // not implemented yet
335 return NPT_ERROR_NOT_IMPLEMENTED;
336 }
337
338 /*----------------------------------------------------------------------
339 | NPT_BufferedInputStream::Tell
340 +---------------------------------------------------------------------*/
341 NPT_Result
342 NPT_BufferedInputStream::Tell(NPT_Position& offset)
343 {
344 // not implemented yet
345 offset = 0;
346 return NPT_ERROR_NOT_IMPLEMENTED;
347 }
348
349 /*----------------------------------------------------------------------
350 | NPT_BufferedInputStream::GetSize
351 +---------------------------------------------------------------------*/
352 NPT_Result
353 NPT_BufferedInputStream::GetSize(NPT_LargeSize& size)
354 {
355 return m_Source->GetSize(size);
356 }
357
358 /*----------------------------------------------------------------------
359 | NPT_BufferedInputStream::GetAvailable
360 +---------------------------------------------------------------------*/
361 NPT_Result
362 NPT_BufferedInputStream::GetAvailable(NPT_LargeSize& available)
363 {
364 NPT_LargeSize source_available = 0;
365 NPT_Result result = m_Source->GetAvailable(source_available);
366 if (NPT_SUCCEEDED(result)) {
367 available = m_Buffer.valid-m_Buffer.offset + source_available;
368 return NPT_SUCCESS;
369 } else {
370 available = m_Buffer.valid-m_Buffer.offset;
371 return available?NPT_SUCCESS:result;
372 }
373 }