diff --git a/implementations/javascript/src/codec.js b/implementations/javascript/src/codec.js index 25595c1..61482e0 100644 --- a/implementations/javascript/src/codec.js +++ b/implementations/javascript/src/codec.js @@ -13,6 +13,7 @@ class EncodeError extends Error { this.irritant = irritant; } } +class ShortPacket extends DecodeError {} class Decoder { constructor(packet, options) { @@ -22,22 +23,18 @@ class Decoder { this.shortForms = options.shortForms || {}; } - peekbyte() { - if (this.index >= this.packet.length) throw new DecodeError("Short packet"); - // ^ NOTE: greater-than-or-equal-to, not greater-than. - return this.packet[this.index]; - } - - advance(count) { - const start = this.index; - this.index += (count === void 0 ? 1 : count); - return start; - } - nextbyte() { - const val = this.peekbyte(); - this.advance(); - return val; + if (this.index >= this.packet.length) throw new ShortPacket("Short packet"); + // ^ NOTE: greater-than-or-equal-to, not greater-than. + return this.packet[this.index++]; + } + + nextbytes(n) { + const start = this.index; + this.index += n; + if (this.index > this.packet.length) throw new ShortPacket("Short packet"); + // ^ NOTE: greater-than, not greater-than-or-equal-to. + return new DataView(this.packet.buffer, this.packet.byteOffset + start, n); } wirelength(arg) { @@ -52,36 +49,25 @@ class Decoder { return (this.varint() << 7) + (v - 128); } - nextbytes(n) { - const start = this.advance(n); - if (this.index > this.packet.length) throw new DecodeError("Short packet"); - // ^ NOTE: greater-than, not greater-than-or-equal-to. - return new DataView(this.packet.buffer, this.packet.byteOffset + start, n); - } - nextvalues(n) { const result = []; for (let i = 0; i < n; i++) result.push(this.next()); return result; } - peekop() { - const b = this.peekbyte(); + nextop() { + const b = this.nextbyte(); const major = b >> 6; const minor = (b >> 4) & 3; const arg = b & 15; return [major, minor, arg]; } - nextop() { - const op = this.peekop(); - this.advance(); - return op; - } - peekend(arg) { - const [a,i,r] = this.peekop(); - return (a === 0) && (i === 3) && (r === arg); + const [a,i,r] = this.nextop(); + const result = (a === 0) && (i === 3) && (r === arg); + if (!result) this.index--; + return result; } binarystream(arg, minor) { @@ -335,6 +321,7 @@ class Encoder { Object.assign(module.exports, { DecodeError, EncodeError, + ShortPacket, Decoder, Encoder, }); diff --git a/implementations/javascript/test/samples.txt b/implementations/javascript/test/samples.txt index 7721127..397b7ea 100644 --- a/implementations/javascript/test/samples.txt +++ b/implementations/javascript/test/samples.txt @@ -12,6 +12,7 @@ 26626865626c6c6060616f36 27626865626c6c6060616f37 2c111213143c +2c2563616263352563646566353c 2cc2516111c2516212c25163133c 410d 417f diff --git a/implementations/javascript/test/test-codec.js b/implementations/javascript/test/test-codec.js index 0d5f93c..2102690 100644 --- a/implementations/javascript/test/test-codec.js +++ b/implementations/javascript/test/test-codec.js @@ -71,6 +71,7 @@ describe('hex samples', () => { { expected: Bytes.from("hello"), encodesTo: '6568656c6c6f', }, { expected: Symbol.for("hello"), encodesTo: '7568656c6c6f', }, { expected: Immutable.Seq([1, 2, 3, 4]), }, + { expected: Preserves.fromJS(["abc", "def"]), encodesTo: 'c25361626353646566' }, { expected: Preserves.fromJS([["a", 1], ["b", 2], ["c", 3]]), encodesTo: 'c3c2516111c2516212c2516313', }, { expected: 13, }, diff --git a/implementations/python/preserves/__init__.py b/implementations/python/preserves/__init__.py index 2d44921..22d6568 100644 --- a/implementations/python/preserves/__init__.py +++ b/implementations/python/preserves/__init__.py @@ -1,6 +1,6 @@ from .preserves import Float, Symbol, Record, ImmutableDict -from .preserves import DecodeError, EncodeError +from .preserves import DecodeError, EncodeError, ShortPacket from .preserves import Decoder, Encoder diff --git a/implementations/python/preserves/preserves.py b/implementations/python/preserves/preserves.py index 4001898..a3cc8e1 100644 --- a/implementations/python/preserves/preserves.py +++ b/implementations/python/preserves/preserves.py @@ -119,6 +119,7 @@ def dict_kvs(d): class DecodeError(ValueError): pass class EncodeError(ValueError): pass +class ShortPacket(DecodeError): pass class Codec(object): def __init__(self): @@ -183,21 +184,19 @@ class Decoder(Codec): self.packet = packet self.index = 0 - def peekbyte(self): - if self.index < len(self.packet): - return _ord(self.packet[self.index]) - else: - raise DecodeError('Short packet') - - def advance(self, count=1): - start = self.index - self.index = self.index + count - return start - def nextbyte(self): - val = self.peekbyte() - self.advance() - return val + if self.index >= len(self.packet): + raise ShortPacket('Short packet') + self.index = self.index + 1 + return _ord(self.packet[self.index - 1]) + + def nextbytes(self, n): + start = self.index + end = start + n + if end > len(self.packet): + raise ShortPacket('Short packet') + self.index = end + return self.packet[start : end] def wirelength(self, arg): if arg < 15: @@ -211,30 +210,24 @@ class Decoder(Codec): else: return self.varint() * 128 + (v - 128) - def nextbytes(self, n): - start = self.advance(n) - return self.packet[start : self.index] - def nextvalues(self, n): result = [] for i in range(n): result.append(self.next()) return result - def peekop(self): - b = self.peekbyte() + def nextop(self): + b = self.nextbyte() major = b >> 6 minor = (b >> 4) & 3 arg = b & 15 return (major, minor, arg) - def nextop(self): - op = self.peekop() - self.advance() - return op - def peekend(self, arg): - return self.peekop() == (0, 3, arg) + matched = (self.nextop() == (0, 3, arg)) + if not matched: + self.index = self.index - 1 + return matched def binarystream(self, arg, minor): result = [] diff --git a/implementations/python/preserves/test_preserves.py b/implementations/python/preserves/test_preserves.py index c0e6767..0131b4d 100644 --- a/implementations/python/preserves/test_preserves.py +++ b/implementations/python/preserves/test_preserves.py @@ -199,3 +199,8 @@ class CodecTests(unittest.TestCase): self._roundtrip((False,) * 15, _buf(0xCF, 0x0F, b'\x00' * 15)) self._roundtrip((False,) * 100, _buf(0xCF, 0x64, b'\x00' * 100)) self._roundtrip((False,) * 200, _buf(0xCF, 0xC8, 0x01, b'\x00' * 200)) + + def test_format_c_twice(self): + self._roundtrip(SequenceStream([StringStream([b'abc']), StringStream([b'def'])]), + _buf(0x2C, 0x25, 0x63, 'abc', 0x35, 0x25, 0x63, 'def', 0x35, 0x3C), + back=(u'abc', u'def'))