Parse chunk data on demand

This commit is contained in:
Matthias Schiffer 2015-02-01 04:14:42 +01:00
parent fc1fc8fbbc
commit 8a8a41a800
14 changed files with 74 additions and 98 deletions

View file

@ -40,34 +40,47 @@ private:
size_t len;
public:
static uint16_t parse16(const uint8_t *buf) {
return (buf[0] << 8) | buf[1];
}
static uint32_t parse32(const uint8_t *buf) {
return (uint32_t(buf[0]) << 24) | (uint32_t(buf[1]) << 16) | (uint32_t(buf[2]) << 8) | uint32_t(buf[3]);
}
static uint64_t parse64(const uint8_t *buf) {
return (uint64_t(buf[0]) << 56) | (uint64_t(buf[1]) << 48) | (uint64_t(buf[2]) << 40) | (uint64_t(buf[3]) << 32)
| (uint64_t(buf[4]) << 24) | (uint64_t(buf[5]) << 16) | (uint64_t(buf[6]) << 8) | uint64_t(buf[7]);
}
Buffer(const uint8_t *data0, size_t len0) : data(data0), len(len0) {}
uint8_t get() {
if (!len)
throw std::runtime_error("Buffer::get(): buffer underrun");
data++;
len--;
return data[-1];
}
std::string getString(size_t n) {
const uint8_t * get(size_t n) {
if (n > len)
throw std::runtime_error("Buffer::get(): buffer underrun");
data += n;
len -= n;
return std::string(reinterpret_cast<const char *>(data - n), n);
return (data - n);
}
void getData(void *buf, size_t n) {
if (n > len)
throw std::runtime_error("Buffer::get(): buffer underrun");
data += n;
len -= n;
std::memcpy(buf, data - n, n);
uint8_t get8() {
return *get(1);
}
uint16_t get16() {
return parse16(get(2));
}
uint32_t get32() {
return parse32(get(4));
}
uint64_t get64() {
return parse64(get(8));
}
};
}

View file

@ -38,22 +38,26 @@ class ByteArrayTag : public Tag {
private:
friend class Tag;
std::vector<uint8_t> value;
uint32_t len;
const uint8_t *value;
ByteArrayTag(Buffer *buffer) {
uint32_t len = uint32_t(buffer->get()) << 24;
len |= uint32_t(buffer->get()) << 16;
len |= uint32_t(buffer->get()) << 8;
len |= uint32_t(buffer->get());
value.resize(len);
buffer->getData(value.data(), len);
len = buffer->get32();
value = buffer->get(len);
}
public:
virtual Type getType() const {
return Type::ByteArray;
}
uint32_t getLength() const {
return len;
}
const uint8_t & operator[](size_t i) const {
return value[i];
}
};
}

View file

@ -39,7 +39,7 @@ private:
uint8_t value;
ByteTag(Buffer *buffer) {
value = buffer->get();
value = buffer->get8();
}
public:

View file

