From 6d25a5c62422fb00e12fd7576833cd876f02d8ff Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Mon, 27 May 2024 18:03:56 -0500 Subject: [PATCH] Refactor to remove magic number 31 (indef length) --- decode.go | 76 +++++++++++++++++++++++++++++++++---------------------- valid.go | 25 ++++++++++++++---- 2 files changed, 66 insertions(+), 35 deletions(-) diff --git a/decode.go b/decode.go index 4760d692..ba58bca0 100644 --- a/decode.go +++ b/decode.go @@ -1324,12 +1324,16 @@ const ( additionalInformationMask = 0x1f ) -func getType(b byte) cborType { - return cborType(b & typeMask) +func getType(raw byte) cborType { + return cborType(raw & typeMask) } -func getAdditionalInformation(b byte) byte { - return b & additionalInformationMask +func getAdditionalInformation(raw byte) byte { + return raw & additionalInformationMask +} + +func isIndefiniteLength(ai byte) bool { + return ai == additionalInformationAsIndefiniteLengthFlag } func parseInitialByte(b byte) (t cborType, ai byte) { @@ -1337,11 +1341,12 @@ func parseInitialByte(b byte) (t cborType, ai byte) { } const ( - maxAdditionalInformationWithoutArgument = 23 - additionalInformationWith1ByteArgument = 24 - additionalInformationWith2ByteArgument = 25 - additionalInformationWith4ByteArgument = 26 - additionalInformationWith8ByteArgument = 27 + maxAdditionalInformationWithoutArgument = 23 + additionalInformationWith1ByteArgument = 24 + additionalInformationWith2ByteArgument = 25 + additionalInformationWith4ByteArgument = 26 + additionalInformationWith8ByteArgument = 27 + additionalInformationAsIndefiniteLengthFlag = 31 ) const ( @@ -2049,8 +2054,8 @@ func (d *decoder) parse(skipSelfDescribedTag bool) (interface{}, error) { //noli // and only if the slice is backed by a copy of the input. Callers are // responsible for making a copy if necessary. func (d *decoder) parseByteString() ([]byte, bool) { - _, ai, val := d.getHead() - if ai != 31 { + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + if !indefiniteLength { b := d.data[d.off : d.off+int(val)] d.off += int(val) return b, false @@ -2141,8 +2146,8 @@ func (d *decoder) applyByteStringTextConversion( // to prevent creating an extra copy of string. Caller should wrap returned // byte slice as string when needed. func (d *decoder) parseTextString() ([]byte, error) { - _, ai, val := d.getHead() - if ai != 31 { + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + if !indefiniteLength { b := d.data[d.off : d.off+int(val)] d.off += int(val) if d.dm.utf8 == UTF8RejectInvalid && !utf8.Valid(b) { @@ -2168,8 +2173,8 @@ func (d *decoder) parseTextString() ([]byte, error) { } func (d *decoder) parseArray() ([]interface{}, error) { - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) if !hasSize { count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance @@ -2190,8 +2195,8 @@ func (d *decoder) parseArray() ([]interface{}, error) { } func (d *decoder) parseArrayToSlice(v reflect.Value, tInfo *typeInfo) error { - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) if !hasSize { count = d.numOfItemsUntilBreak() // peek ahead to get array size to preallocate slice for better performance @@ -2212,8 +2217,8 @@ func (d *decoder) parseArrayToSlice(v reflect.Value, tInfo *typeInfo) error { } func (d *decoder) parseArrayToArray(v reflect.Value, tInfo *typeInfo) error { - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) gi := 0 vLen := v.Len() @@ -2242,8 +2247,8 @@ func (d *decoder) parseArrayToArray(v reflect.Value, tInfo *typeInfo) error { } func (d *decoder) parseMap() (interface{}, error) { - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) m := make(map[interface{}]interface{}) var k, e interface{} @@ -2307,8 +2312,8 @@ func (d *decoder) parseMap() (interface{}, error) { } func (d *decoder) parseMapToMap(v reflect.Value, tInfo *typeInfo) error { //nolint:gocyclo - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) if v.IsNil() { mapsize := count @@ -2432,8 +2437,8 @@ func (d *decoder) parseArrayToStruct(v reflect.Value, tInfo *typeInfo) error { } start := d.off - t, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) if !hasSize { count = d.numOfItemsUntilBreak() // peek ahead to get array size @@ -2442,7 +2447,7 @@ func (d *decoder) parseArrayToStruct(v reflect.Value, tInfo *typeInfo) error { d.off = start d.skip() return &UnmarshalTypeError{ - CBORType: t.String(), + CBORType: cborTypeArray.String(), GoType: tInfo.typ.String(), errorMsg: "cannot decode CBOR array to struct with different number of elements", } @@ -2507,8 +2512,8 @@ func (d *decoder) parseMapToStruct(v reflect.Value, tInfo *typeInfo) error { //n var err, lastErr error // Get CBOR map size - _, ai, val := d.getHead() - hasSize := (ai != 31) + _, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() + hasSize := !indefiniteLength count := int(val) // Keeps track of matched struct fields @@ -2791,9 +2796,9 @@ func (d *decoder) getRegisteredTagItem(vt reflect.Type) *tagItem { // skip moves data offset to the next item. skip assumes data is well-formed, // and does not perform bounds checking. func (d *decoder) skip() { - t, ai, val := d.getHead() + t, _, val, indefiniteLength := d.getHeadWithIndefiniteLengthFlag() - if ai == 31 { + if indefiniteLength { switch t { case cborTypeByteString, cborTypeTextString, cborTypeArray, cborTypeMap: for { @@ -2822,6 +2827,17 @@ func (d *decoder) skip() { } } +func (d *decoder) getHeadWithIndefiniteLengthFlag() ( + t cborType, + ai byte, + val uint64, + indefiniteLength bool, +) { + t, ai, val = d.getHead() + indefiniteLength = isIndefiniteLength(ai) + return +} + // getHead assumes data is well-formed, and does not perform bounds checking. func (d *decoder) getHead() (t cborType, ai byte, val uint64) { t, ai = parseInitialByte(d.data[d.off]) diff --git a/valid.go b/valid.go index a60f6139..95dc74ee 100644 --- a/valid.go +++ b/valid.go @@ -100,14 +100,14 @@ func (d *decoder) wellformed(allowExtraData bool, checkBuiltinTags bool) error { // wellformedInternal checks data's well-formedness and returns max depth and error. func (d *decoder) wellformedInternal(depth int, checkBuiltinTags bool) (int, error) { //nolint:gocyclo - t, ai, val, err := d.wellformedHead() + t, _, val, indefiniteLength, err := d.wellformedHeadWithIndefiniteLengthFlag() if err != nil { return 0, err } switch t { case cborTypeByteString, cborTypeTextString: - if ai == 31 { + if indefiniteLength { if d.dm.indefLength == IndefLengthForbidden { return 0, &IndefiniteLengthError{t} } @@ -129,7 +129,7 @@ func (d *decoder) wellformedInternal(depth int, checkBuiltinTags bool) (int, err return 0, &MaxNestedLevelError{d.dm.maxNestedLevels} } - if ai == 31 { + if indefiniteLength { if d.dm.indefLength == IndefLengthForbidden { return 0, &IndefiniteLengthError{t} } @@ -228,7 +228,7 @@ func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltin if t != nt { return 0, &SyntaxError{"cbor: wrong element type " + nt.String() + " for indefinite-length " + t.String()} } - if ai == 31 { + if isIndefiniteLength(ai) { return 0, &SyntaxError{"cbor: indefinite-length " + t.String() + " chunk is not definite-length"} } if depth, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil { @@ -275,6 +275,21 @@ func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int, checkBui return maxDepth, nil } +func (d *decoder) wellformedHeadWithIndefiniteLengthFlag() ( + t cborType, + ai byte, + val uint64, + indefiniteLength bool, + err error, +) { + t, ai, val, err = d.wellformedHead() + if err != nil { + return + } + indefiniteLength = isIndefiniteLength(ai) + return +} + func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error) { dataLen := len(d.data) - d.off if dataLen == 0 { @@ -348,7 +363,7 @@ func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error) return t, ai, val, nil } - if ai == 31 { + if isIndefiniteLength(ai) { switch t { case cborTypePositiveInt, cborTypeNegativeInt, cborTypeTag: return 0, 0, 0, &SyntaxError{"cbor: invalid additional information " + strconv.Itoa(int(ai)) + " for type " + t.String()}