blob: 754065d97a89ef68ea5e3ab603b0b8124f0af441 [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
10SkStreamBuffer::SkStreamBuffer(SkStream* stream)
11 : fStream(stream)
Leon Scroggins III932efed2016-12-16 11:39:51 -050012 , fPosition(0)
scroggo19b91532016-10-24 09:03:26 -070013 , fBytesBuffered(0)
Leon Scroggins III932efed2016-12-16 11:39:51 -050014 , fHasLengthAndPosition(stream->hasLength() && stream->hasPosition())
15 , 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
75 SkASSERT(position + length <= fStream->getLength());
76
77 const size_t oldPosition = fStream->getPosition();
78 if (!fStream->seek(position)) {
79 return nullptr;
80 }
81
82 sk_sp<SkData> data(SkData::MakeUninitialized(length));
83 void* dst = data->writable_data();
84 const bool success = fStream->read(dst, length) == length;
85 fStream->seek(oldPosition);
86 return success ? data : nullptr;
scroggo19b91532016-10-24 09:03:26 -070087}