@ -36,17 +36,10 @@ class DoubleTag : public Tag {
private:
friend class Tag;
DoubleTag(Buffer *buffer) {
uint64_t value;
const uint8_t *ptr;
value = uint64_t(buffer->get()) << 56;
value |= uint64_t(buffer->get()) << 48;
value |= uint64_t(buffer->get()) << 40;
value |= uint64_t(buffer->get()) << 32;
value |= uint64_t(buffer->get()) << 24;
value |= uint64_t(buffer->get()) << 16;
value |= uint64_t(buffer->get()) << 8;
value |= uint64_t(buffer->get());
DoubleTag(Buffer *buffer) {
ptr = buffer->get(8);
}
public:

View file

@ -36,13 +36,10 @@ class FloatTag : public Tag {
private:
friend class Tag;
FloatTag(Buffer *buffer) {
uint32_t value;
const uint8_t *ptr;
value = uint32_t(buffer->get()) << 24;
value |= uint32_t(buffer->get()) << 16;
value |= uint32_t(buffer->get()) << 8;
value |= uint32_t(buffer->get());
FloatTag(Buffer *buffer) {
ptr = buffer->get(4);
}
public:

View file

@ -38,24 +38,12 @@ class IntArrayTag : public Tag {
private:
friend class Tag;
std::vector<uint32_t> value;
uint32_t len;
const uint8_t *ptr;
IntArrayTag(Buffer *buffer) {
uint32_t len = uint32_t(buffer->get()) << 24;
len |= uint32_t(buffer->get()) << 16;
len |= uint32_t(buffer->get()) << 8;
len |= uint32_t(buffer->get());
value.resize(len);
for (uint32_t i = 0; i < len; i++) {
uint32_t v = uint32_t(buffer->get()) << 24;
v |= uint32_t(buffer->get()) << 16;
v |= uint32_t(buffer->get()) << 8;
v |= uint32_t(buffer->get());
value[i] = v;
}
len = buffer->get32();
ptr = buffer->get(4*len);
}
public:

View file

@ -36,13 +36,10 @@ class IntTag : public Tag {
private:
friend class Tag;
uint32_t value;
const uint8_t *ptr;
IntTag(Buffer *buffer) {
value = uint32_t(buffer->get()) << 24;
value |= uint32_t(buffer->get()) << 16;
value |= uint32_t(buffer->get()) << 8;
value |= uint32_t(buffer->get());
ptr = buffer->get(4);
}
public:
@ -51,7 +48,7 @@ public:
}
uint32_t getValue() const {
return value;
return Buffer::parse32(ptr);
}
};

View file

@ -53,10 +53,7 @@ private:
Type type;
ListTag(Type type0, Buffer *buffer) : type(type0) {
uint32_t len = uint32_t(buffer->get()) << 24;
len |= uint32_t(buffer->get()) << 16;
len |= uint32_t(buffer->get()) << 8;
len |= uint32_t(buffer->get());
uint32_t len = buffer->get32();
this->resize(len);

View file

@ -36,17 +36,10 @@ class LongTag : public Tag {
private:
friend class Tag;
uint64_t value;
const uint8_t *ptr;
LongTag(Buffer *buffer) {
value = uint64_t(buffer->get()) << 56;
value |= uint64_t(buffer->get()) << 48;
value |= uint64_t(buffer->get()) << 40;
value |= uint64_t(buffer->get()) << 32;
value |= uint64_t(buffer->get()) << 24;
value |= uint64_t(buffer->get()) << 16;
value |= uint64_t(buffer->get()) << 8;
value |= uint64_t(buffer->get());
ptr = buffer->get(8);
}
public:
@ -55,7 +48,7 @@ public:
}
uint64_t getValue() const {
return value;
return Buffer::parse64(ptr);
}
};

View file

@ -36,11 +36,10 @@ class ShortTag : public Tag {
private:
friend class Tag;
uint16_t value;
const uint8_t *ptr;
ShortTag(Buffer *buffer) {
value = buffer->get() << 8;
value |= buffer->get();
ptr = buffer->get(2);
}
public:
@ -49,7 +48,7 @@ public:
}
uint16_t getValue() const {
return value;
return Buffer::parse16(ptr);
}
};

View file

@ -36,23 +36,18 @@ class StringTag : public Tag {
private:
friend class Tag;
std::string value;
uint16_t len;
const uint8_t *ptr;
StringTag(Buffer *buffer) {
uint16_t len = buffer->get() << 8;
len |= buffer->get();
value = buffer->getString(len);
len = buffer->get16();
ptr = buffer->get(len);
}
public:
virtual Type getType() const {
return Type::String;
}
const std::string & getValue() const {
return value;
}
};
}

View file

@ -90,7 +90,7 @@ std::shared_ptr<const Tag> Tag::readTag(Type type, Buffer *buffer) {
}
std::shared_ptr<const Tag> Tag::readList(Buffer *buffer) {
Type type = static_cast<Type>(buffer->get());
Type type = static_cast<Type>(buffer->get8());
switch (type) {
case Type::End:
@ -135,13 +135,12 @@ std::shared_ptr<const Tag> Tag::readList(Buffer *buffer) {
}
std::pair<std::string, std::shared_ptr<const Tag>> Tag::readNamedTag(Buffer *buffer) {
Type type = static_cast<Type>(buffer->get());
Type type = static_cast<Type>(buffer->get8());
if (type == Type::End)
return std::make_pair("", std::shared_ptr<EndTag>(new EndTag()));
uint16_t len = buffer->get() << 8;
len |= buffer->get();
std::string name = buffer->getString(len);
uint16_t len = buffer->get16();
std::string name(reinterpret_cast<const char*>(buffer->get(len)), len);
return std::make_pair(name, readTag(type, buffer));
}

View file

@ -82,7 +82,6 @@ Chunk::Chunk(uint8_t *buffer, size_t buflen) {
if (format != 2)
throw std::invalid_argument("unknown chunk format");
UniqueCPtr<uint8_t[]> data;
size_t len;
std::tie(data, len) = inflateChunk(buffer+5, size-1);

View file

@ -43,6 +43,8 @@ public:
static const size_t SIZE = 16;
private:
UniqueCPtr<uint8_t[]> data;
static std::pair<UniqueCPtr<uint8_t[]>, size_t> inflateChunk(uint8_t *data, size_t len);
std::shared_ptr<const NBT::ListTag<NBT::CompoundTag>> sections;