ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.9
Committed: Sun Mar 3 04:45:18 2002 UTC (22 years, 2 months ago) by root
Branch: MAIN
Changes since 1.8: +37 -5 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     #define MAGIC_R_deref 6 /* storable NO (reference, freeze) */
29 root 1.1 #define MAGIC_HI 7 /* room for one higher storable major */
30    
31     #define IN_RANGE(v,l,h) ((unsigned int)((unsigned)(v) - (unsigned)(l)) <= (unsigned)(h) - (unsigned)(l))
32    
33     static CV *storable_mstore, *storable_mretrieve;
34    
35     static SV *
36     compress_sv (SV *data, char cprepend, char uprepend)
37     {
38     STRLEN usize, csize;
39     char *src = (char *)SvPV (data, usize);
40    
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     if (usize < 0x80)
54     {
55     dst[skip++] = usize;
56     }
57     else if (usize < 0x800)
58     {
59     dst[skip++] = (( usize >> 6) | 0xc0);
60     dst[skip++] = (( usize & 0x3f) | 0x80);
61     }
62     else if (usize < 0x10000)
63     {
64     dst[skip++] = (( usize >> 12) | 0xe0);
65     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
66     dst[skip++] = (( usize & 0x3f) | 0x80);
67     }
68     else if (usize < 0x200000)
69     {
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     else if (usize < 0x4000000)
76     {
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     else
84     croak ("compress can only compress up to %ld bytes", 0x4000000-1);
85    
86     /* 11 bytes is the smallest compressible string */
87     csize = usize < 11 ? 0 :
88     lzf_compress (src, usize,
89     dst + skip,
90     usize - skip);
91    
92     if (csize)
93     {
94     SvCUR_set (ret, csize + skip);
95     }
96     else if (!uprepend)
97     {
98     SvREFCNT_dec (ret);
99     ret = SvREFCNT_inc (data);
100     }
101     else
102     {
103     *dst++ = 0;
104    
105     Move ((void *)src, (void *)dst, usize, unsigned char);
106    
107     SvCUR_set (ret, usize + 1);
108     }
109    
110     return ret;
111     }
112     else
113     return newSVpv ("", 0);
114     }
115    
116     static SV *
117     decompress_sv (SV *data, int skip)
118     {
119     STRLEN usize, csize;
120     unsigned char *src = (unsigned char *)SvPV (data, csize) + skip;
121    
122     if (csize)
123     {
124     void *dst;
125     SV *ret;
126    
127     csize -= skip;
128    
129     if (src[0])
130     {
131     if (!(src[0] & 0x80))
132     {
133     csize -= 1;
134     usize = *src++ & 0xff;
135     }
136     else if (!(src[0] & 0x20))
137     {
138     csize -= 2;
139     usize = *src++ & 0x1f;
140     usize = (usize << 6) | (*src++ & 0x3f);
141     }
142     else if (!(src[0] & 0x10))
143     {
144     csize -= 3;
145     usize = *src++ & 0x0f;
146     usize = (usize << 6) | (*src++ & 0x3f);
147     usize = (usize << 6) | (*src++ & 0x3f);
148     }
149     else if (!(src[0] & 0x08))
150     {
151     csize -= 4;
152     usize = *src++ & 0x07;
153     usize = (usize << 6) | (*src++ & 0x3f);
154     usize = (usize << 6) | (*src++ & 0x3f);
155     usize = (usize << 6) | (*src++ & 0x3f);
156     }
157     else if (!(src[0] & 0x04))
158     {
159     csize -= 5;
160     usize = *src++ & 0x03;
161     usize = (usize << 6) | (*src++ & 0x3f);
162     usize = (usize << 6) | (*src++ & 0x3f);
163     usize = (usize << 6) | (*src++ & 0x3f);
164     usize = (usize << 6) | (*src++ & 0x3f);
165     }
166     else
167     croak ("compressed data corrupted");
168    
169     ret = NEWSV (0, usize);
170     SvPOK_only (ret);
171     dst = SvPVX (ret);
172    
173     if (lzf_decompress (src, csize, dst, usize) != usize)
174     croak ("compressed data corrupted", csize, skip, usize);
175     }
176     else
177     {
178     usize = csize - 1;
179     ret = NEWSV (0, usize);
180     SvPOK_only (ret);
181    
182     Move ((void *)(src + 1), (void *)SvPVX (ret), usize, unsigned char);
183     }
184    
185     SvCUR_set (ret, usize);
186    
187     return ret;
188     }
189     else
190     return newSVpvn ("", 0);
191     }
192    
193     static void
194     need_storable(void)
195     {
196 root 1.2 #if PATCHLEVEL < 6
197     perl_eval_pv ("require Storable;", 1);
198     #else
199 root 1.1 load_module (PERL_LOADMOD_NOIMPORT, newSVpv ("Storable", 0), Nullsv);
200 root 1.2 #endif
201 root 1.1
202     storable_mstore = GvCV (gv_fetchpv ("Storable::mstore" , TRUE, SVt_PVCV));
203     storable_mretrieve = GvCV (gv_fetchpv ("Storable::mretrieve", TRUE, SVt_PVCV));
204     }
205    
206     MODULE = Compress::LZF PACKAGE = Compress::LZF
207    
208     void
209     compress(data)
210     SV * data
211     PROTOTYPE: $
212     PPCODE:
213     XPUSHs (sv_2mortal (compress_sv (data, 0, 1)));
214    
215     void
216     decompress(data)
217     SV * data
218     PROTOTYPE: $
219     PPCODE:
220     XPUSHs (sv_2mortal (decompress_sv (data, 0)));
221    
222     void
223     sfreeze(sv)
224     SV * sv
225     ALIAS:
226     sfreeze_cr = 1
227     sfreeze_c = 2
228     PROTOTYPE: $
229     PPCODE:
230    
231 root 1.4 if (!SvOK (sv))
232     XPUSHs (sv_2mortal (newSVpvn ("\02", 1))); /* 02 == MAGIC_undef */
233     else if (SvTYPE(sv) != SVt_IV
234 root 1.3 && SvTYPE(sv) != SVt_NV
235 root 1.9 && SvTYPE(sv) != SVt_PV) /* mstore */
236 root 1.1 {
237 root 1.9 int deref = !SvROK (sv);
238    
239 root 1.1 if (!storable_mstore)
240     need_storable ();
241    
242 root 1.9 if (deref)
243     sv = newRV_noinc (sv);
244    
245 root 1.1 PUSHMARK (SP);
246     XPUSHs (sv);
247     PUTBACK;
248    
249     if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
250     croak ("Storable::mstore didn't return a single scalar");
251    
252     SPAGAIN;
253    
254     sv = POPs;
255    
256     if (SvPVX (sv)[0] != MAGIC_R)
257     croak ("Storable format changed, need newer version of Compress::LZF");
258    
259     if (ix) /* compress */
260 root 1.9 XPUSHs (sv_2mortal (compress_sv (sv, deref ? MAGIC_CR_deref : MAGIC_CR, 0)));
261 root 1.1 else
262 root 1.9 {
263     if (deref)
264     SvPVX (sv)[0] = MAGIC_R_deref;
265    
266     XPUSHs (sv);
267     }
268 root 1.1 }
269 root 1.4 else if (sv && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI))
270 root 1.1 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, 1))); /* need to prefix only */
271     else if (ix == 2) /* compress always */
272     XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, 0)));
273     else /* don't compress */
274     XPUSHs (sv_2mortal (SvREFCNT_inc (sv)));
275    
276     void
277     sthaw(sv)
278     SV * sv
279     PROTOTYPE: $
280     PPCODE:
281    
282 root 1.9 int deref = 0;
283    
284 root 1.7 SvGETMAGIC (sv);
285 root 1.6 if (SvPOK (sv) && IN_RANGE (SvPV_nolen (sv)[0], MAGIC_LO, MAGIC_HI))
286 root 1.1 {
287     switch (SvPVX (sv)[0])
288     {
289 root 1.4 case MAGIC_undef:
290     XPUSHs (sv_2mortal (NEWSV (0, 0)));
291     break;
292    
293 root 1.1 case MAGIC_U:
294     XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
295     break;
296    
297     case MAGIC_C:
298     XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
299     break;
300    
301 root 1.9 case MAGIC_CR_deref:
302     deref = 1;
303 root 1.1 case MAGIC_CR:
304     sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
305 root 1.9 case MAGIC_R_deref:
306     if (SvPVX (sv)[0] == MAGIC_R_deref)
307     {
308     deref = 1;
309     SvPVX (sv)[0] = MAGIC_R;
310     }
311 root 1.1 case MAGIC_R:
312     if (!storable_mstore)
313     need_storable ();
314    
315     PUSHMARK (SP);
316     XPUSHs (sv);
317     PUTBACK;
318    
319     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
320     croak ("Storable::mstore didn't return a single scalar");
321    
322     SPAGAIN;
323    
324 root 1.9 if (deref)
325     {
326     SV *ref = SvREFCNT_inc (SvRV (TOPs));
327    
328     SvREFCNT_dec (TOPs); /* destroy superfluous ref */
329     SETs (ref);
330    
331     if (SvPVX (sv)[0] == MAGIC_R)
332     SvPVX (sv)[0] = MAGIC_R;
333     }
334    
335     XPUSHs (POPs); /* this is a nop, hopefully */
336 root 1.1
337     break;
338    
339     default:
340     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
341     }
342     }
343     else
344     XPUSHs (sv_2mortal (SvREFCNT_inc (sv)));