ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.25
Committed: Wed Jan 9 20:41:18 2008 UTC (16 years, 4 months ago) by root
Branch: MAIN
CVS Tags: rel-3_4, rel-3_11
Changes since 1.24: +15 -3 lines
Log Message:
*** empty log message ***

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     need_storable(void)
224     {
225 root 1.14 load_module (PERL_LOADMOD_NOIMPORT, serializer_package, Nullsv);
226 root 1.1
227 root 1.24 storable_mstore = GvCV (gv_fetchpv (SvPVbyte_nolen (serializer_mstore ), TRUE, SVt_PVCV));
228     storable_mretrieve = 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     storable_mstore =
249     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    
289 root 1.1 if (!storable_mstore)
290 root 1.25 {
291     PUTBACK;
292     need_storable ();
293     SPAGAIN;
294     }
295 root 1.1
296 root 1.9 if (deref)
297     sv = newRV_noinc (sv);
298    
299 root 1.1 PUSHMARK (SP);
300     XPUSHs (sv);
301     PUTBACK;
302    
303     if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
304     croak ("Storable::mstore didn't return a single scalar");
305    
306     SPAGAIN;
307    
308     sv = POPs;
309    
310 root 1.20 if (SvPVX (sv)[0] == MAGIC_R)
311     {
312     if (deref)
313     SvPVX (sv)[0] = MAGIC_R_deref;
314     }
315     else
316     {
317     char pfx[2];
318    
319     pfx[0] = MAGIC_undef;
320     pfx[1] = deref ? MAGIC_R_deref : MAGIC_R;
321 root 1.1
322 root 1.20 sv_insert (sv, 0, 0, pfx, 2);
323     }
324 root 1.10
325 root 1.1 if (ix) /* compress */
326 root 1.10 sv = sv_2mortal (compress_sv (sv, deref ? MAGIC_CR_deref : MAGIC_CR, -1));
327 root 1.9
328 root 1.10 XPUSHs (sv);
329 root 1.1 }
330 root 1.13 else if (SvPOKp (sv) && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI))
331 root 1.10 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, MAGIC_U))); /* need to prefix only */
332 root 1.1 else if (ix == 2) /* compress always */
333 root 1.10 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, -1)));
334 root 1.15 else if (SvNIOK (sv)) /* don't compress */
335     {
336     STRLEN len;
337     char *s = SvPV (sv, len);
338     XPUSHs (sv_2mortal (newSVpvn (s, len)));
339     }
340 root 1.1 else /* don't compress */
341 root 1.15 XPUSHs (sv_2mortal (newSVsv (sv)));
342 root 1.1
343     void
344     sthaw(sv)
345     SV * sv
346     PROTOTYPE: $
347     PPCODE:
348 root 1.20 {
349     STRLEN svlen;
350 root 1.9 int deref = 0;
351    
352 root 1.7 SvGETMAGIC (sv);
353 root 1.24 if (SvPOK (sv) && IN_RANGE (SvPVbyte (sv, svlen)[0], MAGIC_LO, MAGIC_HI))
354 root 1.1 {
355 root 1.20 redo:
356    
357 root 1.1 switch (SvPVX (sv)[0])
358     {
359 root 1.4 case MAGIC_undef:
360 root 1.20 if (svlen <= 1)
361     XPUSHs (sv_2mortal (NEWSV (0, 0)));
362     else
363     {
364     if (SvPVX (sv)[1] == MAGIC_R_deref)
365     deref = 1;
366     else if (SvPVX (sv)[1] != MAGIC_R)
367     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
368    
369     sv_chop (sv, SvPVX (sv) + 2);
370    
371     if (!storable_mstore)
372 root 1.25 {
373     PUTBACK;
374     need_storable ();
375     SPAGAIN;
376     }
377 root 1.20
378     PUSHMARK (SP);
379     XPUSHs (sv);
380     PUTBACK;
381    
382     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
383     croak ("Storable::mstore didn't return a single scalar");
384    
385     SPAGAIN;
386    
387     if (deref)
388     SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
389     else
390     SETs (sv_2mortal (newSVsv (TOPs)));
391     }
392 root 1.4 break;
393    
394 root 1.1 case MAGIC_U:
395     XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
396     break;
397    
398     case MAGIC_C:
399     XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
400     break;
401    
402 root 1.10 case MAGIC_R_deref:
403     deref = 1;
404     SvPVX (sv)[0] = MAGIC_R;
405     goto handle_MAGIC_R;
406    
407 root 1.9 case MAGIC_CR_deref:
408     deref = 1;
409 root 1.1 case MAGIC_CR:
410     sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
411 root 1.10 if (deref)
412     if (SvPVX (sv)[0] == MAGIC_R_deref)
413 root 1.9 SvPVX (sv)[0] = MAGIC_R;
414 root 1.20
415     goto redo;
416 root 1.10
417 root 1.1 case MAGIC_R:
418 root 1.10 handle_MAGIC_R:
419 root 1.1 if (!storable_mstore)
420 root 1.25 {
421     PUTBACK;
422     need_storable ();
423     SPAGAIN;
424     }
425 root 1.1
426     PUSHMARK (SP);
427     XPUSHs (sv);
428     PUTBACK;
429    
430     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
431     croak ("Storable::mstore didn't return a single scalar");
432    
433     SPAGAIN;
434    
435 root 1.9 if (deref)
436     {
437 root 1.10 SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
438 root 1.9
439     if (SvPVX (sv)[0] == MAGIC_R)
440 root 1.10 SvPVX (sv)[0] = MAGIC_R_deref;
441 root 1.9 }
442 root 1.10 else
443 pcg 1.17 SETs (sv_2mortal (newSVsv (TOPs)));
444 root 1.1
445     break;
446    
447     default:
448     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
449     }
450     }
451     else
452 root 1.11 XPUSHs (sv_2mortal (newSVsv (sv)));
453 root 1.20 }
454 pcg 1.16