From dccce22bc54a4e2a4adb67bf2a52c813b3f0109f Mon Sep 17 00:00:00 2001 From: Ben VandenBos Date: Fri, 9 Feb 2018 12:06:09 -0800 Subject: [PATCH] (js) Throw an error is we encounter an unknown enum value while decoding --- .gitignore | 2 + kiwi.js | 12 ++- test/test-schema-callback.h | 128 ++++++++++++++++++++++ test/test-schema.h | 175 ++++++++++++++++++++++++++++++ test/test-schema.js | 184 +++++++++++++++++++++++++++----- test/test-schema.kiwi | 4 +- test/test-schema.sk | 206 ++++++++++++++++++++++++++++++++++++ test/test-schema.ts | 18 ++++ test/test.js | 35 ++++++ 9 files changed, 732 insertions(+), 32 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..76efb07 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.vscode diff --git a/kiwi.js b/kiwi.js index 00d6536..bdf7efd 100644 --- a/kiwi.js +++ b/kiwi.js @@ -689,7 +689,13 @@ var kiwi = exports || kiwi || {}, exports; if (!type) { error('Invalid type ' + quote(field.type) + ' for field ' + quote(field.name), field.line, field.column); } else if (type.kind === 'ENUM') { - code = 'this[' + quote(type.name) + '][bb.readVarUint()]'; + code = [ + '(function (t) {', + ' var byte = bb.readVarUint();', + ' if (undefined == t[' + quote(type.name) + '][byte]) { throw new Error("Attempted to parse invalid enum"); }', + ' return t[' + quote(type.name) + '][byte];', + '})(this)', + ].join('\n'); } else { code = 'this[' + quote('decode' + type.name) + '](bb)'; } @@ -703,11 +709,11 @@ var kiwi = exports || kiwi || {}, exports; if (field.isArray) { if (field.isDeprecated) { lines.push(indent + 'var length = bb.readVarUint();'); - lines.push(indent + 'while (length-- > 0) ' + code + ';'); + lines.push(indent + 'while (length-- > 0) { ' + code + ' };'); } else { lines.push(indent + 'var values = result[' + quote(field.name) + '] = [];'); lines.push(indent + 'var length = bb.readVarUint();'); - lines.push(indent + 'while (length-- > 0) values.push(' + code + ');'); + lines.push(indent + 'while (length-- > 0) { values.push(' + code + '); }'); } } diff --git a/test/test-schema-callback.h b/test/test-schema-callback.h index 113b63d..be518c1 100644 --- a/test/test-schema-callback.h +++ b/test/test-schema-callback.h @@ -25,6 +25,9 @@ class Visitor { virtual void visitStringStruct(const char *x) = 0; virtual void visitCompoundStruct(uint32_t x, uint32_t y) = 0; virtual void visitNestedStruct(uint32_t a, uint32_t b_x, uint32_t b_y, uint32_t c) = 0; + virtual void beginEnumMessage() = 0; + virtual void visitEnumMessage_x(Enum x) = 0; + virtual void endEnumMessage() = 0; virtual void beginBoolMessage() = 0; virtual void visitBoolMessage_x(bool x) = 0; virtual void endBoolMessage() = 0; @@ -52,6 +55,10 @@ class Visitor { virtual void visitNestedMessage_b() = 0; virtual void visitNestedMessage_c(uint32_t c) = 0; virtual void endNestedMessage() = 0; + virtual void beginEnumArrayStruct() = 0; + virtual void visitEnumArrayStruct_x_count(uint32_t size) = 0; + virtual void visitEnumArrayStruct_x_element(Enum x) = 0; + virtual void endEnumArrayStruct() = 0; virtual void beginBoolArrayStruct() = 0; virtual void visitBoolArrayStruct_x_count(uint32_t size) = 0; virtual void visitBoolArrayStruct_x_element(bool x) = 0; @@ -82,6 +89,10 @@ class Visitor { virtual void visitCompoundArrayStruct_y_count(uint32_t size) = 0; virtual void visitCompoundArrayStruct_y_element(uint32_t y) = 0; virtual void endCompoundArrayStruct() = 0; + virtual void beginEnumArrayMessage() = 0; + virtual void visitEnumArrayMessage_x_count(uint32_t size) = 0; + virtual void visitEnumArrayMessage_x_element(Enum x) = 0; + virtual void endEnumArrayMessage() = 0; virtual void beginBoolArrayMessage() = 0; virtual void visitBoolArrayMessage_x_count(uint32_t size) = 0; virtual void visitBoolArrayMessage_x_element(bool x) = 0; @@ -179,6 +190,9 @@ class Writer : public Visitor { virtual void visitStringStruct(const char *x) override; virtual void visitCompoundStruct(uint32_t x, uint32_t y) override; virtual void visitNestedStruct(uint32_t a, uint32_t b_x, uint32_t b_y, uint32_t c) override; + virtual void beginEnumMessage() override; + virtual void visitEnumMessage_x(Enum x) override; + virtual void endEnumMessage() override; virtual void beginBoolMessage() override; virtual void visitBoolMessage_x(bool x) override; virtual void endBoolMessage() override; @@ -206,6 +220,10 @@ class Writer : public Visitor { virtual void visitNestedMessage_b() override; virtual void visitNestedMessage_c(uint32_t c) override; virtual void endNestedMessage() override; + virtual void beginEnumArrayStruct() override; + virtual void visitEnumArrayStruct_x_count(uint32_t size) override; + virtual void visitEnumArrayStruct_x_element(Enum x) override; + virtual void endEnumArrayStruct() override; virtual void beginBoolArrayStruct() override; virtual void visitBoolArrayStruct_x_count(uint32_t size) override; virtual void visitBoolArrayStruct_x_element(bool x) override; @@ -236,6 +254,10 @@ class Writer : public Visitor { virtual void visitCompoundArrayStruct_y_count(uint32_t size) override; virtual void visitCompoundArrayStruct_y_element(uint32_t y) override; virtual void endCompoundArrayStruct() override; + virtual void beginEnumArrayMessage() override; + virtual void visitEnumArrayMessage_x_count(uint32_t size) override; + virtual void visitEnumArrayMessage_x_element(Enum x) override; + virtual void endEnumArrayMessage() override; virtual void beginBoolArrayMessage() override; virtual void visitBoolArrayMessage_x_count(uint32_t size) override; virtual void visitBoolArrayMessage_x_element(bool x) override; @@ -324,6 +346,7 @@ bool parseFloatStruct(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseStringStruct(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseCompoundStruct(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseNestedStruct(kiwi::ByteBuffer &bb, Visitor &visitor); +bool parseEnumMessage(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseBoolMessage(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseByteMessage(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseIntMessage(kiwi::ByteBuffer &bb, Visitor &visitor); @@ -332,6 +355,7 @@ bool parseFloatMessage(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseStringMessage(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseCompoundMessage(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseNestedMessage(kiwi::ByteBuffer &bb, Visitor &visitor); +bool parseEnumArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseBoolArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseByteArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseIntArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor); @@ -339,6 +363,7 @@ bool parseUintArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseFloatArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseStringArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseCompoundArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor); +bool parseEnumArrayMessage(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseBoolArrayMessage(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseByteArrayMessage(kiwi::ByteBuffer &bb, Visitor &visitor); bool parseIntArrayMessage(kiwi::ByteBuffer &bb, Visitor &visitor); @@ -430,6 +455,27 @@ bool parseNestedStruct(kiwi::ByteBuffer &bb, Visitor &visitor) { return true; } +bool parseEnumMessage(kiwi::ByteBuffer &bb, Visitor &visitor) { + visitor.beginEnumMessage(); + while (true) { + uint32_t _type; + if (!bb.readVarUint(_type)) return false; + switch (_type) { + case 0: { + visitor.endEnumMessage(); + return true; + } + case 1: { + Enum x; + if (!bb.readVarUint(reinterpret_cast(x))) return false; + visitor.visitEnumMessage_x(x); + break; + } + default: return false; + } + } +} + bool parseBoolMessage(kiwi::ByteBuffer &bb, Visitor &visitor) { visitor.beginBoolMessage(); while (true) { @@ -615,6 +661,20 @@ bool parseNestedMessage(kiwi::ByteBuffer &bb, Visitor &visitor) { } } +bool parseEnumArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor) { + visitor.beginEnumArrayStruct(); + uint32_t _x_count; + if (!bb.readVarUint(_x_count)) return false; + visitor.visitEnumArrayStruct_x_count(_x_count); + while (_x_count-- > 0) { + Enum x; + if (!bb.readVarUint(reinterpret_cast(x))) return false; + visitor.visitEnumArrayStruct_x_element(x); + } + visitor.endEnumArrayStruct(); + return true; +} + bool parseBoolArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor) { visitor.beginBoolArrayStruct(); uint32_t _x_count; @@ -721,6 +781,32 @@ bool parseCompoundArrayStruct(kiwi::ByteBuffer &bb, Visitor &visitor) { return true; } +bool parseEnumArrayMessage(kiwi::ByteBuffer &bb, Visitor &visitor) { + visitor.beginEnumArrayMessage(); + while (true) { + uint32_t _type; + if (!bb.readVarUint(_type)) return false; + switch (_type) { + case 0: { + visitor.endEnumArrayMessage(); + return true; + } + case 1: { + uint32_t _x_count; + if (!bb.readVarUint(_x_count)) return false; + visitor.visitEnumArrayMessage_x_count(_x_count); + while (_x_count-- > 0) { + Enum x; + if (!bb.readVarUint(reinterpret_cast(x))) return false; + visitor.visitEnumArrayMessage_x_element(x); + } + break; + } + default: return false; + } + } +} + bool parseBoolArrayMessage(kiwi::ByteBuffer &bb, Visitor &visitor) { visitor.beginBoolArrayMessage(); while (true) { @@ -1208,6 +1294,18 @@ void Writer::visitNestedStruct(uint32_t a, uint32_t b_x, uint32_t b_y, uint32_t _bb.writeVarUint(c); } +void Writer::beginEnumMessage() { +} + +void Writer::visitEnumMessage_x(Enum x) { + _bb.writeVarUint(1); + _bb.writeVarUint(static_cast(x)); +} + +void Writer::endEnumMessage() { + _bb.writeVarUint(0); +} + void Writer::beginBoolMessage() { } @@ -1318,6 +1416,20 @@ void Writer::endNestedMessage() { _bb.writeVarUint(0); } +void Writer::beginEnumArrayStruct() { +} + +void Writer::visitEnumArrayStruct_x_count(uint32_t size) { + _bb.writeVarUint(size); +} + +void Writer::visitEnumArrayStruct_x_element(Enum x) { + _bb.writeVarUint(static_cast(x)); +} + +void Writer::endEnumArrayStruct() { +} + void Writer::beginBoolArrayStruct() { } @@ -1424,6 +1536,22 @@ void Writer::visitCompoundArrayStruct_y_element(uint32_t y) { void Writer::endCompoundArrayStruct() { } +void Writer::beginEnumArrayMessage() { +} + +void Writer::visitEnumArrayMessage_x_count(uint32_t size) { + _bb.writeVarUint(1); + _bb.writeVarUint(size); +} + +void Writer::visitEnumArrayMessage_x_element(Enum x) { + _bb.writeVarUint(static_cast(x)); +} + +void Writer::endEnumArrayMessage() { + _bb.writeVarUint(0); +} + void Writer::beginBoolArrayMessage() { } diff --git a/test/test-schema.h b/test/test-schema.h index 96c0169..e7d284d 100644 --- a/test/test-schema.h +++ b/test/test-schema.h @@ -8,6 +8,7 @@ namespace test { class BinarySchema { public: bool parse(kiwi::ByteBuffer &bb); + bool skipEnumMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; bool skipBoolMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; bool skipByteMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; bool skipIntMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; @@ -16,6 +17,7 @@ class BinarySchema { bool skipStringMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; bool skipCompoundMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; bool skipNestedMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; + bool skipEnumArrayMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; bool skipBoolArrayMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; bool skipByteArrayMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; bool skipIntArrayMessageField(kiwi::ByteBuffer &bb, uint32_t id) const; @@ -29,6 +31,7 @@ class BinarySchema { private: kiwi::BinarySchema _schema; + uint32_t _indexEnumMessage = 0; uint32_t _indexBoolMessage = 0; uint32_t _indexByteMessage = 0; uint32_t _indexIntMessage = 0; @@ -37,6 +40,7 @@ class BinarySchema { uint32_t _indexStringMessage = 0; uint32_t _indexCompoundMessage = 0; uint32_t _indexNestedMessage = 0; + uint32_t _indexEnumArrayMessage = 0; uint32_t _indexBoolArrayMessage = 0; uint32_t _indexByteArrayMessage = 0; uint32_t _indexIntArrayMessage = 0; @@ -63,6 +67,7 @@ class FloatStruct; class StringStruct; class CompoundStruct; class NestedStruct; +class EnumMessage; class BoolMessage; class ByteMessage; class IntMessage; @@ -71,6 +76,7 @@ class FloatMessage; class StringMessage; class CompoundMessage; class NestedMessage; +class EnumArrayStruct; class BoolArrayStruct; class ByteArrayStruct; class IntArrayStruct; @@ -78,6 +84,7 @@ class UintArrayStruct; class FloatArrayStruct; class StringArrayStruct; class CompoundArrayStruct; +class EnumArrayMessage; class BoolArrayMessage; class ByteArrayMessage; class IntArrayMessage; @@ -254,6 +261,22 @@ class NestedStruct { uint32_t _data_c = {}; }; +class EnumMessage { +public: + EnumMessage() { (void)_flags; } + + Enum *x(); + const Enum *x() const; + void set_x(const Enum &value); + + bool encode(kiwi::ByteBuffer &bb); + bool decode(kiwi::ByteBuffer &bb, kiwi::MemoryPool &pool, const BinarySchema *schema = nullptr); + +private: + uint32_t _flags[1] = {}; + Enum _data_x = {}; +}; + class BoolMessage { public: BoolMessage() { (void)_flags; } @@ -397,6 +420,22 @@ class NestedMessage { uint32_t _data_c = {}; }; +class EnumArrayStruct { +public: + EnumArrayStruct() { (void)_flags; } + + kiwi::Array *x(); + const kiwi::Array *x() const; + kiwi::Array &set_x(kiwi::MemoryPool &pool, uint32_t count); + + bool encode(kiwi::ByteBuffer &bb); + bool decode(kiwi::ByteBuffer &bb, kiwi::MemoryPool &pool, const BinarySchema *schema = nullptr); + +private: + uint32_t _flags[1] = {}; + kiwi::Array _data_x = {}; +}; + class BoolArrayStruct { public: BoolArrayStruct() { (void)_flags; } @@ -514,6 +553,22 @@ class CompoundArrayStruct { kiwi::Array _data_y = {}; }; +class EnumArrayMessage { +public: + EnumArrayMessage() { (void)_flags; } + + kiwi::Array *x(); + const kiwi::Array *x() const; + kiwi::Array &set_x(kiwi::MemoryPool &pool, uint32_t count); + + bool encode(kiwi::ByteBuffer &bb); + bool decode(kiwi::ByteBuffer &bb, kiwi::MemoryPool &pool, const BinarySchema *schema = nullptr); + +private: + uint32_t _flags[1] = {}; + kiwi::Array _data_x = {}; +}; + class BoolArrayMessage { public: BoolArrayMessage() { (void)_flags; } @@ -830,6 +885,7 @@ class SortedStruct { bool BinarySchema::parse(kiwi::ByteBuffer &bb) { if (!_schema.parse(bb)) return false; + _schema.findDefinition("EnumMessage", _indexEnumMessage); _schema.findDefinition("BoolMessage", _indexBoolMessage); _schema.findDefinition("ByteMessage", _indexByteMessage); _schema.findDefinition("IntMessage", _indexIntMessage); @@ -838,6 +894,7 @@ bool BinarySchema::parse(kiwi::ByteBuffer &bb) { _schema.findDefinition("StringMessage", _indexStringMessage); _schema.findDefinition("CompoundMessage", _indexCompoundMessage); _schema.findDefinition("NestedMessage", _indexNestedMessage); + _schema.findDefinition("EnumArrayMessage", _indexEnumArrayMessage); _schema.findDefinition("BoolArrayMessage", _indexBoolArrayMessage); _schema.findDefinition("ByteArrayMessage", _indexByteArrayMessage); _schema.findDefinition("IntArrayMessage", _indexIntArrayMessage); @@ -851,6 +908,10 @@ bool BinarySchema::parse(kiwi::ByteBuffer &bb) { return true; } +bool BinarySchema::skipEnumMessageField(kiwi::ByteBuffer &bb, uint32_t id) const { + return _schema.skipField(bb, _indexEnumMessage, id); +} + bool BinarySchema::skipBoolMessageField(kiwi::ByteBuffer &bb, uint32_t id) const { return _schema.skipField(bb, _indexBoolMessage, id); } @@ -883,6 +944,10 @@ bool BinarySchema::skipNestedMessageField(kiwi::ByteBuffer &bb, uint32_t id) con return _schema.skipField(bb, _indexNestedMessage, id); } +bool BinarySchema::skipEnumArrayMessageField(kiwi::ByteBuffer &bb, uint32_t id) const { + return _schema.skipField(bb, _indexEnumArrayMessage, id); +} + bool BinarySchema::skipBoolArrayMessageField(kiwi::ByteBuffer &bb, uint32_t id) const { return _schema.skipField(bb, _indexBoolArrayMessage, id); } @@ -1205,6 +1270,47 @@ bool NestedStruct::decode(kiwi::ByteBuffer &_bb, kiwi::MemoryPool &_pool, const return true; } +Enum *EnumMessage::x() { + return _flags[0] & 1 ? &_data_x : nullptr; +} + +const Enum *EnumMessage::x() const { + return _flags[0] & 1 ? &_data_x : nullptr; +} + +void EnumMessage::set_x(const Enum &value) { + _flags[0] |= 1; _data_x = value; +} + +bool EnumMessage::encode(kiwi::ByteBuffer &_bb) { + if (x() != nullptr) { + _bb.writeVarUint(1); + _bb.writeVarUint(static_cast(_data_x)); + } + _bb.writeVarUint(0); + return true; +} + +bool EnumMessage::decode(kiwi::ByteBuffer &_bb, kiwi::MemoryPool &_pool, const BinarySchema *_schema) { + while (true) { + uint32_t _type; + if (!_bb.readVarUint(_type)) return false; + switch (_type) { + case 0: + return true; + case 1: { + if (!_bb.readVarUint(reinterpret_cast(_data_x))) return false; + set_x(_data_x); + break; + } + default: { + if (!_schema || !_schema->skipEnumMessageField(_bb, _type)) return false; + break; + } + } + } +} + bool *BoolMessage::x() { return _flags[0] & 1 ? &_data_x : nullptr; } @@ -1596,6 +1702,32 @@ bool NestedMessage::decode(kiwi::ByteBuffer &_bb, kiwi::MemoryPool &_pool, const } } +kiwi::Array *EnumArrayStruct::x() { + return _flags[0] & 1 ? &_data_x : nullptr; +} + +const kiwi::Array *EnumArrayStruct::x() const { + return _flags[0] & 1 ? &_data_x : nullptr; +} + +kiwi::Array &EnumArrayStruct::set_x(kiwi::MemoryPool &pool, uint32_t count) { + _flags[0] |= 1; return _data_x = pool.array(count); +} + +bool EnumArrayStruct::encode(kiwi::ByteBuffer &_bb) { + if (x() == nullptr) return false; + _bb.writeVarUint(_data_x.size()); + for (Enum &_it : _data_x) _bb.writeVarUint(static_cast(_it)); + return true; +} + +bool EnumArrayStruct::decode(kiwi::ByteBuffer &_bb, kiwi::MemoryPool &_pool, const BinarySchema *_schema) { + uint32_t _count; + if (!_bb.readVarUint(_count)) return false; + for (Enum &_it : set_x(_pool, _count)) if (!_bb.readVarUint(reinterpret_cast(_it))) return false; + return true; +} + kiwi::Array *BoolArrayStruct::x() { return _flags[0] & 1 ? &_data_x : nullptr; } @@ -1795,6 +1927,49 @@ bool CompoundArrayStruct::decode(kiwi::ByteBuffer &_bb, kiwi::MemoryPool &_pool, return true; } +kiwi::Array *EnumArrayMessage::x() { + return _flags[0] & 1 ? &_data_x : nullptr; +} + +const kiwi::Array *EnumArrayMessage::x() const { + return _flags[0] & 1 ? &_data_x : nullptr; +} + +kiwi::Array &EnumArrayMessage::set_x(kiwi::MemoryPool &pool, uint32_t count) { + _flags[0] |= 1; return _data_x = pool.array(count); +} + +bool EnumArrayMessage::encode(kiwi::ByteBuffer &_bb) { + if (x() != nullptr) { + _bb.writeVarUint(1); + _bb.writeVarUint(_data_x.size()); + for (Enum &_it : _data_x) _bb.writeVarUint(static_cast(_it)); + } + _bb.writeVarUint(0); + return true; +} + +bool EnumArrayMessage::decode(kiwi::ByteBuffer &_bb, kiwi::MemoryPool &_pool, const BinarySchema *_schema) { + uint32_t _count; + while (true) { + uint32_t _type; + if (!_bb.readVarUint(_type)) return false; + switch (_type) { + case 0: + return true; + case 1: { + if (!_bb.readVarUint(_count)) return false; + for (Enum &_it : set_x(_pool, _count)) if (!_bb.readVarUint(reinterpret_cast(_it))) return false; + break; + } + default: { + if (!_schema || !_schema->skipEnumArrayMessageField(_bb, _type)) return false; + break; + } + } + } +} + kiwi::Array *BoolArrayMessage::x() { return _flags[0] & 1 ? &_data_x : nullptr; } diff --git a/test/test-schema.js b/test/test-schema.js index 5c686fe..5e329a5 100644 --- a/test/test-schema.js +++ b/test/test-schema.js @@ -13,10 +13,18 @@ test["decodeEnumStruct"] = function(bb) { bb = new this.ByteBuffer(bb); } - result["x"] = this["Enum"][bb.readVarUint()]; + result["x"] = (function (t) { + var byte = bb.readVarUint(); + if (undefined == t["Enum"][byte]) { throw new Error("Attempted to parse invalid enum"); } + return t["Enum"][byte]; +})(this); var values = result["y"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(this["Enum"][bb.readVarUint()]); + while (length-- > 0) { values.push((function (t) { + var byte = bb.readVarUint(); + if (undefined == t["Enum"][byte]) { throw new Error("Attempted to parse invalid enum"); } + return t["Enum"][byte]; +})(this)); } return result; }; @@ -262,6 +270,45 @@ test["encodeNestedStruct"] = function(message, bb) { if (isTopLevel) return bb.toUint8Array(); }; +test["decodeEnumMessage"] = function(bb) { + var result = {}; + if (!(bb instanceof this.ByteBuffer)) { + bb = new this.ByteBuffer(bb); + } + + while (true) { + switch (bb.readVarUint()) { + case 0: + return result; + + case 1: + result["x"] = (function (t) { + var byte = bb.readVarUint(); + if (undefined == t["Enum"][byte]) { throw new Error("Attempted to parse invalid enum"); } + return t["Enum"][byte]; +})(this); + break; + + default: + throw new Error("Attempted to parse invalid message"); + } + } +}; + +test["encodeEnumMessage"] = function(message, bb) { + var isTopLevel = !bb; + if (isTopLevel) bb = new this.ByteBuffer(); + + var value = message["x"]; + if (value != null) { + bb.writeVarUint(1); + var encoded = this["Enum"][value]; if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"Enum\""); bb.writeVarUint(encoded); + } + bb.writeVarUint(0); + + if (isTopLevel) return bb.toUint8Array(); +}; + test["decodeBoolMessage"] = function(bb) { var result = {}; if (!(bb instanceof this.ByteBuffer)) { @@ -572,6 +619,41 @@ test["encodeNestedMessage"] = function(message, bb) { if (isTopLevel) return bb.toUint8Array(); }; +test["decodeEnumArrayStruct"] = function(bb) { + var result = {}; + if (!(bb instanceof this.ByteBuffer)) { + bb = new this.ByteBuffer(bb); + } + + var values = result["x"] = []; + var length = bb.readVarUint(); + while (length-- > 0) { values.push((function (t) { + var byte = bb.readVarUint(); + if (undefined == t["Enum"][byte]) { throw new Error("Attempted to parse invalid enum"); } + return t["Enum"][byte]; +})(this)); } + return result; +}; + +test["encodeEnumArrayStruct"] = function(message, bb) { + var isTopLevel = !bb; + if (isTopLevel) bb = new this.ByteBuffer(); + + var value = message["x"]; + if (value != null) { + var values = value, n = values.length; + bb.writeVarUint(n); + for (var i = 0; i < n; i++) { + value = values[i]; + var encoded = this["Enum"][value]; if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"Enum\""); bb.writeVarUint(encoded); + } + } else { + throw new Error("Missing required field \"x\""); + } + + if (isTopLevel) return bb.toUint8Array(); +}; + test["decodeBoolArrayStruct"] = function(bb) { var result = {}; if (!(bb instanceof this.ByteBuffer)) { @@ -580,7 +662,7 @@ test["decodeBoolArrayStruct"] = function(bb) { var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(!!bb.readByte()); + while (length-- > 0) { values.push(!!bb.readByte()); } return result; }; @@ -611,7 +693,7 @@ test["decodeByteArrayStruct"] = function(bb) { var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readByte()); + while (length-- > 0) { values.push(bb.readByte()); } return result; }; @@ -642,7 +724,7 @@ test["decodeIntArrayStruct"] = function(bb) { var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarInt()); + while (length-- > 0) { values.push(bb.readVarInt()); } return result; }; @@ -673,7 +755,7 @@ test["decodeUintArrayStruct"] = function(bb) { var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } return result; }; @@ -704,7 +786,7 @@ test["decodeFloatArrayStruct"] = function(bb) { var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarFloat()); + while (length-- > 0) { values.push(bb.readVarFloat()); } return result; }; @@ -735,7 +817,7 @@ test["decodeStringArrayStruct"] = function(bb) { var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readString()); + while (length-- > 0) { values.push(bb.readString()); } return result; }; @@ -766,10 +848,10 @@ test["decodeCompoundArrayStruct"] = function(bb) { var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } var values = result["y"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } return result; }; @@ -804,6 +886,52 @@ test["encodeCompoundArrayStruct"] = function(message, bb) { if (isTopLevel) return bb.toUint8Array(); }; +test["decodeEnumArrayMessage"] = function(bb) { + var result = {}; + if (!(bb instanceof this.ByteBuffer)) { + bb = new this.ByteBuffer(bb); + } + + while (true) { + switch (bb.readVarUint()) { + case 0: + return result; + + case 1: + var values = result["x"] = []; + var length = bb.readVarUint(); + while (length-- > 0) { values.push((function (t) { + var byte = bb.readVarUint(); + if (undefined == t["Enum"][byte]) { throw new Error("Attempted to parse invalid enum"); } + return t["Enum"][byte]; +})(this)); } + break; + + default: + throw new Error("Attempted to parse invalid message"); + } + } +}; + +test["encodeEnumArrayMessage"] = function(message, bb) { + var isTopLevel = !bb; + if (isTopLevel) bb = new this.ByteBuffer(); + + var value = message["x"]; + if (value != null) { + bb.writeVarUint(1); + var values = value, n = values.length; + bb.writeVarUint(n); + for (var i = 0; i < n; i++) { + value = values[i]; + var encoded = this["Enum"][value]; if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"Enum\""); bb.writeVarUint(encoded); + } + } + bb.writeVarUint(0); + + if (isTopLevel) return bb.toUint8Array(); +}; + test["decodeBoolArrayMessage"] = function(bb) { var result = {}; if (!(bb instanceof this.ByteBuffer)) { @@ -818,7 +946,7 @@ test["decodeBoolArrayMessage"] = function(bb) { case 1: var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(!!bb.readByte()); + while (length-- > 0) { values.push(!!bb.readByte()); } break; default: @@ -860,7 +988,7 @@ test["decodeByteArrayMessage"] = function(bb) { case 1: var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readByte()); + while (length-- > 0) { values.push(bb.readByte()); } break; default: @@ -902,7 +1030,7 @@ test["decodeIntArrayMessage"] = function(bb) { case 1: var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarInt()); + while (length-- > 0) { values.push(bb.readVarInt()); } break; default: @@ -944,7 +1072,7 @@ test["decodeUintArrayMessage"] = function(bb) { case 1: var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } break; default: @@ -986,7 +1114,7 @@ test["decodeFloatArrayMessage"] = function(bb) { case 1: var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarFloat()); + while (length-- > 0) { values.push(bb.readVarFloat()); } break; default: @@ -1028,7 +1156,7 @@ test["decodeStringArrayMessage"] = function(bb) { case 1: var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readString()); + while (length-- > 0) { values.push(bb.readString()); } break; default: @@ -1070,13 +1198,13 @@ test["decodeCompoundArrayMessage"] = function(bb) { case 1: var values = result["x"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } break; case 2: var values = result["y"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } break; default: @@ -1172,13 +1300,13 @@ test["decodeNonDeprecatedMessage"] = function(bb) { case 3: var values = result["c"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } break; case 4: var values = result["d"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } break; case 5: @@ -1281,12 +1409,12 @@ test["decodeDeprecatedMessage"] = function(bb) { case 3: var values = result["c"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } break; case 4: var length = bb.readVarUint(); - while (length-- > 0) bb.readVarUint(); + while (length-- > 0) { bb.readVarUint() }; break; case 5: @@ -1364,22 +1492,22 @@ test["decodeSortedStruct"] = function(bb) { result["f2"] = bb.readString(); var values = result["a3"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(!!bb.readByte()); + while (length-- > 0) { values.push(!!bb.readByte()); } var values = result["b3"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readByte()); + while (length-- > 0) { values.push(bb.readByte()); } var values = result["c3"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarInt()); + while (length-- > 0) { values.push(bb.readVarInt()); } var values = result["d3"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarUint()); + while (length-- > 0) { values.push(bb.readVarUint()); } var values = result["e3"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readVarFloat()); + while (length-- > 0) { values.push(bb.readVarFloat()); } var values = result["f3"] = []; var length = bb.readVarUint(); - while (length-- > 0) values.push(bb.readString()); + while (length-- > 0) { values.push(bb.readString()); } return result; }; diff --git a/test/test-schema.kiwi b/test/test-schema.kiwi index 1ae72cc..04e6cb7 100644 --- a/test/test-schema.kiwi +++ b/test/test-schema.kiwi @@ -6,7 +6,6 @@ enum Enum { } struct EnumStruct { Enum x; Enum[] y; } - struct BoolStruct { bool x; } struct ByteStruct { byte x; } struct IntStruct { int x; } @@ -16,6 +15,7 @@ struct StringStruct { string x; } struct CompoundStruct { uint x; uint y; } struct NestedStruct { uint a; CompoundStruct b; uint c; } +message EnumMessage { Enum x = 1; } message BoolMessage { bool x = 1; } message ByteMessage { byte x = 1; } message IntMessage { int x = 1; } @@ -25,6 +25,7 @@ message StringMessage { string x = 1; } message CompoundMessage { uint x = 1; uint y = 2; } message NestedMessage { uint a = 1; CompoundMessage b = 2; uint c = 3; } +struct EnumArrayStruct { Enum[] x; } struct BoolArrayStruct { bool[] x; } struct ByteArrayStruct { byte[] x; } struct IntArrayStruct { int[] x; } @@ -33,6 +34,7 @@ struct FloatArrayStruct { float[] x; } struct StringArrayStruct { string[] x; } struct CompoundArrayStruct { uint[] x; uint[] y; } +message EnumArrayMessage { Enum[] x = 1; } message BoolArrayMessage { bool[] x = 1; } message ByteArrayMessage { byte[] x = 1; } message IntArrayMessage { int[] x = 1; } diff --git a/test/test-schema.sk b/test/test-schema.sk index 596d3ad..d4a52f2 100644 --- a/test/test-schema.sk +++ b/test/test-schema.sk @@ -1,6 +1,7 @@ namespace test { class BinarySchema { var _schema = Kiwi.BinarySchema.new + var _indexEnumMessage = 0 var _indexBoolMessage = 0 var _indexByteMessage = 0 var _indexIntMessage = 0 @@ -9,6 +10,7 @@ namespace test { var _indexStringMessage = 0 var _indexCompoundMessage = 0 var _indexNestedMessage = 0 + var _indexEnumArrayMessage = 0 var _indexBoolArrayMessage = 0 var _indexByteArrayMessage = 0 var _indexIntArrayMessage = 0 @@ -22,6 +24,7 @@ namespace test { def parse(bytes Uint8Array) { _schema.parse(Kiwi.ByteBuffer.new(bytes)) + _indexEnumMessage = _schema.findDefinition("EnumMessage") _indexBoolMessage = _schema.findDefinition("BoolMessage") _indexByteMessage = _schema.findDefinition("ByteMessage") _indexIntMessage = _schema.findDefinition("IntMessage") @@ -30,6 +33,7 @@ namespace test { _indexStringMessage = _schema.findDefinition("StringMessage") _indexCompoundMessage = _schema.findDefinition("CompoundMessage") _indexNestedMessage = _schema.findDefinition("NestedMessage") + _indexEnumArrayMessage = _schema.findDefinition("EnumArrayMessage") _indexBoolArrayMessage = _schema.findDefinition("BoolArrayMessage") _indexByteArrayMessage = _schema.findDefinition("ByteArrayMessage") _indexIntArrayMessage = _schema.findDefinition("IntArrayMessage") @@ -42,6 +46,10 @@ namespace test { _indexDeprecatedMessage = _schema.findDefinition("DeprecatedMessage") } + def skipEnumMessageField(bb Kiwi.ByteBuffer, id int) { + _schema.skipField(bb, _indexEnumMessage, id) + } + def skipBoolMessageField(bb Kiwi.ByteBuffer, id int) { _schema.skipField(bb, _indexBoolMessage, id) } @@ -74,6 +82,10 @@ namespace test { _schema.skipField(bb, _indexNestedMessage, id) } + def skipEnumArrayMessageField(bb Kiwi.ByteBuffer, id int) { + _schema.skipField(bb, _indexEnumArrayMessage, id) + } + def skipBoolArrayMessageField(bb Kiwi.ByteBuffer, id int) { _schema.skipField(bb, _indexBoolArrayMessage, id) } @@ -641,6 +653,72 @@ namespace test { } } + class EnumMessage { + var _flags0 = 0 + var _x Enum = .A + + def has_x bool { + return (_flags0 & 1) != 0 + } + + def x Enum { + assert(has_x) + return _x + } + + def x=(value Enum) { + _x = value + _flags0 |= 1 + } + + def encode(bb Kiwi.ByteBuffer) { + if has_x { + bb.writeVarUint(1) + bb.writeVarUint(Enum.encode(_x)) + } + + bb.writeVarUint(0) + } + + def encode Uint8Array { + var bb = Kiwi.ByteBuffer.new + encode(bb) + return bb.toUint8Array + } + } + + namespace EnumMessage { + def decode(bytes Uint8Array) EnumMessage { + return decode(Kiwi.ByteBuffer.new(bytes), null) + } + + def decode(bytes Uint8Array, schema BinarySchema) EnumMessage { + return decode(Kiwi.ByteBuffer.new(bytes), schema) + } + + def decode(bb Kiwi.ByteBuffer, schema BinarySchema) EnumMessage { + var self = new + while true { + var type = bb.readVarUint + switch type { + case 0 { + break + } + + case 1 { + self.x = Enum.decode(bb.readVarUint) + } + + default { + if schema == null { Kiwi.DecodeError.throwInvalidMessage } + else { schema.skipEnumMessageField(bb, type) } + } + } + } + return self + } + } + class BoolMessage { var _flags0 = 0 var _x bool = false @@ -1241,6 +1319,60 @@ namespace test { } } + class EnumArrayStruct { + var _flags0 = 0 + var _x List = null + + def has_x bool { + return (_flags0 & 1) != 0 + } + + def x List { + assert(has_x) + return _x + } + + def x=(value List) { + _x = value + _flags0 |= 1 + } + + def encode(bb Kiwi.ByteBuffer) { + assert(has_x) + bb.writeVarUint(_x.count) + for value in _x { + bb.writeVarUint(Enum.encode(value)) + } + } + + def encode Uint8Array { + var bb = Kiwi.ByteBuffer.new + encode(bb) + return bb.toUint8Array + } + } + + namespace EnumArrayStruct { + def decode(bytes Uint8Array) EnumArrayStruct { + return decode(Kiwi.ByteBuffer.new(bytes), null) + } + + def decode(bytes Uint8Array, schema BinarySchema) EnumArrayStruct { + return decode(Kiwi.ByteBuffer.new(bytes), schema) + } + + def decode(bb Kiwi.ByteBuffer, schema BinarySchema) EnumArrayStruct { + var self = new + var count = 0 + count = bb.readVarUint + self.x = [] + for array = self._x; count != 0; count-- { + array.append(Enum.decode(bb.readVarUint)) + } + return self + } + } + class BoolArrayStruct { var _flags0 = 0 var _x List = null @@ -1645,6 +1777,80 @@ namespace test { } } + class EnumArrayMessage { + var _flags0 = 0 + var _x List = null + + def has_x bool { + return (_flags0 & 1) != 0 + } + + def x List { + assert(has_x) + return _x + } + + def x=(value List) { + _x = value + _flags0 |= 1 + } + + def encode(bb Kiwi.ByteBuffer) { + if has_x { + bb.writeVarUint(1) + bb.writeVarUint(_x.count) + for value in _x { + bb.writeVarUint(Enum.encode(value)) + } + } + + bb.writeVarUint(0) + } + + def encode Uint8Array { + var bb = Kiwi.ByteBuffer.new + encode(bb) + return bb.toUint8Array + } + } + + namespace EnumArrayMessage { + def decode(bytes Uint8Array) EnumArrayMessage { + return decode(Kiwi.ByteBuffer.new(bytes), null) + } + + def decode(bytes Uint8Array, schema BinarySchema) EnumArrayMessage { + return decode(Kiwi.ByteBuffer.new(bytes), schema) + } + + def decode(bb Kiwi.ByteBuffer, schema BinarySchema) EnumArrayMessage { + var self = new + var count = 0 + while true { + var type = bb.readVarUint + switch type { + case 0 { + break + } + + case 1 { + count = bb.readVarUint + self.x = [] + for array = self._x; count != 0; count-- { + array.append(Enum.decode(bb.readVarUint)) + } + } + + default { + if schema == null { Kiwi.DecodeError.throwInvalidMessage } + else { schema.skipEnumArrayMessageField(bb, type) } + } + } + } + return self + } + } + class BoolArrayMessage { var _flags0 = 0 var _x List = null diff --git a/test/test-schema.ts b/test/test-schema.ts index f74affd..eeb1070 100644 --- a/test/test-schema.ts +++ b/test/test-schema.ts @@ -43,6 +43,10 @@ export namespace test { c: number; } + export interface EnumMessage { + x?: Enum; + } + export interface BoolMessage { x?: boolean; } @@ -78,6 +82,10 @@ export namespace test { c?: number; } + export interface EnumArrayStruct { + x: Enum[]; + } + export interface BoolArrayStruct { x: boolean[]; } @@ -107,6 +115,10 @@ export namespace test { y: number[]; } + export interface EnumArrayMessage { + x?: Enum[]; + } + export interface BoolArrayMessage { x?: boolean[]; } @@ -197,6 +209,8 @@ export namespace test { decodeCompoundStruct(buffer: Uint8Array): CompoundStruct; encodeNestedStruct(message: NestedStruct): Uint8Array; decodeNestedStruct(buffer: Uint8Array): NestedStruct; + encodeEnumMessage(message: EnumMessage): Uint8Array; + decodeEnumMessage(buffer: Uint8Array): EnumMessage; encodeBoolMessage(message: BoolMessage): Uint8Array; decodeBoolMessage(buffer: Uint8Array): BoolMessage; encodeByteMessage(message: ByteMessage): Uint8Array; @@ -213,6 +227,8 @@ export namespace test { decodeCompoundMessage(buffer: Uint8Array): CompoundMessage; encodeNestedMessage(message: NestedMessage): Uint8Array; decodeNestedMessage(buffer: Uint8Array): NestedMessage; + encodeEnumArrayStruct(message: EnumArrayStruct): Uint8Array; + decodeEnumArrayStruct(buffer: Uint8Array): EnumArrayStruct; encodeBoolArrayStruct(message: BoolArrayStruct): Uint8Array; decodeBoolArrayStruct(buffer: Uint8Array): BoolArrayStruct; encodeByteArrayStruct(message: ByteArrayStruct): Uint8Array; @@ -227,6 +243,8 @@ export namespace test { decodeStringArrayStruct(buffer: Uint8Array): StringArrayStruct; encodeCompoundArrayStruct(message: CompoundArrayStruct): Uint8Array; decodeCompoundArrayStruct(buffer: Uint8Array): CompoundArrayStruct; + encodeEnumArrayMessage(message: EnumArrayMessage): Uint8Array; + decodeEnumArrayMessage(buffer: Uint8Array): EnumArrayMessage; encodeBoolArrayMessage(message: BoolArrayMessage): Uint8Array; decodeBoolArrayMessage(buffer: Uint8Array): BoolArrayMessage; encodeByteArrayMessage(message: ByteArrayMessage): Uint8Array; diff --git a/test/test.js b/test/test.js index 639823c..e8f21fa 100644 --- a/test/test.js +++ b/test/test.js @@ -129,6 +129,20 @@ it('struct nested', function() { check({a: 534, b: {x: 12345, y: 54321}, c: 321}, [150, 4, 185, 96, 177, 168, 3, 193, 2]); }); +it('message enum', function () { + function check(i, o) { + assert.deepEqual(Buffer(schema.encodeEnumMessage(i)), Buffer(o)); + assert.deepEqual(schema.decodeEnumMessage(new Uint8Array(o)), i); + } + + check({}, [0]) + check({ x: 'A' }, [1, 100, 0]) + + assert.throws(function () { + schema.decodeEnumMessage(new Uint8Array([1, 300, 0])) + }, Error) +}) + it('message bool', function() { function check(i, o) { assert.deepEqual(Buffer(schema.encodeBoolMessage(i)), Buffer(o)); @@ -217,6 +231,27 @@ it('message nested', function() { check({c: 123, b: {x: 5, y: 6}, a: 234}, [1, 234, 1, 2, 1, 5, 2, 6, 0, 3, 123, 0]); }); +it('struct enum array', function () { + function check(i, o) { + assert.deepEqual(Buffer(schema.encodeEnumArrayStruct({ x: i })), Buffer(o)); + assert.deepEqual(schema.decodeEnumArrayStruct(new Uint8Array(o)), { x: i }); + } + + check([], [0]); + check(['B', 'A'], [2, 200, 1, 100]); +}); + +it('message enum array', function () { + function check(i, o) { + assert.deepEqual(Buffer(schema.encodeEnumArrayMessage(i)), Buffer(o)); + assert.deepEqual(schema.decodeEnumArrayMessage(new Uint8Array(o)), i); + } + + check({}, [0]); + check({ x: [] }, [1, 0, 0]); + check({ x: ['B', 'A'] }, [1, 2, 200, 1, 100, 0]); +}); + it('struct bool array', function() { function check(i, o) { assert.deepEqual(Buffer(schema.encodeBoolArrayStruct({x: i})), Buffer(o));