ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.11
Committed: Wed Apr 10 14:11:48 2002 UTC (22 years, 1 month ago) by root
Branch: MAIN
Changes since 1.10: +1 -1 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    
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 root 1.10 compress_sv (SV *data, char cprepend, int uprepend)
37 root 1.1 {
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 root 1.10 else if (uprepend < 0)
97 root 1.1 {
98     SvREFCNT_dec (ret);
99     ret = SvREFCNT_inc (data);
100     }
101     else
102     {
103 root 1.10 *dst++ = uprepend;
104 root 1.1
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 root 1.10 XPUSHs (sv_2mortal (compress_sv (data, 0, MAGIC_U)));
214 root 1.1
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.10 SvGETMAGIC (sv);
232    
233 root 1.4 if (!SvOK (sv))
234     XPUSHs (sv_2mortal (newSVpvn ("\02", 1))); /* 02 == MAGIC_undef */
235     else if (SvTYPE(sv) != SVt_IV
236 root 1.10 && SvTYPE(sv) != SVt_NV
237     && SvTYPE(sv) != SVt_PV
238     && SvTYPE(sv) != SVt_PVMG+99999) /* mstore */
239 root 1.1 {
240 root 1.9 int deref = !SvROK (sv);
241    
242 root 1.1 if (!storable_mstore)
243     need_storable ();
244    
245 root 1.9 if (deref)
246     sv = newRV_noinc (sv);
247    
248 root 1.1 PUSHMARK (SP);
249     XPUSHs (sv);
250     PUTBACK;
251    
252     if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
253     croak ("Storable::mstore didn't return a single scalar");
254    
255     SPAGAIN;
256    
257     sv = POPs;
258    
259     if (SvPVX (sv)[0] != MAGIC_R)
260     croak ("Storable format changed, need newer version of Compress::LZF");
261    
262 root 1.10 if (deref)
263     SvPVX (sv)[0] = MAGIC_R_deref;
264    
265 root 1.1 if (ix) /* compress */
266 root 1.10 sv = sv_2mortal (compress_sv (sv, deref ? MAGIC_CR_deref : MAGIC_CR, -1));
267 root 1.9
268 root 1.10 XPUSHs (sv);
269 root 1.1 }
270 root 1.10 else if (SvTYPE (sv) == SVt_PV && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI))
271     XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, MAGIC_U))); /* need to prefix only */
272 root 1.1 else if (ix == 2) /* compress always */
273 root 1.10 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, -1)));
274 root 1.1 else /* don't compress */
275     XPUSHs (sv_2mortal (SvREFCNT_inc (sv)));
276    
277     void
278     sthaw(sv)
279     SV * sv
280     PROTOTYPE: $
281     PPCODE:
282    
283 root 1.9 int deref = 0;
284    
285 root 1.7 SvGETMAGIC (sv);
286 root 1.6 if (SvPOK (sv) && IN_RANGE (SvPV_nolen (sv)[0], MAGIC_LO, MAGIC_HI))
287 root 1.1 {
288     switch (SvPVX (sv)[0])
289     {
290 root 1.4 case MAGIC_undef:
291     XPUSHs (sv_2mortal (NEWSV (0, 0)));
292     break;
293    
294 root 1.1 case MAGIC_U:
295     XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
296     break;
297    
298     case MAGIC_C:
299     XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
300     break;
301    
302 root 1.10 case MAGIC_R_deref:
303     deref = 1;
304     SvPVX (sv)[0] = MAGIC_R;
305     goto handle_MAGIC_R;
306    
307 root 1.9 case MAGIC_CR_deref:
308     deref = 1;
309 root 1.1 case MAGIC_CR:
310     sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
311 root 1.10 if (deref)
312     if (SvPVX (sv)[0] == MAGIC_R_deref)
313 root 1.9 SvPVX (sv)[0] = MAGIC_R;
314 root 1.10 else
315     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
316    
317 root 1.1 case MAGIC_R:
318 root 1.10 handle_MAGIC_R:
319 root 1.1 if (!storable_mstore)
320     need_storable ();
321    
322     PUSHMARK (SP);
323     XPUSHs (sv);
324     PUTBACK;
325    
326     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
327     croak ("Storable::mstore didn't return a single scalar");
328    
329     SPAGAIN;
330    
331 root 1.9 if (deref)
332     {
333 root 1.10 SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
334 root 1.9
335     if (SvPVX (sv)[0] == MAGIC_R)
336 root 1.10 SvPVX (sv)[0] = MAGIC_R_deref;
337 root 1.9 }
338 root 1.10 else
339     XPUSHs (POPs); /* this is a nop, hopefully */
340 root 1.1
341     break;
342    
343     default:
344     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
345     }
346     }
347     else
348 root 1.11 XPUSHs (sv_2mortal (newSVsv (sv)));