blob: e8a6e90a043b0efd043fe82a837f5b30e7b39e64 [file] [log] [blame]
scroggo19b91532016-10-24 09:03:26 -07001/*
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
Mike Reedede7bac2017-07-23 15:30:02 -040010SkStreamBuffer::SkStreamBuffer(std::unique_ptr<SkStream> stream)
11 : fStream(std::move(stream))
Leon Scroggins III932efed2016-12-16 11:39:51 -050012 , fPosition(0)
scroggo19b91532016-10-24 09:03:26 -070013 , fBytesBuffered(0)
Mike Reedede7bac2017-07-23 15:30:02 -040014 , fHasLengthAndPosition(fStream->hasLength() && fStream->hasPosition())
Leon Scroggins III932efed2016-12-16 11:39:51 -050015 , fTrulyBuffered(0)
scroggo19b91532016-10-24 09:03:26 -070016{}
17
Leon Scroggins III932efed2016-12-16 11:39:51 -050018SkStreamBuffer::~SkStreamBuffer() {
19 fMarkedData.foreach([](size_t, SkData** data) { (*data)->unref(); });
20}
21
22const 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
37bool SkStreamBuffer::buffer(size_t totalBytesToBuffer) {
scroggo19b91532016-10-24 09:03:26 -070038 // FIXME (scroggo): What should we do if the client tries to read too much?
39 // Should not be a problem in GIF.
Leon Scroggins III932efed2016-12-16 11:39:51 -050040 SkASSERT(totalBytesToBuffer <= kMaxSize);
scroggo19b91532016-10-24 09:03:26 -070041
Leon Scroggins III932efed2016-12-16 11:39:51 -050042 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
57size_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
67sk_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
Ben Wagner701167c2018-10-22 11:42:28 -040075 SkASSERT(length <= fStream->getLength() &&
76 position <= fStream->getLength() - length);
Leon Scroggins III932efed2016-12-16 11:39:51 -050077
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;
scroggo19b91532016-10-24 09:03:26 -070088}