Home | History | Annotate | Download | only in utils
      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