--- CBOR-XS/XS.pm 2013/11/20 02:03:08 1.20 +++ CBOR-XS/XS.pm 2013/11/22 15:28:38 1.22 @@ -28,12 +28,12 @@ =head1 DESCRIPTION -WARNING! This module is very new, and not very well tested (that's up to -you to do). Furthermore, details of the implementation might change freely -before version 1.0. And lastly, the object serialisation protocol depends -on a pending IANA assignment, and until that assignment is official, this -implementation is not interoperable with other implementations (even -future versions of this module) until the assignment is done. +WARNING! This module is very new, and not very well tested (that's up +to you to do). Furthermore, details of the implementation might change +freely before version 1.0. And lastly, most extensions depend on an IANA +assignment, and until that assignment is official, this implementation is +not interoperable with other implementations (even future versions of this +module) until the assignment is done. You are still invited to try out CBOR, and this module. @@ -56,6 +56,11 @@ As for compactness, C encoded data structures are usually about 20% smaller than the same data encoded as (compact) JSON or L. +In addition to the core CBOR data format, this module implements a number +of extensions, to support cyclic and self-referencing data structures +(see C), string deduplication (see C) and +scalar references (always enabled). + The primary goal of this module is to be I and the secondary goal is to be I. To reach the latter goal it was written in C. @@ -186,6 +191,10 @@ in a deep cloning of the value on decode, in decoders supporting the value sharing extension. +It is recommended to leave it off unless you know your +communication partner supports the value sharing extensions to CBOR +(http://cbor.schmorp.de/value-sharing). + Detecting shared values incurs a runtime overhead when values are encoded that have a reference counter large than one, and might unnecessarily increase the encoded size, as potentially shared values are encode as @@ -201,9 +210,27 @@ exception when it encounters anything it cannot encode as CBOR. This option does not affect C in any way - shared values and -references will always be decoded properly if present. It is recommended -to leave it off unless you know your communications partner supports the -value sharing extensions to CBOR (http://cbor.schmorp.de/value-sharing). +references will always be decoded properly if present. + +=item $cbor = $cbor->allow_stringref ([$enable]) + +=item $enabled = $cbor->get_allow_stringref + +If C<$enable> is true (or missing), then C will try not to encode +the same string twice, but will instead encode a reference to the string +instead. Depending on your data format. this can save a lot of space, but +also results in a very large runtime overhead (expect encoding times to be +2-4 times as high as without). + +It is recommended to leave it off unless you know your +communications partner supports the stringref extension to CBOR +(http://cbor.schmorp.de/stringref). + +If C<$enable> is false (the default), then C will encode +exception when it encounters anything it cannot encode as CBOR. + +This option does not affect C in any way - string references will +always be decoded properly if present. =item $cbor_data = $cbor->encode ($perl_scalar) @@ -602,13 +629,19 @@ =head1 TAG HANDLING AND EXTENSIONS -This section describes how this module handles specific tagged values and -extensions. If a tag is not mentioned here, then the default handling -applies (creating a CBOR::XS::Tagged object on decoding, and only encoding -the tag when explicitly requested). +This section describes how this module handles specific tagged values +and extensions. If a tag is not mentioned here and no additional filters +are provided for it, then the default handling applies (creating a +CBOR::XS::Tagged object on decoding, and only encoding the tag when +explicitly requested). Future versions of this module reserve the right to special case -additional tags (such as bigfloat or base64url). +additional tags (such as base64url). + +=head2 ENFORCED TAGS + +These tags are always handled when decoding, and their handling cannot be +overriden by the user. =over 4 @@ -624,6 +657,11 @@ shared values in the decoded object. They are only encoded, however, when C is enabled. +=item , (stringref-namespace, stringref, L ) + +These tags are automatically decoded when encountered. They are only +encoded, however, when C is enabled. + =item 22098 (indirection, L) This tag is automatically generated when a reference are encountered (with @@ -637,6 +675,94 @@ =back +=head2 OPTIONAL TAGS + +These tags have default filters provided when decoding. Their handling can +be overriden by changing the C<%CBOR::XS::FILTER> entry for the tag, or by +providing a custom C function when decoding. + +When they result in decoding into a specific Perl class, the module +usually provides a corresponding C method as well. + +When any of these need to load additional modules that are not part of the +perl core distribution (e.g. L), it is (currently) up to the user to +provide these modules. The decoding usually fails with an exception if the +required module cannot be loaded. + +=over 4 + +=item 2, 3 (positive/negative bignum) + +These tags are decoded into L objects. The corresponding +C method encodes "small" bigints into normal CBOR +integers, and others into positive/negative CBOR bignums. + +=item 4, 5 (decimal fraction/bigfloat) + +Both decimal fractions and bigfloats are decoded into L +objects. The corresponding C method I +encodes into a decimal fraction. + +CBOR cannot represent bigfloats with I large exponents - conversion +of such big float objects is undefined. + +Also, NaN and infinities are not encoded properly. + +=item 21, 22, 23 (expected later JSON conversion) + +CBOR::XS is not a CBOR-to-JSON converter, and will simply ignore these +tags. + +=item 32 (URI) + +These objects decode into L objects. The corresponding +C method again results in a CBOR URI value. + +=back + +=cut + +our %FILTER = ( + # 0 # rfc4287 datetime, utf-8 + # 1 # unix timestamp, any + + 2 => sub { # pos bigint + require Math::BigInt; + Math::BigInt->new ("0x" . unpack "H*", pop) + }, + + 3 => sub { # neg bigint + require Math::BigInt; + -Math::BigInt->new ("0x" . unpack "H*", pop) + }, + + 4 => sub { # decimal fraction, array + require Math::BigFloat; + Math::BigFloat->new ($_[1][1] . "E" . $_[1][0]) + }, + + 5 => sub { # bigfloat, array + require Math::BigFloat; + scalar Math::BigFloat->new ($_[1][1])->blsft ($_[1][0], 2) + }, + + 21 => sub { pop }, # expected conversion to base64url encoding + 22 => sub { pop }, # expected conversion to base64 encoding + 23 => sub { pop }, # expected conversion to base16 encoding + + # 24 # embedded cbor, byte string + + 32 => sub { + require URI; + URI->new (pop) + }, + + # 33 # base64url rfc4648, utf-8 + # 34 # base64 rfc46484, utf-8 + # 35 # regex pcre/ecma262, utf-8 + # 36 # mime message rfc2045, utf-8 +); + =head1 CBOR and JSON @@ -728,6 +854,72 @@ =cut +our %FILTER = ( + # 0 # rfc4287 datetime, utf-8 + # 1 # unix timestamp, any + + 2 => sub { # pos bigint + require Math::BigInt; + Math::BigInt->new ("0x" . unpack "H*", pop) + }, + + 3 => sub { # neg bigint + require Math::BigInt; + -Math::BigInt->new ("0x" . unpack "H*", pop) + }, + + 4 => sub { # decimal fraction, array + require Math::BigFloat; + Math::BigFloat->new ($_[1][1] . "E" . $_[1][0]) + }, + + 5 => sub { # bigfloat, array + require Math::BigFloat; + scalar Math::BigFloat->new ($_[1][1])->blsft ($_[1][0], 2) + }, + + 21 => sub { pop }, # expected conversion to base64url encoding + 22 => sub { pop }, # expected conversion to base64 encoding + 23 => sub { pop }, # expected conversion to base16 encoding + + # 24 # embedded cbor, byte string + + 32 => sub { + require URI; + URI->new (pop) + }, + + # 33 # base64url rfc4648, utf-8 + # 34 # base64 rfc46484, utf-8 + # 35 # regex pcre/ecma262, utf-8 + # 36 # mime message rfc2045, utf-8 +); + +sub CBOR::XS::default_filter { + &{ $FILTER{$_[0]} or return } +} + +sub URI::TO_CBOR { + my $uri = $_[0]->as_string; + utf8::upgrade $uri; + CBOR::XS::tag 32, $uri +} + +sub Math::BigInt::TO_CBOR { + if ($_[0] >= -2147483648 && $_[0] <= 2147483647) { + $_[0]->numify + } else { + my $hex = substr $_[0]->as_hex, 2; + $hex = "0$hex" if 1 & length $hex; # sigh + CBOR::XS::tag $_[0] >= 0 ? 2 : 3, pack "H*", $hex + } +} + +sub Math::BigFloat::TO_CBOR { + my ($m, $e) = $_[0]->parts; + CBOR::XS::tag 4, [$e->numify, $m] +} + XSLoader::load "CBOR::XS", $VERSION; =head1 SEE ALSO