1 /*****************************************************************
3 | Neptune - Byte Streams
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
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.
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.
30 ****************************************************************/
32 /*----------------------------------------------------------------------
34 +---------------------------------------------------------------------*/
35 #include "NptStreams.h"
37 #include "NptConstants.h"
38 #include "NptStrings.h"
41 /*----------------------------------------------------------------------
43 +---------------------------------------------------------------------*/
44 const NPT_Size NPT_INPUT_STREAM_LOAD_DEFAULT_READ_CHUNK
= 4096;
45 const NPT_LargeSize NPT_INPUT_STREAM_LOAD_MAX_SIZE
= 0x40000000; // 1GB
47 /*----------------------------------------------------------------------
48 | NPT_InputStream::Load
49 +---------------------------------------------------------------------*/
51 NPT_InputStream::Load(NPT_DataBuffer
& buffer
, NPT_Size max_read
/* = 0 */)
54 NPT_LargeSize total_bytes_read
;
57 buffer
.SetDataSize(0);
60 if (max_read
> NPT_INPUT_STREAM_LOAD_MAX_SIZE
) {
61 return NPT_ERROR_INVALID_PARAMETERS
;
64 // try to get the stream 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
;
76 // pre-allocate the buffer
77 if (size
) NPT_CHECK(buffer
.Reserve((NPT_Size
)size
));
79 // read the data from the file
82 NPT_LargeSize available
= 0;
83 NPT_LargeSize bytes_to_read
;
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
;
93 bytes_to_read
= NPT_INPUT_STREAM_LOAD_DEFAULT_READ_CHUNK
;
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
;
101 // stop if we've read everything
102 if (bytes_to_read
== 0) break;
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
;
109 NPT_CHECK(buffer
.Reserve((NPT_Size
)(total_bytes_read
+bytes_to_read
)));
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
);
118 } while(NPT_SUCCEEDED(result
) && (size
==0 || total_bytes_read
< size
));
120 if (result
== NPT_ERROR_EOS
) {
127 /*----------------------------------------------------------------------
128 | NPT_InputStream::ReadFully
129 +---------------------------------------------------------------------*/
131 NPT_InputStream::ReadFully(void* buffer
, NPT_Size bytes_to_read
)
134 if (bytes_to_read
== 0) return NPT_SUCCESS
;
136 // read until failure
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
);
150 /*----------------------------------------------------------------------
151 | NPT_InputStream::ReadUI64
152 +---------------------------------------------------------------------*/
154 NPT_InputStream::ReadUI64(NPT_UInt64
& value
)
156 unsigned char buffer
[8];
158 // read bytes from the stream
160 result
= ReadFully((void*)buffer
, 8);
161 if (NPT_FAILED(result
)) {
166 // convert bytes to value
167 value
= NPT_BytesToInt64Be(buffer
);
172 /*----------------------------------------------------------------------
173 | NPT_InputStream::ReadUI32
174 +---------------------------------------------------------------------*/
176 NPT_InputStream::ReadUI32(NPT_UInt32
& value
)
178 unsigned char buffer
[4];
180 // read bytes from the stream
182 result
= ReadFully((void*)buffer
, 4);
183 if (NPT_FAILED(result
)) {
188 // convert bytes to value
189 value
= NPT_BytesToInt32Be(buffer
);
194 /*----------------------------------------------------------------------
195 | NPT_InputStream::ReadUI24
196 +---------------------------------------------------------------------*/
198 NPT_InputStream::ReadUI24(NPT_UInt32
& value
)
200 unsigned char buffer
[3];
202 // read bytes from the stream
204 result
= ReadFully((void*)buffer
, 3);
205 if (NPT_FAILED(result
)) {
210 // convert bytes to value
211 value
= NPT_BytesToInt24Be(buffer
);
216 /*----------------------------------------------------------------------
217 | NPT_InputStream::ReadUI16
218 +---------------------------------------------------------------------*/
220 NPT_InputStream::ReadUI16(NPT_UInt16
& value
)
222 unsigned char buffer
[2];
224 // read bytes from the stream
226 result
= ReadFully((void*)buffer
, 2);
227 if (NPT_FAILED(result
)) {
232 // convert bytes to value
233 value
= NPT_BytesToInt16Be(buffer
);
238 /*----------------------------------------------------------------------
239 | NPT_InputStream::ReadUI08
240 +---------------------------------------------------------------------*/
242 NPT_InputStream::ReadUI08(NPT_UInt8
& value
)
244 unsigned char buffer
[1];
246 // read bytes from the stream
248 result
= ReadFully((void*)buffer
, 1);
249 if (NPT_FAILED(result
)) {
254 // convert bytes to value
260 /*----------------------------------------------------------------------
261 | NPT_InputStream::Skip
262 +---------------------------------------------------------------------*/
264 NPT_InputStream::Skip(NPT_Size count
)
266 // get the current location
267 NPT_Position position
;
268 NPT_CHECK(Tell(position
));
271 return Seek(position
+count
);
274 /*----------------------------------------------------------------------
275 | NPT_OutputStream::WriteFully
276 +---------------------------------------------------------------------*/
278 NPT_OutputStream::WriteFully(const void* buffer
, NPT_Size bytes_to_write
)
281 if (bytes_to_write
== 0) return NPT_SUCCESS
;
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
);
297 /*----------------------------------------------------------------------
298 | NPT_OutputStream::WriteString
299 +---------------------------------------------------------------------*/
301 NPT_OutputStream::WriteString(const char* buffer
)
304 NPT_Size string_length
;
305 if (buffer
== NULL
|| (string_length
= NPT_StringLength(buffer
)) == 0) {
310 return WriteFully((const void*)buffer
, string_length
);
313 /*----------------------------------------------------------------------
314 | NPT_OutputStream::WriteLine
315 +---------------------------------------------------------------------*/
317 NPT_OutputStream::WriteLine(const char* buffer
)
319 NPT_CHECK(WriteString(buffer
));
320 NPT_CHECK(WriteFully((const void*)"\r\n", 2));
325 /*----------------------------------------------------------------------
326 | NPT_OutputStream::WriteUI64
327 +---------------------------------------------------------------------*/
329 NPT_OutputStream::WriteUI64(NPT_UInt64 value
)
331 unsigned char buffer
[8];
333 // convert value to bytes
334 NPT_BytesFromInt64Be(buffer
, value
);
336 // write bytes to the stream
337 return WriteFully((void*)buffer
, 8);
340 /*----------------------------------------------------------------------
341 | NPT_OutputStream::WriteUI32
342 +---------------------------------------------------------------------*/
344 NPT_OutputStream::WriteUI32(NPT_UInt32 value
)
346 unsigned char buffer
[4];
348 // convert value to bytes
349 NPT_BytesFromInt32Be(buffer
, value
);
351 // write bytes to the stream
352 return WriteFully((void*)buffer
, 4);
355 /*----------------------------------------------------------------------
356 | NPT_OutputStream::WriteUI24
357 +---------------------------------------------------------------------*/
359 NPT_OutputStream::WriteUI24(NPT_UInt32 value
)
361 unsigned char buffer
[3];
363 // convert value to bytes
364 NPT_BytesFromInt24Be(buffer
, value
);
366 // write bytes to the stream
367 return WriteFully((void*)buffer
, 3);
370 /*----------------------------------------------------------------------
371 | NPT_OutputStream::WriteUI16
372 +---------------------------------------------------------------------*/
374 NPT_OutputStream::WriteUI16(NPT_UInt16 value
)
376 unsigned char buffer
[2];
378 // convert value to bytes
379 NPT_BytesFromInt16Be(buffer
, value
);
381 // write bytes to the stream
382 return WriteFully((void*)buffer
, 2);
385 /*----------------------------------------------------------------------
386 | NPT_OutputStream::WriteUI08
387 +---------------------------------------------------------------------*/
389 NPT_OutputStream::WriteUI08(NPT_UInt8 value
)
391 return WriteFully((void*)&value
, 1);
394 /*----------------------------------------------------------------------
395 | NPT_MemoryStream::NPT_MemoryStream
396 +---------------------------------------------------------------------*/
397 NPT_MemoryStream::NPT_MemoryStream(NPT_Size initial_capacity
) :
398 m_Buffer(initial_capacity
),
404 /*----------------------------------------------------------------------
405 | NPT_MemoryStream::NPT_MemoryStream
406 +---------------------------------------------------------------------*/
407 NPT_MemoryStream::NPT_MemoryStream(const void* data
, NPT_Size size
) :
408 m_Buffer(data
, size
),
414 /*----------------------------------------------------------------------
415 | NPT_MemoryStream::Read
416 +---------------------------------------------------------------------*/
418 NPT_MemoryStream::Read(void* buffer
,
419 NPT_Size bytes_to_read
,
420 NPT_Size
* bytes_read
)
422 // check for shortcut
423 if (bytes_to_read
== 0) {
424 if (bytes_read
) *bytes_read
= 0;
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
;
436 NPT_CopyMemory(buffer
, (void*)(((char*)m_Buffer
.UseData())+m_ReadOffset
), bytes_to_read
);
437 m_ReadOffset
+= bytes_to_read
;
439 if (bytes_read
) *bytes_read
= bytes_to_read
;
441 return bytes_to_read
?NPT_SUCCESS
:NPT_ERROR_EOS
;
444 /*----------------------------------------------------------------------
445 | NPT_MemoryStream::InputSeek
446 +---------------------------------------------------------------------*/
448 NPT_MemoryStream::InputSeek(NPT_Position offset
)
450 if (offset
> m_Buffer
.GetDataSize()) {
451 return NPT_ERROR_OUT_OF_RANGE
;
453 m_ReadOffset
= (NPT_Size
)offset
;
458 /*----------------------------------------------------------------------
459 | NPT_MemoryStream::Write
460 +---------------------------------------------------------------------*/
462 NPT_MemoryStream::Write(const void* data
,
463 NPT_Size bytes_to_write
,
464 NPT_Size
* bytes_written
)
466 NPT_CHECK(m_Buffer
.Reserve(m_WriteOffset
+bytes_to_write
));
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
);
473 if (bytes_written
) *bytes_written
= bytes_to_write
;
478 /*----------------------------------------------------------------------
479 | NPT_MemoryStream::OutputSeek
480 +---------------------------------------------------------------------*/
482 NPT_MemoryStream::OutputSeek(NPT_Position offset
)
484 if (offset
<= m_Buffer
.GetDataSize()) {
485 m_WriteOffset
= (NPT_Size
)offset
;
488 return NPT_ERROR_OUT_OF_RANGE
;
492 /*----------------------------------------------------------------------
493 | NPT_MemoryStream::SetDataSize
494 +---------------------------------------------------------------------*/
496 NPT_MemoryStream::SetDataSize(NPT_Size size
)
498 // update data amount in buffer
499 NPT_CHECK(m_Buffer
.SetDataSize(size
));
501 // adjust the read and write offsets
502 if (m_ReadOffset
> size
) m_ReadOffset
= size
;
503 if (m_WriteOffset
> size
) m_WriteOffset
= size
;
508 /*----------------------------------------------------------------------
509 | NPT_StreamToStreamCopy
510 +---------------------------------------------------------------------*/
511 const unsigned int NPT_STREAM_COPY_BUFFER_SIZE
= 65536; // copy 64k at a time
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 NPT_LargeSize
* bytes_written
/* = NULL */)
520 if (bytes_written
) *bytes_written
= 0;
522 // seek into the input if required
524 NPT_CHECK(from
.Seek(offset
));
527 // allocate a buffer for the transfer
528 NPT_LargeSize bytes_transfered
= 0;
529 NPT_Byte
* buffer
= new NPT_Byte
[NPT_STREAM_COPY_BUFFER_SIZE
];
530 NPT_Result result
= NPT_SUCCESS
;
531 if (buffer
== NULL
) return NPT_ERROR_OUT_OF_MEMORY
;
533 // copy until an error occurs or the end of stream is reached
536 NPT_Size bytes_to_read
= NPT_STREAM_COPY_BUFFER_SIZE
;
537 NPT_Size bytes_read
= 0;
539 // a max size was specified
540 if (size
-bytes_transfered
< NPT_STREAM_COPY_BUFFER_SIZE
) {
541 bytes_to_read
= (NPT_Size
)(size
-bytes_transfered
);
544 result
= from
.Read(buffer
, bytes_to_read
, &bytes_read
);
545 if (NPT_FAILED(result
)) {
546 if (result
== NPT_ERROR_EOS
) result
= NPT_SUCCESS
;
549 if (bytes_read
== 0) continue;
551 NPT_Size buffer_bytes_to_write
= bytes_read
;
552 NPT_Byte
* buffer_bytes
= (NPT_Byte
*)buffer
;
553 while (buffer_bytes_to_write
) {
554 NPT_Size buffer_bytes_written
= 0;
555 result
= to
.Write(buffer_bytes
, buffer_bytes_to_write
, &buffer_bytes_written
);
556 if (NPT_FAILED(result
)) goto end
;
557 NPT_ASSERT(buffer_bytes_written
<= buffer_bytes_to_write
);
558 buffer_bytes_to_write
-= buffer_bytes_written
;
559 if (bytes_written
) *bytes_written
+= buffer_bytes_written
;
560 buffer_bytes
+= buffer_bytes_written
;
565 bytes_transfered
+= bytes_read
;
566 if (bytes_transfered
>= size
) break;
571 // free the buffer and return
576 /*----------------------------------------------------------------------
577 | NPT_StringOutputStream::NPT_StringOutputStream
578 +---------------------------------------------------------------------*/
579 NPT_StringOutputStream::NPT_StringOutputStream(NPT_Size size
) :
580 m_String(new NPT_String
),
581 m_StringIsOwned(true)
583 m_String
->Reserve(size
);
587 /*----------------------------------------------------------------------
588 | NPT_StringOutputStream::NPT_StringOutputStream
589 +---------------------------------------------------------------------*/
590 NPT_StringOutputStream::NPT_StringOutputStream(NPT_String
* storage
) :
592 m_StringIsOwned(false)
596 /*----------------------------------------------------------------------
597 | NPT_StringOutputStream::~NPT_StringOutputStream
598 +---------------------------------------------------------------------*/
599 NPT_StringOutputStream::~NPT_StringOutputStream()
601 if (m_StringIsOwned
) delete m_String
;
604 /*----------------------------------------------------------------------
605 | NPT_StringOutputStream::Write
606 +---------------------------------------------------------------------*/
608 NPT_StringOutputStream::Write(const void* buffer
, NPT_Size bytes_to_write
, NPT_Size
* bytes_written
/* = NULL */)
610 m_String
->Append((const char*)buffer
, bytes_to_write
);
611 if (bytes_written
) *bytes_written
= bytes_to_write
;
615 /*----------------------------------------------------------------------
616 | NPT_SubInputStream::NPT_SubInputStream
617 +---------------------------------------------------------------------*/
618 NPT_SubInputStream::NPT_SubInputStream(NPT_InputStreamReference
& source
,
620 NPT_LargeSize size
) :
628 /*----------------------------------------------------------------------
629 | NPT_SubInputStream::Read
630 +---------------------------------------------------------------------*/
632 NPT_SubInputStream::Read(void* buffer
,
633 NPT_Size bytes_to_read
,
634 NPT_Size
* bytes_read
)
637 if (bytes_read
) *bytes_read
= 0;
640 if (bytes_to_read
== 0) {
645 if (m_Position
+bytes_to_read
> m_Size
) {
646 bytes_to_read
= (NPT_Size
)(m_Size
- m_Position
);
649 // check for end of substream
650 if (bytes_to_read
== 0) {
651 return NPT_ERROR_EOS
;
654 // seek inside the source
656 result
= m_Source
->Seek(m_Start
+m_Position
);
657 if (NPT_FAILED(result
)) {
661 // read from the source
662 NPT_Size source_bytes_read
= 0;
663 result
= m_Source
->Read(buffer
, bytes_to_read
, &source_bytes_read
);
664 if (NPT_SUCCEEDED(result
)) {
665 m_Position
+= source_bytes_read
;
666 if (bytes_read
) *bytes_read
= source_bytes_read
;
671 /*----------------------------------------------------------------------
672 | NPT_SubInputStream::Seek
673 +---------------------------------------------------------------------*/
675 NPT_SubInputStream::Seek(NPT_Position position
)
677 if (position
== m_Position
) return NPT_SUCCESS
;
678 if (position
> m_Size
) return NPT_ERROR_OUT_OF_RANGE
;
679 m_Position
= position
;
683 /*----------------------------------------------------------------------
684 | NPT_SubInputStream::Tell
685 +---------------------------------------------------------------------*/
687 NPT_SubInputStream::Tell(NPT_Position
& position
)
689 position
= m_Position
;
693 /*----------------------------------------------------------------------
694 | NPT_SubInputStream::GetSize
695 +---------------------------------------------------------------------*/
697 NPT_SubInputStream::GetSize(NPT_LargeSize
& size
)
703 /*----------------------------------------------------------------------
704 | NPT_SubInputStream::GetAvailable
705 +---------------------------------------------------------------------*/
707 NPT_SubInputStream::GetAvailable(NPT_LargeSize
& available
)
709 available
= m_Size
-m_Position
;
713 /*----------------------------------------------------------------------
714 | NPT_NullOutputStream::Write
715 +---------------------------------------------------------------------*/
717 NPT_NullOutputStream::Write(const void* /*buffer*/,
718 NPT_Size bytes_to_write
,
719 NPT_Size
* bytes_written
/* = NULL */)
721 if (bytes_written
) *bytes_written
= bytes_to_write
;