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