Home | History | Annotate | Download | only in codec
      1 /*
      2  * Copyright 2016 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 "SkStreamBuffer.h"
      9 
     10 SkStreamBuffer::SkStreamBuffer(std::unique_ptr<SkStream> stream)
     11     : fStream(std::move(stream))
     12     , fPosition(0)
     13     , fBytesBuffered(0)
     14     , fHasLengthAndPosition(fStream->hasLength() && fStream->hasPosition())
     15     , fTrulyBuffered(0)
     16 {}
     17 
     18 SkStreamBuffer::~SkStreamBuffer() {
     19     fMarkedData.foreach([](size_t, SkData** data) { (*data)->unref(); });
     20 }
     21 
     22 const char* SkStreamBuffer::get() const {
     23     SkASSERT(fBytesBuffered >= 1);
     24     if (fHasLengthAndPosition && fTrulyBuffered < fBytesBuffered) {
     25         const size_t bytesToBuffer = fBytesBuffered - fTrulyBuffered;
     26         char* dst = SkTAddOffset<char>(const_cast<char*>(fBuffer), fTrulyBuffered);
     27         SkDEBUGCODE(const size_t bytesRead =)
     28         // This stream is rewindable, so it should be safe to call the non-const
     29         // read()
     30         const_cast<SkStream*>(fStream.get())->read(dst, bytesToBuffer);
     31         SkASSERT(bytesRead == bytesToBuffer);
     32         fTrulyBuffered = fBytesBuffered;
     33     }
     34     return fBuffer;
     35 }
     36 
     37 bool SkStreamBuffer::buffer(size_t totalBytesToBuffer) {
     38     // FIXME (scroggo): What should we do if the client tries to read too much?
     39     // Should not be a problem in GIF.
     40     SkASSERT(totalBytesToBuffer <= kMaxSize);
     41 
     42     if (totalBytesToBuffer <= fBytesBuffered) {
     43         return true;
     44     }
     45 
     46     if (fHasLengthAndPosition) {
     47         const size_t remaining = fStream->getLength() - fStream->getPosition() + fTrulyBuffered;
     48         fBytesBuffered = SkTMin(remaining, totalBytesToBuffer);
     49     } else {
     50         const size_t extraBytes = totalBytesToBuffer - fBytesBuffered;
     51         const size_t bytesBuffered = fStream->read(fBuffer + fBytesBuffered, extraBytes);
     52         fBytesBuffered += bytesBuffered;
     53     }
     54     return fBytesBuffered == totalBytesToBuffer;
     55 }
     56 
     57 size_t SkStreamBuffer::markPosition() {
     58     SkASSERT(fBytesBuffered >= 1);
     59     if (!fHasLengthAndPosition) {
     60         sk_sp<SkData> data(SkData::MakeWithCopy(fBuffer, fBytesBuffered));
     61         SkASSERT(nullptr == fMarkedData.find(fPosition));
     62         fMarkedData.set(fPosition, data.release());
     63     }
     64     return fPosition;
     65 }
     66 
     67 sk_sp<SkData> SkStreamBuffer::getDataAtPosition(size_t position, size_t length) {
     68     if (!fHasLengthAndPosition) {
     69         SkData** data = fMarkedData.find(position);
     70         SkASSERT(data);
     71         SkASSERT((*data)->size() == length);
     72         return sk_ref_sp<SkData>(*data);
     73     }
     74 
     75     SkASSERT(length <= fStream->getLength() &&
     76              position <= fStream->getLength() - length);
     77 
     78     const size_t oldPosition = fStream->getPosition();
     79     if (!fStream->seek(position)) {
     80         return nullptr;
     81     }
     82 
     83     sk_sp<SkData> data(SkData::MakeUninitialized(length));
     84     void* dst = data->writable_data();
     85     const bool success = fStream->read(dst, length) == length;
     86     fStream->seek(oldPosition);
     87     return success ? data : nullptr;
     88 }
     89