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