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 // --------------------------------------------------------------- 41 StreamBuffer::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 // --------------------------------------------------------------- 70 StreamBuffer::~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 // --------------------------------------------------------------- 92 status_t 93 StreamBuffer::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 // --------------------------------------------------------------- 118 ssize_t 119 StreamBuffer::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 // --------------------------------------------------------------- 164 void 165 StreamBuffer::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 // --------------------------------------------------------------- 195 off_t 196 StreamBuffer::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 // --------------------------------------------------------------- 240 off_t 241 StreamBuffer::Position() 242 { 243 off_t position = fStream->Position(); 244 if (fToRead) 245 position -= 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 // --------------------------------------------------------------- 267 ssize_t 268 StreamBuffer::_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