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