From 5be5e3b20e7cebcc99c4bc4ca3f4311496ecb4fb Mon Sep 17 00:00:00 2001 From: Alberto Restifo Date: Fri, 24 Apr 2020 11:57:12 +0200 Subject: [PATCH] Add support for big numbers --- spec/rfc_spec.cr | 6 +++--- src/cbor.cr | 2 ++ src/cbor/diagnostic.cr | 23 ++++++++++++++++++++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/spec/rfc_spec.cr b/spec/rfc_spec.cr index 2ffe10f..534ed90 100644 --- a/spec/rfc_spec.cr +++ b/spec/rfc_spec.cr @@ -27,9 +27,9 @@ tests = [ { %(1000000), "1a 00 0f 42 40" }, { %(1000000000000), "1b 00 00 00 e8 d4 a5 10 00" }, { %(18446744073709551615), "1b ff ff ff ff ff ff ff ff" }, - # { %(18446744073709551616), "c2 49 01 00 00 00 00 00 00 00 00" }, + { %(18446744073709551616), "c2 49 01 00 00 00 00 00 00 00 00" }, { %(-18446744073709551616), "3b ff ff ff ff ff ff ff ff" }, - # { %(-18446744073709551617), "c3 49 01 00 00 00 00 00 00 00 00" }, + { %(-18446744073709551617), "c3 49 01 00 00 00 00 00 00 00 00" }, { %(-1), "20" }, { %(-10), "29" }, { %(-100), "38 63" }, @@ -54,7 +54,7 @@ tests = [ { %(simple(255)), "f8 ff" }, { %(0("2013-03-21T20:04:00Z")), "c0 74 32 30 31 33 2d 30 33 2d 32 31 54 32 30 3a 30 34 3a 30 30 5a" }, { %(1(1363896240)), "c1 1a 51 4b 67 b0" }, - # { %(1(1363896240.5)), "c1 fb 41 d4 52 d9 ec 20 00 00" }, + { %(1(1363896240.5)), "c1 fb 41 d4 52 d9 ec 20 00 00" }, { %(23(h'01020304')), "d7 44 01 02 03 04" }, { %(24(h'6449455446')), "d8 18 45 64 49 45 54 46" }, { %(32("http://www.example.com")), "d8 20 76 68 74 74 70 3a 2f 2f 77 77 77 2e 65 78 61 6d 70 6c 65 2e 63 6f 6d" }, diff --git a/src/cbor.cr b/src/cbor.cr index 8418855..a1312c9 100644 --- a/src/cbor.cr +++ b/src/cbor.cr @@ -1,3 +1,5 @@ +require "big" + require "./cbor/**" # TODO: Write documentation for `CBOR` diff --git a/src/cbor/diagnostic.cr b/src/cbor/diagnostic.cr index da06286..6d58652 100644 --- a/src/cbor/diagnostic.cr +++ b/src/cbor/diagnostic.cr @@ -53,7 +53,14 @@ class CBOR::Diagnostic when Token::SimpleValueT token.value.to_diagnostic when Token::TagT - "#{token.value.value.to_s}(#{next_value})" + case token.value + when Tag::PositiveBigNum + read_big_int + when Tag::NegativeBigNum + read_big_int(negative: true) + else + "#{token.value.value.to_s}(#{next_value})" + end when Token::FloatT return "NaN" if token.value.nan? return token.value.to_s if token.value.finite? @@ -103,6 +110,20 @@ class CBOR::Diagnostic key_pairs end + private def read_big_int(negative : Bool = false) : String + token = @lexer.next_token + raise ParseError.new("Unexpected EOF after tag") unless token + raise ParseError.new("Unexpected type #{token.class}, want Token::BytesT") unless token.is_a?(Token::BytesT) + + big = BigInt.new(token.value.hexstring, 16) + if negative + big *= -1 + big -= 1 + end + + big.to_s + end + private def key_value(key : Token::T, value : Token::T) : String "#{to_diagnostic(key)}: #{to_diagnostic(value)}" end