ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.19
Committed: Tue Aug 3 15:07:51 2004 UTC (19 years, 9 months ago) by pcg
Branch: MAIN
CVS Tags: rel-1_5
Changes since 1.18: +0 -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 root 1.14 static SV *serializer_package, *serializer_mstore, *serializer_mretrieve;
34 root 1.1 static CV *storable_mstore, *storable_mretrieve;
35    
36     static SV *
37 root 1.10 compress_sv (SV *data, char cprepend, int uprepend)
38 root 1.1 {
39     STRLEN usize, csize;
40     char *src = (char *)SvPV (data, usize);
41    
42     if (usize)
43     {
44     SV *ret = NEWSV (0, usize + 1);
45     unsigned char *dst;
46     int skip = 0;
47    
48     SvPOK_only (ret);
49     dst = (unsigned char *)SvPVX (ret);
50    
51     if (cprepend)
52     dst[skip++] = cprepend;
53    
54     if (usize < 0x80)
55     {
56     dst[skip++] = usize;
57     }
58     else if (usize < 0x800)
59     {
60     dst[skip++] = (( usize >> 6) | 0xc0);
61     dst[skip++] = (( usize & 0x3f) | 0x80);
62     }
63     else if (usize < 0x10000)
64     {
65     dst[skip++] = (( usize >> 12) | 0xe0);
66     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
67     dst[skip++] = (( usize & 0x3f) | 0x80);
68     }
69     else if (usize < 0x200000)
70     {
71     dst[skip++] = (( usize >> 18) | 0xf0);
72     dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
73     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
74     dst[skip++] = (( usize & 0x3f) | 0x80);
75     }
76     else if (usize < 0x4000000)
77     {
78     dst[skip++] = (( usize >> 24) | 0xf8);
79     dst[skip++] = (((usize >> 18) & 0x3f) | 0x80);
80     dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
81     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
82     dst[skip++] = (( usize & 0x3f) | 0x80);
83     }
84     else
85     croak ("compress can only compress up to %ld bytes", 0x4000000-1);
86    
87     /* 11 bytes is the smallest compressible string */
88     csize = usize < 11 ? 0 :
89     lzf_compress (src, usize,
90     dst + skip,
91     usize - skip);
92    
93     if (csize)
94     {
95     SvCUR_set (ret, csize + skip);
96     }
97 root 1.10 else if (uprepend < 0)
98 root 1.1 {
99     SvREFCNT_dec (ret);
100     ret = SvREFCNT_inc (data);
101     }
102     else
103     {
104 root 1.10 *dst++ = uprepend;
105 root 1.1
106     Move ((void *)src, (void *)dst, usize, unsigned char);
107    
108     SvCUR_set (ret, usize + 1);
109     }
110    
111     return ret;
112     }
113     else
114     return newSVpv ("", 0);
115     }
116    
117     static SV *
118     decompress_sv (SV *data, int skip)
119     {
120     STRLEN usize, csize;
121     unsigned char *src = (unsigned char *)SvPV (data, csize) + skip;
122    
123     if (csize)
124     {
125     void *dst;
126     SV *ret;
127    
128     csize -= skip;
129    
130     if (src[0])
131     {
132     if (!(src[0] & 0x80))
133     {
134     csize -= 1;
135     usize = *src++ & 0xff;
136     }
137     else if (!(src[0] & 0x20))
138     {
139     csize -= 2;
140     usize = *src++ & 0x1f;
141     usize = (usize << 6) | (*src++ & 0x3f);
142     }
143     else if (!(src[0] & 0x10))
144     {
145     csize -= 3;
146     usize = *src++ & 0x0f;
147     usize = (usize << 6) | (*src++ & 0x3f);
148     usize = (usize << 6) | (*src++ & 0x3f);
149     }
150     else if (!(src[0] & 0x08))
151     {
152     csize -= 4;
153     usize = *src++ & 0x07;
154     usize = (usize << 6) | (*src++ & 0x3f);
155     usize = (usize << 6) | (*src++ & 0x3f);
156     usize = (usize << 6) | (*src++ & 0x3f);
157     }
158     else if (!(src[0] & 0x04))
159     {
160     csize -= 5;
161     usize = *src++ & 0x03;
162     usize = (usize << 6) | (*src++ & 0x3f);
163     usize = (usize << 6) | (*src++ & 0x3f);
164     usize = (usize << 6) | (*src++ & 0x3f);
165     usize = (usize << 6) | (*src++ & 0x3f);
166     }
167     else
168 root 1.13 croak ("compressed data corrupted (invalid length)");
169 root 1.1
170     ret = NEWSV (0, usize);
171     SvPOK_only (ret);
172     dst = SvPVX (ret);
173    
174     if (lzf_decompress (src, csize, dst, usize) != usize)
175 root 1.13 croak ("compressed data corrupted (size mismatch)", csize, skip, usize);
176 root 1.1 }
177     else
178     {
179     usize = csize - 1;
180     ret = NEWSV (0, usize);
181     SvPOK_only (ret);
182    
183     Move ((void *)(src + 1), (void *)SvPVX (ret), usize, unsigned char);
184     }
185    
186     SvCUR_set (ret, usize);
187    
188     return ret;
189     }
190     else
191     return newSVpvn ("", 0);
192     }
193    
194     static void
195     need_storable(void)
196     {
197 root 1.2 #if PATCHLEVEL < 6
198 root 1.14 char req[8192];
199     sprintf (req, "require %s;", SvPV_nolen (serializer_package));
200     perl_eval_pv (req, 1);
201 root 1.2 #else
202 root 1.14 load_module (PERL_LOADMOD_NOIMPORT, serializer_package, Nullsv);
203 root 1.2 #endif
204 root 1.1
205 root 1.14 storable_mstore = GvCV (gv_fetchpv (SvPV_nolen (serializer_mstore ), TRUE, SVt_PVCV));
206     storable_mretrieve = GvCV (gv_fetchpv (SvPV_nolen (serializer_mretrieve), TRUE, SVt_PVCV));
207 root 1.1 }
208    
209     MODULE = Compress::LZF PACKAGE = Compress::LZF
210 root 1.14
211     BOOT:
212     serializer_package = newSVpv ("Storable", 0);
213     serializer_mstore = newSVpv ("Storable::mstore", 0);
214     serializer_mretrieve = newSVpv ("Storable::mretrieve", 0);
215    
216     void
217     set_serializer(package, mstore, mretrieve)
218     SV * package
219     SV * mstore
220     SV * mretrieve
221     PROTOTYPE: $$$
222     PPCODE:
223     SvSetSV (serializer_package , package );
224     SvSetSV (serializer_mstore , mstore );
225     SvSetSV (serializer_mretrieve, mretrieve);
226     storable_mstore =
227     storable_mretrieve = 0;
228 root 1.1
229     void
230     compress(data)
231     SV * data
232     PROTOTYPE: $
233     PPCODE:
234 root 1.10 XPUSHs (sv_2mortal (compress_sv (data, 0, MAGIC_U)));
235 root 1.1
236     void
237     decompress(data)
238     SV * data
239     PROTOTYPE: $
240     PPCODE:
241     XPUSHs (sv_2mortal (decompress_sv (data, 0)));
242    
243     void
244     sfreeze(sv)
245     SV * sv
246     ALIAS:
247     sfreeze_cr = 1
248     sfreeze_c = 2
249     PROTOTYPE: $
250     PPCODE:
251    
252 root 1.10 SvGETMAGIC (sv);
253    
254 root 1.4 if (!SvOK (sv))
255     XPUSHs (sv_2mortal (newSVpvn ("\02", 1))); /* 02 == MAGIC_undef */
256 root 1.12 else if (SvROK (sv)
257     || (SvTYPE(sv) != SVt_IV
258     && SvTYPE(sv) != SVt_NV
259     && SvTYPE(sv) != SVt_PV
260 root 1.15 && SvTYPE(sv) != SVt_PVIV
261     && SvTYPE(sv) != SVt_PVNV
262 root 1.12 && SvTYPE(sv) != SVt_PVMG)) /* mstore */
263 root 1.1 {
264 root 1.9 int deref = !SvROK (sv);
265    
266 root 1.1 if (!storable_mstore)
267     need_storable ();
268    
269 root 1.9 if (deref)
270     sv = newRV_noinc (sv);
271    
272 root 1.1 PUSHMARK (SP);
273     XPUSHs (sv);
274     PUTBACK;
275    
276     if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
277     croak ("Storable::mstore didn't return a single scalar");
278    
279     SPAGAIN;
280    
281     sv = POPs;
282    
283     if (SvPVX (sv)[0] != MAGIC_R)
284     croak ("Storable format changed, need newer version of Compress::LZF");
285    
286 root 1.10 if (deref)
287     SvPVX (sv)[0] = MAGIC_R_deref;
288    
289 root 1.1 if (ix) /* compress */
290 root 1.10 sv = sv_2mortal (compress_sv (sv, deref ? MAGIC_CR_deref : MAGIC_CR, -1));
291 root 1.9
292 root 1.10 XPUSHs (sv);
293 root 1.1 }
294 root 1.13 else if (SvPOKp (sv) && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI))
295 root 1.10 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, MAGIC_U))); /* need to prefix only */
296 root 1.1 else if (ix == 2) /* compress always */
297 root 1.10 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, -1)));
298 root 1.15 else if (SvNIOK (sv)) /* don't compress */
299     {
300     STRLEN len;
301     char *s = SvPV (sv, len);
302     XPUSHs (sv_2mortal (newSVpvn (s, len)));
303     }
304 root 1.1 else /* don't compress */
305 root 1.15 XPUSHs (sv_2mortal (newSVsv (sv)));
306 root 1.1
307     void
308     sthaw(sv)
309     SV * sv
310     PROTOTYPE: $
311     PPCODE:
312    
313 root 1.9 int deref = 0;
314    
315 root 1.7 SvGETMAGIC (sv);
316 root 1.6 if (SvPOK (sv) && IN_RANGE (SvPV_nolen (sv)[0], MAGIC_LO, MAGIC_HI))
317 root 1.1 {
318     switch (SvPVX (sv)[0])
319     {
320 root 1.4 case MAGIC_undef:
321     XPUSHs (sv_2mortal (NEWSV (0, 0)));
322     break;
323    
324 root 1.1 case MAGIC_U:
325     XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
326     break;
327    
328     case MAGIC_C:
329     XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
330     break;
331    
332 root 1.10 case MAGIC_R_deref:
333     deref = 1;
334     SvPVX (sv)[0] = MAGIC_R;
335     goto handle_MAGIC_R;
336    
337 root 1.9 case MAGIC_CR_deref:
338     deref = 1;
339 root 1.1 case MAGIC_CR:
340     sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
341 root 1.10 if (deref)
342     if (SvPVX (sv)[0] == MAGIC_R_deref)
343 root 1.9 SvPVX (sv)[0] = MAGIC_R;
344 root 1.10 else
345     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
346    
347 root 1.1 case MAGIC_R:
348 root 1.10 handle_MAGIC_R:
349 root 1.1 if (!storable_mstore)
350     need_storable ();
351    
352     PUSHMARK (SP);
353     XPUSHs (sv);
354     PUTBACK;
355    
356     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
357     croak ("Storable::mstore didn't return a single scalar");
358    
359     SPAGAIN;
360    
361 root 1.9 if (deref)
362     {
363 root 1.10 SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
364 root 1.9
365     if (SvPVX (sv)[0] == MAGIC_R)
366 root 1.10 SvPVX (sv)[0] = MAGIC_R_deref;
367 root 1.9 }
368 root 1.10 else
369 pcg 1.17 SETs (sv_2mortal (newSVsv (TOPs)));
370 root 1.1
371     break;
372    
373     default:
374     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
375     }
376     }
377     else
378 root 1.11 XPUSHs (sv_2mortal (newSVsv (sv)));
379 pcg 1.16