1e26a1248SJérôme Duval /* 2e26a1248SJérôme Duval * Copyright 2003-2008, Haiku, Inc. All rights reserved. 3e26a1248SJérôme Duval * Distributed under the terms of the MIT License. 4e26a1248SJérôme Duval * 5e26a1248SJérôme Duval * Authors : 6e26a1248SJérôme Duval * Michael Wilber 7e26a1248SJérôme Duval * Jérôme Duval 8e26a1248SJérôme Duval */ 9c56079fbSMatthew Wilber 10c56079fbSMatthew Wilber #include <stdio.h> 119640a42eSStephan Aßmus #include <string.h> 12c56079fbSMatthew Wilber #include "StreamBuffer.h" 13c56079fbSMatthew Wilber 14c56079fbSMatthew Wilber #ifndef min 15c56079fbSMatthew Wilber #define min(x,y) (((x) < (y)) ? (x) : (y)) 16c56079fbSMatthew Wilber #endif 17c56079fbSMatthew Wilber 18c56079fbSMatthew Wilber #ifndef max 19c56079fbSMatthew Wilber #define max(x,y) (((x) > (y)) ? (x) : (y)) 20c56079fbSMatthew Wilber #endif 21c56079fbSMatthew Wilber 22c56079fbSMatthew Wilber // --------------------------------------------------------------- 23c56079fbSMatthew Wilber // Constructor 24c56079fbSMatthew Wilber // 25c56079fbSMatthew Wilber // Initializes the StreamBuffer to read from pstream, buffering 26c56079fbSMatthew Wilber // nbuffersize bytes of data at a time. Note that if nbuffersize 27c56079fbSMatthew Wilber // is smaller than MIN_BUFFER_SIZE, MIN_BUFFER_SIZE is used 28c56079fbSMatthew Wilber // as the buffer size. 29c56079fbSMatthew Wilber // 30c56079fbSMatthew Wilber // Preconditions: 31c56079fbSMatthew Wilber // 32c56079fbSMatthew Wilber // Parameters: pstream, the stream to be buffered 33c56079fbSMatthew Wilber // 34c56079fbSMatthew Wilber // nbuffersize, number of bytes to be read from 35c56079fbSMatthew Wilber // pstream at a time 36c56079fbSMatthew Wilber // 37c56079fbSMatthew Wilber // Postconditions: 38c56079fbSMatthew Wilber // 39c56079fbSMatthew Wilber // Returns: 40c56079fbSMatthew Wilber // --------------------------------------------------------------- 41e26a1248SJérôme Duval StreamBuffer::StreamBuffer(BPositionIO *pstream, size_t nbuffersize, bool toRead) 42c56079fbSMatthew Wilber { 43e26a1248SJérôme Duval fStream = pstream; 44e26a1248SJérôme Duval fBuffer = NULL; 45e26a1248SJérôme Duval fBufferSize = 0; 46e26a1248SJérôme Duval fLen = 0; 47e26a1248SJérôme Duval fPos = 0; 48e26a1248SJérôme Duval fToRead = toRead; 49c56079fbSMatthew Wilber 50c56079fbSMatthew Wilber if (!pstream) 51c56079fbSMatthew Wilber return; 52c56079fbSMatthew Wilber 53e26a1248SJérôme Duval fBufferSize = max(nbuffersize, MIN_BUFFER_SIZE); 54e26a1248SJérôme Duval fBuffer = new uint8[fBufferSize]; 55c56079fbSMatthew Wilber } 56c56079fbSMatthew Wilber 57c56079fbSMatthew Wilber // --------------------------------------------------------------- 58c56079fbSMatthew Wilber // Destructor 59c56079fbSMatthew Wilber // 60c56079fbSMatthew Wilber // Destroys data allocated for this object 61c56079fbSMatthew Wilber // 62c56079fbSMatthew Wilber // Preconditions: 63c56079fbSMatthew Wilber // 64c56079fbSMatthew Wilber // Parameters: 65c56079fbSMatthew Wilber // 66c56079fbSMatthew Wilber // Postconditions: 67c56079fbSMatthew Wilber // 68c56079fbSMatthew Wilber // Returns: 69c56079fbSMatthew Wilber // --------------------------------------------------------------- 70c56079fbSMatthew Wilber StreamBuffer::~StreamBuffer() 71c56079fbSMatthew Wilber { 72e26a1248SJérôme Duval if (!fToRead && fLen > 0) 73e26a1248SJérôme Duval fStream->Write(fBuffer, fLen); 74e26a1248SJérôme Duval delete[] fBuffer; 75e26a1248SJérôme Duval fBuffer = NULL; 76c56079fbSMatthew Wilber } 77c56079fbSMatthew Wilber 78c56079fbSMatthew Wilber // --------------------------------------------------------------- 79c56079fbSMatthew Wilber // InitCheck 80c56079fbSMatthew Wilber // 81c56079fbSMatthew Wilber // Determines whether the constructor failed or not 82c56079fbSMatthew Wilber // 83c56079fbSMatthew Wilber // Preconditions: 84c56079fbSMatthew Wilber // 85c56079fbSMatthew Wilber // Parameters: 86c56079fbSMatthew Wilber // 87c56079fbSMatthew Wilber // Postconditions: 88c56079fbSMatthew Wilber // 89c56079fbSMatthew Wilber // Returns: B_OK if object has been initialized successfully, 90c56079fbSMatthew Wilber // B_ERROR if not 91c56079fbSMatthew Wilber // --------------------------------------------------------------- 92c56079fbSMatthew Wilber status_t 93c56079fbSMatthew Wilber StreamBuffer::InitCheck() 94c56079fbSMatthew Wilber { 95e26a1248SJérôme Duval if (fStream && fBuffer) 96c56079fbSMatthew Wilber return B_OK; 97c56079fbSMatthew Wilber else 98c56079fbSMatthew Wilber return B_ERROR; 99c56079fbSMatthew Wilber } 100c56079fbSMatthew Wilber 101c56079fbSMatthew Wilber // --------------------------------------------------------------- 102c56079fbSMatthew Wilber // Read 103c56079fbSMatthew Wilber // 104c56079fbSMatthew Wilber // Copies up to nbytes of data from the stream into pinto 105c56079fbSMatthew Wilber // 106c56079fbSMatthew Wilber // Preconditions: ReadStream() must be called once before this 107c56079fbSMatthew Wilber // function is called (the constructor does this) 108c56079fbSMatthew Wilber // 109c56079fbSMatthew Wilber // Parameters: pinto, the buffer to be copied to 110c56079fbSMatthew Wilber // 111c56079fbSMatthew Wilber // nbytes, the maximum number of bytes to copy 112c56079fbSMatthew Wilber // 113c56079fbSMatthew Wilber // Postconditions: 114c56079fbSMatthew Wilber // 115c56079fbSMatthew Wilber // Returns: the number of bytes successfully read or an 116c56079fbSMatthew Wilber // error code returned by BPositionIO::Read() 117c56079fbSMatthew Wilber // --------------------------------------------------------------- 118c56079fbSMatthew Wilber ssize_t 1199640a42eSStephan Aßmus StreamBuffer::Read(void *_pinto, size_t nbytes) 120c56079fbSMatthew Wilber { 1219640a42eSStephan Aßmus if (_pinto == NULL) 1229640a42eSStephan Aßmus return B_BAD_VALUE; 123e26a1248SJérôme Duval if (nbytes == 0) 124e26a1248SJérôme Duval return 0; 125e26a1248SJérôme Duval 126c56079fbSMatthew Wilber ssize_t result = B_ERROR; 1279640a42eSStephan Aßmus uint8 *pinto = (uint8 *)_pinto; 128c56079fbSMatthew Wilber 129e26a1248SJérôme Duval size_t totalRead = min(nbytes, fLen - fPos); 130e26a1248SJérôme Duval memcpy(pinto, fBuffer + fPos, totalRead); 131e26a1248SJérôme Duval fPos += totalRead; 1329640a42eSStephan Aßmus pinto += totalRead; 133e26a1248SJérôme Duval nbytes -= totalRead; 134c56079fbSMatthew Wilber 135e26a1248SJérôme Duval while (nbytes > 0) { 136e26a1248SJérôme Duval result = _ReadStream(); 137e26a1248SJérôme Duval if (result <= 0) 138c56079fbSMatthew Wilber return result; 139e26a1248SJérôme Duval if (result > 0) { 140e26a1248SJérôme Duval size_t left = min(nbytes, fLen - fPos); 141e26a1248SJérôme Duval memcpy(pinto, fBuffer + fPos, left); 142e26a1248SJérôme Duval fPos += left; 1439640a42eSStephan Aßmus pinto += left; 144e26a1248SJérôme Duval nbytes -= left; 145e26a1248SJérôme Duval totalRead += left; 146e26a1248SJérôme Duval } 147c56079fbSMatthew Wilber } 148c56079fbSMatthew Wilber 149e26a1248SJérôme Duval return totalRead; 150c56079fbSMatthew Wilber } 151c56079fbSMatthew Wilber 152e26a1248SJérôme Duval 153e26a1248SJérôme Duval // --------------------------------------------------------------- 154e26a1248SJérôme Duval // Write 155e26a1248SJérôme Duval // 156e26a1248SJérôme Duval // Copies up to nbytes of data from pinto into the stream 157e26a1248SJérôme Duval // 158e26a1248SJérôme Duval // Parameters: pinto, the buffer to be copied from 159e26a1248SJérôme Duval // nbytes, the maximum number of bytes to copy 160e26a1248SJérôme Duval // 161e26a1248SJérôme Duval // Returns: the number of bytes successfully read or an 162e26a1248SJérôme Duval // error code returned by BPositionIO::Read() 163e26a1248SJérôme Duval // --------------------------------------------------------------- 164e26a1248SJérôme Duval void 165e26a1248SJérôme Duval StreamBuffer::Write(void *pinto, size_t nbytes) 166e26a1248SJérôme Duval { 167e26a1248SJérôme Duval if (nbytes < fBufferSize - fLen) { 168e26a1248SJérôme Duval memcpy(fBuffer + fLen, pinto, nbytes); 169e26a1248SJérôme Duval fLen += nbytes; 170e26a1248SJérôme Duval } else { 171e26a1248SJérôme Duval if (fLen > 0) { 172e26a1248SJérôme Duval fStream->Write(fBuffer, fLen); 173e26a1248SJérôme Duval fLen = 0; 174e26a1248SJérôme Duval } 175e26a1248SJérôme Duval fStream->Write(pinto, nbytes); 176e26a1248SJérôme Duval } 177e26a1248SJérôme Duval } 178e26a1248SJérôme Duval 179e26a1248SJérôme Duval 180c56079fbSMatthew Wilber // --------------------------------------------------------------- 181c56079fbSMatthew Wilber // Seek 182c56079fbSMatthew Wilber // 183e26a1248SJérôme Duval // Seeks the stream to the given position. If the seek operation fails, 184e26a1248SJérôme Duval // the read buffer will be reset. 185c56079fbSMatthew Wilber // 186e26a1248SJérôme Duval // Preconditions: fBuffer must be allocated and fBufferSize 187c56079fbSMatthew Wilber // must be valid 188c56079fbSMatthew Wilber // 189c56079fbSMatthew Wilber // Parameters: 190c56079fbSMatthew Wilber // 191c56079fbSMatthew Wilber // Postconditions: 192c56079fbSMatthew Wilber // 193ac437673SJérôme Duval // Returns: the new position 194c56079fbSMatthew Wilber // --------------------------------------------------------------- 195ac437673SJérôme Duval off_t 196ac437673SJérôme Duval StreamBuffer::Seek(off_t position, uint32 seekMode) 197c56079fbSMatthew Wilber { 198ac437673SJérôme Duval // just seek in the current buffer if the new position is in it 199ac437673SJérôme Duval if (seekMode == SEEK_CUR) { 200ac437673SJérôme Duval if (fToRead 201ac437673SJérôme Duval && (fPos + position < fLen) 202ac437673SJérôme Duval && (fPos + position >= 0)) { 203ac437673SJérôme Duval fPos += position; 204ac437673SJérôme Duval return Position(); 205ac437673SJérôme Duval } else if (!fToRead 206ac437673SJérôme Duval && (fLen + position < fBufferSize) 207ac437673SJérôme Duval && (fLen + position >= 0)) { 208ac437673SJérôme Duval fLen += position; 209ac437673SJérôme Duval return Position(); 210ac437673SJérôme Duval } 211ac437673SJérôme Duval } 212ac437673SJérôme Duval 213ac437673SJérôme Duval // flush if something to write 214ac437673SJérôme Duval if (!fToRead 215ac437673SJérôme Duval && fLen > 0) { 216ac437673SJérôme Duval fStream->Write(fBuffer, fLen); 217ac437673SJérôme Duval } 218ac437673SJérôme Duval 219e26a1248SJérôme Duval fLen = 0; 220e26a1248SJérôme Duval fPos = 0; 221c56079fbSMatthew Wilber 222ac437673SJérôme Duval return fStream->Seek(position, seekMode); 223c56079fbSMatthew Wilber } 224c56079fbSMatthew Wilber 22545ff9decSJérôme Duval 22645ff9decSJérôme Duval // --------------------------------------------------------------- 22745ff9decSJérôme Duval // Position 22845ff9decSJérôme Duval // 22945ff9decSJérôme Duval // Returns the current position in the stream. 23045ff9decSJérôme Duval // 23145ff9decSJérôme Duval // Preconditions: fBuffer must be allocated and fBufferSize 23245ff9decSJérôme Duval // must be valid 23345ff9decSJérôme Duval // 23445ff9decSJérôme Duval // Parameters: 23545ff9decSJérôme Duval // 23645ff9decSJérôme Duval // Postconditions: 23745ff9decSJérôme Duval // 23845ff9decSJérôme Duval // Returns: the position 23945ff9decSJérôme Duval // --------------------------------------------------------------- 24045ff9decSJérôme Duval off_t 24145ff9decSJérôme Duval StreamBuffer::Position() 24245ff9decSJérôme Duval { 24345ff9decSJérôme Duval off_t position = fStream->Position(); 24445ff9decSJérôme Duval if (fToRead) 245*cc6736afSJérôme Duval position -= (fLen - fPos); 24645ff9decSJérôme Duval else 24745ff9decSJérôme Duval position += fLen; 24845ff9decSJérôme Duval return position; 24945ff9decSJérôme Duval } 25045ff9decSJérôme Duval 25145ff9decSJérôme Duval 252c56079fbSMatthew Wilber // --------------------------------------------------------------- 253e26a1248SJérôme Duval // _ReadStream 254c56079fbSMatthew Wilber // 255c56079fbSMatthew Wilber // Fills the stream buffer with data read in from the stream 256c56079fbSMatthew Wilber // 257e26a1248SJérôme Duval // Preconditions: fBuffer must be allocated and fBufferSize 258c56079fbSMatthew Wilber // must be valid 259c56079fbSMatthew Wilber // 260c56079fbSMatthew Wilber // Parameters: 261c56079fbSMatthew Wilber // 262c56079fbSMatthew Wilber // Postconditions: 263c56079fbSMatthew Wilber // 264c56079fbSMatthew Wilber // Returns: the number of bytes successfully read or an 265c56079fbSMatthew Wilber // error code returned by BPositionIO::Read() 266c56079fbSMatthew Wilber // --------------------------------------------------------------- 267c56079fbSMatthew Wilber ssize_t 268e26a1248SJérôme Duval StreamBuffer::_ReadStream() 269c56079fbSMatthew Wilber { 270e26a1248SJérôme Duval ssize_t len = fStream->Read(fBuffer, fBufferSize); 271e26a1248SJérôme Duval if (len < 0) 272e26a1248SJérôme Duval return len; 273e26a1248SJérôme Duval fLen = len; 274e26a1248SJérôme Duval fPos = 0; 275e26a1248SJérôme Duval return fLen; 276c56079fbSMatthew Wilber } 277