From 2d70a30aa95dd9e8515a4e4256d67f825b8e9e7b Mon Sep 17 00:00:00 2001 From: Aurora Gaffney Date: Wed, 12 Jul 2023 21:31:53 -0500 Subject: [PATCH] feat: support for CBOR tags for arbitrarily large ints Fixes #360 --- cbor/value.go | 19 ++++++++++++++++++- cbor/value_test.go | 16 ++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/cbor/value.go b/cbor/value.go index a9f75514..fa14236b 100644 --- a/cbor/value.go +++ b/cbor/value.go @@ -18,6 +18,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "math/big" "sort" "strings" ) @@ -94,7 +95,17 @@ func (v *Value) UnmarshalCBOR(data []byte) error { value: &newValue, } } else { - return fmt.Errorf("unsupported CBOR tag: %d", tmpTag.Number) + // Fall back to standard CBOR tag parsing for our supported types + var tmpTagDecode interface{} + if _, err := Decode(data, &tmpTagDecode); err != nil { + return err + } + switch tmpTagDecode.(type) { + case int, uint, int64, uint64, bool, big.Int: + v.value = tmpTagDecode + default: + return fmt.Errorf("unsupported CBOR tag number: %d", tmpTag.Number) + } } } default: @@ -218,6 +229,12 @@ func generateAstJson(obj interface{}) ([]byte, error) { return []byte(tmpJson), nil case Constructor: return json.Marshal(obj) + case big.Int: + tmpJson := fmt.Sprintf( + `{"int":%s}`, + v.String(), + ) + return []byte(tmpJson), nil case int, uint, uint64, int64: tmpJsonObj["int"] = v case bool: diff --git a/cbor/value_test.go b/cbor/value_test.go index ecb19d7a..4ad92192 100644 --- a/cbor/value_test.go +++ b/cbor/value_test.go @@ -18,6 +18,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "math/big" "reflect" "strings" "testing" @@ -70,6 +71,15 @@ var testDefs = []struct { }, expectedAstJson: `{"map":[{"k":{"int":1},"v":{"list":[{"int":2}]}},{"k":{"int":3},"v":{"list":[{"int":4}]}}]}`, }, + // [22318265904693663008365, 8535038193994223137511702528] + { + cborHex: "82C24A04B9E028911409DC866DC24C1B9404A39BD8000000000000", + expectedObject: []any{ + *(new(big.Int).SetBytes(test.DecodeHexString("04B9E028911409DC866D"))), + *(new(big.Int).SetBytes(test.DecodeHexString("1B9404A39BD8000000000000"))), + }, + expectedAstJson: `{"list":[{"int":22318265904693663008365},{"int":8535038193994223137511702528}]}`, + }, } func TestValueDecode(t *testing.T) { @@ -198,6 +208,12 @@ func TestLazyValueMarshalJSON(t *testing.T) { strings.ToLower(testDef.cborHex), testDef.expectedAstJson, ) + if testDef.expectedObject == nil { + fullExpectedJson = fmt.Sprintf( + `{"cbor":"%s"}`, + strings.ToLower(testDef.cborHex), + ) + } if !test.JsonStringsEqual(jsonData, []byte(fullExpectedJson)) { t.Fatalf("CBOR did not marshal to expected JSON\n got: %s\n wanted: %s", jsonData, fullExpectedJson) }