Mercurial > projects > hoofbaby
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 } |