Skip to content

Commit

Permalink
Refactor to remove magic number 31 (indef length)
Browse files Browse the repository at this point in the history
  • Loading branch information
fxamacker committed May 27, 2024
1 parent b75278b commit 6d25a5c
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 35 deletions.
76 changes: 46 additions & 30 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -1324,24 +1324,29 @@ 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) {
return getType(b), getAdditionalInformation(b)
}

const (
maxAdditionalInformationWithoutArgument = 23
additionalInformationWith1ByteArgument = 24
additionalInformationWith2ByteArgument = 25
additionalInformationWith4ByteArgument = 26
additionalInformationWith8ByteArgument = 27
maxAdditionalInformationWithoutArgument = 23
additionalInformationWith1ByteArgument = 24
additionalInformationWith2ByteArgument = 25
additionalInformationWith4ByteArgument = 26
additionalInformationWith8ByteArgument = 27
additionalInformationAsIndefiniteLengthFlag = 31
)

const (
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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()
Expand Down Expand Up @@ -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{}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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",
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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])
Expand Down
25 changes: 20 additions & 5 deletions valid.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}
}
Expand All @@ -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}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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()}
Expand Down

0 comments on commit 6d25a5c

Please sign in to comment.