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 
     10 SkFrontBufferedStream* SkFrontBufferedStream::Create(SkStream* stream, size_t bufferSize) {
     11     if (NULL == stream) {
     12         return NULL;
     13     }
     14     return SkNEW_ARGS(SkFrontBufferedStream, (stream, bufferSize));
     15 }
     16 
     17 SkFrontBufferedStream::SkFrontBufferedStream(SkStream* stream, size_t bufferSize)
     18     : fStream(SkRef(stream))
     19     , fOffset(0)
     20     , fBufferedSoFar(0)
     21     , fBufferSize(bufferSize)
     22     , fBuffer(bufferSize) {}
     23 
     24 bool SkFrontBufferedStream::isAtEnd() const {
     25     if (fOffset < fBufferedSoFar) {
     26         // Even if the underlying stream is at the end, this stream has been
     27         // rewound after buffering, so it is not at the end.
     28         return false;
     29     }
     30 
     31     return fStream->isAtEnd();
     32 }
     33 
     34 bool SkFrontBufferedStream::rewind() {
     35     // Only allow a rewind if we have not exceeded the buffer.
     36     if (fOffset <= fBufferSize) {
     37         fOffset = 0;
     38         return true;
     39     }
     40     return false;
     41 }
     42 
     43 bool SkFrontBufferedStream::hasLength() const {
     44     return fStream->hasLength();
     45 }
     46 
     47 size_t SkFrontBufferedStream::getLength() const {
     48     return fStream->getLength();
     49 }
     50 
     51 size_t SkFrontBufferedStream::read(void* voidDst, size_t size) {
     52     // Cast voidDst to a char* for easy addition.
     53     char* dst = reinterpret_cast<char*>(voidDst);
     54     SkDEBUGCODE(const size_t totalSize = size;)
     55     size_t readSoFar = 0;
     56 
     57     // First, read any data that was previously buffered.
     58     if (fOffset < fBufferedSoFar) {
     59         // Some data has already been copied to fBuffer. Read up to the
     60         // lesser of the size requested and the remainder of the buffered
     61         // data.
     62         const size_t bytesToCopy = SkTMin(size, fBufferedSoFar - fOffset);
     63         if (dst != NULL) {
     64             memcpy(dst, this->getBufferAtOffset(), bytesToCopy);
     65         }
     66 
     67         // Update fOffset to the new position. It is guaranteed to be
     68         // within the buffered data.
     69         fOffset += bytesToCopy;
     70         SkASSERT(fOffset <= fBufferedSoFar);
     71 
     72         if (bytesToCopy == size) {
     73             // The entire requested read was inside the already buffered
     74             // data.
     75             SkASSERT(fOffset <= fBufferedSoFar);
     76             return size;
     77         }
     78 
     79         // The requested read extends beyond the buffered data. Update
     80         // the remaining number of bytes needed to read, the number of
     81         // bytes read so far, and the destination buffer.
     82         size -= bytesToCopy;
     83         readSoFar += bytesToCopy;
     84         SkASSERT(size + readSoFar == totalSize);
     85         if (dst != NULL) {
     86             dst += bytesToCopy;
     87         }
     88     }
     89 
     90     // If we got here, we have read everything that was already buffered.
     91     SkASSERT(fOffset >= fBufferedSoFar);
     92 
     93     // Buffer any more data that should be buffered, and copy it to the
     94     // destination.
     95     if (fBufferedSoFar < fBufferSize) {
     96         // Data needs to be buffered. Buffer up to the lesser of the size requested
     97         // and the remainder of the max buffer size.
     98         const size_t bytesToBuffer = SkTMin(size, fBufferSize - fBufferedSoFar);
     99         char* buffer = this->getBufferAtOffset();
    100         const size_t buffered = fStream->read(buffer, bytesToBuffer);
    101         fBufferedSoFar += buffered;
    102         fOffset = fBufferedSoFar;
    103 
    104         // Copy the buffer to the destination buffer and update the amount read.
    105         if (dst != NULL) {
    106             memcpy(dst, buffer, buffered);
    107         }
    108         readSoFar += buffered;
    109 
    110         if (buffered == size || fStream->isAtEnd()) {
    111             // We were able to buffer all of the data requested (or all the data
    112             // remaining in the stream) and provide it to the caller.
    113             SkASSERT(fBufferedSoFar <= fBufferSize);
    114             SkASSERT(totalSize == readSoFar || fStream->isAtEnd());
    115             return readSoFar;
    116         }
    117 
    118         // The requested read extends beyond the length of the buffer. Update
    119         // the remaining number of bytes needed to read and the destination
    120         // buffer.
    121         size -= buffered;
    122         SkASSERT(size + readSoFar == totalSize);
    123         if (dst != NULL) {
    124             dst += buffered;
    125         }
    126     }
    127 
    128     // If we get here, we have buffered all that can be buffered.
    129     SkASSERT(fBufferSize == fBufferedSoFar && fOffset >= fBufferSize);
    130 
    131     // Read directly from the stream.
    132     const size_t bytesReadDirectly = fStream->read(dst, size);
    133     fOffset += bytesReadDirectly;
    134     if (bytesReadDirectly > 0) {
    135         sk_free(fBuffer.detach());
    136     }
    137     return bytesReadDirectly + readSoFar;
    138 }
    139