1 /* 2 * Copyright 2011-2013, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <BufferedDataIO.h> 8 9 #include <new> 10 11 #include <stdio.h> 12 #include <string.h> 13 14 15 //#define TRACE_DATA_IO 16 #ifdef TRACE_DATA_IO 17 # define TRACE(x...) printf(x) 18 #else 19 # define TRACE(x...) ; 20 #endif 21 22 23 BBufferedDataIO::BBufferedDataIO(BDataIO& stream, size_t bufferSize, 24 bool ownsStream, bool partialReads) 25 : 26 fStream(stream), 27 fPosition(0), 28 fSize(0), 29 fDirty(false), 30 fOwnsStream(ownsStream), 31 fPartialReads(partialReads) 32 { 33 fBufferSize = max_c(bufferSize, 512); 34 fBuffer = new(std::nothrow) uint8[fBufferSize]; 35 } 36 37 38 BBufferedDataIO::~BBufferedDataIO() 39 { 40 Flush(); 41 delete[] fBuffer; 42 43 if (fOwnsStream) 44 delete &fStream; 45 } 46 47 48 status_t 49 BBufferedDataIO::InitCheck() const 50 { 51 return fBuffer == NULL ? B_NO_MEMORY : B_OK; 52 } 53 54 55 BDataIO* 56 BBufferedDataIO::Stream() const 57 { 58 return &fStream; 59 } 60 61 62 size_t 63 BBufferedDataIO::BufferSize() const 64 { 65 return fBufferSize; 66 } 67 68 69 bool 70 BBufferedDataIO::OwnsStream() const 71 { 72 return fOwnsStream; 73 } 74 75 76 void 77 BBufferedDataIO::SetOwnsStream(bool ownsStream) 78 { 79 fOwnsStream = ownsStream; 80 } 81 82 83 status_t 84 BBufferedDataIO::Flush() 85 { 86 if (!fDirty) 87 return B_OK; 88 89 ssize_t bytesWritten = fStream.Write(fBuffer + fPosition, fSize); 90 if ((size_t)bytesWritten == fSize) { 91 fDirty = false; 92 fPosition = 0; 93 fSize = 0; 94 return B_OK; 95 } else if (bytesWritten >= 0) { 96 fSize -= bytesWritten; 97 fPosition += bytesWritten; 98 return B_ERROR; 99 } 100 101 return bytesWritten; 102 } 103 104 105 ssize_t 106 BBufferedDataIO::Read(void* buffer, size_t size) 107 { 108 if (buffer == NULL) 109 return B_BAD_VALUE; 110 111 TRACE("%p::Read(size %lu)\n", this, size); 112 113 size_t bytesRead = 0; 114 115 if (fSize > 0) { 116 // fill the part of the stream we already have 117 bytesRead = min_c(size, fSize); 118 TRACE("%p: read %lu bytes we already have in the buffer.\n", this, 119 bytesRead); 120 memcpy(buffer, fBuffer + fPosition, bytesRead); 121 122 buffer = (void*)((uint8_t*)buffer + bytesRead); 123 size -= bytesRead; 124 fPosition += bytesRead; 125 fSize -= bytesRead; 126 127 if (fPartialReads) 128 return bytesRead; 129 } 130 131 if (size > fBufferSize || fBuffer == NULL) { 132 // request is larger than our buffer, just fill it directly 133 return fStream.Read(buffer, size); 134 } 135 136 if (size > 0) { 137 // retrieve next buffer 138 139 status_t status = Flush(); 140 if (status != B_OK) 141 return status; 142 143 TRACE("%p: read %" B_PRIuSIZE " bytes from stream\n", this, 144 fBufferSize); 145 ssize_t nextRead = fStream.Read(fBuffer, fBufferSize); 146 if (nextRead < 0) 147 return nextRead; 148 149 fSize = nextRead; 150 TRACE("%p: retrieved %" B_PRIuSIZE " bytes from stream\n", this, fSize); 151 fPosition = 0; 152 153 // Copy the remaining part 154 size_t copy = min_c(size, fSize); 155 memcpy(buffer, fBuffer, copy); 156 TRACE("%p: copy %" B_PRIuSIZE" bytes to buffer\n", this, copy); 157 158 bytesRead += copy; 159 fPosition = copy; 160 fSize -= copy; 161 } 162 163 return bytesRead; 164 } 165 166 167 ssize_t 168 BBufferedDataIO::Write(const void* buffer, size_t size) 169 { 170 if (buffer == NULL) 171 return B_BAD_VALUE; 172 173 TRACE("%p::Write(size %lu)\n", this, size); 174 175 if (!fDirty) { 176 // Throw away a read-only buffer if necessary 177 TRACE("%p: throw away previous buffer.\n", this); 178 fPosition = 0; 179 fSize = 0; 180 } 181 182 size_t bytesWritten = 0; 183 184 if (size > fBufferSize || fBuffer == NULL) { 185 // request is larger than our buffer, just fill it directly 186 bytesWritten = fSize; 187 188 status_t status = Flush(); 189 if (status != B_OK) 190 return status; 191 192 ssize_t streamWritten = fStream.Write(buffer, size); 193 if (streamWritten >= 0) 194 return bytesWritten + streamWritten; 195 196 return streamWritten; 197 } 198 199 bytesWritten = min_c(size, fBufferSize - fSize - fPosition); 200 TRACE("%p: write %" B_PRIuSIZE " bytes to the buffer.\n", this, 201 bytesWritten); 202 memcpy(fBuffer + fPosition + fSize, buffer, bytesWritten); 203 fSize += bytesWritten; 204 size -= bytesWritten; 205 206 if (size > 0) { 207 status_t status = Flush(); 208 if (status != B_OK) 209 return status; 210 211 memcpy(fBuffer, (uint8*)buffer + bytesWritten, size); 212 fPosition = 0; 213 fSize = size; 214 fDirty = true; 215 bytesWritten += size; 216 } 217 218 return bytesWritten; 219 } 220 221 222 // #pragma mark - FBC 223 224 225 status_t BBufferedDataIO::_Reserved0(void*) { return B_ERROR; } 226 status_t BBufferedDataIO::_Reserved1(void*) { return B_ERROR; } 227 status_t BBufferedDataIO::_Reserved2(void*) { return B_ERROR; } 228 status_t BBufferedDataIO::_Reserved3(void*) { return B_ERROR; } 229 status_t BBufferedDataIO::_Reserved4(void*) { return B_ERROR; } 230