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 Make. 15 FrontBufferedStream(std::unique_ptr<SkStream>, size_t bufferSize); 16 17 size_t read(void* buffer, size_t size) override; 18 19 size_t peek(void* buffer, size_t size) const override; 20 21 bool isAtEnd() const override; 22 23 bool rewind() override; 24 25 bool hasLength() const override { return fHasLength; } 26 27 size_t getLength() const override { return fLength; } 28 29 private: 30 SkStreamRewindable* onDuplicate() const override { return nullptr; } 31 32 std::unique_ptr<SkStream> fStream; 33 const bool fHasLength; 34 const size_t fLength; 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 // nullptr stream. 44 SkAutoTMalloc<char> fBuffer; 45 46 // Read up to size bytes from already buffered data, and copy to 47 // dst, if non-nullptr. 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 // nullptr. 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 // nullptr. 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 std::unique_ptr<SkStreamRewindable> SkFrontBufferedStream::Make(std::unique_ptr<SkStream> stream, 65 size_t bufferSize) { 66 if (!stream) { 67 return nullptr; 68 } 69 return std::unique_ptr<SkStreamRewindable>(new FrontBufferedStream(std::move(stream), 70 bufferSize)); 71 } 72 73 FrontBufferedStream::FrontBufferedStream(std::unique_ptr<SkStream> stream, size_t bufferSize) 74 : fStream(std::move(stream)) 75 , fHasLength(fStream->hasPosition() && fStream->hasLength()) 76 , fLength(fStream->getLength() - fStream->getPosition()) 77 , fOffset(0) 78 , fBufferedSoFar(0) 79 , fBufferSize(bufferSize) 80 , fBuffer(bufferSize) {} 81 82 bool FrontBufferedStream::isAtEnd() const { 83 if (fOffset < fBufferedSoFar) { 84 // Even if the underlying stream is at the end, this stream has been 85 // rewound after buffering, so it is not at the end. 86 return false; 87 } 88 89 return fStream->isAtEnd(); 90 } 91 92 bool FrontBufferedStream::rewind() { 93 // Only allow a rewind if we have not exceeded the buffer. 94 if (fOffset <= fBufferSize) { 95 fOffset = 0; 96 return true; 97 } 98 return false; 99 } 100 101 size_t FrontBufferedStream::readFromBuffer(char* dst, size_t size) { 102 SkASSERT(fOffset < fBufferedSoFar); 103 // Some data has already been copied to fBuffer. Read up to the 104 // lesser of the size requested and the remainder of the buffered 105 // data. 106 const size_t bytesToCopy = SkTMin(size, fBufferedSoFar - fOffset); 107 if (dst != nullptr) { 108 memcpy(dst, fBuffer + fOffset, bytesToCopy); 109 } 110 111 // Update fOffset to the new position. It is guaranteed to be 112 // within the buffered data. 113 fOffset += bytesToCopy; 114 SkASSERT(fOffset <= fBufferedSoFar); 115 116 return bytesToCopy; 117 } 118 119 size_t FrontBufferedStream::bufferAndWriteTo(char* dst, size_t size) { 120 SkASSERT(size > 0); 121 SkASSERT(fOffset >= fBufferedSoFar); 122 SkASSERT(fBuffer); 123 // Data needs to be buffered. Buffer up to the lesser of the size requested 124 // and the remainder of the max buffer size. 125 const size_t bytesToBuffer = SkTMin(size, fBufferSize - fBufferedSoFar); 126 char* buffer = fBuffer + fOffset; 127 const size_t buffered = fStream->read(buffer, bytesToBuffer); 128 129 fBufferedSoFar += buffered; 130 fOffset = fBufferedSoFar; 131 SkASSERT(fBufferedSoFar <= fBufferSize); 132 133 // Copy the buffer to the destination buffer and update the amount read. 134 if (dst != nullptr) { 135 memcpy(dst, buffer, buffered); 136 } 137 138 return buffered; 139 } 140 141 size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) { 142 SkASSERT(size > 0); 143 // If we get here, we have buffered all that can be buffered. 144 SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize); 145 146 const size_t bytesReadDirectly = fStream->read(dst, size); 147 fOffset += bytesReadDirectly; 148 149 // If we have read past the end of the buffer, rewinding is no longer 150 // supported, so we can go ahead and free the memory. 151 if (bytesReadDirectly > 0) { 152 sk_free(fBuffer.release()); 153 } 154 155 return bytesReadDirectly; 156 } 157 158 size_t FrontBufferedStream::peek(void* dst, size_t size) const { 159 // Keep track of the offset so we can return to it. 160 const size_t start = fOffset; 161 162 if (start >= fBufferSize) { 163 // This stream is not able to buffer. 164 return 0; 165 } 166 167 size = SkTMin(size, fBufferSize - start); 168 FrontBufferedStream* nonConstThis = const_cast<FrontBufferedStream*>(this); 169 const size_t bytesRead = nonConstThis->read(dst, size); 170 nonConstThis->fOffset = start; 171 return bytesRead; 172 } 173 174 size_t FrontBufferedStream::read(void* voidDst, size_t size) { 175 // Cast voidDst to a char* for easy addition. 176 char* dst = reinterpret_cast<char*>(voidDst); 177 SkDEBUGCODE(const size_t totalSize = size;) 178 const size_t start = fOffset; 179 180 // First, read any data that was previously buffered. 181 if (fOffset < fBufferedSoFar) { 182 const size_t bytesCopied = this->readFromBuffer(dst, size); 183 184 // Update the remaining number of bytes needed to read 185 // and the destination buffer. 186 size -= bytesCopied; 187 SkASSERT(size + (fOffset - start) == totalSize); 188 if (dst != nullptr) { 189 dst += bytesCopied; 190 } 191 } 192 193 // Buffer any more data that should be buffered, and copy it to the 194 // destination. 195 if (size > 0 && fBufferedSoFar < fBufferSize && !fStream->isAtEnd()) { 196 const size_t buffered = this->bufferAndWriteTo(dst, size); 197 198 // Update the remaining number of bytes needed to read 199 // and the destination buffer. 200 size -= buffered; 201 SkASSERT(size + (fOffset - start) == totalSize); 202 if (dst != nullptr) { 203 dst += buffered; 204 } 205 } 206 207 if (size > 0 && !fStream->isAtEnd()) { 208 SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size); 209 SkDEBUGCODE(size -= bytesReadDirectly;) 210 SkASSERT(size + (fOffset - start) == totalSize); 211 } 212 213 return fOffset - start; 214 } 215