1/*
2 * Copyright 2020 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 "experimental/skrive/src/reader/StreamReader.h"
9#include "include/core/SkStream.h"
10#include "include/core/SkString.h"
11
12#include <vector>
13
14namespace skrive::internal {
15
16namespace {
17
18class BinaryReader final : public StreamReader {
19public:
20    explicit BinaryReader(std::unique_ptr<SkStreamAsset> stream)
21        : fStream(std::move(stream)) {}
22
23private:
24    bool validateSize(size_t sz) const {
25        const auto next_pos  = fStream->getPosition() + sz,
26                   block_end = fBlockStack.empty() ? fStream->getLength()
27                                                   : fBlockStack.back().block_end;
28        return next_pos <= block_end;
29    }
30
31    uint16_t readId(const char label[]) override {
32        return this->readUInt16(label);
33    }
34
35    bool readBool(const char[]) override {
36        uint8_t v;
37
38        return validateSize(sizeof(v)) && fStream->readU8(&v)
39                ? v == 1
40                : false;
41    }
42
43    float readFloat(const char[]) override {
44        float v;
45
46        return validateSize(sizeof(v)) && fStream->readScalar(&v)
47                ? v
48                : 0.0f;
49    }
50
51    uint8_t readUInt8(const char[]) override {
52        uint8_t v;
53
54        return validateSize(sizeof(v)) && fStream->readU8(&v)
55                ? v
56                : 0;
57    }
58
59    uint16_t readUInt16(const char[]) override {
60        uint16_t v;
61
62        return validateSize(sizeof(v)) && fStream->readU16(&v)
63                ? v
64                : 0;
65    }
66
67    uint32_t readUInt32(const char[]) override {
68        uint32_t v;
69
70        return validateSize(sizeof(v)) && fStream->readU32(&v)
71                ? v
72                : 0;
73    }
74
75    SkString readString(const char[]) override {
76        uint32_t length;
77        if (!validateSize(sizeof(length)) || !fStream->readU32(&length)) {
78            return SkString();
79        }
80
81        SkString str(length);
82        return validateSize(length) && fStream->read(str.writable_str(), length) == length
83            ? str
84            : SkString();
85    }
86
87    size_t readFloatArray(const char[], float dst[], size_t count) override {
88        if (!validateSize(count * sizeof(float))) {
89            return 0;
90        }
91
92        return fStream->read(dst, count * sizeof(float)) / sizeof(float);
93    }
94
95    uint8_t readLength8() override {
96        return this->readUInt8(nullptr);
97    }
98
99    uint16_t readLength16() override {
100        return this->readUInt16(nullptr);
101    }
102
103    // nops
104    bool   openArray(const char[]) override { return true; }
105    void  closeArray()             override {}
106    bool  openObject(const char[]) override { return true; }
107    void closeObject()             override {}
108
109    BlockType openBlock() override {
110        uint8_t  block_type;
111        uint32_t block_size;
112
113        if (this->validateSize(sizeof(block_type) + sizeof(block_size)) &&
114            fStream->readU8 (&block_type) &&
115            fStream->readU32(&block_size)) {
116            const auto block_end = std::min(fStream->getPosition() + block_size,
117                                            fStream->getLength());
118            fBlockStack.push_back({block_end});
119            return static_cast<BlockType>(block_type);
120        }
121
122        return BlockType::kEoB;
123    }
124
125    void closeBlock() override {
126        SkASSERT(!fBlockStack.empty());
127        SkASSERT(fStream->getPosition() <= fBlockStack.back().block_end);
128
129        if (fStream->getPosition() < fBlockStack.back().block_end) {
130            const auto skip = fBlockStack.back().block_end - fStream->getPosition();
131            SkDebugf("!! skipping %zu bytes in block\n", skip);
132            fStream->skip(skip);
133        }
134
135        fBlockStack.pop_back();
136    }
137
138    const std::unique_ptr<SkStreamAsset> fStream;
139
140    struct BlockRec {
141        size_t block_end;
142    };
143
144    std::vector<BlockRec> fBlockStack;
145};
146
147} // namespace
148
149std::unique_ptr<StreamReader> MakeBinaryStreamReader(std::unique_ptr<SkStreamAsset> stream) {
150    return std::make_unique<BinaryReader>(std::move(stream));
151}
152
153}  // namespace skrive::internal
154