--- CBOR-XS/XS.pm 2016/04/25 21:44:13 1.56 +++ CBOR-XS/XS.pm 2016/11/25 06:13:16 1.62 @@ -66,7 +66,7 @@ use common::sense; -our $VERSION = 1.5; +our $VERSION = 1.51; our @ISA = qw(Exporter); our @EXPORT = qw(encode_cbor decode_cbor); @@ -182,7 +182,7 @@ This means that such values will only be encoded once, and will not result in a deep cloning of the value on decode, in decoders supporting the value sharing extension. This also makes it possible to encode cyclic data -structures (which need C to ne enabled to be decoded by this +structures (which need C to be enabled to be decoded by this module). It is recommended to leave it off unless you know your @@ -442,7 +442,7 @@ subsequent calls to C or C start to parse a new CBOR value from the beginning of the C<$buffer> again. -This method can be caled at any time, but it I be called if you want +This method can be called at any time, but it I be called if you want to change your C<$buffer> or there was a decoding error and you want to reuse the C<$cbor> object for future incremental parsings. @@ -940,6 +940,15 @@ See L for more info. +=item 30 (rational numbers) + +These tags are decoded into L objects. The corresponding +C method encodes rational numbers with denominator +C<1> via their numerator only, i.e., they become normal integers or +C. + +See L for more info. + =item 21, 22, 23 (expected later JSON conversion) CBOR::XS is not a CBOR-to-JSON converter, and will simply ignore these @@ -1010,25 +1019,31 @@ CBOR::XS provides a C method for both L and L that tries to encode the number in the simplest possible way, that is, either a CBOR integer, a CBOR bigint/decimal fraction (tag -4) or an arbitrary-exponent decimal fraction (tag 264). +4) or an arbitrary-exponent decimal fraction (tag 264). Rational numbers +(L, tag 30) can also contain bignums as members. -It will also understand base-2 bigfloat or arbitrary-exponent bigfloats -(tags 5 and 265), but it will never generate these on its own. +CBOR::XS will also understand base-2 bigfloat or arbitrary-exponent +bigfloats (tags 5 and 265), but it will never generate these on its own. Using the built-in L support, encoding and decoding decimal fractions is generally fast. Decoding bigints can be slow for very -big numbers, and decoding bigfloats or arbitrary-exponent bigfloats can be -extremely slow (minutes, decades) for large exponents. +big numbers (tens of thousands of digits, something that could potentially +be caught by limiting the size of CBOR texts), and decoding bigfloats or +arbitrary-exponent bigfloats can be I slow (minutes, decades) +for large exponents (roughly 40 bit and longer). Additionally, L can take advantage of other bignum -libraries, such as L, which cannot handle big -floats with large exponents, and might simply abort or crash your program, -due to their code quality. +libraries, such as L, which cannot handle big floats with large +exponents, and might simply abort or crash your program, due to their code +quality. This can be a concern if you want to parse untrusted CBOR. If it is, you -need to disable decoding of tag 2 (bigint) and 3 (negative bigint) types, -which will also disable bigfloat support (to be sure, you can also disable -types 4, 5, 264 and 265). +might want to disable decoding of tag 2 (bigint) and 3 (negative bigint) +types. You should also disable types 5 and 265, as these can be slow even +without bigints. + +Disabling bigints will also partially or fully disable types that rely on +them, e.g. rational numbers that use bignums. =head1 CBOR IMPLEMENTATION NOTES @@ -1112,12 +1127,12 @@ 2 => sub { # pos bigint require Math::BigInt; - Math::BigInt->from_hex ("0x" . unpack "H*", pop) + Math::BigInt->new ("0x" . unpack "H*", pop) }, 3 => sub { # neg bigint require Math::BigInt; - -Math::BigInt->from_hex ("0x" . unpack "H*", pop) + -Math::BigInt->new ("0x" . unpack "H*", pop) }, 4 => sub { # decimal fraction, array @@ -1125,11 +1140,26 @@ Math::BigFloat->new ($_[1][1] . "E" . $_[1][0]) }, + 264 => sub { # decimal fraction with arbitrary exponent + require Math::BigFloat; + Math::BigFloat->new ($_[1][1] . "E" . $_[1][0]) + }, + 5 => sub { # bigfloat, array require Math::BigFloat; scalar Math::BigFloat->new ($_[1][1]) * Math::BigFloat->new (2)->bpow ($_[1][0]) }, + 265 => sub { # bigfloat with arbitrary exponent + require Math::BigFloat; + scalar Math::BigFloat->new ($_[1][1]) * Math::BigFloat->new (2)->bpow ($_[1][0]) + }, + + 30 => sub { # rational number + require Math::BigRat; + Math::BigRat->new ("$_[1][0]/$_[1][1]") # separate parameters only work in recent versons + }, + 21 => sub { pop }, # expected conversion to base64url encoding 22 => sub { pop }, # expected conversion to base64 encoding 23 => sub { pop }, # expected conversion to base16 encoding @@ -1145,16 +1175,6 @@ # 34 # base64 rfc46484, utf-8 # 35 # regex pcre/ecma262, utf-8 # 36 # mime message rfc2045, utf-8 - - 264 => sub { # decimal fraction with arbitrary exponent - require Math::BigFloat; - Math::BigFloat->new ($_[1][1] . "E" . $_[1][0]) - }, - - 265 => sub { # bigfloat with arbitrary exponent - require Math::BigFloat; - scalar Math::BigFloat->new ($_[1][1]) * Math::BigFloat->new (2)->bpow ($_[1][0]) - }, ); sub CBOR::XS::default_filter { @@ -1185,6 +1205,16 @@ : tag 264, [$e, $m] } +sub Math::BigRat::TO_CBOR { + my ($n, $d) = $_[0]->parts; + + # older versions of BigRat need *1, as they not always return numbers + + $d*1 == 1 + ? $n*1 + : tag 30, [$n*1, $d*1] +} + sub Time::Piece::TO_CBOR { tag 1, 0 + $_[0]->epoch }