return YACErrNotEnough;
}
const uint64_t chunkLen = yacFromBE(buf + 1, 8);
- if (chunkLen > SIZE_MAX) {
+ if (chunkLen > (SIZE_MAX - 1)) {
return YACErrLenTooBig;
}
- if (chunkLen == 0) {
- return YACErrBlobBadLen;
- }
- atom->v.blob.chunkLen = (size_t)chunkLen;
+ atom->v.blob.chunkLen = (size_t)chunkLen + 1;
break;
}
return false;
}
buf[0] = YACAtomBlob;
- yacToBE(buf + 1, 8, (uint64_t)chunkLen);
+ yacToBE(buf + 1, 8, (uint64_t)chunkLen - 1);
return true;
}
return "BadUTF8";
case YACErrIntNonMinimal:
return "IntNonMinimal";
- case YACErrBlobBadLen:
- return "BlobBadLen";
case YACErrBlobBadAtom:
return "BlobBadAtom";
case YACErrBlobBadTerm:
// Invalid UTF-8 codepoint or zero byte met.
// @item YACErrIntNonMinimal
// Non minimal integer encoding.
-// @item YACErrBlobBadLen
-// Blob with invalid chunk length.
// @item YACErrBlobBadAtom
// Blob contains unexpected atom.
// @item YACErrBlobBadTerm
YACErrLenTooBig,
YACErrBadUTF8,
YACErrIntNonMinimal,
- YACErrBlobBadLen,
YACErrBlobBadAtom,
YACErrBlobBadTerm,
YACErrTAI64TooBig,
ErrMapBadKey = errors.New("map bad key")
ErrMapUnordered = errors.New("map unordered")
ErrMapNoVal = errors.New("map no value")
- ErrBlobBadLen = errors.New("blob bad len")
ErrBlobBadAtom = errors.New("blob unexpected atom")
ErrBlobBadTerm = errors.New("blob bad terminator")
)
return
}
chunkLen := FromBE(buf[1 : 1+8])
- if chunkLen == 0 {
- err = ErrBlobBadLen
- return
- }
- if chunkLen >= (1 << 63) {
+ if chunkLen >= (1<<63)-1 {
err = ErrLenTooBig
return
}
+ chunkLen++
item.V = chunkLen
case AtomFloat16, AtomFloat32, AtomFloat64, AtomFloat128, AtomFloat256:
func AtomBlobEncode(buf []byte, chunkLen int) []byte {
l := make([]byte, 9)
l[0] = byte(AtomBlob)
- ToBE(l[1:], uint64(chunkLen))
+ ToBE(l[1:], uint64(chunkLen-1))
return append(buf, l...)
}
if isinstance(v, Blob):
v = v.v
l = v.l
- assert (l > 0) and (l <= ((1<<64)-1))
+ assert (l > 0) and (l <= (1<<64))
self.v = v
self.l = l
def encode(self):
- raws = [self.tags[0].to_bytes(1, "big"), self.l.to_bytes(8, "big")]
+ raws = [self.tags[0].to_bytes(1, "big"), (self.l - 1).to_bytes(8, "big")]
chunks = len(self.v) // (self.l)
for i in range(chunks):
raws.append(Nil().encode())
data = data[1:]
if len(data) < 8:
raise NotEnoughData(8)
- l = int.from_bytes(data[:8], "big")
+ l = 1 + int.from_bytes(data[:8], "big")
data = data[8:]
vs = []
while True:
in a streaming way, when data may not fit in memory at once.
64-bit big-endian integer follows the BLOB tag, setting the following
-chunks payload size. Then come zero or more NIL tags with fixed-length
-payload after each of them. Blob is terminated by @ref{Strings, BIN},
-probably having zero length.
+chunks payload size (+1). Then come zero or more NIL tags with
+fixed-length payload after each of them. Blob is terminated by
+@ref{Strings, BIN}, probably having zero length.
Data format definition must specify exact chunk size expected to be
used, if it needs deterministic encoding.
@multitable @columnfractions .5 .5
-@item BLOB(5, "") @tab @code{0B 0000000000000005 80}
-@item BLOB(5, "12345") @tab @code{0B 0000000000000005 01 3132333435 80}
-@item BLOB(5, "123456") @tab @code{0B 0000000000000005 01 3132333435 81 36}
-@item BLOB(500, "123") @tab @code{0B 00000000000001F4 83 313233}
-@item BLOB(2, "12345") @tab @code{0B 0000000000000002 01 3132 01 3334 81 35}
+@item BLOB(5, "") @tab @code{0B 0000000000000004 80}
+@item BLOB(5, "12345") @tab @code{0B 0000000000000004 01 3132333435 80}
+@item BLOB(5, "123456") @tab @code{0B 0000000000000004 01 3132333435 81 36}
+@item BLOB(500, "123") @tab @code{0B 00000000000001F3 83 313233}
+@item BLOB(2, "12345") @tab @code{0B 0000000000000001 01 3132 01 3334 81 35}
@end multitable
proc BLOB {chunkLen v} {
char [expr 0x0B]
- toBE 8 $chunkLen
+ toBE 8 [expr {$chunkLen - 1}]
set vl [string length $v]
set chunks [expr {$vl / $chunkLen}]
for {set i 0} {$i < $chunks} {incr i} {