Merge pull request #26386 from ksooo/guiinfo-fix-listitem-filenamenoextension
[xbmc.git] / lib / libUPnP / Neptune / Source / Core / NptStreams.cpp
blob79909fa0d8d70e033592099c034299f8d463b7bf
1 /*****************************************************************
3 | Neptune - Byte Streams
5 | Copyright (c) 2002-2008, Axiomatic Systems, LLC.
6 | All rights reserved.
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 /*----------------------------------------------------------------------
33 | includes
34 +---------------------------------------------------------------------*/
35 #include "NptStreams.h"
36 #include "NptUtils.h"
37 #include "NptConstants.h"
38 #include "NptStrings.h"
39 #include "NptDebug.h"
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 = 0x40000000; // 1GB
47 /*----------------------------------------------------------------------
48 | NPT_InputStream::Load
49 +---------------------------------------------------------------------*/
50 NPT_Result
51 NPT_InputStream::Load(NPT_DataBuffer& buffer, NPT_Size max_read /* = 0 */)
53 NPT_Result result;
54 NPT_LargeSize total_bytes_read;
56 // reset the buffer
57 buffer.SetDataSize(0);
59 // check the limits
60 if (max_read > NPT_INPUT_STREAM_LOAD_MAX_SIZE) {
61 return NPT_ERROR_INVALID_PARAMETERS;
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;
72 } else {
73 size = max_read;
76 // pre-allocate the buffer
77 if (size) NPT_CHECK(buffer.Reserve((NPT_Size)size));
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;
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;
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)));
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);
118 } while(NPT_SUCCEEDED(result) && (size==0 || total_bytes_read < size));
120 if (result == NPT_ERROR_EOS) {
121 return NPT_SUCCESS;
122 } else {
123 return result;
127 /*----------------------------------------------------------------------
128 | NPT_InputStream::ReadFully
129 +---------------------------------------------------------------------*/
130 NPT_Result
131 NPT_InputStream::ReadFully(void* buffer, NPT_Size bytes_to_read)
133 // shortcut
134 if (bytes_to_read == 0) return NPT_SUCCESS;
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);
147 return NPT_SUCCESS;
150 /*----------------------------------------------------------------------
151 | NPT_InputStream::ReadUI64
152 +---------------------------------------------------------------------*/
153 NPT_Result
154 NPT_InputStream::ReadUI64(NPT_UInt64& value)
156 unsigned char buffer[8];
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;
166 // convert bytes to value
167 value = NPT_BytesToInt64Be(buffer);
169 return NPT_SUCCESS;
172 /*----------------------------------------------------------------------
173 | NPT_InputStream::ReadUI32
174 +---------------------------------------------------------------------*/
175 NPT_Result
176 NPT_InputStream::ReadUI32(NPT_UInt32& value)
178 unsigned char buffer[4];
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;
188 // convert bytes to value
189 value = NPT_BytesToInt32Be(buffer);
191 return NPT_SUCCESS;
194 /*----------------------------------------------------------------------
195 | NPT_InputStream::ReadUI24
196 +---------------------------------------------------------------------*/
197 NPT_Result
198 NPT_InputStream::ReadUI24(NPT_UInt32& value)
200 unsigned char buffer[3];
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;
210 // convert bytes to value
211 value = NPT_BytesToInt24Be(buffer);
213 return NPT_SUCCESS;
216 /*----------------------------------------------------------------------
217 | NPT_InputStream::ReadUI16
218 +---------------------------------------------------------------------*/
219 NPT_Result
220 NPT_InputStream::ReadUI16(NPT_UInt16& value)
222 unsigned char buffer[2];
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;
232 // convert bytes to value
233 value = NPT_BytesToInt16Be(buffer);
235 return NPT_SUCCESS;
238 /*----------------------------------------------------------------------
239 | NPT_InputStream::ReadUI08
240 +---------------------------------------------------------------------*/
241 NPT_Result
242 NPT_InputStream::ReadUI08(NPT_UInt8& value)
244 unsigned char buffer[1];
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;
254 // convert bytes to value
255 value = buffer[0];
257 return NPT_SUCCESS;
260 /*----------------------------------------------------------------------
261 | NPT_InputStream::Skip
262 +---------------------------------------------------------------------*/
263 NPT_Result
264 NPT_InputStream::Skip(NPT_Size count)
266 // get the current location
267 NPT_Position position;
268 NPT_CHECK(Tell(position));
270 // seek ahead
271 return Seek(position+count);
274 /*----------------------------------------------------------------------
275 | NPT_OutputStream::WriteFully
276 +---------------------------------------------------------------------*/
277 NPT_Result
278 NPT_OutputStream::WriteFully(const void* buffer, NPT_Size bytes_to_write)
280 // shortcut
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);
294 return NPT_SUCCESS;
297 /*----------------------------------------------------------------------
298 | NPT_OutputStream::WriteString
299 +---------------------------------------------------------------------*/
300 NPT_Result
301 NPT_OutputStream::WriteString(const char* buffer)
303 // shortcut
304 NPT_Size string_length;
305 if (buffer == NULL || (string_length = NPT_StringLength(buffer)) == 0) {
306 return NPT_SUCCESS;
309 // write the string
310 return WriteFully((const void*)buffer, string_length);
313 /*----------------------------------------------------------------------
314 | NPT_OutputStream::WriteLine
315 +---------------------------------------------------------------------*/
316 NPT_Result
317 NPT_OutputStream::WriteLine(const char* buffer)
319 NPT_CHECK(WriteString(buffer));
320 NPT_CHECK(WriteFully((const void*)"\r\n", 2));
322 return NPT_SUCCESS;
325 /*----------------------------------------------------------------------
326 | NPT_OutputStream::WriteUI64
327 +---------------------------------------------------------------------*/
328 NPT_Result
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 +---------------------------------------------------------------------*/
343 NPT_Result
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 +---------------------------------------------------------------------*/
358 NPT_Result
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 +---------------------------------------------------------------------*/
373 NPT_Result
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 +---------------------------------------------------------------------*/
388 NPT_Result
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),
399 m_ReadOffset(0),
400 m_WriteOffset(0)
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)
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)
422 // check for shortcut
423 if (bytes_to_read == 0) {
424 if (bytes_read) *bytes_read = 0;
425 return NPT_SUCCESS;
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;
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;
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 +---------------------------------------------------------------------*/
447 NPT_Result
448 NPT_MemoryStream::InputSeek(NPT_Position offset)
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;
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)
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;
475 return NPT_SUCCESS;
478 /*----------------------------------------------------------------------
479 | NPT_MemoryStream::OutputSeek
480 +---------------------------------------------------------------------*/
481 NPT_Result
482 NPT_MemoryStream::OutputSeek(NPT_Position offset)
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;
492 /*----------------------------------------------------------------------
493 | NPT_MemoryStream::SetDataSize
494 +---------------------------------------------------------------------*/
495 NPT_Result
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;
505 return NPT_SUCCESS;
508 /*----------------------------------------------------------------------
509 | NPT_StreamToStreamCopy
510 +---------------------------------------------------------------------*/
511 const unsigned int NPT_STREAM_COPY_BUFFER_SIZE = 65536; // copy 64k 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 NPT_LargeSize* bytes_written /* = NULL */)
519 // default values
520 if (bytes_written) *bytes_written = 0;
522 // seek into the input if required
523 if (offset) {
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
534 for (;;) {
535 // read some data
536 NPT_Size bytes_to_read = NPT_STREAM_COPY_BUFFER_SIZE;
537 NPT_Size bytes_read = 0;
538 if (size) {
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;
547 break;
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;
563 // update the counts
564 if (size) {
565 bytes_transfered += bytes_read;
566 if (bytes_transfered >= size) break;
570 end:
571 // free the buffer and return
572 delete[] buffer;
573 return result;
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) :
591 m_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 +---------------------------------------------------------------------*/
607 NPT_Result
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;
612 return NPT_SUCCESS;
615 /*----------------------------------------------------------------------
616 | NPT_SubInputStream::NPT_SubInputStream
617 +---------------------------------------------------------------------*/
618 NPT_SubInputStream::NPT_SubInputStream(NPT_InputStreamReference& source,
619 NPT_Position start,
620 NPT_LargeSize size) :
621 m_Source(source),
622 m_Position(0),
623 m_Start(start),
624 m_Size(size)
628 /*----------------------------------------------------------------------
629 | NPT_SubInputStream::Read
630 +---------------------------------------------------------------------*/
631 NPT_Result
632 NPT_SubInputStream::Read(void* buffer,
633 NPT_Size bytes_to_read,
634 NPT_Size* bytes_read)
636 // default values
637 if (bytes_read) *bytes_read = 0;
639 // shortcut
640 if (bytes_to_read == 0) {
641 return NPT_SUCCESS;
644 // clamp to range
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
655 NPT_Result result;
656 result = m_Source->Seek(m_Start+m_Position);
657 if (NPT_FAILED(result)) {
658 return 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;
668 return result;
671 /*----------------------------------------------------------------------
672 | NPT_SubInputStream::Seek
673 +---------------------------------------------------------------------*/
674 NPT_Result
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;
680 return NPT_SUCCESS;
683 /*----------------------------------------------------------------------
684 | NPT_SubInputStream::Tell
685 +---------------------------------------------------------------------*/
686 NPT_Result
687 NPT_SubInputStream::Tell(NPT_Position& position)
689 position = m_Position;
690 return NPT_SUCCESS;
693 /*----------------------------------------------------------------------
694 | NPT_SubInputStream::GetSize
695 +---------------------------------------------------------------------*/
696 NPT_Result
697 NPT_SubInputStream::GetSize(NPT_LargeSize& size)
699 size = m_Size;
700 return NPT_SUCCESS;
703 /*----------------------------------------------------------------------
704 | NPT_SubInputStream::GetAvailable
705 +---------------------------------------------------------------------*/
706 NPT_Result
707 NPT_SubInputStream::GetAvailable(NPT_LargeSize& available)
709 available = m_Size-m_Position;
710 return NPT_SUCCESS;
713 /*----------------------------------------------------------------------
714 | NPT_NullOutputStream::Write
715 +---------------------------------------------------------------------*/
716 NPT_Result
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;
722 return NPT_SUCCESS;