mirror of
https://github.com/msgpack/msgpack-c.git
synced 2025-10-24 17:30:46 +02:00
Fix streaming unpacking for splitted packed data
This commit is contained in:
@@ -20,8 +20,6 @@ my $input = [
|
|||||||
my $packed = Data::MessagePack->pack($input);
|
my $packed = Data::MessagePack->pack($input);
|
||||||
|
|
||||||
foreach my $size(1 .. 16) {
|
foreach my $size(1 .. 16) {
|
||||||
local $TODO = "Splitted byte streaming is not yet supported (bufer size: $size)";
|
|
||||||
|
|
||||||
my $up = Data::MessagePack::Unpacker->new();
|
my $up = Data::MessagePack::Unpacker->new();
|
||||||
|
|
||||||
open my $stream, '<:bytes :scalar', \$packed;
|
open my $stream, '<:bytes :scalar', \$packed;
|
||||||
@@ -29,7 +27,7 @@ foreach my $size(1 .. 16) {
|
|||||||
my $buff;
|
my $buff;
|
||||||
my $done = 0;
|
my $done = 0;
|
||||||
while( read($stream, $buff, $size) ) {
|
while( read($stream, $buff, $size) ) {
|
||||||
#note "buff: ", join " ", map { unpack 'H2', $_ } split //, $buff;
|
note "buff: ", join " ", map { unpack 'H2', $_ } split //, $buff;
|
||||||
|
|
||||||
$done = $up->execute($buff);
|
$done = $up->execute($buff);
|
||||||
}
|
}
|
||||||
|
|||||||
22
perl/t/16_unpacker_for_larges.t
Normal file
22
perl/t/16_unpacker_for_larges.t
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
use strict;
|
||||||
|
use Test::More;
|
||||||
|
use Data::MessagePack;
|
||||||
|
|
||||||
|
foreach my $data("abc") {
|
||||||
|
my $packed = Data::MessagePack->pack($data);
|
||||||
|
|
||||||
|
my $unpacker = Data::MessagePack::Unpacker->new;
|
||||||
|
note "buff: ", join " ", map { unpack 'H2', $_ } split //, $packed;
|
||||||
|
|
||||||
|
my $offset = 0;
|
||||||
|
foreach my $byte(split //, $packed) {
|
||||||
|
note "offset: $offset";
|
||||||
|
$offset += $unpacker->execute($byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
ok $unpacker->is_finished, 'finished';
|
||||||
|
is_deeply $unpacker->data, $data, 'data';
|
||||||
|
}
|
||||||
|
|
||||||
|
done_testing;
|
||||||
|
|
||||||
@@ -9,11 +9,13 @@ typedef struct {
|
|||||||
} my_cxt_t;
|
} my_cxt_t;
|
||||||
START_MY_CXT
|
START_MY_CXT
|
||||||
|
|
||||||
|
// context data for execute_template()
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool finished;
|
bool finished;
|
||||||
bool incremented;
|
|
||||||
bool utf8;
|
bool utf8;
|
||||||
|
SV* buffer;
|
||||||
} unpack_user;
|
} unpack_user;
|
||||||
|
#define UNPACK_USER_INIT { false, false, NULL }
|
||||||
|
|
||||||
#include "msgpack/unpack_define.h"
|
#include "msgpack/unpack_define.h"
|
||||||
|
|
||||||
@@ -301,7 +303,7 @@ XS(xs_unpack) {
|
|||||||
msgpack_unpack_t mp;
|
msgpack_unpack_t mp;
|
||||||
template_init(&mp);
|
template_init(&mp);
|
||||||
|
|
||||||
unpack_user const u = {false, false, false};
|
unpack_user const u = UNPACK_USER_INIT;
|
||||||
mp.user = u;
|
mp.user = u;
|
||||||
|
|
||||||
size_t from = 0;
|
size_t from = 0;
|
||||||
@@ -326,14 +328,6 @@ XS(xs_unpack) {
|
|||||||
/* ------------------------------ stream -- */
|
/* ------------------------------ stream -- */
|
||||||
/* http://twitter.com/frsyuki/status/13249304748 */
|
/* http://twitter.com/frsyuki/status/13249304748 */
|
||||||
|
|
||||||
STATIC_INLINE void _reset(SV* const self) {
|
|
||||||
dTHX;
|
|
||||||
unpack_user const u = {false, false, false};
|
|
||||||
|
|
||||||
UNPACKER(self, mp);
|
|
||||||
template_init(mp);
|
|
||||||
mp->user = u;
|
|
||||||
}
|
|
||||||
|
|
||||||
XS(xs_unpacker_new) {
|
XS(xs_unpacker_new) {
|
||||||
dXSARGS;
|
dXSARGS;
|
||||||
@@ -345,9 +339,14 @@ XS(xs_unpacker_new) {
|
|||||||
msgpack_unpack_t *mp;
|
msgpack_unpack_t *mp;
|
||||||
|
|
||||||
Newxz(mp, 1, msgpack_unpack_t);
|
Newxz(mp, 1, msgpack_unpack_t);
|
||||||
|
template_init(mp);
|
||||||
|
unpack_user const u = UNPACK_USER_INIT;
|
||||||
|
mp->user = u;
|
||||||
|
|
||||||
|
mp->user.buffer = newSV(80);
|
||||||
|
sv_setpvs(mp->user.buffer, "");
|
||||||
|
|
||||||
sv_setref_pv(self, "Data::MessagePack::Unpacker", mp);
|
sv_setref_pv(self, "Data::MessagePack::Unpacker", mp);
|
||||||
_reset(self);
|
|
||||||
|
|
||||||
ST(0) = self;
|
ST(0) = self;
|
||||||
XSRETURN(1);
|
XSRETURN(1);
|
||||||
@@ -378,21 +377,44 @@ _execute_impl(SV* const self, SV* const data, UV const offset, UV const limit) {
|
|||||||
dTHX;
|
dTHX;
|
||||||
|
|
||||||
if(offset >= limit) {
|
if(offset >= limit) {
|
||||||
Perl_croak(aTHX_ "offset (%"UVuf") is bigger than data buffer size (%"UVuf")",
|
Perl_croak(aTHX_
|
||||||
|
"offset (%"UVuf") is bigger than data buffer size (%"UVuf")",
|
||||||
offset, limit);
|
offset, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNPACKER(self, mp);
|
UNPACKER(self, mp);
|
||||||
|
|
||||||
size_t from = offset;
|
size_t from = offset;
|
||||||
const char* const dptr = SvPV_nolen_const(data);
|
const char* dptr = SvPV_nolen_const(data);
|
||||||
|
STRLEN dlen = limit;
|
||||||
|
|
||||||
int const ret = template_execute(mp, dptr, limit, &from);
|
if(SvCUR(mp->user.buffer) != 0) {
|
||||||
|
sv_catpvn(mp->user.buffer, dptr, dlen);
|
||||||
|
dptr = SvPV_const(mp->user.buffer, dlen);
|
||||||
|
from = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int const ret = template_execute(mp, dptr, dlen, &from);
|
||||||
|
// ret < 0 : error
|
||||||
|
// ret == 0 : insufficient
|
||||||
|
// ret > 0 : success
|
||||||
|
|
||||||
if(ret < 0) {
|
if(ret < 0) {
|
||||||
Perl_croak(aTHX_ "Data::MessagePack::Unpacker: parse error while executing");
|
Perl_croak(aTHX_
|
||||||
|
"Data::MessagePack::Unpacker: parse error while executing");
|
||||||
}
|
}
|
||||||
|
|
||||||
mp->user.finished = (ret > 0) ? true : false;
|
mp->user.finished = (ret > 0) ? true : false;
|
||||||
|
if(!mp->user.finished) {
|
||||||
|
template_init(mp); // reset the state
|
||||||
|
sv_setpvn(mp->user.buffer, dptr, dlen);
|
||||||
|
from = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sv_setpvs(mp->user.buffer, "");
|
||||||
|
}
|
||||||
|
//warn(">> (%d) dlen=%d, from=%d, rest=%d",
|
||||||
|
// (int)ret, (int)dlen, (int)from, dlen - from);
|
||||||
return from;
|
return from;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,12 +486,12 @@ XS(xs_unpacker_reset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UNPACKER(ST(0), mp);
|
UNPACKER(ST(0), mp);
|
||||||
bool const utf8 = mp->user.utf8; // save
|
|
||||||
|
|
||||||
SV* const data = template_data(mp);
|
SV* const data = template_data(mp);
|
||||||
SvREFCNT_dec(data);
|
SvREFCNT_dec(data);
|
||||||
_reset(ST(0));
|
|
||||||
mp->user.utf8 = utf8;
|
template_init(mp);
|
||||||
|
sv_setpvs(mp->user.buffer, "");
|
||||||
|
|
||||||
XSRETURN(0);
|
XSRETURN(0);
|
||||||
}
|
}
|
||||||
@@ -484,6 +506,7 @@ XS(xs_unpacker_destroy) {
|
|||||||
|
|
||||||
SV* const data = template_data(mp);
|
SV* const data = template_data(mp);
|
||||||
SvREFCNT_dec(data);
|
SvREFCNT_dec(data);
|
||||||
|
SvREFCNT_dec(mp->user.buffer);
|
||||||
Safefree(mp);
|
Safefree(mp);
|
||||||
|
|
||||||
XSRETURN(0);
|
XSRETURN(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user