/** Copyright 2003-2008, Haiku, Inc. All rights reserved.* Distributed under the terms of the MIT License.** Authors :* Michael Wilber* JΓ©rΓ΄me Duval*/#include <stdio.h>#include <string.h>#include "StreamBuffer.h"#ifndef min#define min(x,y) (((x) < (y)) ? (x) : (y))#endif#ifndef max#define max(x,y) (((x) > (y)) ? (x) : (y))#endif// ---------------------------------------------------------------// Constructor//// Initializes the StreamBuffer to read from pstream, buffering// nbuffersize bytes of data at a time. Note that if nbuffersize// is smaller than MIN_BUFFER_SIZE, MIN_BUFFER_SIZE is used// as the buffer size.//// Preconditions://// Parameters: pstream, the stream to be buffered//// nbuffersize, number of bytes to be read from// pstream at a time//// Postconditions://// Returns:// ---------------------------------------------------------------StreamBuffer::StreamBuffer(BPositionIO *pstream, size_t nbuffersize, bool toRead){fStream = pstream;fBuffer = NULL;fBufferSize = 0;fLen = 0;fPos = 0;fToRead = toRead;if (!pstream)return;fBufferSize = max(nbuffersize, MIN_BUFFER_SIZE);fBuffer = new uint8[fBufferSize];}// ---------------------------------------------------------------// Destructor//// Destroys data allocated for this object//// Preconditions://// Parameters://// Postconditions://// Returns:// ---------------------------------------------------------------StreamBuffer::~StreamBuffer(){if (!fToRead && fLen > 0)fStream->Write(fBuffer, fLen);delete[] fBuffer;fBuffer = NULL;}// ---------------------------------------------------------------// InitCheck//// Determines whether the constructor failed or not//// Preconditions://// Parameters://// Postconditions://// Returns: B_OK if object has been initialized successfully,// B_ERROR if not// ---------------------------------------------------------------status_tStreamBuffer::InitCheck(){if (fStream && fBuffer)return B_OK;elsereturn B_ERROR;}// ---------------------------------------------------------------// Read//// Copies up to nbytes of data from the stream into pinto//// Preconditions: ReadStream() must be called once before this// function is called (the constructor does this)//// Parameters: pinto, the buffer to be copied to//// nbytes, the maximum number of bytes to copy//// Postconditions://// Returns: the number of bytes successfully read or an// error code returned by BPositionIO::Read()// ---------------------------------------------------------------ssize_tStreamBuffer::Read(void *_pinto, size_t nbytes){if (_pinto == NULL)return B_BAD_VALUE;if (nbytes == 0)return 0;ssize_t result = B_ERROR;uint8 *pinto = (uint8 *)_pinto;size_t totalRead = min(nbytes, fLen - fPos);memcpy(pinto, fBuffer + fPos, totalRead);fPos += totalRead;pinto += totalRead;nbytes -= totalRead;while (nbytes > 0) {result = _ReadStream();if (result <= 0)return result;if (result > 0) {size_t left = min(nbytes, fLen - fPos);memcpy(pinto, fBuffer + fPos, left);fPos += left;pinto += left;nbytes -= left;totalRead += left;}}return totalRead;}// ---------------------------------------------------------------// Write//// Copies up to nbytes of data from pinto into the stream//// Parameters: pinto, the buffer to be copied from// nbytes, the maximum number of bytes to copy//// Returns: the number of bytes successfully read or an// error code returned by BPositionIO::Read()// ---------------------------------------------------------------voidStreamBuffer::Write(void *pinto, size_t nbytes){if (nbytes < fBufferSize - fLen) {memcpy(fBuffer + fLen, pinto, nbytes);fLen += nbytes;} else {if (fLen > 0) {fStream->Write(fBuffer, fLen);fLen = 0;}fStream->Write(pinto, nbytes);}}// ---------------------------------------------------------------// Seek//// Seeks the stream to the given position. If the seek operation fails,// the read buffer will be reset.//// Preconditions: fBuffer must be allocated and fBufferSize// must be valid//// Parameters://// Postconditions://// Returns: the new position// ---------------------------------------------------------------off_tStreamBuffer::Seek(off_t position, uint32 seekMode){// just seek in the current buffer if the new position is in itif (seekMode == SEEK_CUR) {if (fToRead&& (fPos + position < fLen)&& (fPos + position >= 0)) {fPos += position;return Position();} else if (!fToRead&& (fLen + position < fBufferSize)&& (fLen + position >= 0)) {fLen += position;return Position();}}// flush if something to writeif (!fToRead&& fLen > 0) {fStream->Write(fBuffer, fLen);}fLen = 0;fPos = 0;return fStream->Seek(position, seekMode);}// ---------------------------------------------------------------// Position//// Returns the current position in the stream.//// Preconditions: fBuffer must be allocated and fBufferSize// must be valid//// Parameters://// Postconditions://// Returns: the position// ---------------------------------------------------------------off_tStreamBuffer::Position(){off_t position = fStream->Position();if (fToRead)position -= (fLen - fPos);elseposition += fLen;return position;}// ---------------------------------------------------------------// _ReadStream//// Fills the stream buffer with data read in from the stream//// Preconditions: fBuffer must be allocated and fBufferSize// must be valid//// Parameters://// Postconditions://// Returns: the number of bytes successfully read or an// error code returned by BPositionIO::Read()// ---------------------------------------------------------------ssize_tStreamBuffer::_ReadStream(){ssize_t len = fStream->Read(fBuffer, fBufferSize);if (len < 0)return len;fLen = len;fPos = 0;return fLen;}