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