ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.21
Committed: Wed Sep 27 15:52:47 2006 UTC (17 years, 7 months ago) by root
Branch: MAIN
CVS Tags: rel-1_7
Changes since 1.20: +10 -7 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     /* try to be compatible with older perls */
6     /* SvPV_nolen() macro first defined in 5.005_55 */
7     /* this is slow, not threadsafe, but works */
8     #include "patchlevel.h"
9     #if (PATCHLEVEL == 4) || ((PATCHLEVEL == 5) && (SUBVERSION < 55))
10     static STRLEN nolen_na;
11     # define SvPV_nolen(sv) SvPV ((sv), nolen_na)
12     #endif
13 root 1.2 #if PATCHLEVEL < 6
14     # define call_sv perl_call_sv
15     #endif
16 root 1.1
17     #include "lzf_c.c"
18     #include "lzf_d.c"
19    
20     /* we re-use the storable header for our purposes */
21     #define MAGIC_LO 0
22     #define MAGIC_U 0 /* uncompressed data follows */
23     #define MAGIC_C 1 /* compressed data follows */
24 root 1.4 #define MAGIC_undef 2 /* the special value undef */
25     #define MAGIC_CR 3 /* storable (reference, freeze), compressed */
26 root 1.1 #define MAGIC_R 4 /* storable (reference, freeze) */
27 root 1.9 #define MAGIC_CR_deref 5 /* storable (NO reference, freeze), compressed */
28 root 1.10 #define MAGIC_R_deref 6 /* storable (NO reference, freeze) */
29 root 1.1 #define MAGIC_HI 7 /* room for one higher storable major */
30 root 1.20 /* for historical reasons, MAGIC_undef + MAGIC_R and MAGIC_undef + MAGIC_R_deref are used, too */
31 root 1.1
32     #define IN_RANGE(v,l,h) ((unsigned int)((unsigned)(v) - (unsigned)(l)) <= (unsigned)(h) - (unsigned)(l))
33    
34 root 1.14 static SV *serializer_package, *serializer_mstore, *serializer_mretrieve;
35 root 1.1 static CV *storable_mstore, *storable_mretrieve;
36    
37 root 1.20 #if Size_t_size > 4
38     # define MAX_LENGTH ((Size_t)0x80000000L)
39     #else
40     # define MAX_LENGTH ((Size_t) 0x8000000L)
41     #endif
42    
43 root 1.1 static SV *
44 root 1.10 compress_sv (SV *data, char cprepend, int uprepend)
45 root 1.1 {
46     STRLEN usize, csize;
47     char *src = (char *)SvPV (data, usize);
48    
49     if (usize)
50     {
51     SV *ret = NEWSV (0, usize + 1);
52     unsigned char *dst;
53     int skip = 0;
54    
55     SvPOK_only (ret);
56     dst = (unsigned char *)SvPVX (ret);
57    
58     if (cprepend)
59     dst[skip++] = cprepend;
60    
61 root 1.20 if (usize <= 0x7f)
62 root 1.1 {
63     dst[skip++] = usize;
64     }
65 root 1.20 else if (usize <= 0x7ff)
66 root 1.1 {
67     dst[skip++] = (( usize >> 6) | 0xc0);
68     dst[skip++] = (( usize & 0x3f) | 0x80);
69     }
70 root 1.20 else if (usize <= 0xffff)
71 root 1.1 {
72     dst[skip++] = (( usize >> 12) | 0xe0);
73     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
74     dst[skip++] = (( usize & 0x3f) | 0x80);
75     }
76 root 1.20 else if (usize <= 0x1fffff)
77 root 1.1 {
78     dst[skip++] = (( usize >> 18) | 0xf0);
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 <= 0x3ffffff)
84 root 1.1 {
85     dst[skip++] = (( usize >> 24) | 0xf8);
86     dst[skip++] = (((usize >> 18) & 0x3f) | 0x80);
87     dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
88     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
89     dst[skip++] = (( usize & 0x3f) | 0x80);
90     }
91 root 1.20 else if (usize <= 0x7fffffff)
92     {
93     dst[skip++] = (( usize >> 30) | 0xfc);
94     dst[skip++] = (((usize >> 24) & 0x3f) | 0x80);
95     dst[skip++] = (((usize >> 18) & 0x3f) | 0x80);
96     dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
97     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
98     dst[skip++] = (( usize & 0x3f) | 0x80);
99     }
100 root 1.1 else
101 root 1.20 croak ("compress can only compress up to %ld bytes", 0x7fffffffL);
102 root 1.1
103     /* 11 bytes is the smallest compressible string */
104     csize = usize < 11 ? 0 :
105     lzf_compress (src, usize,
106     dst + skip,
107     usize - skip);
108    
109     if (csize)
110     {
111     SvCUR_set (ret, csize + skip);
112     }
113 root 1.10 else if (uprepend < 0)
114 root 1.1 {
115     SvREFCNT_dec (ret);
116     ret = SvREFCNT_inc (data);
117     }
118     else
119     {
120 root 1.10 *dst++ = uprepend;
121 root 1.1
122     Move ((void *)src, (void *)dst, usize, unsigned char);
123    
124     SvCUR_set (ret, usize + 1);
125     }
126    
127     return ret;
128     }
129     else
130     return newSVpv ("", 0);
131     }
132    
133     static SV *
134     decompress_sv (SV *data, int skip)
135     {
136     STRLEN usize, csize;
137     unsigned char *src = (unsigned char *)SvPV (data, csize) + skip;
138    
139     if (csize)
140     {
141     void *dst;
142     SV *ret;
143    
144     csize -= skip;
145    
146     if (src[0])
147     {
148 root 1.21 if (!(src[0] & 0x80) && csize >= 1)
149 root 1.1 {
150     csize -= 1;
151     usize = *src++ & 0xff;
152     }
153 root 1.21 else if (!(src[0] & 0x20) && csize >= 2)
154 root 1.1 {
155     csize -= 2;
156     usize = *src++ & 0x1f;
157     usize = (usize << 6) | (*src++ & 0x3f);
158     }
159 root 1.21 else if (!(src[0] & 0x10) && csize >= 3)
160 root 1.1 {
161     csize -= 3;
162     usize = *src++ & 0x0f;
163     usize = (usize << 6) | (*src++ & 0x3f);
164     usize = (usize << 6) | (*src++ & 0x3f);
165     }
166 root 1.21 else if (!(src[0] & 0x08) && csize >= 4)
167 root 1.1 {
168     csize -= 4;
169     usize = *src++ & 0x07;
170     usize = (usize << 6) | (*src++ & 0x3f);
171     usize = (usize << 6) | (*src++ & 0x3f);
172     usize = (usize << 6) | (*src++ & 0x3f);
173     }
174 root 1.21 else if (!(src[0] & 0x04) && csize >= 5)
175 root 1.1 {
176     csize -= 5;
177     usize = *src++ & 0x03;
178     usize = (usize << 6) | (*src++ & 0x3f);
179     usize = (usize << 6) | (*src++ & 0x3f);
180     usize = (usize << 6) | (*src++ & 0x3f);
181     usize = (usize << 6) | (*src++ & 0x3f);
182     }
183 root 1.21 else if (!(src[0] & 0x02) && csize >= 6)
184 root 1.20 {
185     csize -= 6;
186     usize = *src++ & 0x01;
187     usize = (usize << 6) | (*src++ & 0x3f);
188     usize = (usize << 6) | (*src++ & 0x3f);
189     usize = (usize << 6) | (*src++ & 0x3f);
190     usize = (usize << 6) | (*src++ & 0x3f);
191     usize = (usize << 6) | (*src++ & 0x3f);
192     }
193 root 1.1 else
194 root 1.13 croak ("compressed data corrupted (invalid length)");
195 root 1.21
196     if (!usize)
197     croak ("compressed data corrupted (invalid length)");
198 root 1.1
199     ret = NEWSV (0, usize);
200     SvPOK_only (ret);
201     dst = SvPVX (ret);
202    
203     if (lzf_decompress (src, csize, dst, usize) != usize)
204 root 1.13 croak ("compressed data corrupted (size mismatch)", csize, skip, usize);
205 root 1.1 }
206     else
207     {
208     usize = csize - 1;
209 root 1.21 ret = NEWSV (0, usize | 1);
210 root 1.1 SvPOK_only (ret);
211    
212     Move ((void *)(src + 1), (void *)SvPVX (ret), usize, unsigned char);
213     }
214    
215     SvCUR_set (ret, usize);
216    
217     return ret;
218     }
219     else
220     return newSVpvn ("", 0);
221     }
222    
223     static void
224     need_storable(void)
225     {
226 root 1.2 #if PATCHLEVEL < 6
227 root 1.14 char req[8192];
228     sprintf (req, "require %s;", SvPV_nolen (serializer_package));
229     perl_eval_pv (req, 1);
230 root 1.2 #else
231 root 1.14 load_module (PERL_LOADMOD_NOIMPORT, serializer_package, Nullsv);
232 root 1.2 #endif
233 root 1.1
234 root 1.14 storable_mstore = GvCV (gv_fetchpv (SvPV_nolen (serializer_mstore ), TRUE, SVt_PVCV));
235     storable_mretrieve = GvCV (gv_fetchpv (SvPV_nolen (serializer_mretrieve), TRUE, SVt_PVCV));
236 root 1.1 }
237    
238     MODULE = Compress::LZF PACKAGE = Compress::LZF
239 root 1.14
240     BOOT:
241     serializer_package = newSVpv ("Storable", 0);
242 root 1.20 serializer_mstore = newSVpv ("Storable::net_mstore", 0);
243 root 1.14 serializer_mretrieve = newSVpv ("Storable::mretrieve", 0);
244    
245     void
246     set_serializer(package, mstore, mretrieve)
247     SV * package
248     SV * mstore
249     SV * mretrieve
250     PROTOTYPE: $$$
251     PPCODE:
252     SvSetSV (serializer_package , package );
253     SvSetSV (serializer_mstore , mstore );
254     SvSetSV (serializer_mretrieve, mretrieve);
255     storable_mstore =
256     storable_mretrieve = 0;
257 root 1.1
258     void
259     compress(data)
260     SV * data
261     PROTOTYPE: $
262     PPCODE:
263 root 1.10 XPUSHs (sv_2mortal (compress_sv (data, 0, MAGIC_U)));
264 root 1.1
265     void
266     decompress(data)
267     SV * data
268     PROTOTYPE: $
269     PPCODE:
270     XPUSHs (sv_2mortal (decompress_sv (data, 0)));
271    
272     void
273     sfreeze(sv)
274     SV * sv
275     ALIAS:
276     sfreeze_cr = 1
277     sfreeze_c = 2
278     PROTOTYPE: $
279     PPCODE:
280    
281 root 1.10 SvGETMAGIC (sv);
282    
283 root 1.4 if (!SvOK (sv))
284     XPUSHs (sv_2mortal (newSVpvn ("\02", 1))); /* 02 == MAGIC_undef */
285 root 1.12 else if (SvROK (sv)
286     || (SvTYPE(sv) != SVt_IV
287     && SvTYPE(sv) != SVt_NV
288     && SvTYPE(sv) != SVt_PV
289 root 1.15 && SvTYPE(sv) != SVt_PVIV
290     && SvTYPE(sv) != SVt_PVNV
291 root 1.12 && SvTYPE(sv) != SVt_PVMG)) /* mstore */
292 root 1.1 {
293 root 1.9 int deref = !SvROK (sv);
294    
295 root 1.1 if (!storable_mstore)
296     need_storable ();
297    
298 root 1.9 if (deref)
299     sv = newRV_noinc (sv);
300    
301 root 1.1 PUSHMARK (SP);
302     XPUSHs (sv);
303     PUTBACK;
304    
305     if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
306     croak ("Storable::mstore didn't return a single scalar");
307    
308     SPAGAIN;
309    
310     sv = POPs;
311    
312 root 1.20 if (SvPVX (sv)[0] == MAGIC_R)
313     {
314     if (deref)
315     SvPVX (sv)[0] = MAGIC_R_deref;
316     }
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.20 if (SvPOK (sv) && IN_RANGE (SvPV (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     need_storable ();
375    
376     PUSHMARK (SP);
377     XPUSHs (sv);
378     PUTBACK;
379    
380     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
381     croak ("Storable::mstore didn't return a single scalar");
382    
383     SPAGAIN;
384    
385     if (deref)
386     SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
387     else
388     SETs (sv_2mortal (newSVsv (TOPs)));
389     }
390 root 1.4 break;
391    
392 root 1.1 case MAGIC_U:
393     XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
394     break;
395    
396     case MAGIC_C:
397     XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
398     break;
399    
400 root 1.10 case MAGIC_R_deref:
401     deref = 1;
402     SvPVX (sv)[0] = MAGIC_R;
403     goto handle_MAGIC_R;
404    
405 root 1.9 case MAGIC_CR_deref:
406     deref = 1;
407 root 1.1 case MAGIC_CR:
408     sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
409 root 1.10 if (deref)
410     if (SvPVX (sv)[0] == MAGIC_R_deref)
411 root 1.9 SvPVX (sv)[0] = MAGIC_R;
412 root 1.20
413     goto redo;
414 root 1.10
415 root 1.1 case MAGIC_R:
416 root 1.10 handle_MAGIC_R:
417 root 1.1 if (!storable_mstore)
418     need_storable ();
419    
420     PUSHMARK (SP);
421     XPUSHs (sv);
422     PUTBACK;
423    
424     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
425     croak ("Storable::mstore didn't return a single scalar");
426    
427     SPAGAIN;
428    
429 root 1.9 if (deref)
430     {
431 root 1.10 SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
432 root 1.9
433     if (SvPVX (sv)[0] == MAGIC_R)
434 root 1.10 SvPVX (sv)[0] = MAGIC_R_deref;
435 root 1.9 }
436 root 1.10 else
437 pcg 1.17 SETs (sv_2mortal (newSVsv (TOPs)));
438 root 1.1
439     break;
440    
441     default:
442     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
443     }
444     }
445     else
446 root 1.11 XPUSHs (sv_2mortal (newSVsv (sv)));
447 root 1.20 }
448 pcg 1.16