ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.29
Committed: Wed Dec 17 00:36:09 2008 UTC (15 years, 5 months ago) by root
Branch: MAIN
CVS Tags: rel-3_42
Changes since 1.28: +1 -1 lines
Log Message:
3.42

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