--- Compress-LZF/LZF.xs 2001/09/27 20:05:38 1.4 +++ Compress-LZF/LZF.xs 2006/07/07 15:47:10 1.20 @@ -24,14 +24,24 @@ #define MAGIC_undef 2 /* the special value undef */ #define MAGIC_CR 3 /* storable (reference, freeze), compressed */ #define MAGIC_R 4 /* storable (reference, freeze) */ +#define MAGIC_CR_deref 5 /* storable (NO reference, freeze), compressed */ +#define MAGIC_R_deref 6 /* storable (NO reference, freeze) */ #define MAGIC_HI 7 /* room for one higher storable major */ +/* for historical reasons, MAGIC_undef + MAGIC_R and MAGIC_undef + MAGIC_R_deref are used, too */ #define IN_RANGE(v,l,h) ((unsigned int)((unsigned)(v) - (unsigned)(l)) <= (unsigned)(h) - (unsigned)(l)) +static SV *serializer_package, *serializer_mstore, *serializer_mretrieve; static CV *storable_mstore, *storable_mretrieve; +#if Size_t_size > 4 +# define MAX_LENGTH ((Size_t)0x80000000L) +#else +# define MAX_LENGTH ((Size_t) 0x8000000L) +#endif + static SV * -compress_sv (SV *data, char cprepend, char uprepend) +compress_sv (SV *data, char cprepend, int uprepend) { STRLEN usize, csize; char *src = (char *)SvPV (data, usize); @@ -48,29 +58,29 @@ if (cprepend) dst[skip++] = cprepend; - if (usize < 0x80) + if (usize <= 0x7f) { dst[skip++] = usize; } - else if (usize < 0x800) + else if (usize <= 0x7ff) { dst[skip++] = (( usize >> 6) | 0xc0); dst[skip++] = (( usize & 0x3f) | 0x80); } - else if (usize < 0x10000) + else if (usize <= 0xffff) { dst[skip++] = (( usize >> 12) | 0xe0); dst[skip++] = (((usize >> 6) & 0x3f) | 0x80); dst[skip++] = (( usize & 0x3f) | 0x80); } - else if (usize < 0x200000) + else if (usize <= 0x1fffff) { dst[skip++] = (( usize >> 18) | 0xf0); dst[skip++] = (((usize >> 12) & 0x3f) | 0x80); dst[skip++] = (((usize >> 6) & 0x3f) | 0x80); dst[skip++] = (( usize & 0x3f) | 0x80); } - else if (usize < 0x4000000) + else if (usize <= 0x3ffffff) { dst[skip++] = (( usize >> 24) | 0xf8); dst[skip++] = (((usize >> 18) & 0x3f) | 0x80); @@ -78,8 +88,17 @@ dst[skip++] = (((usize >> 6) & 0x3f) | 0x80); dst[skip++] = (( usize & 0x3f) | 0x80); } + else if (usize <= 0x7fffffff) + { + dst[skip++] = (( usize >> 30) | 0xfc); + dst[skip++] = (((usize >> 24) & 0x3f) | 0x80); + dst[skip++] = (((usize >> 18) & 0x3f) | 0x80); + dst[skip++] = (((usize >> 12) & 0x3f) | 0x80); + dst[skip++] = (((usize >> 6) & 0x3f) | 0x80); + dst[skip++] = (( usize & 0x3f) | 0x80); + } else - croak ("compress can only compress up to %ld bytes", 0x4000000-1); + croak ("compress can only compress up to %ld bytes", 0x7fffffffL); /* 11 bytes is the smallest compressible string */ csize = usize < 11 ? 0 : @@ -91,14 +110,14 @@ { SvCUR_set (ret, csize + skip); } - else if (!uprepend) + else if (uprepend < 0) { SvREFCNT_dec (ret); ret = SvREFCNT_inc (data); } else { - *dst++ = 0; + *dst++ = uprepend; Move ((void *)src, (void *)dst, usize, unsigned char); @@ -161,15 +180,25 @@ usize = (usize << 6) | (*src++ & 0x3f); usize = (usize << 6) | (*src++ & 0x3f); } + else if (!(src[0] & 0x02)) + { + csize -= 6; + usize = *src++ & 0x01; + usize = (usize << 6) | (*src++ & 0x3f); + usize = (usize << 6) | (*src++ & 0x3f); + usize = (usize << 6) | (*src++ & 0x3f); + usize = (usize << 6) | (*src++ & 0x3f); + usize = (usize << 6) | (*src++ & 0x3f); + } else - croak ("compressed data corrupted"); + croak ("compressed data corrupted (invalid length)"); ret = NEWSV (0, usize); SvPOK_only (ret); dst = SvPVX (ret); if (lzf_decompress (src, csize, dst, usize) != usize) - croak ("compressed data corrupted", csize, skip, usize); + croak ("compressed data corrupted (size mismatch)", csize, skip, usize); } else { @@ -192,23 +221,43 @@ need_storable(void) { #if PATCHLEVEL < 6 - perl_eval_pv ("require Storable;", 1); + char req[8192]; + sprintf (req, "require %s;", SvPV_nolen (serializer_package)); + perl_eval_pv (req, 1); #else - load_module (PERL_LOADMOD_NOIMPORT, newSVpv ("Storable", 0), Nullsv); + load_module (PERL_LOADMOD_NOIMPORT, serializer_package, Nullsv); #endif - storable_mstore = GvCV (gv_fetchpv ("Storable::mstore" , TRUE, SVt_PVCV)); - storable_mretrieve = GvCV (gv_fetchpv ("Storable::mretrieve", TRUE, SVt_PVCV)); + storable_mstore = GvCV (gv_fetchpv (SvPV_nolen (serializer_mstore ), TRUE, SVt_PVCV)); + storable_mretrieve = GvCV (gv_fetchpv (SvPV_nolen (serializer_mretrieve), TRUE, SVt_PVCV)); } MODULE = Compress::LZF PACKAGE = Compress::LZF +BOOT: + serializer_package = newSVpv ("Storable", 0); + serializer_mstore = newSVpv ("Storable::net_mstore", 0); + serializer_mretrieve = newSVpv ("Storable::mretrieve", 0); + +void +set_serializer(package, mstore, mretrieve) + SV * package + SV * mstore + SV * mretrieve + PROTOTYPE: $$$ + PPCODE: + SvSetSV (serializer_package , package ); + SvSetSV (serializer_mstore , mstore ); + SvSetSV (serializer_mretrieve, mretrieve); + storable_mstore = + storable_mretrieve = 0; + void compress(data) SV * data PROTOTYPE: $ PPCODE: - XPUSHs (sv_2mortal (compress_sv (data, 0, 1))); + XPUSHs (sv_2mortal (compress_sv (data, 0, MAGIC_U))); void decompress(data) @@ -226,15 +275,26 @@ PROTOTYPE: $ PPCODE: + SvGETMAGIC (sv); + if (!SvOK (sv)) XPUSHs (sv_2mortal (newSVpvn ("\02", 1))); /* 02 == MAGIC_undef */ - else if (SvTYPE(sv) != SVt_IV - && SvTYPE(sv) != SVt_NV - && SvTYPE(sv) != SVt_PV) /* mstore */ + else if (SvROK (sv) + || (SvTYPE(sv) != SVt_IV + && SvTYPE(sv) != SVt_NV + && SvTYPE(sv) != SVt_PV + && SvTYPE(sv) != SVt_PVIV + && SvTYPE(sv) != SVt_PVNV + && SvTYPE(sv) != SVt_PVMG)) /* mstore */ { + int deref = !SvROK (sv); + if (!storable_mstore) need_storable (); + if (deref) + sv = newRV_noinc (sv); + PUSHMARK (SP); XPUSHs (sv); PUTBACK; @@ -246,33 +306,84 @@ sv = POPs; - if (SvPVX (sv)[0] != MAGIC_R) - croak ("Storable format changed, need newer version of Compress::LZF"); + if (SvPVX (sv)[0] == MAGIC_R) + { + if (deref) + SvPVX (sv)[0] = MAGIC_R_deref; + } + else + { + char pfx[2]; + + pfx[0] = MAGIC_undef; + pfx[1] = deref ? MAGIC_R_deref : MAGIC_R; + + sv_insert (sv, 0, 0, pfx, 2); + } if (ix) /* compress */ - XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_CR, 0))); - else - XPUSHs (sv); + sv = sv_2mortal (compress_sv (sv, deref ? MAGIC_CR_deref : MAGIC_CR, -1)); + + XPUSHs (sv); } - else if (sv && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI)) - XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, 1))); /* need to prefix only */ + else if (SvPOKp (sv) && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI)) + XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, MAGIC_U))); /* need to prefix only */ else if (ix == 2) /* compress always */ - XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, 0))); + XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, -1))); + else if (SvNIOK (sv)) /* don't compress */ + { + STRLEN len; + char *s = SvPV (sv, len); + XPUSHs (sv_2mortal (newSVpvn (s, len))); + } else /* don't compress */ - XPUSHs (sv_2mortal (SvREFCNT_inc (sv))); + XPUSHs (sv_2mortal (newSVsv (sv))); void sthaw(sv) SV * sv PROTOTYPE: $ PPCODE: +{ + STRLEN svlen; + int deref = 0; - if (IN_RANGE (SvPV_nolen (sv)[0], MAGIC_LO, MAGIC_HI)) + SvGETMAGIC (sv); + if (SvPOK (sv) && IN_RANGE (SvPV (sv, svlen)[0], MAGIC_LO, MAGIC_HI)) { + redo: + switch (SvPVX (sv)[0]) { case MAGIC_undef: - XPUSHs (sv_2mortal (NEWSV (0, 0))); + if (svlen <= 1) + XPUSHs (sv_2mortal (NEWSV (0, 0))); + else + { + if (SvPVX (sv)[1] == MAGIC_R_deref) + deref = 1; + else if (SvPVX (sv)[1] != MAGIC_R) + croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?"); + + sv_chop (sv, SvPVX (sv) + 2); + + if (!storable_mstore) + need_storable (); + + PUSHMARK (SP); + XPUSHs (sv); + PUTBACK; + + if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR)) + croak ("Storable::mstore didn't return a single scalar"); + + SPAGAIN; + + if (deref) + SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs)))); + else + SETs (sv_2mortal (newSVsv (TOPs))); + } break; case MAGIC_U: @@ -283,9 +394,23 @@ XPUSHs (sv_2mortal (decompress_sv (sv, 1))); break; + case MAGIC_R_deref: + deref = 1; + SvPVX (sv)[0] = MAGIC_R; + goto handle_MAGIC_R; + + case MAGIC_CR_deref: + deref = 1; case MAGIC_CR: sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */ + if (deref) + if (SvPVX (sv)[0] == MAGIC_R_deref) + SvPVX (sv)[0] = MAGIC_R; + + goto redo; + case MAGIC_R: + handle_MAGIC_R: if (!storable_mstore) need_storable (); @@ -298,7 +423,15 @@ SPAGAIN; - XPUSHs (POPs); /* this is a nop, hope the compiler also knows this */ + if (deref) + { + SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs)))); + + if (SvPVX (sv)[0] == MAGIC_R) + SvPVX (sv)[0] = MAGIC_R_deref; + } + else + SETs (sv_2mortal (newSVsv (TOPs))); break; @@ -307,4 +440,6 @@ } } else - XPUSHs (sv_2mortal (SvREFCNT_inc (sv))); + XPUSHs (sv_2mortal (newSVsv (sv))); +} +