Mercurial > projects > hoofbaby
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/deps/Platinum/ThirdParty/Neptune/Source/Core/NptStreams.cpp Mon Jul 06 08:06:28 2009 -0700 @@ -0,0 +1,600 @@ +/***************************************************************** +| +| 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 = 0x100000; // 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::SetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_MemoryStream::SetSize(NPT_Size size) +{ + // try to resize the data 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 = 4096; // copy 4k 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 */) +{ + // 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 (bytes_to_read > (NPT_Size)(size-bytes_transfered)) { + 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; + + // write the data + result = to.WriteFully(buffer, bytes_read); + if (NPT_FAILED(result)) break; + + // update the counts + if (size) { + bytes_transfered += bytes_read; + if (bytes_transfered >= size) break; + } + } + + // 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; +}