ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.20
Committed: Fri Jul 7 15:47:10 2006 UTC (17 years, 10 months ago) by root
Branch: MAIN
Changes since 1.19: +82 -16 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     if (!(src[0] & 0x80))
149     {
150     csize -= 1;
151     usize = *src++ & 0xff;
152     }
153     else if (!(src[0] & 0x20))
154     {
155     csize -= 2;
156     usize = *src++ & 0x1f;
157     usize = (usize << 6) | (*src++ & 0x3f);
158     }
159     else if (!(src[0] & 0x10))
160     {
161     csize -= 3;
162     usize = *src++ & 0x0f;
163     usize = (usize << 6) | (*src++ & 0x3f);
164     usize = (usize << 6) | (*src++ & 0x3f);
165     }
166     else if (!(src[0] & 0x08))
167     {
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     else if (!(src[0] & 0x04))
175     {
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.20 else if (!(src[0] & 0x02))
184     {
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.1
196     ret = NEWSV (0, usize);
197     SvPOK_only (ret);
198     dst = SvPVX (ret);
199    
200     if (lzf_decompress (src, csize, dst, usize) != usize)
201 root 1.13 croak ("compressed data corrupted (size mismatch)", csize, skip, usize);
202 root 1.1 }
203     else
204     {
205     usize = csize - 1;
206     ret = NEWSV (0, usize);
207     SvPOK_only (ret);
208    
209     Move ((void *)(src + 1), (void *)SvPVX (ret), usize, unsigned char);
210     }
211    
212     SvCUR_set (ret, usize);
213    
214     return ret;
215     }
216     else
217     return newSVpvn ("", 0);
218     }
219    
220     static void
221     need_storable(void)
222     {
223 root 1.2 #if PATCHLEVEL < 6
224 root 1.14 char req[8192];
225     sprintf (req, "require %s;", SvPV_nolen (serializer_package));
226     perl_eval_pv (req, 1);
227 root 1.2 #else
228 root 1.14 load_module (PERL_LOADMOD_NOIMPORT, serializer_package, Nullsv);
229 root 1.2 #endif
230 root 1.1
231 root 1.14 storable_mstore = GvCV (gv_fetchpv (SvPV_nolen (serializer_mstore ), TRUE, SVt_PVCV));
232     storable_mretrieve = GvCV (gv_fetchpv (SvPV_nolen (serializer_mretrieve), TRUE, SVt_PVCV));
233 root 1.1 }
234    
235     MODULE = Compress::LZF PACKAGE = Compress::LZF
236 root 1.14
237     BOOT:
238     serializer_package = newSVpv ("Storable", 0);
239 root 1.20 serializer_mstore = newSVpv ("Storable::net_mstore", 0);
240 root 1.14 serializer_mretrieve = newSVpv ("Storable::mretrieve", 0);
241    
242     void
243     set_serializer(package, mstore, mretrieve)
244     SV * package
245     SV * mstore
246     SV * mretrieve
247     PROTOTYPE: $$$
248     PPCODE:
249     SvSetSV (serializer_package , package );
250     SvSetSV (serializer_mstore , mstore );
251     SvSetSV (serializer_mretrieve, mretrieve);
252     storable_mstore =
253     storable_mretrieve = 0;
254 root 1.1
255     void
256     compress(data)
257     SV * data
258     PROTOTYPE: $
259     PPCODE:
260 root 1.10 XPUSHs (sv_2mortal (compress_sv (data, 0, MAGIC_U)));
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     sfreeze_cr = 1
274     sfreeze_c = 2
275     PROTOTYPE: $
276     PPCODE:
277    
278 root 1.10 SvGETMAGIC (sv);
279    
280 root 1.4 if (!SvOK (sv))
281     XPUSHs (sv_2mortal (newSVpvn ("\02", 1))); /* 02 == MAGIC_undef */
282 root 1.12 else if (SvROK (sv)
283     || (SvTYPE(sv) != SVt_IV
284     && SvTYPE(sv) != SVt_NV
285     && SvTYPE(sv) != SVt_PV
286 root 1.15 && SvTYPE(sv) != SVt_PVIV
287     && SvTYPE(sv) != SVt_PVNV
288 root 1.12 && SvTYPE(sv) != SVt_PVMG)) /* mstore */
289 root 1.1 {
290 root 1.9 int deref = !SvROK (sv);
291    
292 root 1.1 if (!storable_mstore)
293     need_storable ();
294    
295 root 1.9 if (deref)
296     sv = newRV_noinc (sv);
297    
298 root 1.1 PUSHMARK (SP);
299     XPUSHs (sv);
300     PUTBACK;
301    
302     if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
303     croak ("Storable::mstore didn't return a single scalar");
304    
305     SPAGAIN;
306    
307     sv = POPs;
308    
309 root 1.20 if (SvPVX (sv)[0] == MAGIC_R)
310     {
311     if (deref)
312     SvPVX (sv)[0] = MAGIC_R_deref;
313     }
314     else
315     {
316     char pfx[2];
317    
318     pfx[0] = MAGIC_undef;
319     pfx[1] = deref ? MAGIC_R_deref : MAGIC_R;
320 root 1.1
321 root 1.20 sv_insert (sv, 0, 0, pfx, 2);
322     }
323 root 1.10
324 root 1.1 if (ix) /* compress */
325 root 1.10 sv = sv_2mortal (compress_sv (sv, deref ? MAGIC_CR_deref : MAGIC_CR, -1));
326 root 1.9
327 root 1.10 XPUSHs (sv);
328 root 1.1 }
329 root 1.13 else if (SvPOKp (sv) && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI))
330 root 1.10 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, MAGIC_U))); /* need to prefix only */
331 root 1.1 else if (ix == 2) /* compress always */
332 root 1.10 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, -1)));
333 root 1.15 else if (SvNIOK (sv)) /* don't compress */
334     {
335     STRLEN len;
336     char *s = SvPV (sv, len);
337     XPUSHs (sv_2mortal (newSVpvn (s, len)));
338     }
339 root 1.1 else /* don't compress */
340 root 1.15 XPUSHs (sv_2mortal (newSVsv (sv)));
341 root 1.1
342     void
343     sthaw(sv)
344     SV * sv
345     PROTOTYPE: $
346     PPCODE:
347 root 1.20 {
348     STRLEN svlen;
349 root 1.9 int deref = 0;
350    
351 root 1.7 SvGETMAGIC (sv);
352 root 1.20 if (SvPOK (sv) && IN_RANGE (SvPV (sv, svlen)[0], MAGIC_LO, MAGIC_HI))
353 root 1.1 {
354 root 1.20 redo:
355    
356 root 1.1 switch (SvPVX (sv)[0])
357     {
358 root 1.4 case MAGIC_undef:
359 root 1.20 if (svlen <= 1)
360     XPUSHs (sv_2mortal (NEWSV (0, 0)));
361     else
362     {
363     if (SvPVX (sv)[1] == MAGIC_R_deref)
364     deref = 1;
365     else if (SvPVX (sv)[1] != MAGIC_R)
366     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
367    
368     sv_chop (sv, SvPVX (sv) + 2);
369    
370     if (!storable_mstore)
371     need_storable ();
372    
373     PUSHMARK (SP);
374     XPUSHs (sv);
375     PUTBACK;
376    
377     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
378     croak ("Storable::mstore didn't return a single scalar");
379    
380     SPAGAIN;
381    
382     if (deref)
383     SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
384     else
385     SETs (sv_2mortal (newSVsv (TOPs)));
386     }
387 root 1.4 break;
388    
389 root 1.1 case MAGIC_U:
390     XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
391     break;
392    
393     case MAGIC_C:
394     XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
395     break;
396    
397 root 1.10 case MAGIC_R_deref:
398     deref = 1;
399     SvPVX (sv)[0] = MAGIC_R;
400     goto handle_MAGIC_R;
401    
402 root 1.9 case MAGIC_CR_deref:
403     deref = 1;
404 root 1.1 case MAGIC_CR:
405     sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
406 root 1.10 if (deref)
407     if (SvPVX (sv)[0] == MAGIC_R_deref)
408 root 1.9 SvPVX (sv)[0] = MAGIC_R;
409 root 1.20
410     goto redo;
411 root 1.10
412 root 1.1 case MAGIC_R:
413 root 1.10 handle_MAGIC_R:
414 root 1.1 if (!storable_mstore)
415     need_storable ();
416    
417     PUSHMARK (SP);
418     XPUSHs (sv);
419     PUTBACK;
420    
421     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
422     croak ("Storable::mstore didn't return a single scalar");
423    
424     SPAGAIN;
425    
426 root 1.9 if (deref)
427     {
428 root 1.10 SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
429 root 1.9
430     if (SvPVX (sv)[0] == MAGIC_R)
431 root 1.10 SvPVX (sv)[0] = MAGIC_R_deref;
432 root 1.9 }
433 root 1.10 else
434 pcg 1.17 SETs (sv_2mortal (newSVsv (TOPs)));
435 root 1.1
436     break;
437    
438     default:
439     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
440     }
441     }
442     else
443 root 1.11 XPUSHs (sv_2mortal (newSVsv (sv)));
444 root 1.20 }
445 pcg 1.16