diff --git a/perl/MessagePack.c b/perl/MessagePack.c index e5835268..6b9010cd 100644 --- a/perl/MessagePack.c +++ b/perl/MessagePack.c @@ -20,10 +20,14 @@ XS(xs_unpacker_data); XS(xs_unpacker_reset); XS(xs_unpacker_destroy); +void boot_Data__MessagePack_pack(void); + XS(boot_Data__MessagePack) { dXSARGS; HV * stash; + boot_Data__MessagePack_pack(); + newXS("Data::MessagePack::pack", xs_pack, __FILE__); newXS("Data::MessagePack::unpack", xs_unpack, __FILE__); stash = gv_stashpvn("Data::MessagePack", strlen("Data::MessagePack"), TRUE); diff --git a/perl/lib/Data/MessagePack.pm b/perl/lib/Data/MessagePack.pm index 2368a5b8..e2046694 100644 --- a/perl/lib/Data/MessagePack.pm +++ b/perl/lib/Data/MessagePack.pm @@ -5,6 +5,7 @@ use XSLoader; use 5.008001; our $VERSION = '0.03'; +our $PreferInteger = 0; XSLoader::load(__PACKAGE__, $VERSION); diff --git a/perl/pack.c b/perl/pack.c index c8987fef..b329551b 100644 --- a/perl/pack.c +++ b/perl/pack.c @@ -26,7 +26,7 @@ typedef struct { char *end; /* SvEND (sv) */ SV *sv; /* result scalar */ } enc_t; -void need(enc_t *enc, STRLEN len); +static void need(enc_t *enc, STRLEN len); #define msgpack_pack_user enc_t* @@ -41,7 +41,7 @@ void need(enc_t *enc, STRLEN len); #define PACK_WRAPPER(t) _PACK_WRAPPER(t) #define INIT_SIZE 32 /* initial scalar size to be allocated */ -void need(enc_t *enc, STRLEN len) +static void need(enc_t *enc, STRLEN len) { if (enc->cur + len >= enc->end) { STRLEN cur = enc->cur - (char *)SvPVX (enc->sv); @@ -51,16 +51,92 @@ void need(enc_t *enc, STRLEN len) } } -static int looks_like_int(const char *str, size_t len) { - int i; - for (i=0; i 11) { return 0; } + negative = 1; + ++p; + } else { + /* length(0xFFFFFFFF) == 10 */ + if (len > 10) { return 0; } + } + +#if '9'=='8'+1 && '8'=='7'+1 && '7'=='6'+1 && '6'=='5'+1 && '5'=='4'+1 \ + && '4'=='3'+1 && '3'=='2'+1 && '2'=='1'+1 && '1'=='0'+1 + do { + unsigned int c = ((int)*(p++)) - '0'; + if (c > 9) { return 0; } + num = num * 10 + c; + } while(p < pe); +#else + do { + switch (*(p++)) { + case '0': num = num * 10 + 0; break; + case '1': num = num * 10 + 1; break; + case '2': num = num * 10 + 2; break; + case '3': num = num * 10 + 3; break; + case '4': num = num * 10 + 4; break; + case '5': num = num * 10 + 5; break; + case '6': num = num * 10 + 6; break; + case '7': num = num * 10 + 7; break; + case '8': num = num * 10 + 8; break; + case '9': num = num * 10 + 9; break; + default: return 0; + } + } while(p < pe); +#endif + + if (negative) { + if (num > 0x80000000) { return 0; } + msgpack_pack_int32(enc, ((int32_t)num) * -1); + } else { + if (num > 0xFFFFFFFF) { return 0; } + msgpack_pack_uint32(enc, (uint32_t)num); + } + return 1; } + static void _msgpack_pack_sv(enc_t *enc, SV* val) { if (val==NULL) { msgpack_pack_nil(enc); @@ -131,11 +207,8 @@ static void _msgpack_pack_sv(enc_t *enc, SV* val) { if (SvPOKp(val)) { STRLEN len; char * cval = SvPV(val, len); - const int U32_STRLEN = 10; /* length(0xFFFFFFFF) */ - SV* pref_int = get_sv("Data::MessagePack::PreferInteger", 0); - if (pref_int && SvTRUE(pref_int) && len <= U32_STRLEN && looks_like_int(cval, len) && SvUV(val) < U32_MAX) { - PACK_WRAPPER(uint32)(enc, SvUV(val)); + if (s_pref_int && try_int(enc, cval, len)) { return; } diff --git a/perl/t/05_preferred_int.t b/perl/t/05_preferred_int.t index 176430eb..39c725a6 100644 --- a/perl/t/05_preferred_int.t +++ b/perl/t/05_preferred_int.t @@ -17,15 +17,24 @@ sub pis ($$) { } my @dat = ( + '', 'a0', '0', '00', '1', '01', - '10', '0a', + '10', '0a', + '-1', 'ff', + '-10', 'f6', + '-', 'a1 2d', ''.0xEFFF => 'cd ef ff', ''.0xFFFF => 'cd ff ff', ''.0xFFFFFF => 'ce 00 ff ff ff', - ''.0xFFFFFFFF => 'aa 34 32 39 34 39 36 37 32 39 35', + ''.0xFFFFFFFF => 'ce ff ff ff ff', ''.0xFFFFFFFFF => 'ab 36 38 37 31 39 34 37 36 37 33 35', ''.0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF => 'b4 38 2e 33 30 37 36 37 34 39 37 33 36 35 35 37 32 65 2b 33 34', + '-'.0x8000000 => 'd2 f8 00 00 00', + '-'.0x80000000 => 'd2 80 00 00 00', + '-'.0x800000000 => 'ac 2d 33 34 33 35 39 37 33 38 33 36 38', + '-'.0x8000000000 => 'ad 2d 35 34 39 37 35 35 38 31 33 38 38 38', + '-'.0x800000000000000000000000000000 => 'b5 2d 36 2e 36 34 36 31 33 39 39 37 38 39 32 34 35 38 65 2b 33 35', {'0' => '1'}, '81 00 01', {'abc' => '1'}, '81 a3 61 62 63 01', );