ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.31
Committed: Sun Aug 25 18:13:26 2013 UTC (10 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-3_7
Changes since 1.30: +21 -9 lines
Log Message:
3.7

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.23 #define LZF_STANDALONE 1
6     #define LZF_STATE_ARG 1
7    
8 root 1.1 #include "lzf_c.c"
9     #include "lzf_d.c"
10 root 1.31 #include "lzf_c_best.c"
11 root 1.1
12     /* we re-use the storable header for our purposes */
13     #define MAGIC_LO 0
14     #define MAGIC_U 0 /* uncompressed data follows */
15     #define MAGIC_C 1 /* compressed data follows */
16 root 1.4 #define MAGIC_undef 2 /* the special value undef */
17     #define MAGIC_CR 3 /* storable (reference, freeze), compressed */
18 root 1.1 #define MAGIC_R 4 /* storable (reference, freeze) */
19 root 1.9 #define MAGIC_CR_deref 5 /* storable (NO reference, freeze), compressed */
20 root 1.10 #define MAGIC_R_deref 6 /* storable (NO reference, freeze) */
21 root 1.1 #define MAGIC_HI 7 /* room for one higher storable major */
22 root 1.20 /* for historical reasons, MAGIC_undef + MAGIC_R and MAGIC_undef + MAGIC_R_deref are used, too */
23 root 1.1
24     #define IN_RANGE(v,l,h) ((unsigned int)((unsigned)(v) - (unsigned)(l)) <= (unsigned)(h) - (unsigned)(l))
25    
26 root 1.14 static SV *serializer_package, *serializer_mstore, *serializer_mretrieve;
27 root 1.1 static CV *storable_mstore, *storable_mretrieve;
28    
29 root 1.20 #if Size_t_size > 4
30     # define MAX_LENGTH ((Size_t)0x80000000L)
31     #else
32     # define MAX_LENGTH ((Size_t) 0x8000000L)
33     #endif
34    
35 root 1.1 static SV *
36 root 1.31 compress_sv (SV *data, char cprepend, int uprepend, int best)
37 root 1.1 {
38 root 1.23 LZF_STATE *state;
39 root 1.1 STRLEN usize, csize;
40 root 1.24 char *src = (char *)SvPVbyte (data, usize);
41 root 1.1
42     if (usize)
43     {
44     SV *ret = NEWSV (0, usize + 1);
45     unsigned char *dst;
46     int skip = 0;
47    
48     SvPOK_only (ret);
49     dst = (unsigned char *)SvPVX (ret);
50    
51     if (cprepend)
52     dst[skip++] = cprepend;
53    
54 root 1.20 if (usize <= 0x7f)
55 root 1.1 {
56     dst[skip++] = usize;
57     }
58 root 1.31 else if (usize <= 0x7ff)
59 root 1.1 {
60     dst[skip++] = (( usize >> 6) | 0xc0);
61     dst[skip++] = (( usize & 0x3f) | 0x80);
62     }
63 root 1.20 else if (usize <= 0xffff)
64 root 1.1 {
65     dst[skip++] = (( usize >> 12) | 0xe0);
66     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
67     dst[skip++] = (( usize & 0x3f) | 0x80);
68     }
69 root 1.20 else if (usize <= 0x1fffff)
70 root 1.1 {
71     dst[skip++] = (( usize >> 18) | 0xf0);
72     dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
73     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
74     dst[skip++] = (( usize & 0x3f) | 0x80);
75     }
76 root 1.20 else if (usize <= 0x3ffffff)
77 root 1.1 {
78     dst[skip++] = (( usize >> 24) | 0xf8);
79     dst[skip++] = (((usize >> 18) & 0x3f) | 0x80);
80     dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
81     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
82     dst[skip++] = (( usize & 0x3f) | 0x80);
83     }
84 root 1.20 else if (usize <= 0x7fffffff)
85     {
86     dst[skip++] = (( usize >> 30) | 0xfc);
87     dst[skip++] = (((usize >> 24) & 0x3f) | 0x80);
88     dst[skip++] = (((usize >> 18) & 0x3f) | 0x80);
89     dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
90     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
91     dst[skip++] = (( usize & 0x3f) | 0x80);
92     }
93 root 1.1 else
94 root 1.20 croak ("compress can only compress up to %ld bytes", 0x7fffffffL);
95 root 1.1
96 root 1.23 New (0, state, 1, LZF_STATE);
97     if (!state)
98     croak ("Compress::LZF unable to allocate memory for compression state");
99    
100 root 1.1 /* 11 bytes is the smallest compressible string */
101     csize = usize < 11 ? 0 :
102 root 1.31 (best ? lzf_compress_best (src, usize, dst + skip, usize - skip)
103     : lzf_compress (src, usize, dst + skip, usize - skip, *state));
104 root 1.23
105     Safefree (state);
106 root 1.1
107     if (csize)
108     {
109     SvCUR_set (ret, csize + skip);
110     }
111 root 1.10 else if (uprepend < 0)
112 root 1.1 {
113     SvREFCNT_dec (ret);
114     ret = SvREFCNT_inc (data);
115     }
116     else
117     {
118 root 1.10 *dst++ = uprepend;
119 root 1.1
120     Move ((void *)src, (void *)dst, usize, unsigned char);
121    
122     SvCUR_set (ret, usize + 1);
123     }
124    
125     return ret;
126     }
127     else
128     return newSVpv ("", 0);
129     }
130    
131     static SV *
132     decompress_sv (SV *data, int skip)
133     {
134     STRLEN usize, csize;
135 root 1.24 unsigned char *src = (unsigned char *)SvPVbyte (data, csize) + skip;
136 root 1.1
137     if (csize)
138     {
139     void *dst;
140     SV *ret;
141    
142     csize -= skip;
143    
144     if (src[0])
145     {
146 root 1.21 if (!(src[0] & 0x80) && csize >= 1)
147 root 1.1 {
148     csize -= 1;
149     usize = *src++ & 0xff;
150     }
151 root 1.21 else if (!(src[0] & 0x20) && csize >= 2)
152 root 1.1 {
153     csize -= 2;
154     usize = *src++ & 0x1f;
155     usize = (usize << 6) | (*src++ & 0x3f);
156     }
157 root 1.21 else if (!(src[0] & 0x10) && csize >= 3)
158 root 1.1 {
159     csize -= 3;
160     usize = *src++ & 0x0f;
161     usize = (usize << 6) | (*src++ & 0x3f);
162     usize = (usize << 6) | (*src++ & 0x3f);
163     }
164 root 1.21 else if (!(src[0] & 0x08) && csize >= 4)
165 root 1.1 {
166     csize -= 4;
167     usize = *src++ & 0x07;
168     usize = (usize << 6) | (*src++ & 0x3f);
169     usize = (usize << 6) | (*src++ & 0x3f);
170     usize = (usize << 6) | (*src++ & 0x3f);
171     }
172 root 1.21 else if (!(src[0] & 0x04) && csize >= 5)
173 root 1.1 {
174     csize -= 5;
175     usize = *src++ & 0x03;
176     usize = (usize << 6) | (*src++ & 0x3f);
177     usize = (usize << 6) | (*src++ & 0x3f);
178     usize = (usize << 6) | (*src++ & 0x3f);
179     usize = (usize << 6) | (*src++ & 0x3f);
180     }
181 root 1.21 else if (!(src[0] & 0x02) && csize >= 6)
182 root 1.20 {
183     csize -= 6;
184     usize = *src++ & 0x01;
185     usize = (usize << 6) | (*src++ & 0x3f);
186     usize = (usize << 6) | (*src++ & 0x3f);
187     usize = (usize << 6) | (*src++ & 0x3f);
188     usize = (usize << 6) | (*src++ & 0x3f);
189     usize = (usize << 6) | (*src++ & 0x3f);
190     }
191 root 1.1 else
192 root 1.13 croak ("compressed data corrupted (invalid length)");
193 root 1.21
194     if (!usize)
195     croak ("compressed data corrupted (invalid length)");
196 root 1.1
197     ret = NEWSV (0, usize);
198     SvPOK_only (ret);
199     dst = SvPVX (ret);
200    
201     if (lzf_decompress (src, csize, dst, usize) != usize)
202 root 1.22 {
203     SvREFCNT_dec (ret);
204     croak ("compressed data corrupted (size mismatch)", csize, skip, usize);
205     }
206 root 1.1 }
207     else
208     {
209     usize = csize - 1;
210 root 1.21 ret = NEWSV (0, usize | 1);
211 root 1.1 SvPOK_only (ret);
212    
213     Move ((void *)(src + 1), (void *)SvPVX (ret), usize, unsigned char);
214     }
215    
216     SvCUR_set (ret, usize);
217    
218     return ret;
219     }
220     else
221     return newSVpvn ("", 0);
222     }
223    
224     static void
225 root 1.27 need_storable (void)
226 root 1.1 {
227 root 1.30 eval_sv (sv_2mortal (newSVpvf ("require %s", SvPVbyte_nolen (serializer_package))), G_VOID | G_DISCARD);
228 root 1.1
229 root 1.27 storable_mstore = (CV *)SvREFCNT_inc (GvCV (gv_fetchpv (SvPVbyte_nolen (serializer_mstore ), TRUE, SVt_PVCV)));
230     storable_mretrieve = (CV *)SvREFCNT_inc (GvCV (gv_fetchpv (SvPVbyte_nolen (serializer_mretrieve), TRUE, SVt_PVCV)));
231 root 1.1 }
232    
233     MODULE = Compress::LZF PACKAGE = Compress::LZF
234 root 1.14
235     BOOT:
236     serializer_package = newSVpv ("Storable", 0);
237 root 1.20 serializer_mstore = newSVpv ("Storable::net_mstore", 0);
238 root 1.14 serializer_mretrieve = newSVpv ("Storable::mretrieve", 0);
239    
240     void
241     set_serializer(package, mstore, mretrieve)
242     SV * package
243     SV * mstore
244     SV * mretrieve
245     PROTOTYPE: $$$
246     PPCODE:
247     SvSetSV (serializer_package , package );
248     SvSetSV (serializer_mstore , mstore );
249     SvSetSV (serializer_mretrieve, mretrieve);
250 root 1.27 SvREFCNT_dec (storable_mstore ); storable_mstore = 0;
251     SvREFCNT_dec (storable_mretrieve); storable_mretrieve = 0;
252 root 1.1
253     void
254     compress(data)
255     SV * data
256 root 1.31 ALIAS:
257     compress_best = 1
258 root 1.1 PROTOTYPE: $
259     PPCODE:
260 root 1.31 XPUSHs (sv_2mortal (compress_sv (data, 0, MAGIC_U, ix)));
261 root 1.1
262     void
263     decompress(data)
264     SV * data
265     PROTOTYPE: $
266     PPCODE:
267     XPUSHs (sv_2mortal (decompress_sv (data, 0)));
268    
269     void
270     sfreeze(sv)
271     SV * sv
272     ALIAS:
273 root 1.31 sfreeze = 0
274     sfreeze_cr = 1
275     sfreeze_c = 2
276     sfreeze_best = 4
277     sfreeze_cr_best = 5
278     sfreeze_c_best = 6
279 root 1.1 PROTOTYPE: $
280     PPCODE:
281 root 1.31 {
282     int best = ix & 4;
283     ix &= 3;
284 root 1.1
285 root 1.10 SvGETMAGIC (sv);
286    
287 root 1.4 if (!SvOK (sv))
288     XPUSHs (sv_2mortal (newSVpvn ("\02", 1))); /* 02 == MAGIC_undef */
289 root 1.12 else if (SvROK (sv)
290 root 1.24 || SvUTF8 (sv)
291     || (SvTYPE(sv) != SVt_IV
292     && SvTYPE(sv) != SVt_NV
293     && SvTYPE(sv) != SVt_PV
294     && SvTYPE(sv) != SVt_PVIV
295     && SvTYPE(sv) != SVt_PVNV
296     && SvTYPE(sv) != SVt_PVMG)) /* mstore */
297 root 1.1 {
298 root 1.9 int deref = !SvROK (sv);
299 root 1.26 char *pv;
300 root 1.9
301 root 1.1 if (!storable_mstore)
302 root 1.25 {
303     PUTBACK;
304     need_storable ();
305     SPAGAIN;
306     }
307 root 1.1
308 root 1.9 if (deref)
309     sv = newRV_noinc (sv);
310    
311 root 1.1 PUSHMARK (SP);
312     XPUSHs (sv);
313     PUTBACK;
314    
315     if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
316 root 1.28 croak ("%s didn't return a single scalar", SvPVbyte_nolen (serializer_mstore));
317 root 1.1
318     SPAGAIN;
319    
320     sv = POPs;
321 root 1.26 pv = SvPV_nolen (sv);
322 root 1.1
323 root 1.26 if (*pv == MAGIC_R)
324 root 1.20 {
325     if (deref)
326 root 1.26 *pv = MAGIC_R_deref;
327 root 1.20 }
328     else
329     {
330     char pfx[2];
331    
332     pfx[0] = MAGIC_undef;
333     pfx[1] = deref ? MAGIC_R_deref : MAGIC_R;
334 root 1.1
335 root 1.20 sv_insert (sv, 0, 0, pfx, 2);
336     }
337 root 1.10
338 root 1.1 if (ix) /* compress */
339 root 1.31 sv = sv_2mortal (compress_sv (sv, deref ? MAGIC_CR_deref : MAGIC_CR, -1, best));
340 root 1.9
341 root 1.10 XPUSHs (sv);
342 root 1.1 }
343 root 1.13 else if (SvPOKp (sv) && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI))
344 root 1.31 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, MAGIC_U, best))); /* need to prefix only */
345 root 1.1 else if (ix == 2) /* compress always */
346 root 1.31 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, -1, best)));
347 root 1.15 else if (SvNIOK (sv)) /* don't compress */
348     {
349     STRLEN len;
350     char *s = SvPV (sv, len);
351     XPUSHs (sv_2mortal (newSVpvn (s, len)));
352     }
353 root 1.1 else /* don't compress */
354 root 1.15 XPUSHs (sv_2mortal (newSVsv (sv)));
355 root 1.31 }
356 root 1.1
357     void
358     sthaw(sv)
359     SV * sv
360     PROTOTYPE: $
361     PPCODE:
362 root 1.20 {
363     STRLEN svlen;
364 root 1.9 int deref = 0;
365    
366 root 1.7 SvGETMAGIC (sv);
367 root 1.24 if (SvPOK (sv) && IN_RANGE (SvPVbyte (sv, svlen)[0], MAGIC_LO, MAGIC_HI))
368 root 1.1 {
369 root 1.20 redo:
370    
371 root 1.1 switch (SvPVX (sv)[0])
372     {
373 root 1.4 case MAGIC_undef:
374 root 1.20 if (svlen <= 1)
375     XPUSHs (sv_2mortal (NEWSV (0, 0)));
376     else
377     {
378     if (SvPVX (sv)[1] == MAGIC_R_deref)
379     deref = 1;
380     else if (SvPVX (sv)[1] != MAGIC_R)
381     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
382    
383     sv_chop (sv, SvPVX (sv) + 2);
384    
385     if (!storable_mstore)
386 root 1.25 {
387     PUTBACK;
388     need_storable ();
389     SPAGAIN;
390     }
391 root 1.20
392     PUSHMARK (SP);
393     XPUSHs (sv);
394     PUTBACK;
395    
396     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
397 root 1.28 croak ("%s didn't return a single scalar", SvPVbyte_nolen (serializer_mretrieve));
398 root 1.20
399     SPAGAIN;
400    
401     if (deref)
402     SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
403     else
404     SETs (sv_2mortal (newSVsv (TOPs)));
405     }
406 root 1.4 break;
407    
408 root 1.1 case MAGIC_U:
409     XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
410     break;
411    
412     case MAGIC_C:
413     XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
414     break;
415    
416 root 1.10 case MAGIC_R_deref:
417     deref = 1;
418     SvPVX (sv)[0] = MAGIC_R;
419     goto handle_MAGIC_R;
420    
421 root 1.9 case MAGIC_CR_deref:
422     deref = 1;
423 root 1.1 case MAGIC_CR:
424     sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
425 root 1.10 if (deref)
426     if (SvPVX (sv)[0] == MAGIC_R_deref)
427 root 1.9 SvPVX (sv)[0] = MAGIC_R;
428 root 1.20
429     goto redo;
430 root 1.10
431 root 1.1 case MAGIC_R:
432 root 1.10 handle_MAGIC_R:
433 root 1.1 if (!storable_mstore)
434 root 1.25 {
435     PUTBACK;
436     need_storable ();
437     SPAGAIN;
438     }
439 root 1.1
440     PUSHMARK (SP);
441     XPUSHs (sv);
442     PUTBACK;
443    
444     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
445 root 1.28 croak ("%s didn't return a single scalar", SvPVbyte_nolen (serializer_mretrieve));
446 root 1.1
447     SPAGAIN;
448    
449 root 1.9 if (deref)
450     {
451 root 1.10 SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
452 root 1.9
453     if (SvPVX (sv)[0] == MAGIC_R)
454 root 1.10 SvPVX (sv)[0] = MAGIC_R_deref;
455 root 1.9 }
456 root 1.10 else
457 pcg 1.17 SETs (sv_2mortal (newSVsv (TOPs)));
458 root 1.1
459     break;
460    
461     default:
462     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
463     }
464     }
465     else
466 root 1.11 XPUSHs (sv_2mortal (newSVsv (sv)));
467 root 1.20 }
468 pcg 1.16