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