mirror of
https://github.com/msgpack/msgpack-c.git
synced 2025-03-19 04:52:59 +01:00
added perl support
This commit is contained in:
parent
5bd53f018f
commit
d449b1d20d
34
perl/Makefile.PL
Normal file
34
perl/Makefile.PL
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
use inc::Module::Install;
|
||||||
|
name 'Data-MessagePack';
|
||||||
|
all_from 'lib/Data/MessagePack.pm';
|
||||||
|
|
||||||
|
perl_version '5.008005';
|
||||||
|
license 'perl';
|
||||||
|
can_cc or die "This module requires a C compiler";
|
||||||
|
|
||||||
|
my $ccflags = '-I../ ';
|
||||||
|
|
||||||
|
makemaker_args(
|
||||||
|
OBJECT => '$(O_FILES)',
|
||||||
|
LIBS => [''],
|
||||||
|
CCFLAGS => $ccflags,
|
||||||
|
clean => {
|
||||||
|
FILES => q{
|
||||||
|
*.stackdump
|
||||||
|
*.gcov *.gcda *.gcno
|
||||||
|
*.out
|
||||||
|
nytprof
|
||||||
|
cover_db
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
tests 't/*.t';
|
||||||
|
author_tests('xt');
|
||||||
|
|
||||||
|
auto_set_repository;
|
||||||
|
build_requires 'Test::More';
|
||||||
|
use_test_base;
|
||||||
|
auto_include;
|
||||||
|
WriteAll;
|
||||||
|
|
39
perl/MessagePack.c
Normal file
39
perl/MessagePack.c
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include "EXTERN.h"
|
||||||
|
#include "perl.h"
|
||||||
|
#include "XSUB.h"
|
||||||
|
#include "ppport.h"
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
XS(xs_pack);
|
||||||
|
XS(xs_unpack);
|
||||||
|
XS(xs_unpacker_new);
|
||||||
|
XS(xs_unpacker_execute);
|
||||||
|
XS(xs_unpacker_execute_limit);
|
||||||
|
XS(xs_unpacker_is_finished);
|
||||||
|
XS(xs_unpacker_data);
|
||||||
|
XS(xs_unpacker_reset);
|
||||||
|
|
||||||
|
XS(boot_Data__MessagePack) {
|
||||||
|
dXSARGS;
|
||||||
|
HV * stash;
|
||||||
|
|
||||||
|
newXS("Data::MessagePack::pack", xs_pack, __FILE__);
|
||||||
|
newXS("Data::MessagePack::unpack", xs_unpack, __FILE__);
|
||||||
|
stash = gv_stashpvn("Data::MessagePack", strlen("Data::MessagePack"), TRUE);
|
||||||
|
newCONSTSUB(stash, "true", &PL_sv_yes);
|
||||||
|
newCONSTSUB(stash, "false", &PL_sv_no);
|
||||||
|
|
||||||
|
newXS("Data::MessagePack::Unpacker::new", xs_unpacker_new, __FILE__);
|
||||||
|
newXS("Data::MessagePack::Unpacker::execute", xs_unpacker_execute, __FILE__);
|
||||||
|
newXS("Data::MessagePack::Unpacker::execute_limit", xs_unpacker_execute_limit, __FILE__);
|
||||||
|
newXS("Data::MessagePack::Unpacker::is_finished", xs_unpacker_is_finished, __FILE__);
|
||||||
|
newXS("Data::MessagePack::Unpacker::data", xs_unpacker_data, __FILE__);
|
||||||
|
newXS("Data::MessagePack::Unpacker::reset", xs_unpacker_reset, __FILE__);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
16
perl/benchmark/p1.pl
Normal file
16
perl/benchmark/p1.pl
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Data::MessagePack;
|
||||||
|
use JSON::XS;
|
||||||
|
use Benchmark ':all';
|
||||||
|
|
||||||
|
my $a = [0..2**24];
|
||||||
|
|
||||||
|
print "-- serialize\n";
|
||||||
|
cmpthese(
|
||||||
|
-1 => {
|
||||||
|
json => sub { JSON::XS::encode_json($a) },
|
||||||
|
mp => sub { Data::MessagePack->pack($a) },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
33
perl/lib/Data/MessagePack.pm
Normal file
33
perl/lib/Data/MessagePack.pm
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package Data::MessagePack;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use XSLoader;
|
||||||
|
|
||||||
|
our $VERSION = 0.01;
|
||||||
|
|
||||||
|
XSLoader::load(__PACKAGE__, $VERSION);
|
||||||
|
|
||||||
|
1;
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Data::MessagePack - messagepack
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
my $packed = Data::MessagePack->pack($dat);
|
||||||
|
my $unpacked = Data::MessagePack->unpack($dat);
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Data::MessagePack is a binary packer for perl.
|
||||||
|
|
||||||
|
=head1 AUTHORS
|
||||||
|
|
||||||
|
Tokuhiro Matsuno
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
L<http://msgpack.sourceforge.jp/>
|
||||||
|
|
52
perl/lib/Data/MessagePack/Unpacker.pod
Normal file
52
perl/lib/Data/MessagePack/Unpacker.pod
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Data::MessagePack::Unpacker - messagepack streaming deserializer
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
my $up = Data::MessagePack::Unpacker->new;
|
||||||
|
my $ret = $up->execute($v, 0);
|
||||||
|
if ($ret != length($v)) {
|
||||||
|
fail "extra bytes";
|
||||||
|
}
|
||||||
|
return Dumper($up->data);
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This is an streaming deserializer for messagepack.
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
=over 4
|
||||||
|
|
||||||
|
=item my $up = Data::MessagePack::Unpacker->new()
|
||||||
|
|
||||||
|
create new stream deserializer
|
||||||
|
|
||||||
|
=item $up->execute()
|
||||||
|
|
||||||
|
=item $up->execute_limit()
|
||||||
|
|
||||||
|
=item $up->is_finished()
|
||||||
|
|
||||||
|
is this deserializer finished?
|
||||||
|
|
||||||
|
=item $up->data()
|
||||||
|
|
||||||
|
returns deserialized object.
|
||||||
|
|
||||||
|
=item $up->reset()
|
||||||
|
|
||||||
|
reset the stream deserializer, without memory zone.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 AUTHORS
|
||||||
|
|
||||||
|
Tokuhiro Matsuno
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
L<Data::MessagePack>
|
||||||
|
|
122
perl/pack.c
Normal file
122
perl/pack.c
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include "EXTERN.h"
|
||||||
|
#include "perl.h"
|
||||||
|
#include "XSUB.h"
|
||||||
|
#include "ppport.h"
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "msgpack/pack_define.h"
|
||||||
|
|
||||||
|
#define msgpack_pack_inline_func(name) \
|
||||||
|
static inline void msgpack_pack ## name
|
||||||
|
|
||||||
|
#define msgpack_pack_inline_func_cint(name) \
|
||||||
|
static inline void msgpack_pack ## name
|
||||||
|
|
||||||
|
#define msgpack_pack_user SV*
|
||||||
|
|
||||||
|
#define msgpack_pack_append_buffer(user, buf, len) \
|
||||||
|
sv_catpvn(user, (const char*)(buf), len);
|
||||||
|
|
||||||
|
#include "msgpack/pack_template.h"
|
||||||
|
|
||||||
|
#define _PACK_WRAPPER(t) msgpack_pack_##t
|
||||||
|
#define PACK_WRAPPER(t) _PACK_WRAPPER(t)
|
||||||
|
|
||||||
|
// move to pack.c
|
||||||
|
static void _msgpack_pack_sv(SV* buf, SV* val) {
|
||||||
|
if (val==NULL) {
|
||||||
|
msgpack_pack_nil(buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SvTYPE(val)) {
|
||||||
|
case SVt_NULL:
|
||||||
|
msgpack_pack_nil(buf);
|
||||||
|
break;
|
||||||
|
case SVt_IV:
|
||||||
|
if (SvIOK_UV(val)) {
|
||||||
|
msgpack_pack_uint32(buf, SvUV(val));
|
||||||
|
} else {
|
||||||
|
PACK_WRAPPER(IVTYPE)(buf, SvIV(val));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SVt_PVNV:
|
||||||
|
{
|
||||||
|
STRLEN len = 0;
|
||||||
|
char *pv = SvPV(val, len);
|
||||||
|
if (len == 1 && *pv == '1') {
|
||||||
|
msgpack_pack_true(buf);
|
||||||
|
} else if (len == 0 && *pv==0) {
|
||||||
|
msgpack_pack_false(buf);
|
||||||
|
} else {
|
||||||
|
msgpack_pack_nil(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SVt_PV:
|
||||||
|
{
|
||||||
|
STRLEN len;
|
||||||
|
char * cval = SvPV(val, len);
|
||||||
|
msgpack_pack_raw(buf, len);
|
||||||
|
msgpack_pack_raw_body(buf, cval, len);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SVt_NV:
|
||||||
|
PACK_WRAPPER(NVTYPE)(buf, SvNV(val));
|
||||||
|
break;
|
||||||
|
case SVt_PVAV:
|
||||||
|
{
|
||||||
|
AV* ary = (AV*)val;
|
||||||
|
int len = av_len(ary) + 1;
|
||||||
|
int i;
|
||||||
|
msgpack_pack_array(buf, len);
|
||||||
|
for (i=0; i<len; i++) {
|
||||||
|
SV** svp = av_fetch(ary, i, 0);
|
||||||
|
if (svp) {
|
||||||
|
_msgpack_pack_sv(buf, *svp);
|
||||||
|
} else {
|
||||||
|
msgpack_pack_nil(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SVt_PVHV:
|
||||||
|
{
|
||||||
|
HV* hval = (HV*)val;
|
||||||
|
int count = hv_iterinit(hval);
|
||||||
|
HE* he;
|
||||||
|
|
||||||
|
msgpack_pack_map(buf, count);
|
||||||
|
|
||||||
|
while (he = hv_iternext(hval)) {
|
||||||
|
_msgpack_pack_sv(buf, hv_iterkeysv(he));
|
||||||
|
_msgpack_pack_sv(buf, HeVAL(he));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SVt_RV:
|
||||||
|
_msgpack_pack_sv(buf, SvRV(val));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sv_dump(val);
|
||||||
|
Perl_croak(aTHX_ "msgpack for perl doesn't supported this type: %d\n", SvTYPE(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(xs_pack) {
|
||||||
|
dXSARGS;
|
||||||
|
PERL_UNUSED_VAR(items);
|
||||||
|
|
||||||
|
SV* buf = newSVpv("", 0);
|
||||||
|
SV* val = ST(1);
|
||||||
|
|
||||||
|
_msgpack_pack_sv(buf, val);
|
||||||
|
|
||||||
|
ST(0) = buf;
|
||||||
|
XSRETURN(1);
|
||||||
|
}
|
6984
perl/ppport.h
Normal file
6984
perl/ppport.h
Normal file
File diff suppressed because it is too large
Load Diff
6
perl/t/00_compile.t
Normal file
6
perl/t/00_compile.t
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use Test::More tests => 1;
|
||||||
|
|
||||||
|
use_ok 'Data::MessagePack';
|
||||||
|
|
61
perl/t/01_pack.t
Normal file
61
perl/t/01_pack.t
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use t::Util;
|
||||||
|
use Test::More;
|
||||||
|
use Data::MessagePack;
|
||||||
|
|
||||||
|
sub packit {
|
||||||
|
local $_ = unpack("H*", Data::MessagePack->pack($_[0]));
|
||||||
|
s/(..)/$1 /g;
|
||||||
|
s/ $//;
|
||||||
|
$_;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pis ($$) {
|
||||||
|
is packit($_[0]), $_[1], 'dump ' . $_[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
my @dat = (
|
||||||
|
0, '00',
|
||||||
|
1, '01',
|
||||||
|
127, '7f',
|
||||||
|
128, 'cc 80',
|
||||||
|
255, 'cc ff',
|
||||||
|
256, 'cd 01 00',
|
||||||
|
65535, 'cd ff ff',
|
||||||
|
65536, 'ce 00 01 00 00',
|
||||||
|
-1, 'ff',
|
||||||
|
-32, 'e0',
|
||||||
|
-33, 'd0 df',
|
||||||
|
-128, 'd0 80',
|
||||||
|
-129, 'd1 ff 7f',
|
||||||
|
-32768, 'd1 80 00',
|
||||||
|
-32769, 'd2 ff ff 7f ff',
|
||||||
|
1.0, 'cb 3f f0 00 00 00 00 00 00',
|
||||||
|
"", 'a0',
|
||||||
|
"a", 'a1 61',
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 'bf 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61',
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 'da 00 20 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61',
|
||||||
|
undef, 'c0',
|
||||||
|
Data::MessagePack::true(), 'c3',
|
||||||
|
Data::MessagePack::false(), 'c2',
|
||||||
|
[], '90',
|
||||||
|
[+[]], '91 90',
|
||||||
|
[[], undef], '92 90 c0',
|
||||||
|
{'a', 0}, '81 a1 61 00',
|
||||||
|
8388608, 'ce 00 80 00 00',
|
||||||
|
|
||||||
|
[undef, false, true], '93 c0 c2 c3',
|
||||||
|
["", "a", "bc", "def"], '94 a0 a1 61 a2 62 63 a3 64 65 66',
|
||||||
|
[[], [[undef]]], '92 90 91 91 c0',
|
||||||
|
[undef, false, true], '93 c0 c2 c3',
|
||||||
|
[[0, 64, 127], [-32, -16, -1]], '92 93 00 40 7f 93 e0 f0 ff',
|
||||||
|
[0, -128, -1, 0, -32768, -1, 0, -2147483648, -1], '99 00 d0 80 ff 00 d1 80 00 ff 00 d2 80 00 00 00 ff',
|
||||||
|
2147483648, 'ce 80 00 00 00',
|
||||||
|
-2147483648, 'd2 80 00 00 00',
|
||||||
|
);
|
||||||
|
@dat = (2147483648, 'ce 80 00 00 00');
|
||||||
|
plan tests => 1*(scalar(@dat)/2);
|
||||||
|
|
||||||
|
for (my $i=0; $i<scalar(@dat); ) {
|
||||||
|
pis $dat[$i++], $dat[$i++];
|
||||||
|
}
|
||||||
|
|
24
perl/t/02_unpack.t
Normal file
24
perl/t/02_unpack.t
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use Test::More;
|
||||||
|
use Data::MessagePack;
|
||||||
|
use t::Util;
|
||||||
|
no warnings 'uninitialized'; # i need this. i need this.
|
||||||
|
|
||||||
|
sub unpackit {
|
||||||
|
my $v = $_[0];
|
||||||
|
$v =~ s/ //g;
|
||||||
|
$v = pack 'H*', $v;
|
||||||
|
return Data::MessagePack->unpack($v);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pis ($$) {
|
||||||
|
is_deeply unpackit($_[0]), $_[1], 'dump ' . $_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
my @dat = do 't/data.pl';
|
||||||
|
|
||||||
|
plan tests => 1*(scalar(@dat)/2);
|
||||||
|
|
||||||
|
for (my $i=0; $i<scalar(@dat); ) {
|
||||||
|
pis $dat[$i++], $dat[$i++];
|
||||||
|
}
|
||||||
|
|
32
perl/t/03_stream_unpack.t
Normal file
32
perl/t/03_stream_unpack.t
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use t::Util;
|
||||||
|
use Test::More;
|
||||||
|
use Data::MessagePack;
|
||||||
|
|
||||||
|
no warnings 'uninitialized'; # i need this. i need this.
|
||||||
|
|
||||||
|
my $up = Data::MessagePack::Unpacker->new;
|
||||||
|
sub unpackit {
|
||||||
|
my $v = $_[0];
|
||||||
|
$v =~ s/ //g;
|
||||||
|
$v = pack 'H*', $v;
|
||||||
|
$up->reset;
|
||||||
|
my $ret = $up->execute($v, 0);
|
||||||
|
if ($ret != length($v)) {
|
||||||
|
fail "extra bytes";
|
||||||
|
}
|
||||||
|
return $up->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pis ($$) {
|
||||||
|
is_deeply unpackit($_[0]), $_[1], 'dump ' . $_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
my @dat = do 't/data.pl';
|
||||||
|
|
||||||
|
plan tests => 1*(scalar(@dat)/2) + 1;
|
||||||
|
|
||||||
|
isa_ok $up, 'Data::MessagePack::Unpacker';
|
||||||
|
for (my $i=0; $i<scalar(@dat); ) {
|
||||||
|
pis $dat[$i++], $dat[$i++];
|
||||||
|
}
|
||||||
|
|
24
perl/t/04_invert.t
Normal file
24
perl/t/04_invert.t
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
use Test::More;
|
||||||
|
use Data::MessagePack;
|
||||||
|
use t::Util;
|
||||||
|
no warnings 'uninitialized'; # i need this. i need this.
|
||||||
|
|
||||||
|
sub invert {
|
||||||
|
return Data::MessagePack->unpack(
|
||||||
|
Data::MessagePack->pack($_[0]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub pis ($) {
|
||||||
|
is_deeply invert($_[0]), $_[0], 'dump ' . $_[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
my @dat = do 't/data.pl';
|
||||||
|
|
||||||
|
plan tests => 1*(scalar(@dat)/2);
|
||||||
|
|
||||||
|
for (my $i=0; $i<scalar(@dat); ) {
|
||||||
|
$i++;
|
||||||
|
pis $dat[$i++];
|
||||||
|
}
|
||||||
|
|
20
perl/t/Util.pm
Normal file
20
perl/t/Util.pm
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package t::Util;
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
sub import {
|
||||||
|
my $pkg = caller(0);
|
||||||
|
|
||||||
|
strict->import;
|
||||||
|
warnings->import;
|
||||||
|
|
||||||
|
no strict 'refs';
|
||||||
|
*{"$pkg\::true"} = sub () {
|
||||||
|
Data::MessagePack::true()
|
||||||
|
};
|
||||||
|
*{"$pkg\::false"} = sub () {
|
||||||
|
Data::MessagePack::false()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
15
perl/t/data.pl
Normal file
15
perl/t/data.pl
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
no warnings 'uninitialized'; # i need this. i need this.
|
||||||
|
(
|
||||||
|
'93 c0 c2 c3' => [undef, false, true],
|
||||||
|
'94 a0 a1 61 a2 62 63 a3 64 65 66', ["", "a", "bc", "def"],
|
||||||
|
'92 90 91 91 c0', [[], [[undef]]],
|
||||||
|
'93 c0 c2 c3', [undef, false, true],
|
||||||
|
'ce 80 00 00 00', 2147483648,
|
||||||
|
'99 cc 00 cc 80 cc ff cd 00 00 cd 80 00 cd ff ff ce 00 00 00 00 ce 80 00 00 00 ce ff ff ff ff', [0, 128, 255, 0, 32768, 65535, 0, 2147483648, 4294967295],
|
||||||
|
'92 93 00 40 7f 93 e0 f0 ff', [[0, 64, 127], [-32, -16, -1]],
|
||||||
|
'96 dc 00 00 dc 00 01 c0 dc 00 02 c2 c3 dd 00 00 00 00 dd 00 00 00 01 c0 dd 00 00 00 02 c2 c3', [[], [undef], [false, true], [], [undef], [false, true]],
|
||||||
|
'96 da 00 00 da 00 01 61 da 00 02 61 62 db 00 00 00 00 db 00 00 00 01 61 db 00 00 00 02 61 62', ["", "a", "ab", "", "a", "ab"],
|
||||||
|
'99 d0 00 d0 80 d0 ff d1 00 00 d1 80 00 d1 ff ff d2 00 00 00 00 d2 80 00 00 00 d2 ff ff ff ff', [0, -128, -1, 0, -32768, -1, 0, -2147483648, -1],
|
||||||
|
'82 c2 81 c0 c0 c3 81 c0 80', {false,{undef,undef}, true,{undef,{}}},
|
||||||
|
'96 de 00 00 de 00 01 c0 c2 de 00 02 c0 c2 c3 c2 df 00 00 00 00 df 00 00 00 01 c0 c2 df 00 00 00 02 c0 c2 c3 c2', [{}, {undef,false}, {true,false, undef,false}, {}, {undef,false}, {true,false, undef,false}],
|
||||||
|
)
|
268
perl/unpack.c
Normal file
268
perl/unpack.c
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "EXTERN.h"
|
||||||
|
#include "perl.h"
|
||||||
|
#include "XSUB.h"
|
||||||
|
#include "ppport.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int finished;
|
||||||
|
SV* source;
|
||||||
|
} unpack_user;
|
||||||
|
|
||||||
|
#include "msgpack/unpack_define.h"
|
||||||
|
|
||||||
|
#define msgpack_unpack_struct(name) \
|
||||||
|
struct template ## name
|
||||||
|
|
||||||
|
#define msgpack_unpack_func(ret, name) \
|
||||||
|
ret template ## name
|
||||||
|
|
||||||
|
#define msgpack_unpack_callback(name) \
|
||||||
|
template_callback ## name
|
||||||
|
|
||||||
|
#define msgpack_unpack_object SV*
|
||||||
|
|
||||||
|
#define msgpack_unpack_user unpack_user
|
||||||
|
|
||||||
|
struct template_context;
|
||||||
|
typedef struct template_context msgpack_unpack_t;
|
||||||
|
|
||||||
|
static void template_init(msgpack_unpack_t* u);
|
||||||
|
|
||||||
|
static SV* template_data(msgpack_unpack_t* u);
|
||||||
|
|
||||||
|
static int template_execute(msgpack_unpack_t* u,
|
||||||
|
const char* data, size_t len, size_t* off);
|
||||||
|
|
||||||
|
static inline SV* template_callback_root(unpack_user* u)
|
||||||
|
{ return &PL_sv_undef; }
|
||||||
|
|
||||||
|
static inline int template_callback_uint8(unpack_user* u, uint8_t d, SV** o)
|
||||||
|
{ *o = newSVuv(d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_uint16(unpack_user* u, uint16_t d, SV** o)
|
||||||
|
{ *o = newSVuv(d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_uint32(unpack_user* u, uint32_t d, SV** o)
|
||||||
|
{ *o = newSVuv(d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_uint64(unpack_user* u, uint64_t d, SV** o)
|
||||||
|
{ *o = newSVuv(d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_int8(unpack_user* u, int8_t d, SV** o)
|
||||||
|
{ *o = newSViv((long)d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_int16(unpack_user* u, int16_t d, SV** o)
|
||||||
|
{ *o = newSViv((long)d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_int32(unpack_user* u, int32_t d, SV** o)
|
||||||
|
{ *o = newSViv((long)d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_int64(unpack_user* u, int64_t d, SV** o)
|
||||||
|
{ *o = newSViv(d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_float(unpack_user* u, float d, SV** o)
|
||||||
|
{ *o = newSVnv(d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_double(unpack_user* u, double d, SV** o)
|
||||||
|
{ *o = newSVnv(d); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_nil(unpack_user* u, SV** o)
|
||||||
|
{ *o = &PL_sv_undef; return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_true(unpack_user* u, SV** o)
|
||||||
|
{ *o = &PL_sv_yes; return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_false(unpack_user* u, SV** o)
|
||||||
|
{ *o = &PL_sv_no; return 0;}
|
||||||
|
|
||||||
|
static inline int template_callback_array(unpack_user* u, unsigned int n, SV** o)
|
||||||
|
{ AV* a = newAV(); *o = (SV*)newRV_noinc((SV*)a); av_extend(a, n); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_array_item(unpack_user* u, SV** c, SV* o)
|
||||||
|
{ av_push((AV*)SvRV(*c), o); SvREFCNT_inc(o); return 0; } // FIXME set value directry RARRAY_PTR(obj)[RARRAY_LEN(obj)++]
|
||||||
|
|
||||||
|
static inline int template_callback_map(unpack_user* u, unsigned int n, SV** o)
|
||||||
|
{ HV * h = newHV(); *o = newRV_noinc((SV*)h); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_map_item(unpack_user* u, SV** c, SV* k, SV* v)
|
||||||
|
{ hv_store_ent((HV*)SvRV(*c), k, v, 0); SvREFCNT_inc(v); return 0; }
|
||||||
|
|
||||||
|
static inline int template_callback_raw(unpack_user* u, const char* b, const char* p, unsigned int l, SV** o)
|
||||||
|
{ *o = (l == 0) ? newSVpv("", 0) : newSVpv(p, l); return 0; }
|
||||||
|
|
||||||
|
#define UNPACKER(from, name) \
|
||||||
|
msgpack_unpack_t *name; \
|
||||||
|
name = INT2PTR(msgpack_unpack_t*, SvROK((from)) ? SvIV(SvRV((from))) : SvIV((from))); \
|
||||||
|
if(name == NULL) { \
|
||||||
|
Perl_croak(aTHX_ "NULL found for " # name " when shouldn't be."); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "msgpack/unpack_template.h"
|
||||||
|
|
||||||
|
SV* _msgpack_unpack(SV* data, int limit) {
|
||||||
|
msgpack_unpack_t mp;
|
||||||
|
unpack_user u = {0, &PL_sv_undef};
|
||||||
|
int ret;
|
||||||
|
size_t from = 0;
|
||||||
|
STRLEN dlen;
|
||||||
|
const char * dptr = SvPV_const(data, dlen);
|
||||||
|
|
||||||
|
template_init(&mp);
|
||||||
|
mp.user = u;
|
||||||
|
|
||||||
|
mp.user.source = data;
|
||||||
|
ret = template_execute(&mp, dptr, (size_t)dlen, &from);
|
||||||
|
mp.user.source = &PL_sv_undef;
|
||||||
|
|
||||||
|
if(ret < 0) {
|
||||||
|
Perl_croak(aTHX_ "parse error.");
|
||||||
|
} else if(ret == 0) {
|
||||||
|
Perl_croak(aTHX_ "insufficient bytes.");
|
||||||
|
} else {
|
||||||
|
if(from < dlen) {
|
||||||
|
Perl_croak(aTHX_ "extra bytes.");
|
||||||
|
}
|
||||||
|
return template_data(&mp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(xs_unpack_limit) {
|
||||||
|
dXSARGS;
|
||||||
|
|
||||||
|
if (items != 3) {
|
||||||
|
Perl_croak(aTHX_ "Usage: Data::MessagePack->unpack('datadata', $limit)");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
int limit = SvIV(ST(2));
|
||||||
|
ST(0) = _msgpack_unpack(ST(1), limit);
|
||||||
|
}
|
||||||
|
XSRETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XS(xs_unpack) {
|
||||||
|
dXSARGS;
|
||||||
|
msgpack_unpack_t mp;
|
||||||
|
|
||||||
|
if (items != 2) {
|
||||||
|
Perl_croak(aTHX_ "Usage: Data::MessagePack->unpack('datadata')");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
ST(0) = _msgpack_unpack(ST(1), sv_len(ST(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
XSRETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------ stream -- */
|
||||||
|
|
||||||
|
static void _reset(SV* self) {
|
||||||
|
UNPACKER(self, mp);
|
||||||
|
template_init(mp);
|
||||||
|
unpack_user u = {0, &PL_sv_undef};
|
||||||
|
mp->user = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(xs_unpacker_new) {
|
||||||
|
dXSARGS;
|
||||||
|
SV* self = sv_newmortal();
|
||||||
|
msgpack_unpack_t *mp;
|
||||||
|
|
||||||
|
Newx(mp, 1, msgpack_unpack_t);
|
||||||
|
|
||||||
|
sv_setref_pv(self, "Data::MessagePack::Unpacker", mp);
|
||||||
|
_reset(self);
|
||||||
|
|
||||||
|
ST(0) = self;
|
||||||
|
XSRETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SV* _execute_impl(SV* self, SV* data, UV off, I32 limit) {
|
||||||
|
UNPACKER(self, mp);
|
||||||
|
|
||||||
|
size_t from = off;
|
||||||
|
const char* dptr = SvPV_nolen_const(data);
|
||||||
|
long dlen = limit;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if(from >= dlen) {
|
||||||
|
Perl_croak(aTHX_ "offset is bigger than data buffer size.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mp->user.source = data;
|
||||||
|
ret = template_execute(mp, dptr, (size_t)dlen, &from);
|
||||||
|
mp->user.source = &PL_sv_undef;
|
||||||
|
|
||||||
|
if(ret < 0) {
|
||||||
|
Perl_croak(aTHX_ "parse error.");
|
||||||
|
} else if(ret > 0) {
|
||||||
|
mp->user.finished = 1;
|
||||||
|
return newSVuv(from);
|
||||||
|
} else {
|
||||||
|
mp->user.finished = 0;
|
||||||
|
return newSVuv(from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(xs_unpacker_execute) {
|
||||||
|
dXSARGS;
|
||||||
|
SV* self = ST(0);
|
||||||
|
SV* data = ST(1);
|
||||||
|
IV off = SvIV(ST(2));
|
||||||
|
|
||||||
|
ST(0) = _execute_impl(self, data, off, sv_len(data));
|
||||||
|
|
||||||
|
XSRETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(xs_unpacker_execute_limit) {
|
||||||
|
dXSARGS;
|
||||||
|
SV* self = ST(0);
|
||||||
|
SV* data = ST(1);
|
||||||
|
IV off = SvIV(ST(2));
|
||||||
|
IV limit = SvIV(ST(3));
|
||||||
|
|
||||||
|
ST(0) = _execute_impl(self, data, off, limit);
|
||||||
|
|
||||||
|
XSRETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(xs_unpacker_is_finished) {
|
||||||
|
dXSARGS;
|
||||||
|
|
||||||
|
UNPACKER(ST(0), mp);
|
||||||
|
ST(0) = (mp->user.finished) ? &PL_sv_yes : &PL_sv_no;
|
||||||
|
|
||||||
|
XSRETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(xs_unpacker_data) {
|
||||||
|
dXSARGS;
|
||||||
|
|
||||||
|
UNPACKER(ST(0), mp);
|
||||||
|
ST(0) = template_data(mp);
|
||||||
|
|
||||||
|
XSRETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(xs_unpacker_reset) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 1) {
|
||||||
|
Perl_croak(aTHX_ "Usage: $unpacker->reset()");
|
||||||
|
}
|
||||||
|
|
||||||
|
_reset(ST(0));
|
||||||
|
|
||||||
|
XSRETURN(0);
|
||||||
|
}
|
||||||
|
|
4
perl/xt/99_pod.t
Normal file
4
perl/xt/99_pod.t
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
use Test::More;
|
||||||
|
eval "use Test::Pod 1.00";
|
||||||
|
plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
|
||||||
|
all_pod_files_ok();
|
Loading…
x
Reference in New Issue
Block a user