1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkFrontBufferedStream.h" 9 #include "SkStream.h" 10 #include "SkTemplates.h" 11 12 class FrontBufferedStream : public SkStreamRewindable { 13 public: 14 // Called by Create. 15 FrontBufferedStream(SkStream*, size_t bufferSize); 16 17 virtual size_t read(void* buffer, size_t size) SK_OVERRIDE; 18 19 virtual bool isAtEnd() const SK_OVERRIDE; 20 21 virtual bool rewind() SK_OVERRIDE; 22 23 virtual bool hasPosition() const SK_OVERRIDE { return true; } 24 25 virtual size_t getPosition() const SK_OVERRIDE { return fOffset; } 26 27 virtual bool hasLength() const SK_OVERRIDE; 28 29 virtual size_t getLength() const SK_OVERRIDE; 30 31 virtual SkStreamRewindable* duplicate() const SK_OVERRIDE { return NULL; } 32 33 private: 34 SkAutoTUnref<SkStream> fStream; 35 // Current offset into the stream. Always >= 0. 36 size_t fOffset; 37 // Amount that has been buffered by calls to read. Will always be less than 38 // fBufferSize. 39 size_t fBufferedSoFar; 40 // Total size of the buffer. 41 const size_t fBufferSize; 42 // FIXME: SkAutoTMalloc throws on failure. Instead, Create should return a 43 // NULL stream. 44 SkAutoTMalloc<char> fBuffer; 45 46 // Read up to size bytes from already buffered data, and copy to 47 // dst, if non-NULL. Updates fOffset. Assumes that fOffset is less 48 // than fBufferedSoFar. 49 size_t readFromBuffer(char* dst, size_t size); 50 51 // Buffer up to size bytes from the stream, and copy to dst if non- 52 // NULL. Updates fOffset and fBufferedSoFar. Assumes that fOffset is 53 // less than fBufferedSoFar, and size is greater than 0. 54 size_t bufferAndWriteTo(char* dst, size_t size); 55 56 // Read up to size bytes directly from the stream and into dst if non- 57 // NULL. Updates fOffset. Assumes fOffset is at or beyond the buffered 58 // data, and size is greater than 0. 59 size_t readDirectlyFromStream(char* dst, size_t size); 60 61 typedef SkStream INHERITED; 62 }; 63 64 SkStreamRewindable* SkFrontBufferedStream::Create(SkStream* stream, size_t bufferSize) { 65 if (NULL == stream) { 66 return NULL; 67 } 68 return SkNEW_ARGS(FrontBufferedStream, (stream, bufferSize)); 69 } 70 71 FrontBufferedStream::FrontBufferedStream(SkStream* stream, size_t bufferSize) 72 : fStream(SkRef(stream)) 73 , fOffset(0) 74 , fBufferedSoFar(0) 75 , fBufferSize(bufferSize) 76 , fBuffer(bufferSize) {} 77 78 bool FrontBufferedStream::isAtEnd() const { 79 if (fOffset < fBufferedSoFar) { 80 // Even if the underlying stream is at the end, this stream has been 81 // rewound after buffering, so it is not at the end. 82 return false; 83 } 84 85 return fStream->isAtEnd(); 86 } 87 88 bool FrontBufferedStream::rewind() { 89 // Only allow a rewind if we have not exceeded the buffer. 90 if (fOffset <= fBufferSize) { 91 fOffset = 0; 92 return true; 93 } 94 return false; 95 } 96 97 bool FrontBufferedStream::hasLength() const { 98 return fStream->hasLength(); 99 } 100 101 size_t FrontBufferedStream::getLength() const { 102 return fStream->getLength(); 103 } 104 105 size_t FrontBufferedStream::readFromBuffer(char* dst, size_t size) { 106 SkASSERT(fOffset < fBufferedSoFar); 107 // Some data has already been copied to fBuffer. Read up to the 108 // lesser of the size requested and the remainder of the buffered 109 // data. 110 const size_t bytesToCopy = SkTMin(size, fBufferedSoFar - fOffset); 111 if (dst != NULL) { 112 memcpy(dst, fBuffer + fOffset, bytesToCopy); 113 } 114 115 // Update fOffset to the new position. It is guaranteed to be 116 // within the buffered data. 117 fOffset += bytesToCopy; 118 SkASSERT(fOffset <= fBufferedSoFar); 119 120 return bytesToCopy; 121 } 122 123 size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) { 124 SkASSERT(size > 0); 125 SkASSERT(fOffset >= fBufferedSoFar); 126 // Data needs to be buffered. Buffer up to the lesser of the size requested 127 // and the remainder of the max buffer size. 128 const size_t bytesToBuffer = SkTMin(size, fBufferSize - fBufferedSoFar); 129 char* buffer = fBuffer + fOffset; 130 const size_t buffered = fStream->read(buffer, bytesToBuffer); 131 132 fBufferedSoFar += buffered; 133 fOffset = fBufferedSoFar; 134 SkASSERT(fBufferedSoFar <= fBufferSize); 135 136 // Copy the buffer to the destination buffer and update the amount read. 137 if (dst != NULL) { 138 memcpy(dst, buffer, buffered); 139 } 140 141 return buffered; 142 } 143 144 size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) { 145 SkASSERT(size > 0); 146 // If we get here, we have buffered all that can be buffered. 147 SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize); 148 149 const size_t bytesReadDirectly = fStream->read(dst, size); 150 fOffset += bytesReadDirectly; 151 152 // If we have read past the end of the buffer, rewinding is no longer 153 // supported, so we can go ahead and free the memory. 154 if (bytesReadDirectly > 0) { 155 fBuffer.reset(0); 156 } 157 158 return bytesReadDirectly; 159 } 160 161 size_t FrontBufferedStream::read(void* voidDst, size_t size) { 162 // Cast voidDst to a char* for easy addition. 163 char* dst = reinterpret_cast<char*>(voidDst); 164 SkDEBUGCODE(const size_t totalSize = size;) 165 const size_t start = fOffset; 166 167 // First, read any data that was previously buffered. 168 if (fOffset < fBufferedSoFar) { 169 const size_t bytesCopied = this->readFromBuffer(dst, size); 170 171 // Update the remaining number of bytes needed to read 172 // and the destination buffer. 173 size -= bytesCopied; 174 SkASSERT(size + (fOffset - start) == totalSize); 175 if (dst != NULL) { 176 dst += bytesCopied; 177 } 178 } 179 180 // Buffer any more data that should be buffered, and copy it to the 181 // destination. 182 if (size > 0 && fBufferedSoFar < fBufferSize) { 183 const size_t buffered = this->bufferAndWriteTo(dst, size); 184 185 // Update the remaining number of bytes needed to read 186 // and the destination buffer. 187 size -= buffered; 188 SkASSERT(size + (fOffset - start) == totalSize); 189 if (dst != NULL) { 190 dst += buffered; 191 } 192 } 193 194 if (size > 0 && !fStream->isAtEnd()) { 195 SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size); 196 SkDEBUGCODE(size -= bytesReadDirectly;) 197 SkASSERT(size + (fOffset - start) == totalSize); 198 } 199 200 return fOffset - start; 201 } 202