ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.14
Committed: Thu Sep 5 04:44:55 2002 UTC (21 years, 8 months ago) by root
Branch: MAIN
Changes since 1.13: +25 -4 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     && SvTYPE(sv) != SVt_PVMG)) /* mstore */
261 root 1.1 {
262 root 1.9 int deref = !SvROK (sv);
263    
264 root 1.1 if (!storable_mstore)
265     need_storable ();
266    
267 root 1.9 if (deref)
268     sv = newRV_noinc (sv);
269    
270 root 1.1 PUSHMARK (SP);
271     XPUSHs (sv);
272     PUTBACK;
273    
274     if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
275     croak ("Storable::mstore didn't return a single scalar");
276    
277     SPAGAIN;
278    
279     sv = POPs;
280    
281     if (SvPVX (sv)[0] != MAGIC_R)
282     croak ("Storable format changed, need newer version of Compress::LZF");
283    
284 root 1.10 if (deref)
285     SvPVX (sv)[0] = MAGIC_R_deref;
286    
287 root 1.1 if (ix) /* compress */
288 root 1.10 sv = sv_2mortal (compress_sv (sv, deref ? MAGIC_CR_deref : MAGIC_CR, -1));
289 root 1.9
290 root 1.10 XPUSHs (sv);
291 root 1.1 }
292 root 1.13 else if (SvPOKp (sv) && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI))
293 root 1.10 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, MAGIC_U))); /* need to prefix only */
294 root 1.1 else if (ix == 2) /* compress always */
295 root 1.10 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, -1)));
296 root 1.1 else /* don't compress */
297     XPUSHs (sv_2mortal (SvREFCNT_inc (sv)));
298    
299     void
300     sthaw(sv)
301     SV * sv
302     PROTOTYPE: $
303     PPCODE:
304    
305 root 1.9 int deref = 0;
306    
307 root 1.7 SvGETMAGIC (sv);
308 root 1.6 if (SvPOK (sv) && IN_RANGE (SvPV_nolen (sv)[0], MAGIC_LO, MAGIC_HI))
309 root 1.1 {
310     switch (SvPVX (sv)[0])
311     {
312 root 1.4 case MAGIC_undef:
313     XPUSHs (sv_2mortal (NEWSV (0, 0)));
314     break;
315    
316 root 1.1 case MAGIC_U:
317     XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
318     break;
319    
320     case MAGIC_C:
321     XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
322     break;
323    
324 root 1.10 case MAGIC_R_deref:
325     deref = 1;
326     SvPVX (sv)[0] = MAGIC_R;
327     goto handle_MAGIC_R;
328    
329 root 1.9 case MAGIC_CR_deref:
330     deref = 1;
331 root 1.1 case MAGIC_CR:
332     sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
333 root 1.10 if (deref)
334     if (SvPVX (sv)[0] == MAGIC_R_deref)
335 root 1.9 SvPVX (sv)[0] = MAGIC_R;
336 root 1.10 else
337     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
338    
339 root 1.1 case MAGIC_R:
340 root 1.10 handle_MAGIC_R:
341 root 1.1 if (!storable_mstore)
342     need_storable ();
343    
344     PUSHMARK (SP);
345     XPUSHs (sv);
346     PUTBACK;
347    
348     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
349     croak ("Storable::mstore didn't return a single scalar");
350    
351     SPAGAIN;
352    
353 root 1.9 if (deref)
354     {
355 root 1.10 SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
356 root 1.9
357     if (SvPVX (sv)[0] == MAGIC_R)
358 root 1.10 SvPVX (sv)[0] = MAGIC_R_deref;
359 root 1.9 }
360 root 1.10 else
361     XPUSHs (POPs); /* this is a nop, hopefully */
362 root 1.1
363     break;
364    
365     default:
366     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
367     }
368     }
369     else
370 root 1.11 XPUSHs (sv_2mortal (newSVsv (sv)));