summaryrefslogtreecommitdiff
path: root/perl/lib/Data
diff options
context:
space:
mode:
authorgfx <gfuji@cpan.org>2010-09-18 14:30:08 +0900
committergfx <gfuji@cpan.org>2010-09-18 14:30:08 +0900
commitc707392a5a9307504595f6fb9f11930a6a514531 (patch)
tree6969ef44edb4178f5e736a4187bc92f4a3fd7acb /perl/lib/Data
parent1f07721ec41147e02fa49aea19a3f6aa7b1eb723 (diff)
downloadmsgpack-python-c707392a5a9307504595f6fb9f11930a6a514531.tar.gz
perl: fix int64_t unpacking in both XS and PP
Diffstat (limited to 'perl/lib/Data')
-rw-r--r--perl/lib/Data/MessagePack/PP.pm67
1 files changed, 41 insertions, 26 deletions
diff --git a/perl/lib/Data/MessagePack/PP.pm b/perl/lib/Data/MessagePack/PP.pm
index abb6e9a..c3ce230 100644
--- a/perl/lib/Data/MessagePack/PP.pm
+++ b/perl/lib/Data/MessagePack/PP.pm
@@ -16,12 +16,44 @@ use strict;
use B ();
BEGIN {
+ my $unpack_int64_slow;
+ my $unpack_uint64_slow;
+
+ if(!eval { pack 'Q', 1 }) { # don't have quad types
+ $unpack_int64_slow = sub {
+ require Math::BigInt;
+ my $high = Math::BigInt->new( unpack_int32( $_[0], $_[1]) );
+ my $low = Math::BigInt->new( unpack_uint32( $_[0], $_[1] + 4) );
+
+ return +($high << 32 | $low)->bstr;
+ };
+ $unpack_uint64_slow = sub {
+ require Math::BigInt;
+ my $high = Math::BigInt->new( unpack_uint32( $_[0], $_[1]) );
+ my $low = Math::BigInt->new( unpack_uint32( $_[0], $_[1] + 4) );
+ return +($high << 32 | $low)->bstr;
+ };
+ }
+
+ *unpack_uint16 = sub { return unpack 'n', substr( $_[0], $_[1], 2 ) };
+ *unpack_uint32 = sub { return unpack 'N', substr( $_[0], $_[1], 4 ) };
+
# for pack and unpack compatibility
if ( $] < 5.010 ) {
# require $Config{byteorder}; my $bo_is_le = ( $Config{byteorder} =~ /^1234/ );
# which better?
my $bo_is_le = unpack ( 'd', "\x00\x00\x00\x00\x00\x00\xf0\x3f") == 1; # 1.0LE
+ *unpack_int16 = sub {
+ my $v = unpack 'n', substr( $_[0], $_[1], 2 );
+ return $v ? $v - 0x10000 : 0;
+ };
+ *unpack_int32 = sub {
+ no warnings; # avoid for warning about Hexadecimal number
+ my $v = unpack 'N', substr( $_[0], $_[1], 4 );
+ return $v ? $v - 0x100000000 : 0;
+ };
+
# In reality, since 5.9.2 '>' is introduced. but 'n!' and 'N!'?
if($bo_is_le) {
*pack_uint64 = sub {
@@ -46,20 +78,11 @@ BEGIN {
return unpack( 'd', pack( 'N2', @v[1,0] ) );
};
- *unpack_int16 = sub {
- my $v = unpack 'n', substr( $_[0], $_[1], 2 );
- return $v ? $v - 0x10000 : 0;
- };
- *unpack_int32 = sub {
- no warnings; # avoid for warning about Hexadecimal number
- my $v = unpack 'N', substr( $_[0], $_[1], 4 );
- return $v ? $v - 0x100000000 : 0;
- };
- *unpack_int64 = sub {
+ *unpack_int64 = $unpack_int64_slow ||_sub {
my @v = unpack( 'V*', substr( $_[0], $_[1], 8 ) );
return unpack( 'q', pack( 'N2', @v[1,0] ) );
};
- *unpack_uint64 = sub {
+ *unpack_uint64 = $unpack_uint64_slow || sub {
my @v = unpack( 'V*', substr( $_[0], $_[1], 8 ) );
return unpack( 'Q', pack( 'N2', @v[1,0] ) );
};
@@ -71,17 +94,8 @@ BEGIN {
*unpack_float = sub { return unpack( 'f', substr( $_[0], $_[1], 4 ) ); };
*unpack_double = sub { return unpack( 'd', substr( $_[0], $_[1], 8 ) ); };
- *unpack_int16 = sub {
- my $v = unpack 'n', substr( $_[0], $_[1], 2 );
- return $v ? $v - 0x10000 : 0;
- };
- *unpack_int32 = sub {
- no warnings; # avoid for warning about Hexadecimal number
- my $v = unpack 'N', substr( $_[0], $_[1], 4 );
- return $v ? $v - 0x100000000 : 0;
- };
- *unpack_int64 = sub { pack 'q', substr( $_[0], $_[1], 8 ); };
- *unpack_uint64 = sub { pack 'Q', substr( $_[0], $_[1], 8 ); };
+ *unpack_int64 = $unpack_int64_slow || sub { pack 'q', substr( $_[0], $_[1], 8 ); };
+ *unpack_uint64 = $unpack_uint64_slow || sub { pack 'Q', substr( $_[0], $_[1], 8 ); };
}
}
else {
@@ -93,8 +107,9 @@ BEGIN {
*unpack_double = sub { return unpack( 'd>', substr( $_[0], $_[1], 8 ) ); };
*unpack_int16 = sub { return unpack( 'n!', substr( $_[0], $_[1], 2 ) ); };
*unpack_int32 = sub { return unpack( 'N!', substr( $_[0], $_[1], 4 ) ); };
- *unpack_int64 = sub { return unpack( 'q>', substr( $_[0], $_[1], 8 ) ); };
- *unpack_uint64 = sub { return unpack( 'Q>', substr( $_[0], $_[1], 8 ) ); };
+
+ *unpack_int64 = $unpack_int64_slow || sub { return unpack( 'q>', substr( $_[0], $_[1], 8 ) ); };
+ *unpack_uint64 = $unpack_uint64_slow || sub { return unpack( 'Q>', substr( $_[0], $_[1], 8 ) ); };
}
}
@@ -283,11 +298,11 @@ sub _unpack {
}
elsif ( $byte == 0xcd ) { # uint16
$p += 2;
- return CORE::unpack 'n', substr( $value, $p - 2, 2 );
+ return unpack_uint16( $value, $p - 2 );
}
elsif ( $byte == 0xce ) { # unit32
$p += 4;
- return CORE::unpack 'N', substr( $value, $p - 4, 4 );
+ return unpack_uint32( $value, $p - 4 );
}
elsif ( $byte == 0xcf ) { # unit64
$p += 8;