return "TAI64NonMinimal";
case YACErrMapBadKey:
return "MapBadKey";
- case YACErrMapNoVal:
- return "MapNoVal";
case YACErrMapUnordered:
return "MapUnordered";
case YACErrNoMem:
return "UnsatisfiedSchema";
case YACErrDeepRecursion:
return "DeepRecursion";
+ case YACErrUnexpectedEOC:
+ return "UnexpectedEOC";
default:
return "unknown";
}
// Invalid TAI64 attoseconds value.
// @item YACErrMapBadKey
// Either bad type of map's key, or it is empty.
-// @item YACErrMapNoVal
-// Missing value in a map.
// @item YACErrMapUnordered
// Unordered map keys.
// @item YACErrNoMem
// Unsatisfied structure's schema.
// @item YACErrDeepRecursion
// Too deep recursion involved during parsing.
+// @item YACErrUnexpectedEOC
+// Unexpected EOC met.
// @end table
// @end deftp
enum YACErr {
YACErrTAI64IsLeap,
YACErrTAI64NonMinimal,
YACErrMapBadKey,
- YACErrMapNoVal,
YACErrMapUnordered,
YACErrNoMem,
YACErrUnsatisfiedSchema,
YACErrDeepRecursion,
+ YACErrUnexpectedEOC,
};
// TEXINFO: YACErr2Str
const unsigned char *buf,
const size_t len,
const bool allowContainers,
+ const bool expectEOC,
const size_t recursionDepth)
{
if (recursionDepth >= parseMaxRecursionDepth) {
#pragma clang diagnostic ignored "-Wswitch-enum"
switch (items->list[item].atom.typ) {
#pragma clang diagnostic pop
+ case YACItemEOC:
+ if (!expectEOC) {
+ return YACErrUnexpectedEOC;
+ }
case YACItemList: {
if (!allowContainers) {
return YACErrUnknownType;
size_t cur = 0;
size_t idx = item;
for (;;) {
- err = yacItemsParse(items, off, buf, len, true, recursionDepth + 1);
+ err = yacItemsParse(items, off, buf, len, true, true, recursionDepth + 1);
if (err != YACErrNo) {
return err;
}
size_t prevKeyLen = 0;
const unsigned char *prevKey = NULL;
for (;;) {
- err = yacItemsParse(items, off, buf, len, false, recursionDepth + 1);
+ err = yacItemsParse(items, off, buf, len, false, true, recursionDepth + 1);
if (err != YACErrNo) {
return err;
}
}
prev = cur;
idx = (items->len) - 1;
- err = yacItemsParse(items, off, buf, len, true, recursionDepth + 1);
+ err = yacItemsParse(items, off, buf, len, true, false, recursionDepth + 1);
if (err != YACErrNo) {
return err;
}
cur = idx + 1;
- if (items->list[cur].atom.typ == YACItemEOC) {
- return YACErrMapNoVal;
- }
items->list[prev].next = cur;
prev = cur;
idx = (items->len) - 1;
size_t cur = 0;
bool eoc = false;
while (!eoc) {
- err = yacItemsParse(items, off, buf, len, false, recursionDepth + 1);
+ err = yacItemsParse(items, off, buf, len, false, true, recursionDepth + 1);
if (err != YACErrNo) {
return err;
}
const unsigned char *buf,
const size_t len)
{
- return yacItemsParse(items, off, buf, len, true, 0);
+ return yacItemsParse(items, off, buf, len, true, false, 0);
}
bool
}
(*off) += got;
if (atom->typ == YACItemEOC) {
- return YACErrMapNoVal;
+ return YACErrUnexpectedEOC;
}
err = cb(key, keyLen, false, 0, cbState, atom, off, buf, len);
if (err != YACErrNo) {
ErrBadUTF8 = errors.New("invalid UTF-8")
ErrMapBadKey = errors.New("map bad key")
ErrMapUnordered = errors.New("map unordered")
- ErrMapNoVal = errors.New("map no value")
ErrBlobBadAtom = errors.New("blob unexpected atom")
ErrBlobBadTerm = errors.New("blob bad terminator")
+ ErrUnexpectedEOC = errors.New("unexpected EOC")
)
func AtomDecode(buf []byte) (item *Item, off int, err error) {
func itemDecode(
buf []byte,
- allowContainers bool,
+ allowContainers, expectEOC bool,
recursionDepth int,
) (item *Item, tail []byte, err error) {
if recursionDepth > ParseMaxRecursionDepth {
buf = buf[off:]
tail = buf
switch item.Typ() {
+ case ItemEOC:
+ if !expectEOC {
+ err = ErrUnexpectedEOC
+ return
+ }
case ItemList:
if !allowContainers {
err = ErrUnknownType
var sub *Item
var v []*Item
for {
- sub, buf, err = itemDecode(buf, true, recursionDepth+1)
+ sub, buf, err = itemDecode(buf, true, true, recursionDepth+1)
tail = buf
if err != nil {
tail = buf
var sub *Item
var keyPrev string
for {
- sub, buf, err = itemDecode(buf, false, recursionDepth+1)
+ sub, buf, err = itemDecode(buf, false, true, recursionDepth+1)
tail = buf
if err != nil {
return
}
keyPrev = s
}
- sub, buf, err = itemDecode(buf, true, recursionDepth+1)
+ sub, buf, err = itemDecode(buf, true, false, recursionDepth+1)
tail = buf
if err != nil {
return
}
- if sub.T == byte(ItemEOC) {
- err = ErrMapNoVal
- return
- }
v[keyPrev] = sub
}
item.V = v
var sub *Item
BlobCycle:
for {
- sub, buf, err = itemDecode(buf, false, recursionDepth+1)
+ sub, buf, err = itemDecode(buf, false, true, recursionDepth+1)
tail = buf
if err != nil {
return
}
func ItemDecode(buf []byte) (item *Item, tail []byte, err error) {
- return itemDecode(buf, true, 0)
+ return itemDecode(buf, true, false, 0)
}
return secs - diff
-def _loads(v, sets=False, leapsecUTCAllow=False, _allowContainers=True):
+def _loads(v, sets=False, leapsecUTCAllow=False, _expectEOC=False, _allowContainers=True):
if len(v) == 0:
raise NotEnoughData(1)
b = v[0]
if b == TagEOC:
+ if not _expectEOC:
+ raise DecodeError("unexpected EOC")
return _EOC, v[1:]
if b == TagNIL:
return None, v[1:]
ret = []
v = v[1:]
while True:
- i, v = loads(v, sets=sets, leapsecUTCAllow=leapsecUTCAllow)
+ i, v = loads(v, sets=sets, leapsecUTCAllow=leapsecUTCAllow, _expectEOC=True)
if i == _EOC:
break
ret.append(i)
kPrev = ""
allNILs = True
while True:
- k, v = _loads(v, _allowContainers=False)
+ k, v = _loads(v, _expectEOC=True, _allowContainers=False)
if k == _EOC:
break
if not isinstance(k, str):
if len(k) == 0:
raise DecodeError("empty key")
raise DecodeError("unsorted keys")
- i, v = loads(v, sets=sets, leapsecUTCAllow=leapsecUTCAllow)
- if i == _EOC:
- raise DecodeError("unexpected EOC")
+ i, v = loads(v, sets=sets, leapsecUTCAllow=leapsecUTCAllow, _expectEOC=False)
ret[k] = i
kPrev = k
if i is not None:
v = v[1+8:]
raws = []
while True:
- i, v = _loads(v, _allowContainers=False)
+ i, v = _loads(v, _expectEOC=True, _allowContainers=False)
if i is None:
if len(v) < l:
raise NotEnoughData(l-len(v)+1)
@given(binary(min_size=1, max_size=1), binary(max_size=8))
def runTest(self, hdr: bytes, body: bytes) -> None:
self.assertSequenceEqual(dumps(Raw(hdr[0], body)), hdr + body)
+
+
+class TestLonelyEOC(TestCase):
+ def runTest(self) -> None:
+ with self.assertRaises(DecodeError) as err:
+ loads(b"\x00")
+ self.assertEqual(str(err.exception), "unexpected EOC")