[skrive] Initial binary reader plumbing
TBR= Change-Id: Ib94516bfba881fd3fdd7b09631f14366f6ac98da Reviewed-on: https://skia-review.googlesource.com/c/skia/+/295573 Commit-Queue: Florin Malita <fmalita@chromium.org> Commit-Queue: Florin Malita <fmalita@google.com> Reviewed-by: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
739e1caf35
commit
1da2556a09
@ -30,7 +30,10 @@ if (skia_enable_skrive) {
|
||||
"../..:skia_private",
|
||||
"../..:tests_config",
|
||||
]
|
||||
sources = [ "tests/JsonReader.cpp" ]
|
||||
sources = [
|
||||
"tests/BinaryReader.cpp",
|
||||
"tests/JsonReader.cpp",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":skrive",
|
||||
|
@ -17,7 +17,10 @@ namespace internal {
|
||||
extern sk_sp<Artboard> parse_artboard(StreamReader*);
|
||||
|
||||
void parse_artboards(const sk_sp<SkRive>& skrive, StreamReader* sr) {
|
||||
for (;;) {
|
||||
const size_t artboard_count = sr->readLength16();
|
||||
skrive->artboards().reserve(artboard_count);
|
||||
|
||||
for (size_t i = 0; i < artboard_count; ++i) {
|
||||
StreamReader::AutoBlock block(sr);
|
||||
if (block.type() == StreamReader::BlockType::kEoB) {
|
||||
break;
|
||||
@ -36,6 +39,9 @@ static sk_sp<SkRive> parse_skrive(std::unique_ptr<StreamReader> sr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto version = sr->readUInt32("version");
|
||||
SkDebugf(".. loading version %d\n", version);
|
||||
|
||||
auto skrive = sk_make_sp<SkRive>();
|
||||
|
||||
for (;;) {
|
||||
@ -60,7 +66,10 @@ static sk_sp<SkRive> parse_skrive(std::unique_ptr<StreamReader> sr) {
|
||||
} // namespace internal
|
||||
|
||||
sk_sp<SkRive> SkRive::Builder::make(std::unique_ptr<SkStreamAsset> stream) {
|
||||
return parse_skrive(internal::StreamReader::Make(std::move(stream)));
|
||||
auto reader = internal::StreamReader::Make(std::move(stream));
|
||||
|
||||
return reader ? parse_skrive(std::move(reader))
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
} // namespace skrive
|
||||
|
@ -7,12 +7,125 @@
|
||||
|
||||
#include "experimental/skrive/src/reader/StreamReader.h"
|
||||
#include "include/core/SkStream.h"
|
||||
#include "include/core/SkString.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace skrive::internal {
|
||||
|
||||
std::unique_ptr<StreamReader> MakeBinaryStreamReader(std::unique_ptr<SkStreamAsset>) {
|
||||
// TODO
|
||||
return nullptr;
|
||||
namespace {
|
||||
|
||||
class BinaryReader final : public StreamReader {
|
||||
public:
|
||||
explicit BinaryReader(std::unique_ptr<SkStreamAsset> stream)
|
||||
: fStream(std::move(stream)) {}
|
||||
|
||||
private:
|
||||
bool validateSize(size_t sz) const {
|
||||
const auto next_pos = fStream->getPosition() + sz,
|
||||
block_end = fBlockStack.empty() ? fStream->getLength()
|
||||
: fBlockStack.back().block_end;
|
||||
return next_pos <= block_end;
|
||||
}
|
||||
|
||||
bool readBool(const char[]) override {
|
||||
uint8_t v;
|
||||
|
||||
return validateSize(sizeof(v)) && fStream->readU8(&v)
|
||||
? v == 1
|
||||
: false;
|
||||
}
|
||||
|
||||
float readFloat(const char[]) override {
|
||||
float v;
|
||||
|
||||
return validateSize(sizeof(v)) && fStream->readScalar(&v)
|
||||
? v
|
||||
: 0.0f;
|
||||
}
|
||||
|
||||
uint16_t readUInt16(const char[]) override {
|
||||
uint16_t v;
|
||||
|
||||
return validateSize(sizeof(v)) && fStream->readU16(&v)
|
||||
? v
|
||||
: 0;
|
||||
}
|
||||
|
||||
uint32_t readUInt32(const char[]) override {
|
||||
uint32_t v;
|
||||
|
||||
return validateSize(sizeof(v)) && fStream->readU32(&v)
|
||||
? v
|
||||
: 0;
|
||||
}
|
||||
|
||||
SkString readString(const char[]) override {
|
||||
uint32_t length;
|
||||
if (!validateSize(sizeof(length)) || !fStream->readU32(&length)) {
|
||||
return SkString();
|
||||
}
|
||||
|
||||
SkString str(length);
|
||||
return validateSize(length) && fStream->read(str.writable_str(), length) == length
|
||||
? str
|
||||
: SkString();
|
||||
}
|
||||
|
||||
size_t readFloatArray(const char[], float dst[], size_t count) override {
|
||||
if (!validateSize(count * sizeof(float))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fStream->read(dst, count * sizeof(float)) / sizeof(float);
|
||||
}
|
||||
|
||||
uint16_t readLength16() override {
|
||||
return this->readUInt16(nullptr);
|
||||
}
|
||||
|
||||
BlockType openBlock() override {
|
||||
uint8_t block_type;
|
||||
uint32_t block_size;
|
||||
|
||||
if (this->validateSize(sizeof(block_type) + sizeof(block_size)) &&
|
||||
fStream->readU8 (&block_type) &&
|
||||
fStream->readU32(&block_size)) {
|
||||
const auto block_end = std::min(fStream->getPosition() + block_size,
|
||||
fStream->getLength());
|
||||
fBlockStack.push_back({block_end});
|
||||
return static_cast<BlockType>(block_type);
|
||||
}
|
||||
|
||||
return BlockType::kEoB;
|
||||
}
|
||||
|
||||
void closeBlock() override {
|
||||
SkASSERT(!fBlockStack.empty());
|
||||
SkASSERT(fStream->getPosition() <= fBlockStack.back().block_end);
|
||||
|
||||
if (fStream->getPosition() < fBlockStack.back().block_end) {
|
||||
const auto skip = fBlockStack.back().block_end - fStream->getPosition();
|
||||
SkDebugf("!! skipping %zu bytes in block\n", skip);
|
||||
fStream->skip(skip);
|
||||
}
|
||||
|
||||
fBlockStack.pop_back();
|
||||
}
|
||||
|
||||
const std::unique_ptr<SkStreamAsset> fStream;
|
||||
|
||||
struct BlockRec {
|
||||
size_t block_end;
|
||||
};
|
||||
|
||||
std::vector<BlockRec> fBlockStack;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<StreamReader> MakeBinaryStreamReader(std::unique_ptr<SkStreamAsset> stream) {
|
||||
return std::make_unique<BinaryReader>(std::move(stream));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -73,6 +73,16 @@ private:
|
||||
return jnum ? static_cast<float>(**jnum) : 0.0f;
|
||||
}
|
||||
|
||||
uint16_t readUInt16(const char label[]) override {
|
||||
return static_cast<uint16_t>(this->readUInt32(label));
|
||||
}
|
||||
|
||||
uint32_t readUInt32(const char label[]) override {
|
||||
const auto* jnum = this->readProp<skjson::NumberValue>(label);
|
||||
|
||||
return jnum ? static_cast<uint32_t>(**jnum) : 0;
|
||||
}
|
||||
|
||||
SkString readString(const char label[]) override {
|
||||
const auto* jstr = this->readProp<skjson::StringValue>(label);
|
||||
|
||||
@ -96,6 +106,17 @@ private:
|
||||
return count;
|
||||
}
|
||||
|
||||
uint16_t readLength16() override {
|
||||
return SkToU16(this->currentLength());
|
||||
}
|
||||
|
||||
size_t currentLength() const {
|
||||
const auto& ctx = fContextStack.back();
|
||||
return ctx.fContainer->is<skjson::ObjectValue>()
|
||||
? ctx.fContainer->as<skjson::ObjectValue>().size()
|
||||
: ctx.fContainer->as<skjson:: ArrayValue>().size();
|
||||
}
|
||||
|
||||
// "Blocks" map to either objects or arrays. For object containers, the block type is encoded
|
||||
// as the key; for array containers, the type is an explicit "type" property *inside* the block
|
||||
// entry - which must be an object in this case.
|
||||
|
@ -13,33 +13,44 @@
|
||||
|
||||
namespace skrive::internal {
|
||||
|
||||
static constexpr char kBinaryPrefix[] = "FLARE";
|
||||
static constexpr char kBinaryPrefix[] = "FLARE";
|
||||
static constexpr size_t kBinaryPrefixSize = sizeof(kBinaryPrefix) - 1;
|
||||
|
||||
extern std::unique_ptr<StreamReader> MakeJsonStreamReader(const char[], size_t);
|
||||
extern std::unique_ptr<StreamReader> MakeBinaryStreamReader(std::unique_ptr<SkStreamAsset>);
|
||||
|
||||
std::unique_ptr<StreamReader> StreamReader::Make(const char data[], size_t len) {
|
||||
if (len >= sizeof(kBinaryPrefix) &&
|
||||
strncmp(data, kBinaryPrefix, strlen(kBinaryPrefix)) == 0) {
|
||||
return MakeBinaryStreamReader(SkMemoryStream::MakeDirect(data, len));
|
||||
std::unique_ptr<StreamReader> StreamReader::Make(const sk_sp<SkData>& data) {
|
||||
if (data->size() >= kBinaryPrefixSize &&
|
||||
!memcmp(data->data(), kBinaryPrefix, kBinaryPrefixSize)) {
|
||||
auto reader = SkMemoryStream::Make(data);
|
||||
reader->skip(kBinaryPrefixSize);
|
||||
|
||||
return MakeBinaryStreamReader(std::move(reader));
|
||||
}
|
||||
|
||||
return MakeJsonStreamReader(data, len);
|
||||
return MakeJsonStreamReader(static_cast<const char*>(data->data()), data->size());
|
||||
}
|
||||
|
||||
std::unique_ptr<StreamReader> StreamReader::Make(std::unique_ptr<SkStreamAsset> stream) {
|
||||
constexpr auto peek_size = sizeof(kBinaryPrefix) - 1;
|
||||
char buf[peek_size];
|
||||
char buf[kBinaryPrefixSize];
|
||||
|
||||
if (stream->peek(buf, peek_size) == peek_size && strncmp(buf, kBinaryPrefix, peek_size) == 0) {
|
||||
// we can stay in streaming mode
|
||||
return MakeBinaryStreamReader(std::move(stream));
|
||||
if (stream->read(buf, kBinaryPrefixSize) == kBinaryPrefixSize) {
|
||||
if (!strncmp(buf, kBinaryPrefix, kBinaryPrefixSize)) {
|
||||
// binary stream - we can stay in streaming mode
|
||||
return MakeBinaryStreamReader(std::move(stream));
|
||||
}
|
||||
} else {
|
||||
// stream too short to hold anything useful
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!stream->rewind()) {
|
||||
SkDebugf("!! failed to rewind stream.\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// read to memory to figure what we're dealing with
|
||||
const auto data = SkData::MakeFromStream(stream.get(), stream->getLength());
|
||||
|
||||
return StreamReader::Make(static_cast<const char*>(data->data()), data->size());
|
||||
return StreamReader::Make(SkData::MakeFromStream(stream.get(), stream->getLength()));
|
||||
}
|
||||
|
||||
SkV2 StreamReader::readV2(const char label[]) {
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
virtual ~StreamReader() = default;
|
||||
|
||||
static std::unique_ptr<StreamReader> Make(std::unique_ptr<SkStreamAsset>);
|
||||
static std::unique_ptr<StreamReader> Make(const char[], size_t);
|
||||
static std::unique_ptr<StreamReader> Make(const sk_sp<SkData>&);
|
||||
|
||||
enum class BlockType : uint8_t {
|
||||
kUnknown = 0,
|
||||
@ -43,8 +43,12 @@ public:
|
||||
|
||||
virtual bool readBool (const char label[]) = 0;
|
||||
virtual float readFloat (const char label[]) = 0;
|
||||
virtual uint16_t readUInt16(const char label[]) = 0;
|
||||
virtual uint32_t readUInt32(const char label[]) = 0;
|
||||
virtual SkString readString(const char label[]) = 0;
|
||||
|
||||
virtual uint16_t readLength16() = 0;
|
||||
|
||||
SkColor4f readColor(const char label[]);
|
||||
SkV2 readV2(const char label[]);
|
||||
|
||||
|
73
experimental/skrive/tests/BinaryReader.cpp
Normal file
73
experimental/skrive/tests/BinaryReader.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2020 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "experimental/skrive/src/reader/StreamReader.h"
|
||||
#include "tests/Test.h"
|
||||
|
||||
using namespace skrive::internal;
|
||||
|
||||
DEF_TEST(SkRive_BinaryReader, reporter) {
|
||||
static constexpr uint8_t bin[] = {
|
||||
0x46, 0x4c, 0x41, 0x52, 0x45, // 'FLARE'
|
||||
0x12, 0x00, 0x00, 0x00, // version: 18
|
||||
0x73, // block type: kArtboards (115)
|
||||
0x38, 0x00, 0x00, 0x00, // block size: 56
|
||||
0x01, 0x00, // container count: 1
|
||||
0x72, // block type: kActorArtboard (114)
|
||||
0x31, 0x00, 0x00, 0x00, // block size: 49
|
||||
0x04, 0x00, 0x00, 0x00, // name len: 4
|
||||
0x46, 0x6f, 0x6f, 0x6f, // name: 'Fooo'
|
||||
// translation:
|
||||
0x00, 0x00, 0x00, 0x00, // 0
|
||||
0x00, 0x00, 0x00, 0x00, // 0
|
||||
0x00, 0xc0, 0x57, 0x44, // width: 863.0
|
||||
0x00, 0xc0, 0x60, 0x44, // height: 899.0
|
||||
// origin:
|
||||
0x00, 0x00, 0x00, 0x00, // 0
|
||||
0x00, 0x00, 0x00, 0x00, // 0
|
||||
0x01, // clipContents: true
|
||||
// color:
|
||||
0x00, 0x00, 0x00, 0x3f, // 0.5
|
||||
0x00, 0x00, 0x00, 0x3f, // 0.5
|
||||
0x00, 0x00, 0x00, 0x3f, // 0.5
|
||||
0x00, 0x00, 0x80, 0x3f, // 1.0
|
||||
};
|
||||
|
||||
auto sr = StreamReader::Make(SkData::MakeWithoutCopy(bin, sizeof(bin)));
|
||||
|
||||
REPORTER_ASSERT(reporter, sr);
|
||||
REPORTER_ASSERT(reporter, sr->readUInt32("version") == 18);
|
||||
{
|
||||
StreamReader::AutoBlock ab(sr);
|
||||
REPORTER_ASSERT(reporter, ab.type() == StreamReader::BlockType::kArtboards);
|
||||
REPORTER_ASSERT(reporter, sr->readLength16() == 1);
|
||||
|
||||
{
|
||||
StreamReader::AutoBlock ab(sr);
|
||||
REPORTER_ASSERT(reporter, ab.type() == StreamReader::BlockType::kActorArtboard);
|
||||
REPORTER_ASSERT(reporter, sr->readString("name").equals("Fooo"));
|
||||
REPORTER_ASSERT(reporter, sr->readV2("translation") == (SkV2{0,0}));
|
||||
REPORTER_ASSERT(reporter, sr->readFloat("width" ) == 863);
|
||||
REPORTER_ASSERT(reporter, sr->readFloat("height") == 899);
|
||||
REPORTER_ASSERT(reporter, sr->readV2("origin") == (SkV2{0,0}));
|
||||
REPORTER_ASSERT(reporter, sr->readBool("clipContents"));
|
||||
REPORTER_ASSERT(reporter, sr->readColor("color") == (SkColor4f{0.5f,0.5f,0.5f,1}));
|
||||
|
||||
REPORTER_ASSERT(reporter, sr->readString("INVALID").equals(""));
|
||||
REPORTER_ASSERT(reporter, sr->readFloat("INVALID" ) == 0);
|
||||
REPORTER_ASSERT(reporter, !sr->readBool("INVALID"));
|
||||
}
|
||||
{
|
||||
StreamReader::AutoBlock ab(sr);
|
||||
REPORTER_ASSERT(reporter, ab.type() == StreamReader::BlockType::kEoB);
|
||||
}
|
||||
}
|
||||
{
|
||||
StreamReader::AutoBlock ab(sr);
|
||||
REPORTER_ASSERT(reporter, ab.type() == StreamReader::BlockType::kEoB);
|
||||
}
|
||||
}
|
@ -27,12 +27,14 @@ DEF_TEST(SkRive_JsonReader, reporter) {
|
||||
]
|
||||
})";
|
||||
|
||||
auto sr = StreamReader::Make(json, strlen(json));
|
||||
auto sr = StreamReader::Make(SkData::MakeWithoutCopy(json, strlen(json)));
|
||||
|
||||
REPORTER_ASSERT(reporter, sr);
|
||||
REPORTER_ASSERT(reporter, sr->readUInt32("version") == 24);
|
||||
{
|
||||
StreamReader::AutoBlock ab(sr);
|
||||
REPORTER_ASSERT(reporter, ab.type() == StreamReader::BlockType::kArtboards);
|
||||
REPORTER_ASSERT(reporter, sr->readLength16() == 1);
|
||||
|
||||
{
|
||||
StreamReader::AutoBlock ab(sr);
|
||||
|
Loading…
Reference in New Issue
Block a user