Mercurial > projects > hoofbaby
diff deps/Platinum/ThirdParty/Neptune/Source/Core/NptBufferedStreams.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/NptBufferedStreams.cpp Mon Jul 06 08:06:28 2009 -0700 @@ -0,0 +1,373 @@ +/***************************************************************** +| +| Neptune - Buffered 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 "NptTypes.h" +#include "NptInterfaces.h" +#include "NptConstants.h" +#include "NptBufferedStreams.h" +#include "NptUtils.h" + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::NPT_BufferedInputStream ++---------------------------------------------------------------------*/ +NPT_BufferedInputStream::NPT_BufferedInputStream(NPT_InputStreamReference& source, NPT_Size buffer_size) : + m_Source(source), + m_SkipNewline(false), + m_Eos(false) +{ + // setup the read buffer + m_Buffer.data = NULL; + m_Buffer.offset = 0; + m_Buffer.valid = 0; + m_Buffer.size = buffer_size; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::~NPT_BufferedInputStream ++---------------------------------------------------------------------*/ +NPT_BufferedInputStream::~NPT_BufferedInputStream() +{ + // release the buffer + delete[] m_Buffer.data; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::SetBufferSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::SetBufferSize(NPT_Size size) +{ + if (m_Buffer.data != NULL) { + // we already have a buffer + if (m_Buffer.size < size) { + // the current buffer is too small, reallocate + NPT_Byte* buffer = new NPT_Byte[size]; + if (buffer == NULL) return NPT_ERROR_OUT_OF_MEMORY; + + // copy existing data + NPT_Size need_to_copy = m_Buffer.valid - m_Buffer.offset; + if (need_to_copy) { + NPT_CopyMemory((void*)buffer, + m_Buffer.data+m_Buffer.offset, + need_to_copy); + } + + // use the new buffer + delete[] m_Buffer.data; + m_Buffer.data = buffer; + m_Buffer.valid -= m_Buffer.offset; + m_Buffer.offset = 0; + } + } + m_Buffer.size = size; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::FillBuffer ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::FillBuffer() +{ + // shortcut + if (m_Eos) return NPT_ERROR_EOS; + + // check that there is nothing left in the buffer and the buffer + // size is not 0 + NPT_ASSERT(m_Buffer.valid == m_Buffer.offset); + NPT_ASSERT(m_Buffer.size != 0); + + // allocate the read buffer if it has not been done yet + if (m_Buffer.data == NULL) { + m_Buffer.data = new NPT_Byte[m_Buffer.size]; + if (m_Buffer.data == NULL) return NPT_ERROR_OUT_OF_MEMORY; + } + + // refill the buffer + m_Buffer.offset = 0; + NPT_Result result = m_Source->Read(m_Buffer.data, m_Buffer.size, &m_Buffer.valid); + if (NPT_FAILED(result)) m_Buffer.valid = 0; + return result; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::ReleaseBuffer ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::ReleaseBuffer() +{ + NPT_ASSERT(m_Buffer.size == 0); + NPT_ASSERT(m_Buffer.offset == m_Buffer.valid); + + delete[] m_Buffer.data; + m_Buffer.data = NULL; + m_Buffer.offset = 0; + m_Buffer.valid = 0; + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::ReadLine ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::ReadLine(char* buffer, + NPT_Size size, + NPT_Size* chars_read, + bool break_on_cr) +{ + NPT_Result result = NPT_SUCCESS; + char* buffer_start = buffer; + bool skip_newline = false; + + // check parameters + if (buffer == NULL || size < 1) return NPT_ERROR_INVALID_PARAMETERS; + + // read until EOF or newline + while (buffer-buffer_start < (long)(size-1)) { + while (m_Buffer.offset != m_Buffer.valid) { + // there is some data left in the buffer + NPT_Byte c = m_Buffer.data[m_Buffer.offset++]; + if (c == '\r') { + if (break_on_cr) { + skip_newline = true; + goto done; + } + } else if (c == '\n') { + if (m_SkipNewline && (buffer == buffer_start)) { + continue; + } + goto done; + } else { + *buffer++ = c; + } + } + + if (m_Buffer.size == 0 && !m_Eos) { + // unbuffered mode + if (m_Buffer.data != NULL) ReleaseBuffer(); + while (NPT_SUCCEEDED(result = m_Source->Read(buffer, 1, NULL))) { + if (*buffer == '\r') { + if (break_on_cr) { + skip_newline = true; + goto done; + } + } else if (*buffer == '\n') { + goto done; + } else { + ++buffer; + } + } + } else { + // refill the buffer + result = FillBuffer(); + } + if (NPT_FAILED(result)) goto done; + } + +done: + // update the newline skipping state + m_SkipNewline = skip_newline; + + // NULL-terminate the line + *buffer = '\0'; + + // return what we have + if (chars_read) *chars_read = (NPT_Size)(buffer-buffer_start); + if (result == NPT_ERROR_EOS) { + m_Eos = true; + if (buffer != buffer_start) { + // we have reached the end of the stream, but we have read + // some chars, so do not return EOS now + return NPT_SUCCESS; + } + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::ReadLine ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::ReadLine(NPT_String& line, + NPT_Size max_chars, + bool break_on_cr) +{ + // clear the line + line.SetLength(0); + + // reserve space for the chars + line.Reserve(max_chars); + + // read the line + NPT_Size chars_read = 0; + NPT_CHECK(ReadLine(line.UseChars(), max_chars, &chars_read, break_on_cr)); + + // adjust the length of the string object + line.SetLength(chars_read); + + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::Read ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::Read(void* buffer, + NPT_Size bytes_to_read, + NPT_Size* bytes_read) +{ + NPT_Result result = NPT_SUCCESS; + NPT_Size total_read = 0; + NPT_Size buffered; + + // check for a possible shortcut + if (bytes_to_read == 0) return NPT_SUCCESS; + + // skip a newline char if needed + if (m_SkipNewline) { + m_SkipNewline = false; + result = Read(buffer, 1, NULL); + if (NPT_FAILED(result)) goto done; + NPT_Byte c = *(NPT_Byte*)buffer; + if (c != '\n') { + buffer = (void*)((NPT_Byte*)buffer+1); + --bytes_to_read; + total_read = 1; + } + } + + // compute how much is buffered + buffered = m_Buffer.valid-m_Buffer.offset; + if (bytes_to_read > buffered) { + // there is not enough in the buffer, take what's there + if (buffered) { + NPT_CopyMemory(buffer, + m_Buffer.data + m_Buffer.offset, + buffered); + buffer = (void*)((NPT_Byte*)buffer+buffered); + m_Buffer.offset += buffered; + bytes_to_read -= buffered; + total_read += buffered; + goto done; + } + + // read the rest from the source + if (m_Buffer.size == 0) { + // unbuffered mode, read directly into the supplied buffer + if (m_Buffer.data != NULL) ReleaseBuffer(); // cleanup if necessary + NPT_Size local_read = 0; + result = m_Source->Read(buffer, bytes_to_read, &local_read); + if (NPT_SUCCEEDED(result)) { + total_read += local_read; + } + goto done; + } else { + // refill the buffer + result = FillBuffer(); + if (NPT_FAILED(result)) goto done; + buffered = m_Buffer.valid; + if (bytes_to_read > buffered) bytes_to_read = buffered; + } + } + + // get what we can from the buffer + if (bytes_to_read) { + NPT_CopyMemory(buffer, + m_Buffer.data + m_Buffer.offset, + bytes_to_read); + m_Buffer.offset += bytes_to_read; + total_read += bytes_to_read; + } + +done: + if (bytes_read) *bytes_read = total_read; + if (result == NPT_ERROR_EOS) { + m_Eos = true; + if (total_read != 0) { + // we have reached the end of the stream, but we have read + // some chars, so do not return EOS now + return NPT_SUCCESS; + } + } + return result; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::Seek ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::Seek(NPT_Position /*offset*/) +{ + // not implemented yet + return NPT_ERROR_NOT_IMPLEMENTED; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::Tell ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::Tell(NPT_Position& offset) +{ + // not implemented yet + offset = 0; + return NPT_ERROR_NOT_IMPLEMENTED; +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::GetSize ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::GetSize(NPT_LargeSize& size) +{ + return m_Source->GetSize(size); +} + +/*---------------------------------------------------------------------- +| NPT_BufferedInputStream::GetAvailable ++---------------------------------------------------------------------*/ +NPT_Result +NPT_BufferedInputStream::GetAvailable(NPT_LargeSize& available) +{ + NPT_LargeSize source_available = 0; + NPT_Result result = m_Source->GetAvailable(source_available); + if (NPT_SUCCEEDED(result)) { + available = m_Buffer.valid-m_Buffer.offset + source_available; + return NPT_SUCCESS; + } else { + available = m_Buffer.valid-m_Buffer.offset; + return available?NPT_SUCCESS:result; + } +}