]> Cypherpunks repositories - keks.git/commitdiff
Slightly more compact BLOB
authorSergey Matveev <stargrave@stargrave.org>
Mon, 24 Nov 2025 16:41:52 +0000 (19:41 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Mon, 24 Nov 2025 16:41:52 +0000 (19:41 +0300)
13 files changed:
c/lib/dec.c
c/lib/enc.c
go/atom-decode.go
go/atom-encode.go
go/blob_test.go
go/int.go [new file with mode: 0644]
py3/keks.py
py3/tests/test_blob.py
py3/tests/test_recursion.py
spec/encoding/BLOB
spec/encoding/FullTable
spec/encoding/index
tcl/keks.tcl

index c726d1d5e6adabed3d1b0ec98c4e95c897b77c674f266da775fa2404cc1afba8..a831f7a51312a466c24cfb1b3179a6e7fafce56ab9f3ebda8f4ed03c5dd07fb5 100644 (file)
@@ -167,11 +167,20 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
         break;
     case KEKSAtomBlob: {
         atom->typ = KEKSItemBlob;
-        (*got) += 8;
-        if (len < (*got)) {
-            return KEKSErrNotEnough;
+        if (buf[1] != KEKSAtomPint) {
+            return KEKSErrBlobBadAtom;
+        }
+        size_t pintGot = 0;
+        struct KEKSAtom pint = {0};
+        enum KEKSErr err = KEKSAtomDecode(&pintGot, &pint, buf + 1, len - 1);
+        if (err != KEKSErrNo) {
+            return err;
         }
-        const uint64_t chunkLen = keksFromBE(buf + 1, 8);
+        (*got) += pintGot;
+        if (pint.typ != KEKSItemPint) {
+            return KEKSErrBlobBadAtom;
+        }
+        const uint64_t chunkLen = pint.v.pint;
         if (chunkLen > (SIZE_MAX - 1)) {
             return KEKSErrLenTooBig;
         }
@@ -182,11 +191,11 @@ KEKSAtomDecode( // NOLINT(misc-no-recursion)
     case KEKSAtomPint:
     case KEKSAtomNint: {
         atom->typ = (tag == KEKSAtomPint) ? KEKSItemPint : KEKSItemNint;
-        size_t binGot = 0;
-        struct KEKSAtom bin = {0};
         if ((buf[1] & (unsigned char)KEKSAtomStrings) == 0) {
             return KEKSErrIntNonBin;
         }
+        size_t binGot = 0;
+        struct KEKSAtom bin = {0};
         enum KEKSErr err = KEKSAtomDecode(&binGot, &bin, buf + 1, len - 1);
         if (err != KEKSErrNo) {
             return err;
index 683a9e3ead34db8cd7b70f9aa6a6b1fad54be8be5b095b2ffa8a77114b3adb21..201dc3c533c65e08348a90c4aac382e72b41365391dff6f432ba1800233067cd 100644 (file)
@@ -256,14 +256,16 @@ KEKSAtomBlobEncode(
     const size_t chunkLen)
 {
     assert(len != NULL);
-    (*len) = 1 + 8;
-    if (cap < 1 + 8) {
+    assert(chunkLen != 0);
+    (*len) = 1;
+    if (cap <= 1) {
         return false;
     }
     assert(buf != NULL);
     buf[0] = KEKSAtomBlob;
-    keksToBE(buf + 1, 8, (uint64_t)chunkLen - 1);
-    return true;
+    bool ok = KEKSAtomUintEncode(len, buf + 1, cap - 1, chunkLen - 1);
+    (*len)++;
+    return ok;
 }
 
 static bool
index 013840989a3b8c3e83d3aa0e9a5aa30e1bf37d774a216da8d1e5b4bde8751b66..cd979837b13c1168026b983c713dc574b24f778fa6e2e0cb76c9d4db849fa1da 100644 (file)
@@ -17,7 +17,6 @@ package keks
 
 import (
        "errors"
-       "math/big"
        "strings"
        "unicode/utf8"
        "unsafe"
@@ -38,6 +37,7 @@ var (
        ErrTAINonMinimal   = errors.New("non-minimal TAI64")
        ErrTAITooManyNsecs = errors.New("too many nanoseconds")
        ErrTAITooManyAsecs = errors.New("too many attoseconds")
+       ErrBlobBadInt      = errors.New("blob with non Pint")
 )
 
 func (ctx *Decoder) DecodeAtom() (t types.Type, err error) {
@@ -98,12 +98,26 @@ func (ctx *Decoder) DecodeAtom() (t types.Type, err error) {
        case AtomMap:
                t = types.Map
        case AtomBLOB:
-               var s string
-               s, err = ctx.getBytes(8)
+               tag, err = ctx.getByte()
+               if err != nil {
+                       return
+               }
+               if AtomType(tag) != AtomPInt {
+                       err = ErrBlobBadInt
+                       return
+               }
+               var isBig bool
+               isBig, err = ctx.getInt(types.UInt)
                if err != nil {
                        return
                }
-               chunkLen := be.Get([]byte(s))
+               if isBig {
+                       ctx.bigints = ctx.bigints[:len(ctx.bigints)-1]
+                       err = ErrLenTooBig
+                       return
+               }
+               chunkLen := ctx.uints[len(ctx.uints)-1]
+               ctx.uints = ctx.uints[:len(ctx.uints)-1]
                if chunkLen >= (1<<63)-1 {
                        err = ErrLenTooBig
                        return
@@ -117,54 +131,13 @@ func (ctx *Decoder) DecodeAtom() (t types.Type, err error) {
                } else {
                        t = types.Int
                }
-               tag, err = ctx.getByte()
-               if err != nil {
-                       return
-               }
-               if tag&AtomStrings == 0 || tag&AtomIsUTF8 != 0 {
-                       err = ErrIntBad
-                       return
-               }
-               var s string
-               s, err = ctx.getStr(tag)
+               var isBig bool
+               isBig, err = ctx.getInt(t)
                if err != nil {
                        return
                }
-               if len(s) == 0 {
-                       if t == types.UInt {
-                               ctx.uints = append(ctx.uints, 0)
-                       } else {
-                               ctx.ints = append(ctx.ints, -1)
-                       }
-                       break
-               }
-               if s[0] == 0 {
-                       err = ErrIntNonMinimal
-                       return
-               }
-               if len(s) > 8 {
-                       bi := new(big.Int).SetBytes([]byte(s))
-                       if t == types.Int {
-                               bi = bi.Add(bi, big.NewInt(1))
-                               bi = bi.Neg(bi)
-                       }
+               if isBig {
                        t = types.BigInt
-                       ctx.bigints = append(ctx.bigints, bi)
-                       break
-               }
-               i := be.Get([]byte(s))
-               if t == types.UInt {
-                       ctx.uints = append(ctx.uints, i)
-               } else {
-                       if i >= (1 << 63) {
-                               bi := new(big.Int).SetBytes([]byte(s))
-                               bi = bi.Add(bi, big.NewInt(1))
-                               bi = bi.Neg(bi)
-                               ctx.bigints = append(ctx.bigints, bi)
-                               t = types.BigInt
-                       } else {
-                               ctx.ints = append(ctx.ints, -1-int64(i))
-                       }
                }
        case AtomFloatNaN:
                t = types.Float
index 7987c4fffccb844e3c4b511a5ba73e1bc00558b514fa5ff0ccb5fa55d1a774e2..74dd91dea5d34eac40ab492bbdbe277e09e7179a8cb91b6ce213bd5796c406a5 100644 (file)
@@ -155,10 +155,13 @@ func FloatEncode(w io.Writer, v *Float) (written int64, err error) {
 
 // Write an encoded BLOB atom.
 func BlobAtomEncode(w io.Writer, chunkLen int64) (written int64, err error) {
-       l := make([]byte, 9)
-       l[0] = byte(AtomBLOB)
-       be.Put(l[1:], uint64(chunkLen-1))
-       return io.Copy(w, bytes.NewReader(l))
+       _, err = io.Copy(w, bytes.NewReader([]byte{byte(AtomBLOB), byte(AtomPInt)}))
+       if err != nil {
+               return
+       }
+       written, err = atomUintEncode(w, uint64(chunkLen-1))
+       written += 2
+       return
 }
 
 // Write an encoded BLOB.
index d8d5114277b6270520e29c12341db3e5572d301caf7890fa1f22c1824c90f535..cbf4b2a80be62c60fd1d210bd98bce2c6a759254ee78b3c2e45d108155908951 100644 (file)
@@ -18,16 +18,15 @@ package keks
 
 import (
        "bytes"
+       "encoding/hex"
        "io"
        "testing"
        "testing/quick"
-
-       "go.cypherpunks.su/keks/be"
 )
 
 func TestBlobMultipleOfChunkLen(t *testing.T) {
        bin := bytes.Join([][]byte{
-               mustHexDec("0B0000000000000003"),
+               mustHexDec("0B0C8103"),
                {0x84},
                []byte("test"),
                {0x84},
@@ -43,7 +42,7 @@ func TestBlobMultipleOfChunkLen(t *testing.T) {
                t.Fatal(err)
        }
        if !bytes.Equal(encoded, bin) {
-               t.Fatal("encoded differs")
+               t.Fatal("encoded differs", hex.EncodeToString(encoded), hex.EncodeToString(bin))
        }
        decoder := NewDecoderFromBytes(append(encoded, Junk...), nil)
        decoded, err := decoder.Decode()
@@ -83,7 +82,7 @@ func TestBlobMultipleOfChunkLen(t *testing.T) {
 
 func TestBlobLargerOfChunkLen(t *testing.T) {
        bin := bytes.Join([][]byte{
-               mustHexDec("0B0000000000000003"),
+               mustHexDec("0B0C8103"),
                {0x84},
                []byte("test"),
                {0x84},
@@ -142,7 +141,7 @@ func TestBlobLargerOfChunkLen(t *testing.T) {
 }
 
 func TestBlobEmpty(t *testing.T) {
-       bin := mustHexDec("0B0000000000000003" + "80")
+       bin := mustHexDec("0B0C8103" + "80")
        encoded, err := EncodeBuf(BlobReader{
                ChunkLen: 4,
                R:        bytes.NewReader(nil),
@@ -241,7 +240,7 @@ func TestBlobSymmetric(t *testing.T) {
 
 func TestBlobNotEnoughData(t *testing.T) {
        bin := bytes.Join([][]byte{
-               mustHexDec("0B0000000000000003"),
+               mustHexDec("0B0C8103"),
                {0x84},
                []byte("test"),
                {0x84},
@@ -254,17 +253,17 @@ func TestBlobNotEnoughData(t *testing.T) {
 }
 
 func TestBlobTooLong(t *testing.T) {
-       bin := make([]byte, 1+8)
-       bin[0] = byte(AtomBLOB)
-       be.Put(bin[1:], (1<<63)-1)
-       _, err := NewDecoderFromBytes(bin, nil).Decode()
+       var buf bytes.Buffer
+       buf.Write([]byte{byte(AtomBLOB)})
+       UIntEncode(&buf, (1<<63)-1)
+       _, err := NewDecoderFromBytes(buf.Bytes(), nil).Decode()
        if err != ErrLenTooBig {
                t.Fatal(err)
        }
 }
 
 func TestBlobNotEnoughDataForLength(t *testing.T) {
-       bin := mustHexDec("0B00000000")
+       bin := mustHexDec("0B0C81")
        _, err := NewDecoderFromBytes(bin, nil).Decode()
        if err != io.ErrUnexpectedEOF {
                t.Fatal(err)
@@ -273,7 +272,7 @@ func TestBlobNotEnoughDataForLength(t *testing.T) {
 
 func TestBlobWrongTerminatorLength(t *testing.T) {
        bin := bytes.Join([][]byte{
-               mustHexDec("0B0000000000000003"),
+               mustHexDec("0B0C8103"),
                {0x84},
                []byte("test"),
                {0x84},
@@ -289,7 +288,7 @@ func TestBlobWrongTerminatorLength(t *testing.T) {
 
 func TestBlobWrongTerminatorTag(t *testing.T) {
        bin := bytes.Join([][]byte{
-               mustHexDec("0B0000000000000003"),
+               mustHexDec("0B0C8103"),
                {0x84},
                []byte("test"),
                {0x84},
@@ -304,10 +303,13 @@ func TestBlobWrongTerminatorTag(t *testing.T) {
 }
 
 func TestBlobTooDeep(t *testing.T) {
-       bin := []byte{byte(AtomBLOB)}
-       bin = append(bin, bytes.Repeat([]byte{0x01}, 8)...)
-       bin = append(bin, bytes.Repeat([]byte{byte(AtomList)}, 1000)...)
-       if _, err := NewDecoderFromBytes(bin, nil).Decode(); err != ErrBlobBadAtom {
+       var buf bytes.Buffer
+       buf.Write([]byte{byte(AtomBLOB)})
+       UIntEncode(&buf, 1)
+       for range 1000 {
+               buf.Write([]byte{byte(AtomList)})
+       }
+       if _, err := NewDecoderFromBytes(buf.Bytes(), nil).Decode(); err != ErrBlobBadAtom {
                t.Fatal(err)
        }
 }
diff --git a/go/int.go b/go/int.go
new file mode 100644 (file)
index 0000000..cdffc12
--- /dev/null
+++ b/go/int.go
@@ -0,0 +1,77 @@
+// KEKS -- Go KEKS codec implementation
+// Copyright (C) 2024-2025 Sergey Matveev <stargrave@stargrave.org>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as
+// published by the Free Software Foundation, version 3 of the License.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package keks
+
+import (
+       "math/big"
+
+       "go.cypherpunks.su/keks/be"
+       "go.cypherpunks.su/keks/types"
+)
+
+func (ctx *Decoder) getInt(t types.Type) (isBig bool, err error) {
+       var tag byte
+       tag, err = ctx.getByte()
+       if err != nil {
+               return
+       }
+       if tag&AtomStrings == 0 || tag&AtomIsUTF8 != 0 {
+               err = ErrIntBad
+               return
+       }
+       var s string
+       s, err = ctx.getStr(tag)
+       if err != nil {
+               return
+       }
+       if len(s) == 0 {
+               if t == types.UInt {
+                       ctx.uints = append(ctx.uints, 0)
+               } else {
+                       ctx.ints = append(ctx.ints, -1)
+               }
+               return
+       }
+       if s[0] == 0 {
+               err = ErrIntNonMinimal
+               return
+       }
+       if len(s) > 8 {
+               isBig = true
+               bi := new(big.Int).SetBytes([]byte(s))
+               if t == types.Int {
+                       bi = bi.Add(bi, big.NewInt(1))
+                       bi = bi.Neg(bi)
+               }
+               ctx.bigints = append(ctx.bigints, bi)
+               return
+       }
+       i := be.Get([]byte(s))
+       if t == types.UInt {
+               ctx.uints = append(ctx.uints, i)
+       } else {
+               if i >= (1 << 63) {
+                       isBig = true
+                       bi := new(big.Int).SetBytes([]byte(s))
+                       bi = bi.Add(bi, big.NewInt(1))
+                       bi = bi.Neg(bi)
+                       ctx.bigints = append(ctx.bigints, bi)
+               } else {
+                       ctx.ints = append(ctx.ints, -1-int64(i))
+               }
+       }
+       return
+}
index d0e2ee60b82e992a8894532a65948992e00aa160be56ba7b1f8dc3cbf2e4d6a7..0cad76513783055f07a272d031963604b00aaa39b5c4da5583fce7b0ac94a609 100755 (executable)
@@ -323,7 +323,7 @@ def dumps(v):
     if isinstance(v, Blob):
         assert (v.l > 0) and (v.l <= (1 << 64))
         l, v = v.l, v.v
-        raws = [TagBlobb, (l-1).to_bytes(8, "big")]
+        raws = [TagBlobb, dumps(l-1)]
         append = raws.append
         chunks = len(v) // l
         for i in range(chunks):
@@ -527,10 +527,12 @@ def _loads(v, sets=False, leapsecUTCAllow=False, _allowContainers=True):
             ret = set(ret.keys())
         return ret, v
     if b == TagBlob:
-        if len(v) < 1+8:
-            raise NotEnoughData(1+8-len(v))
-        l = 1 + int.from_bytes(v[1:1+8], "big")
-        v = v[1+8:]
+        if len(v) < 3:
+            raise NotEnoughData(3-len(v))
+        if v[1] != TagPInt:
+            raise DecodeError("blob without Pint")
+        l, v = _loads(v[1:])
+        l += 1
         raws = []
         while True:
             i, v = _loads(v, _allowContainers=False)
index 2ee62ece76c404d1fdfd078f35d929d3d366dffd7b9ec7f40b4a08d06acbb4ec..b080581e86cbcc8f5cbf8b3128b7f375a2d2e7d488b5f8287a40cf1381429cb9 100644 (file)
@@ -36,7 +36,7 @@ class TestBlob(TestCase):
         self.assertSequenceEqual(
             encoded,
             b"".join((
-                bytes.fromhex("0B0000000000000003"),
+                bytes.fromhex("0B0C8103"),
                 bytes.fromhex("84"), b"test",
                 bytes.fromhex("84"), b"data",
                 bytes.fromhex("80"),
@@ -54,7 +54,7 @@ class TestBlob(TestCase):
         self.assertSequenceEqual(
             encoded,
             b"".join((
-                bytes.fromhex("0B0000000000000003"),
+                bytes.fromhex("0B0C8103"),
                 bytes.fromhex("84"), b"test",
                 bytes.fromhex("84"), b"data",
                 bytes.fromhex("81"), b"2",
@@ -72,7 +72,7 @@ class TestBlob(TestCase):
         self.assertSequenceEqual(
             encoded,
             b"".join((
-                bytes.fromhex("0B0000000000000003"),
+                bytes.fromhex("0B0C8103"),
                 bytes.fromhex("80"),
             )),
         )
@@ -90,7 +90,7 @@ class TestBlob(TestCase):
         chunks = [urandom(chunkLen) for _ in range(chunks)]
         encoded = b"".join((
             b"\x0b",
-            (chunkLen-1).to_bytes(8, "big"),
+            dumps(chunkLen-1),
             b"".join(dumps(chunk) for chunk in chunks),
             b"\x80",
             junk,
@@ -102,7 +102,7 @@ class TestBlob(TestCase):
 
     def test_throws_when_not_enough_data(self) -> None:
         encoded = b"".join((
-            bytes.fromhex("0B0000000000000003"),
+            bytes.fromhex("0B0C8103"),
             bytes.fromhex("84"), b"test",
             bytes.fromhex("84"), b"da",
         ))
@@ -111,14 +111,14 @@ class TestBlob(TestCase):
         self.assertEqual(err.exception.n, 2)
 
     def test_throws_when_not_enough_data_for_length(self) -> None:
-        encoded = bytes.fromhex("0B00000000")
+        encoded = bytes.fromhex("0B0C81")
         with self.assertRaises(NotEnoughData) as err:
             loads(encoded)
-        self.assertEqual(err.exception.n, 8-4)
+        self.assertEqual(err.exception.n, 1)
 
     def test_throws_when_wrong_terminator_length(self) -> None:
         encoded = b"".join((
-            bytes.fromhex("0B0000000000000003"),
+            bytes.fromhex("0B0C8103"),
             bytes.fromhex("84"), b"test",
             bytes.fromhex("84"), b"data",
             bytes.fromhex("8A"), b"terminator",
@@ -129,7 +129,7 @@ class TestBlob(TestCase):
 
     def test_throws_when_wrong_terminator_tag(self) -> None:
         encoded = b"".join((
-            bytes.fromhex("0B0000000000000003"),
+            bytes.fromhex("0B0C8103"),
             bytes.fromhex("84"), b"test",
             bytes.fromhex("84"), b"data",
             bytes.fromhex("04"), b"that was a wrong tag",
index da628b0461967303de4a13ae74ebe50393d29a44eb5a2a52bfcbaf31d8c6598d..b17fc4c58d9edc153bc9935626af30ad6666e7bc93ac74caa4bea95f8a5d3fb2 100644 (file)
@@ -18,6 +18,7 @@ from unittest import TestCase
 
 from keks import _byte
 from keks import DecodeError
+from keks import dumps
 from keks import loads
 from keks import TagBlob
 from keks import TagList
@@ -34,7 +35,7 @@ class TestTooDeepInt(TestCase):
 class TestTooDeepBlob(TestCase):
     def runTest(self) -> None:
         with self.assertRaises(DecodeError) as err:
-            loads(_byte(TagBlob) + (8 * b"\x01") + _byte(TagList) * 1000)
+            loads(_byte(TagBlob) + dumps(1) + _byte(TagList) * 1000)
         self.assertEqual(str(err.exception), "unknown tag")
 
 
index e7eb48dda02fce37f5a8e70928d1bb00fbcc390d282577b6b65717292ae89dee..22dddc12a9dcaead7cf4637d96ecbefc01adba4166a4ed18d668346cbe4601ed 100644 (file)
@@ -1,8 +1,8 @@
 BLOB (binary large object) allows you to transfer binary data in chunks,
 in a streaming way, when data may not fit in memory.
 
-64-bit big-endian integer follows the BLOB tag, setting the following
-chunks payload size (+1). Then come one or more binary [encoding/String]
+[encoding/INT] follows the BLOB tag, setting the following chunks
+payload size, plus one. Then comes one or more binary [encoding/String]
 with the chunk-length payload. All of them, except for the last
 one, must have fixed chunk length payload. Last terminating string's
 payload must be shorter.
@@ -10,12 +10,12 @@ payload must be shorter.
 Data format definition must specify exact chunk size expected to be
 used, if it needs deterministic encoding.
 
-    BLOB chunk-len [BIN(len=chunk-len) || ...] BIN(len<chunk-len)
+    BLOB INT(chunk-len) [BIN(len=chunk-len) || ...] BIN(len<chunk-len)
 
 Example representations:
 
-BLOB {5 ""}       | 0B 0000000000000004 80
-BLOB {5 "12345"}  | 0B 0000000000000004 85 3132333435 80
-BLOB {5 "123456"} | 0B 0000000000000004 85 3132333435 81 36
-BLOB {500 "123"}  | 0B 00000000000001F3 83 313233
-BLOB {2 "12345"}  | 0B 0000000000000001 82 3132 82 3334 81 35
+BLOB {5 ""}       | 0B 0C8105   80
+BLOB {5 "12345"}  | 0B 0C8105   85 3132333435 80
+BLOB {5 "123456"} | 0B 0C8105   85 3132333435 81 36
+BLOB {500 "123"}  | 0B 0C8201F4 83 313233
+BLOB {2 "12345"}  | 0B 0C8102   82 3132 82 3334 81 35
index 2999c36448101f4516f31e0087bd8245888c8a392a139e81d9a8167f4e9de24e..e355c4d32b58381abf023b844662e9ec40964b213a623c0cda5f3cc62c8fa17b 100644 (file)
@@ -10,7 +10,7 @@ dec | hex | bin      | vlen |
 008 | 08  | 00001000 | 0    | [encoding/LIST]
 009 | 09  | 00001001 | 0    | [encoding/MAP]
 010 | 0A  | 00001010 | 0    |
-011 | 0B  | 00001011 | 8+~  | [encoding/BLOB]
+011 | 0B  | 00001011 | 3+~  | [encoding/BLOB]
 012 | 0C  | 00001100 | 1+~  | + [encoding/INT]
 013 | 0D  | 00001101 | 1+~  | - [encoding/INT]
 014 | 0E  | 00001110 | 0    |
index b7f37ba8b45bf650e81005efc4c2d67b4f5960000425215ba20f99188de54a98..6d3fe923a6a758cc946883fc3745b0ff91a26de3bc8f46e96416e1d5e5e68124 100644 (file)
@@ -13,7 +13,7 @@ dec | hex | bin      | vlen |
 008 | 08  | 00001000 | 0    | [encoding/LIST]
 009 | 09  | 00001001 | 0    | [encoding/MAP]
 010 | 0A  | 00001010 |
-011 | 0B  | 00001011 | 8+~  | [encoding/BLOB]
+011 | 0B  | 00001011 | 3+~  | [encoding/BLOB]
 012 | 0C  | 00001100 | 1+~  | + [encoding/INT]
 013 | 0D  | 00001101 | 1+~  | - [encoding/INT]
 ... | ... | ...      | ...  | ...
index af5501ef24b98a714c71f57f424cb1c2bf5eec63e82e852d978ce25824135ed6..4062a09fc923e4f688bbc07304b77c5dd36f76fc055d27f2e12b005dcb5b689a 100755 (executable)
@@ -179,7 +179,7 @@ proc STR {v} {
 proc BLOB {chunkLen v} {
     upvar buf buf
     char [expr 0x0B]
-    toBE 8 [expr {$chunkLen - 1}]
+    INT [expr {$chunkLen - 1}]
     set vl [string length $v]
     set chunks [expr {$vl / $chunkLen}]
     for {set i 0} {$i < $chunks} {incr i} {