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