ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.34
Committed: Mon Jun 29 23:51:28 2015 UTC (8 years, 10 months ago) by root
Branch: MAIN
CVS Tags: rel-3_8, HEAD
Changes since 1.33: +13 -8 lines
Log Message:
3.8

File Contents

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