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 { return fHasLength; } 28 29 virtual size_t getLength() const SK_OVERRIDE { return fLength; } 30 31 virtual SkStreamRewindable* duplicate() const SK_OVERRIDE { return NULL; } 32 33 private: 34 SkAutoTUnref<SkStream> fStream; 35 const bool fHasLength; 36 const size_t fLength; 37 // Current offset into the stream. Always >= 0. 38 size_t fOffset; 39 // Amount that has been buffered by calls to read. Will always be less than 40 // fBufferSize. 41 size_t fBufferedSoFar; 42 // Total size of the buffer. 43 const size_t fBufferSize; 44 // FIXME: SkAutoTMalloc throws on failure. Instead, Create should return a 45 // NULL stream. 46 SkAutoTMalloc<char> fBuffer; 47 48 // Read up to size bytes from already buffered data, and copy to 49 // dst, if non-NULL. Updates fOffset. Assumes that fOffset is less 50 // than fBufferedSoFar. 51 size_t readFromBuffer(char* dst, size_t size); 52 53 // Buffer up to size bytes from the stream, and copy to dst if non- 54 // NULL. Updates fOffset and fBufferedSoFar. Assumes that fOffset is 55 // less than fBufferedSoFar, and size is greater than 0. 56 size_t bufferAndWriteTo(char* dst, size_t size); 57 58 // Read up to size bytes directly from the stream and into dst if non- 59 // NULL. Updates fOffset. Assumes fOffset is at or beyond the buffered 60 // data, and size is greater than 0. 61 size_t readDirectlyFromStream(char* dst, size_t size); 62 63 typedef SkStream INHERITED; 64 }; 65 66 SkStreamRewindable* SkFrontBufferedStream::Create(SkStream* stream, size_t bufferSize) { 67 if (NULL == stream) { 68 return NULL; 69 } 70 return SkNEW_ARGS(FrontBufferedStream, (stream, bufferSize)); 71 } 72 73 FrontBufferedStream::FrontBufferedStream(SkStream* stream, size_t bufferSize) 74 : fStream(SkRef(stream)) 75 , fHasLength(stream->hasPosition() && stream->hasLength()) 76 , fLength(stream->getLength() - stream->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 != NULL) { 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 // Data needs to be buffered. Buffer up to the lesser of the size requested 123 // and the remainder of the max buffer size. 124 const size_t bytesToBuffer = SkTMin(size, fBufferSize - fBufferedSoFar); 125 char* buffer = fBuffer + fOffset; 126 const size_t buffered = fStream->read(buffer, bytesToBuffer); 127 128 fBufferedSoFar += buffered; 129 fOffset = fBufferedSoFar; 130 SkASSERT(fBufferedSoFar <= fBufferSize); 131 132 // Copy the buffer to the destination buffer and update the amount read. 133 if (dst != NULL) { 134 memcpy(dst, buffer, buffered); 135 } 136 137 return buffered; 138 } 139 140 size_t FrontBufferedStream::readDirectlyFromStream(char* dst, size_t size) { 141 SkASSERT(size > 0); 142 // If we get here, we have buffered all that can be buffered. 143 SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize); 144 145 const size_t bytesReadDirectly = fStream->read(dst, size); 146 fOffset += bytesReadDirectly; 147 148 // If we have read past the end of the buffer, rewinding is no longer 149 // supported, so we can go ahead and free the memory. 150 if (bytesReadDirectly > 0) { 151 fBuffer.reset(0); 152 } 153 154 return bytesReadDirectly; 155 } 156 157 size_t FrontBufferedStream::read(void* voidDst, size_t size) { 158 // Cast voidDst to a char* for easy addition. 159 char* dst = reinterpret_cast<char*>(voidDst); 160 SkDEBUGCODE(const size_t totalSize = size;) 161 const size_t start = fOffset; 162 163 // First, read any data that was previously buffered. 164 if (fOffset < fBufferedSoFar) { 165 const size_t bytesCopied = this->readFromBuffer(dst, size); 166 167 // Update the remaining number of bytes needed to read 168 // and the destination buffer. 169 size -= bytesCopied; 170 SkASSERT(size + (fOffset - start) == totalSize); 171 if (dst != NULL) { 172 dst += bytesCopied; 173 } 174 } 175 176 // Buffer any more data that should be buffered, and copy it to the 177 // destination. 178 if (size > 0 && fBufferedSoFar < fBufferSize) { 179 const size_t buffered = this->bufferAndWriteTo(dst, size); 180 181 // Update the remaining number of bytes needed to read 182 // and the destination buffer. 183 size -= buffered; 184 SkASSERT(size + (fOffset - start) == totalSize); 185 if (dst != NULL) { 186 dst += buffered; 187 } 188 } 189 190 if (size > 0 && !fStream->isAtEnd()) { 191 SkDEBUGCODE(const size_t bytesReadDirectly =) this->readDirectlyFromStream(dst, size); 192 SkDEBUGCODE(size -= bytesReadDirectly;) 193 SkASSERT(size + (fOffset - start) == totalSize); 194 } 195 196 return fOffset - start; 197 } 198