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;
+    }
+}