comparison deps/Platinum/ThirdParty/Neptune/Source/Core/NptStreams.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 - Byte 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 "NptStreams.h"
36 #include "NptUtils.h"
37 #include "NptConstants.h"
38 #include "NptStrings.h"
39 #include "NptDebug.h"
40
41 /*----------------------------------------------------------------------
42 | constants
43 +---------------------------------------------------------------------*/
44 const NPT_Size NPT_INPUT_STREAM_LOAD_DEFAULT_READ_CHUNK = 4096;
45 const NPT_LargeSize NPT_INPUT_STREAM_LOAD_MAX_SIZE = 0x100000; // 1GB
46
47 /*----------------------------------------------------------------------
48 | NPT_InputStream::Load
49 +---------------------------------------------------------------------*/
50 NPT_Result
51 NPT_InputStream::Load(NPT_DataBuffer& buffer, NPT_Size max_read /* = 0 */)
52 {
53 NPT_Result result;
54 NPT_LargeSize total_bytes_read;
55
56 // reset the buffer
57 buffer.SetDataSize(0);
58
59 // check the limits
60 if (max_read > NPT_INPUT_STREAM_LOAD_MAX_SIZE) {
61 return NPT_ERROR_INVALID_PARAMETERS;
62 }
63
64 // try to get the stream size
65 NPT_LargeSize size;
66 if (NPT_SUCCEEDED(GetSize(size))) {
67 // make sure we don't read more than max_read
68 if (max_read && max_read < size) size = max_read;
69 if (size > NPT_INPUT_STREAM_LOAD_MAX_SIZE) {
70 return NPT_ERROR_OUT_OF_RANGE;
71 }
72 } else {
73 size = max_read;
74 }
75
76 // pre-allocate the buffer
77 if (size) NPT_CHECK(buffer.Reserve((NPT_Size)size));
78
79 // read the data from the file
80 total_bytes_read = 0;
81 do {
82 NPT_LargeSize available = 0;
83 NPT_LargeSize bytes_to_read;
84 NPT_Size bytes_read;
85 NPT_Byte* data;
86
87 // check if we know how much data is available
88 result = GetAvailable(available);
89 if (NPT_SUCCEEDED(result) && available) {
90 // we know how much is available
91 bytes_to_read = available;
92 } else {
93 bytes_to_read = NPT_INPUT_STREAM_LOAD_DEFAULT_READ_CHUNK;
94 }
95
96 // make sure we don't read more than what was asked
97 if (size != 0 && total_bytes_read+bytes_to_read>size) {
98 bytes_to_read = size-total_bytes_read;
99 }
100
101 // stop if we've read everything
102 if (bytes_to_read == 0) break;
103
104 // ensure that the buffer has enough space
105 if (total_bytes_read+bytes_to_read > NPT_INPUT_STREAM_LOAD_MAX_SIZE) {
106 buffer.SetBufferSize(0);
107 return NPT_ERROR_OUT_OF_RANGE;
108 }
109 NPT_CHECK(buffer.Reserve((NPT_Size)(total_bytes_read+bytes_to_read)));
110
111 // read the data
112 data = buffer.UseData()+total_bytes_read;
113 result = Read((void*)data, (NPT_Size)bytes_to_read, &bytes_read);
114 if (NPT_SUCCEEDED(result) && bytes_read != 0) {
115 total_bytes_read += bytes_read;
116 buffer.SetDataSize((NPT_Size)total_bytes_read);
117 }
118 } while(NPT_SUCCEEDED(result) && (size==0 || total_bytes_read < size));
119
120 if (result == NPT_ERROR_EOS) {
121 return NPT_SUCCESS;
122 } else {
123 return result;
124 }
125 }
126
127 /*----------------------------------------------------------------------
128 | NPT_InputStream::ReadFully
129 +---------------------------------------------------------------------*/
130 NPT_Result
131 NPT_InputStream::ReadFully(void* buffer, NPT_Size bytes_to_read)
132 {
133 // shortcut
134 if (bytes_to_read == 0) return NPT_SUCCESS;
135
136 // read until failure
137 NPT_Size bytes_read;
138 while (bytes_to_read) {
139 NPT_Result result = Read(buffer, bytes_to_read, &bytes_read);
140 if (NPT_FAILED(result)) return result;
141 if (bytes_read == 0) return NPT_ERROR_INTERNAL;
142 NPT_ASSERT(bytes_read <= bytes_to_read);
143 bytes_to_read -= bytes_read;
144 buffer = (void*)(((NPT_Byte*)buffer)+bytes_read);
145 }
146
147 return NPT_SUCCESS;
148 }
149
150 /*----------------------------------------------------------------------
151 | NPT_InputStream::ReadUI64
152 +---------------------------------------------------------------------*/
153 NPT_Result
154 NPT_InputStream::ReadUI64(NPT_UInt64& value)
155 {
156 unsigned char buffer[8];
157
158 // read bytes from the stream
159 NPT_Result result;
160 result = ReadFully((void*)buffer, 8);
161 if (NPT_FAILED(result)) {
162 value = 0;
163 return result;
164 }
165
166 // convert bytes to value
167 value = NPT_BytesToInt64Be(buffer);
168
169 return NPT_SUCCESS;
170 }
171
172 /*----------------------------------------------------------------------
173 | NPT_InputStream::ReadUI32
174 +---------------------------------------------------------------------*/
175 NPT_Result
176 NPT_InputStream::ReadUI32(NPT_UInt32& value)
177 {
178 unsigned char buffer[4];
179
180 // read bytes from the stream
181 NPT_Result result;
182 result = ReadFully((void*)buffer, 4);
183 if (NPT_FAILED(result)) {
184 value = 0;
185 return result;
186 }
187
188 // convert bytes to value
189 value = NPT_BytesToInt32Be(buffer);
190
191 return NPT_SUCCESS;
192 }
193
194 /*----------------------------------------------------------------------
195 | NPT_InputStream::ReadUI24
196 +---------------------------------------------------------------------*/
197 NPT_Result
198 NPT_InputStream::ReadUI24(NPT_UInt32& value)
199 {
200 unsigned char buffer[3];
201
202 // read bytes from the stream
203 NPT_Result result;
204 result = ReadFully((void*)buffer, 3);
205 if (NPT_FAILED(result)) {
206 value = 0;
207 return result;
208 }
209
210 // convert bytes to value
211 value = NPT_BytesToInt24Be(buffer);
212
213 return NPT_SUCCESS;
214 }
215
216 /*----------------------------------------------------------------------
217 | NPT_InputStream::ReadUI16
218 +---------------------------------------------------------------------*/
219 NPT_Result
220 NPT_InputStream::ReadUI16(NPT_UInt16& value)
221 {
222 unsigned char buffer[2];
223
224 // read bytes from the stream
225 NPT_Result result;
226 result = ReadFully((void*)buffer, 2);
227 if (NPT_FAILED(result)) {
228 value = 0;
229 return result;
230 }
231
232 // convert bytes to value
233 value = NPT_BytesToInt16Be(buffer);
234
235 return NPT_SUCCESS;
236 }
237
238 /*----------------------------------------------------------------------
239 | NPT_InputStream::ReadUI08
240 +---------------------------------------------------------------------*/
241 NPT_Result
242 NPT_InputStream::ReadUI08(NPT_UInt8& value)
243 {
244 unsigned char buffer[1];
245
246 // read bytes from the stream
247 NPT_Result result;
248 result = ReadFully((void*)buffer, 1);
249 if (NPT_FAILED(result)) {
250 value = 0;
251 return result;
252 }
253
254 // convert bytes to value
255 value = buffer[0];
256
257 return NPT_SUCCESS;
258 }
259
260 /*----------------------------------------------------------------------
261 | NPT_InputStream::Skip
262 +---------------------------------------------------------------------*/
263 NPT_Result
264 NPT_InputStream::Skip(NPT_Size count)
265 {
266 // get the current location
267 NPT_Position position;
268 NPT_CHECK(Tell(position));
269
270 // seek ahead
271 return Seek(position+count);
272 }
273
274 /*----------------------------------------------------------------------
275 | NPT_OutputStream::WriteFully
276 +---------------------------------------------------------------------*/
277 NPT_Result
278 NPT_OutputStream::WriteFully(const void* buffer, NPT_Size bytes_to_write)
279 {
280 // shortcut
281 if (bytes_to_write == 0) return NPT_SUCCESS;
282
283 // write until failure
284 NPT_Size bytes_written;
285 while (bytes_to_write) {
286 NPT_Result result = Write(buffer, bytes_to_write, &bytes_written);
287 if (NPT_FAILED(result)) return result;
288 if (bytes_written == 0) return NPT_ERROR_INTERNAL;
289 NPT_ASSERT(bytes_written <= bytes_to_write);
290 bytes_to_write -= bytes_written;
291 buffer = (const void*)(((const NPT_Byte*)buffer)+bytes_written);
292 }
293
294 return NPT_SUCCESS;
295 }
296
297 /*----------------------------------------------------------------------
298 | NPT_OutputStream::WriteString
299 +---------------------------------------------------------------------*/
300 NPT_Result
301 NPT_OutputStream::WriteString(const char* buffer)
302 {
303 // shortcut
304 NPT_Size string_length;
305 if (buffer == NULL || (string_length = NPT_StringLength(buffer)) == 0) {
306 return NPT_SUCCESS;
307 }
308
309 // write the string
310 return WriteFully((const void*)buffer, string_length);
311 }
312
313 /*----------------------------------------------------------------------
314 | NPT_OutputStream::WriteLine
315 +---------------------------------------------------------------------*/
316 NPT_Result
317 NPT_OutputStream::WriteLine(const char* buffer)
318 {
319 NPT_CHECK(WriteString(buffer));
320 NPT_CHECK(WriteFully((const void*)"\r\n", 2));
321
322 return NPT_SUCCESS;
323 }
324
325 /*----------------------------------------------------------------------
326 | NPT_OutputStream::WriteUI64
327 +---------------------------------------------------------------------*/
328 NPT_Result
329 NPT_OutputStream::WriteUI64(NPT_UInt64 value)
330 {
331 unsigned char buffer[8];
332
333 // convert value to bytes
334 NPT_BytesFromInt64Be(buffer, value);
335
336 // write bytes to the stream
337 return WriteFully((void*)buffer, 8);
338 }
339
340 /*----------------------------------------------------------------------
341 | NPT_OutputStream::WriteUI32
342 +---------------------------------------------------------------------*/
343 NPT_Result
344 NPT_OutputStream::WriteUI32(NPT_UInt32 value)
345 {
346 unsigned char buffer[4];
347
348 // convert value to bytes
349 NPT_BytesFromInt32Be(buffer, value);
350
351 // write bytes to the stream
352 return WriteFully((void*)buffer, 4);
353 }
354
355 /*----------------------------------------------------------------------
356 | NPT_OutputStream::WriteUI24
357 +---------------------------------------------------------------------*/
358 NPT_Result
359 NPT_OutputStream::WriteUI24(NPT_UInt32 value)
360 {
361 unsigned char buffer[3];
362
363 // convert value to bytes
364 NPT_BytesFromInt24Be(buffer, value);
365
366 // write bytes to the stream
367 return WriteFully((void*)buffer, 3);
368 }
369
370 /*----------------------------------------------------------------------
371 | NPT_OutputStream::WriteUI16
372 +---------------------------------------------------------------------*/
373 NPT_Result
374 NPT_OutputStream::WriteUI16(NPT_UInt16 value)
375 {
376 unsigned char buffer[2];
377
378 // convert value to bytes
379 NPT_BytesFromInt16Be(buffer, value);
380
381 // write bytes to the stream
382 return WriteFully((void*)buffer, 2);
383 }
384
385 /*----------------------------------------------------------------------
386 | NPT_OutputStream::WriteUI08
387 +---------------------------------------------------------------------*/
388 NPT_Result
389 NPT_OutputStream::WriteUI08(NPT_UInt8 value)
390 {
391 return WriteFully((void*)&value, 1);
392 }
393
394 /*----------------------------------------------------------------------
395 | NPT_MemoryStream::NPT_MemoryStream
396 +---------------------------------------------------------------------*/
397 NPT_MemoryStream::NPT_MemoryStream(NPT_Size initial_capacity) :
398 m_Buffer(initial_capacity),
399 m_ReadOffset(0),
400 m_WriteOffset(0)
401 {
402 }
403
404 /*----------------------------------------------------------------------
405 | NPT_MemoryStream::NPT_MemoryStream
406 +---------------------------------------------------------------------*/
407 NPT_MemoryStream::NPT_MemoryStream(const void* data, NPT_Size size) :
408 m_Buffer(data, size),
409 m_ReadOffset(0),
410 m_WriteOffset(0)
411 {
412 }
413
414 /*----------------------------------------------------------------------
415 | NPT_MemoryStream::Read
416 +---------------------------------------------------------------------*/
417 NPT_Result
418 NPT_MemoryStream::Read(void* buffer,
419 NPT_Size bytes_to_read,
420 NPT_Size* bytes_read)
421 {
422 // check for shortcut
423 if (bytes_to_read == 0) {
424 if (bytes_read) *bytes_read = 0;
425 return NPT_SUCCESS;
426 }
427
428 // clip to what's available
429 NPT_Size available = m_Buffer.GetDataSize();
430 if (m_ReadOffset+bytes_to_read > available) {
431 bytes_to_read = available-m_ReadOffset;
432 }
433
434 // copy the data
435 if (bytes_to_read) {
436 NPT_CopyMemory(buffer, (void*)(((char*)m_Buffer.UseData())+m_ReadOffset), bytes_to_read);
437 m_ReadOffset += bytes_to_read;
438 }
439 if (bytes_read) *bytes_read = bytes_to_read;
440
441 return bytes_to_read?NPT_SUCCESS:NPT_ERROR_EOS;
442 }
443
444 /*----------------------------------------------------------------------
445 | NPT_MemoryStream::InputSeek
446 +---------------------------------------------------------------------*/
447 NPT_Result
448 NPT_MemoryStream::InputSeek(NPT_Position offset)
449 {
450 if (offset > m_Buffer.GetDataSize()) {
451 return NPT_ERROR_OUT_OF_RANGE;
452 } else {
453 m_ReadOffset = (NPT_Size)offset;
454 return NPT_SUCCESS;
455 }
456 }
457
458 /*----------------------------------------------------------------------
459 | NPT_MemoryStream::Write
460 +---------------------------------------------------------------------*/
461 NPT_Result
462 NPT_MemoryStream::Write(const void* data,
463 NPT_Size bytes_to_write,
464 NPT_Size* bytes_written)
465 {
466 NPT_CHECK(m_Buffer.Reserve(m_WriteOffset+bytes_to_write));
467
468 NPT_CopyMemory(m_Buffer.UseData()+m_WriteOffset, data, bytes_to_write);
469 m_WriteOffset += bytes_to_write;
470 if (m_WriteOffset > m_Buffer.GetDataSize()) {
471 m_Buffer.SetDataSize(m_WriteOffset);
472 }
473 if (bytes_written) *bytes_written = bytes_to_write;
474
475 return NPT_SUCCESS;
476 }
477
478 /*----------------------------------------------------------------------
479 | NPT_MemoryStream::OutputSeek
480 +---------------------------------------------------------------------*/
481 NPT_Result
482 NPT_MemoryStream::OutputSeek(NPT_Position offset)
483 {
484 if (offset <= m_Buffer.GetDataSize()) {
485 m_WriteOffset = (NPT_Size)offset;
486 return NPT_SUCCESS;
487 } else {
488 return NPT_ERROR_OUT_OF_RANGE;
489 }
490 }
491
492 /*----------------------------------------------------------------------
493 | NPT_MemoryStream::SetSize
494 +---------------------------------------------------------------------*/
495 NPT_Result
496 NPT_MemoryStream::SetSize(NPT_Size size)
497 {
498 // try to resize the data buffer
499 NPT_CHECK(m_Buffer.SetDataSize(size));
500
501 // adjust the read and write offsets
502 if (m_ReadOffset > size) m_ReadOffset = size;
503 if (m_WriteOffset > size) m_WriteOffset = size;
504
505 return NPT_SUCCESS;
506 }
507
508 /*----------------------------------------------------------------------
509 | NPT_StreamToStreamCopy
510 +---------------------------------------------------------------------*/
511 const unsigned int NPT_STREAM_COPY_BUFFER_SIZE = 4096; // copy 4k at a time
512 NPT_Result
513 NPT_StreamToStreamCopy(NPT_InputStream& from,
514 NPT_OutputStream& to,
515 NPT_Position offset /* = 0 */,
516 NPT_LargeSize size /* = 0, 0 means the entire stream */)
517 {
518 // seek into the input if required
519 if (offset) {
520 NPT_CHECK(from.Seek(offset));
521 }
522
523 // allocate a buffer for the transfer
524 NPT_LargeSize bytes_transfered = 0;
525 NPT_Byte* buffer = new NPT_Byte[NPT_STREAM_COPY_BUFFER_SIZE];
526 NPT_Result result = NPT_SUCCESS;
527 if (buffer == NULL) return NPT_ERROR_OUT_OF_MEMORY;
528
529 // copy until an error occurs or the end of stream is reached
530 for (;;) {
531 // read some data
532 NPT_Size bytes_to_read = NPT_STREAM_COPY_BUFFER_SIZE;
533 NPT_Size bytes_read = 0;
534 if (size) {
535 // a max size was specified
536 if (bytes_to_read > (NPT_Size)(size-bytes_transfered)) {
537 bytes_to_read = (NPT_Size)(size-bytes_transfered);
538 }
539 }
540 result = from.Read(buffer, bytes_to_read, &bytes_read);
541 if (NPT_FAILED(result)) {
542 if (result == NPT_ERROR_EOS) result = NPT_SUCCESS;
543 break;
544 }
545 if (bytes_read == 0) continue;
546
547 // write the data
548 result = to.WriteFully(buffer, bytes_read);
549 if (NPT_FAILED(result)) break;
550
551 // update the counts
552 if (size) {
553 bytes_transfered += bytes_read;
554 if (bytes_transfered >= size) break;
555 }
556 }
557
558 // free the buffer and return
559 delete[] buffer;
560 return result;
561 }
562
563 /*----------------------------------------------------------------------
564 | NPT_StringOutputStream::NPT_StringOutputStream
565 +---------------------------------------------------------------------*/
566 NPT_StringOutputStream::NPT_StringOutputStream(NPT_Size size) :
567 m_String(new NPT_String),
568 m_StringIsOwned(true)
569 {
570 m_String->Reserve(size);
571 }
572
573
574 /*----------------------------------------------------------------------
575 | NPT_StringOutputStream::NPT_StringOutputStream
576 +---------------------------------------------------------------------*/
577 NPT_StringOutputStream::NPT_StringOutputStream(NPT_String* storage) :
578 m_String(storage),
579 m_StringIsOwned(false)
580 {
581 }
582
583 /*----------------------------------------------------------------------
584 | NPT_StringOutputStream::~NPT_StringOutputStream
585 +---------------------------------------------------------------------*/
586 NPT_StringOutputStream::~NPT_StringOutputStream()
587 {
588 if (m_StringIsOwned) delete m_String;
589 }
590
591 /*----------------------------------------------------------------------
592 | NPT_StringOutputStream::Write
593 +---------------------------------------------------------------------*/
594 NPT_Result
595 NPT_StringOutputStream::Write(const void* buffer, NPT_Size bytes_to_write, NPT_Size* bytes_written /* = NULL */)
596 {
597 m_String->Append((const char*)buffer, bytes_to_write);
598 if (bytes_written) *bytes_written = bytes_to_write;
599 return NPT_SUCCESS;
600 }