diff options
Diffstat (limited to 'lib/libUPnP/Neptune/Source/Core/NptStreams.cpp')
-rw-r--r-- | lib/libUPnP/Neptune/Source/Core/NptStreams.cpp | 724 |
1 files changed, 724 insertions, 0 deletions
diff --git a/lib/libUPnP/Neptune/Source/Core/NptStreams.cpp b/lib/libUPnP/Neptune/Source/Core/NptStreams.cpp new file mode 100644 index 0000000..79909fa --- /dev/null +++ b/lib/libUPnP/Neptune/Source/Core/NptStreams.cpp @@ -0,0 +1,724 @@ +/***************************************************************** +| +| Neptune - Byte Streams +| +| Copyright (c) 2002-2008, Axiomatic Systems, LLC. +| All rights reserved. +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| * Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| * Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| * Neither the name of Axiomatic Systems nor the +| names of its contributors may be used to endorse or promote products +| derived from this software without specific prior written permission. +| +| THIS SOFTWARE IS PROVIDED BY AXIOMATIC SYSTEMS ''AS IS'' AND ANY +| EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +| DISCLAIMED. IN NO EVENT SHALL AXIOMATIC SYSTEMS BE LIABLE FOR ANY +| DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#include "NptStreams.h" +#include "NptUtils.h" +#include "NptConstants.h" +#include "NptStrings.h" +#include "NptDebug.h" + +/*---------------------------------------------------------------------- +| constants ++---------------------------------------------------------------------*/ +const NPT_Size NPT_INPUT_STREAM_LOAD_DEFAULT_READ_CHUNK = 4096; +const NPT_LargeSize NPT_INPUT_STREAM_LOAD_MAX_SIZE = 0x40000000; // 1GB + +/*---------------------------------------------------------------------- +| NPT_InputStream::Load ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::Load(NPT_DataBuffer& buffer, NPT_Size max_read /* = 0 */) +{ + NPT_Result result; + NPT_LargeSize total_bytes_read; + + // reset the buffer + buffer.SetDataSize(0); + + // check the limits + if (max_read > NPT_INPUT_STREAM_LOAD_MAX_SIZE) { + return NPT_ERROR_INVALID_PARAMETERS; + } + + // try to get the stream size + NPT_LargeSize size; + if (NPT_SUCCEEDED(GetSize(size))) { + // make sure we don't read more than max_read + if (max_read && max_read < size) size = max_read; + if (size > NPT_INPUT_STREAM_LOAD_MAX_SIZE) { + return NPT_ERROR_OUT_OF_RANGE; + } + } else { + size = max_read; + } + + // pre-allocate the buffer + if (size) NPT_CHECK(buffer.Reserve((NPT_Size)size)); + + // read the data from the file + total_bytes_read = 0; + do { + NPT_LargeSize available = 0; + NPT_LargeSize bytes_to_read; + NPT_Size bytes_read; + NPT_Byte* data; + + // check if we know how much data is available + result = GetAvailable(available); + if (NPT_SUCCEEDED(result) && available) { + // we know how much is available + bytes_to_read = available; + } else { + bytes_to_read = NPT_INPUT_STREAM_LOAD_DEFAULT_READ_CHUNK; + } + + // make sure we don't read more than what was asked + if (size != 0 && total_bytes_read+bytes_to_read>size) { + bytes_to_read = size-total_bytes_read; + } + + // stop if we've read everything + if (bytes_to_read == 0) break; + + // ensure that the buffer has enough space + if (total_bytes_read+bytes_to_read > NPT_INPUT_STREAM_LOAD_MAX_SIZE) { + buffer.SetBufferSize(0); + return NPT_ERROR_OUT_OF_RANGE; + } + NPT_CHECK(buffer.Reserve((NPT_Size)(total_bytes_read+bytes_to_read))); + + // read the data + data = buffer.UseData()+total_bytes_read; + result = Read((void*)data, (NPT_Size)bytes_to_read, &bytes_read); + if (NPT_SUCCEEDED(result) && bytes_read != 0) { + total_bytes_read += bytes_read; + buffer.SetDataSize((NPT_Size)total_bytes_read); + } + } while(NPT_SUCCEEDED(result) && (size==0 || total_bytes_read < size)); + + if (result == NPT_ERROR_EOS) { + return NPT_SUCCESS; + } else { + return result; + } +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadFully ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadFully(void* buffer, NPT_Size bytes_to_read) +{ + // shortcut + if (bytes_to_read == 0) return NPT_SUCCESS; + + // read until failure + NPT_Size bytes_read; + while (bytes_to_read) { + NPT_Result result = Read(buffer, bytes_to_read, &bytes_read); + if (NPT_FAILED(result)) return result; + if (bytes_read == 0) return NPT_ERROR_INTERNAL; + NPT_ASSERT(bytes_read <= bytes_to_read); + bytes_to_read -= bytes_read; + buffer = (void*)(((NPT_Byte*)buffer)+bytes_read); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI64 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI64(NPT_UInt64& value) +{ + unsigned char buffer[8]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 8); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = NPT_BytesToInt64Be(buffer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI32 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI32(NPT_UInt32& value) +{ + unsigned char buffer[4]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 4); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = NPT_BytesToInt32Be(buffer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI24 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI24(NPT_UInt32& value) +{ + unsigned char buffer[3]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 3); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = NPT_BytesToInt24Be(buffer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI16 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI16(NPT_UInt16& value) +{ + unsigned char buffer[2]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 2); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = NPT_BytesToInt16Be(buffer); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::ReadUI08 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::ReadUI08(NPT_UInt8& value) +{ + unsigned char buffer[1]; + + // read bytes from the stream + NPT_Result result; + result = ReadFully((void*)buffer, 1); + if (NPT_FAILED(result)) { + value = 0; + return result; + } + + // convert bytes to value + value = buffer[0]; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_InputStream::Skip ++---------------------------------------------------------------------*/ +NPT_Result +NPT_InputStream::Skip(NPT_Size count) +{ + // get the current location + NPT_Position position; + NPT_CHECK(Tell(position)); + + // seek ahead + return Seek(position+count); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteFully ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteFully(const void* buffer, NPT_Size bytes_to_write) +{ + // shortcut + if (bytes_to_write == 0) return NPT_SUCCESS; + + // write until failure + NPT_Size bytes_written; + while (bytes_to_write) { + NPT_Result result = Write(buffer, bytes_to_write, &bytes_written); + if (NPT_FAILED(result)) return result; + if (bytes_written == 0) return NPT_ERROR_INTERNAL; + NPT_ASSERT(bytes_written <= bytes_to_write); + bytes_to_write -= bytes_written; + buffer = (const void*)(((const NPT_Byte*)buffer)+bytes_written); + } + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteString ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteString(const char* buffer) +{ + // shortcut + NPT_Size string_length; + if (buffer == NULL || (string_length = NPT_StringLength(buffer)) == 0) { + return NPT_SUCCESS; + } + + // write the string + return WriteFully((const void*)buffer, string_length); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteLine ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteLine(const char* buffer) +{ + NPT_CHECK(WriteString(buffer)); + NPT_CHECK(WriteFully((const void*)"\r\n", 2)); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI64 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI64(NPT_UInt64 value) +{ + unsigned char buffer[8]; + + // convert value to bytes + NPT_BytesFromInt64Be(buffer, value); + + // write bytes to the stream + return WriteFully((void*)buffer, 8); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI32 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI32(NPT_UInt32 value) +{ + unsigned char buffer[4]; + + // convert value to bytes + NPT_BytesFromInt32Be(buffer, value); + + // write bytes to the stream + return WriteFully((void*)buffer, 4); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI24 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI24(NPT_UInt32 value) +{ + unsigned char buffer[3]; + + // convert value to bytes + NPT_BytesFromInt24Be(buffer, value); + + // write bytes to the stream + return WriteFully((void*)buffer, 3); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI16 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI16(NPT_UInt16 value) +{ + unsigned char buffer[2]; + + // convert value to bytes + NPT_BytesFromInt16Be(buffer, value); + + // write bytes to the stream + return WriteFully((void*)buffer, 2); +} + +/*---------------------------------------------------------------------- +| NPT_OutputStream::WriteUI08 ++---------------------------------------------------------------------*/ +NPT_Result +NPT_OutputStream::WriteUI08(NPT_UInt8 value) +{ + return WriteFully((void*)&value, 1); +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::NPT_MemoryStream ++---------------------------------------------------------------------*/ +NPT_MemoryStream::NPT_MemoryStream(NPT_Size initial_capacity) : + m_Buffer(initial_capacity), + m_ReadOffset(0), + m_WriteOffset(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::NPT_MemoryStream ++---------------------------------------------------------------------*/ +NPT_MemoryStream::NPT_MemoryStream(const void* data, NPT_Size size) : + m_Buffer(data, size), + m_ReadOffset(0), + m_WriteOffset(0) +{ +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + // check for shortcut + if (bytes_to_read == 0) { + if (bytes_read) *bytes_read = 0; + return NPT_SUCCESS; + } + + // clip to what's available + NPT_Size available = m_Buffer.GetDataSize(); + if (m_ReadOffset+bytes_to_read > available) { + bytes_to_read = available-m_ReadOffset; + } + + // copy the data + if (bytes_to_read) { + NPT_CopyMemory(buffer, (void*)(((char*)m_Buffer.UseData())+m_ReadOffset), bytes_to_read); + m_ReadOffset += bytes_to_read; + } + if (bytes_read) *bytes_read = bytes_to_read; + + return bytes_to_read?NPT_SUCCESS:NPT_ERROR_EOS; +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::InputSeek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::InputSeek(NPT_Position offset) +{ + if (offset > m_Buffer.GetDataSize()) { + return NPT_ERROR_OUT_OF_RANGE; + } else { + m_ReadOffset = (NPT_Size)offset; + return NPT_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::Write ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::Write(const void* data, + NPT_Size bytes_to_write, + NPT_Size* bytes_written) +{ + NPT_CHECK(m_Buffer.Reserve(m_WriteOffset+bytes_to_write)); + + NPT_CopyMemory(m_Buffer.UseData()+m_WriteOffset, data, bytes_to_write); + m_WriteOffset += bytes_to_write; + if (m_WriteOffset > m_Buffer.GetDataSize()) { + m_Buffer.SetDataSize(m_WriteOffset); + } + if (bytes_written) *bytes_written = bytes_to_write; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::OutputSeek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::OutputSeek(NPT_Position offset) +{ + if (offset <= m_Buffer.GetDataSize()) { + m_WriteOffset = (NPT_Size)offset; + return NPT_SUCCESS; + } else { + return NPT_ERROR_OUT_OF_RANGE; + } +} + +/*---------------------------------------------------------------------- +| NPT_MemoryStream::SetDataSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::SetDataSize(NPT_Size size) +{ + // update data amount in buffer + NPT_CHECK(m_Buffer.SetDataSize(size)); + + // adjust the read and write offsets + if (m_ReadOffset > size) m_ReadOffset = size; + if (m_WriteOffset > size) m_WriteOffset = size; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_StreamToStreamCopy ++---------------------------------------------------------------------*/ +const unsigned int NPT_STREAM_COPY_BUFFER_SIZE = 65536; // copy 64k at a time +NPT_Result +NPT_StreamToStreamCopy(NPT_InputStream& from, + NPT_OutputStream& to, + NPT_Position offset /* = 0 */, + NPT_LargeSize size /* = 0, 0 means the entire stream */, + NPT_LargeSize* bytes_written /* = NULL */) +{ + // default values + if (bytes_written) *bytes_written = 0; + + // seek into the input if required + if (offset) { + NPT_CHECK(from.Seek(offset)); + } + + // allocate a buffer for the transfer + NPT_LargeSize bytes_transfered = 0; + NPT_Byte* buffer = new NPT_Byte[NPT_STREAM_COPY_BUFFER_SIZE]; + NPT_Result result = NPT_SUCCESS; + if (buffer == NULL) return NPT_ERROR_OUT_OF_MEMORY; + + // copy until an error occurs or the end of stream is reached + for (;;) { + // read some data + NPT_Size bytes_to_read = NPT_STREAM_COPY_BUFFER_SIZE; + NPT_Size bytes_read = 0; + if (size) { + // a max size was specified + if (size-bytes_transfered < NPT_STREAM_COPY_BUFFER_SIZE) { + bytes_to_read = (NPT_Size)(size-bytes_transfered); + } + } + result = from.Read(buffer, bytes_to_read, &bytes_read); + if (NPT_FAILED(result)) { + if (result == NPT_ERROR_EOS) result = NPT_SUCCESS; + break; + } + if (bytes_read == 0) continue; + + NPT_Size buffer_bytes_to_write = bytes_read; + NPT_Byte* buffer_bytes = (NPT_Byte*)buffer; + while (buffer_bytes_to_write) { + NPT_Size buffer_bytes_written = 0; + result = to.Write(buffer_bytes, buffer_bytes_to_write, &buffer_bytes_written); + if (NPT_FAILED(result)) goto end; + NPT_ASSERT(buffer_bytes_written <= buffer_bytes_to_write); + buffer_bytes_to_write -= buffer_bytes_written; + if (bytes_written) *bytes_written += buffer_bytes_written; + buffer_bytes += buffer_bytes_written; + } + + // update the counts + if (size) { + bytes_transfered += bytes_read; + if (bytes_transfered >= size) break; + } + } + +end: + // free the buffer and return + delete[] buffer; + return result; +} + +/*---------------------------------------------------------------------- +| NPT_StringOutputStream::NPT_StringOutputStream ++---------------------------------------------------------------------*/ +NPT_StringOutputStream::NPT_StringOutputStream(NPT_Size size) : + m_String(new NPT_String), + m_StringIsOwned(true) +{ + m_String->Reserve(size); +} + + +/*---------------------------------------------------------------------- +| NPT_StringOutputStream::NPT_StringOutputStream ++---------------------------------------------------------------------*/ +NPT_StringOutputStream::NPT_StringOutputStream(NPT_String* storage) : + m_String(storage), + m_StringIsOwned(false) +{ +} + +/*---------------------------------------------------------------------- +| NPT_StringOutputStream::~NPT_StringOutputStream ++---------------------------------------------------------------------*/ +NPT_StringOutputStream::~NPT_StringOutputStream() +{ + if (m_StringIsOwned) delete m_String; +} + +/*---------------------------------------------------------------------- +| NPT_StringOutputStream::Write ++---------------------------------------------------------------------*/ +NPT_Result +NPT_StringOutputStream::Write(const void* buffer, NPT_Size bytes_to_write, NPT_Size* bytes_written /* = NULL */) +{ + m_String->Append((const char*)buffer, bytes_to_write); + if (bytes_written) *bytes_written = bytes_to_write; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::NPT_SubInputStream ++---------------------------------------------------------------------*/ +NPT_SubInputStream::NPT_SubInputStream(NPT_InputStreamReference& source, + NPT_Position start, + NPT_LargeSize size) : + m_Source(source), + m_Position(0), + m_Start(start), + m_Size(size) +{ +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + // default values + if (bytes_read) *bytes_read = 0; + + // shortcut + if (bytes_to_read == 0) { + return NPT_SUCCESS; + } + + // clamp to range + if (m_Position+bytes_to_read > m_Size) { + bytes_to_read = (NPT_Size)(m_Size - m_Position); + } + + // check for end of substream + if (bytes_to_read == 0) { + return NPT_ERROR_EOS; + } + + // seek inside the source + NPT_Result result; + result = m_Source->Seek(m_Start+m_Position); + if (NPT_FAILED(result)) { + return result; + } + + // read from the source + NPT_Size source_bytes_read = 0; + result = m_Source->Read(buffer, bytes_to_read, &source_bytes_read); + if (NPT_SUCCEEDED(result)) { + m_Position += source_bytes_read; + if (bytes_read) *bytes_read = source_bytes_read; + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::Seek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::Seek(NPT_Position position) +{ + if (position == m_Position) return NPT_SUCCESS; + if (position > m_Size) return NPT_ERROR_OUT_OF_RANGE; + m_Position = position; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::Tell ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::Tell(NPT_Position& position) +{ + position = m_Position; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::GetSize(NPT_LargeSize& size) +{ + size = m_Size; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_SubInputStream::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Result +NPT_SubInputStream::GetAvailable(NPT_LargeSize& available) +{ + available = m_Size-m_Position; + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_NullOutputStream::Write ++---------------------------------------------------------------------*/ +NPT_Result +NPT_NullOutputStream::Write(const void* /*buffer*/, + NPT_Size bytes_to_write, + NPT_Size* bytes_written /* = NULL */) +{ + if (bytes_written) *bytes_written = bytes_to_write; + return NPT_SUCCESS; +} + |