ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.4
Committed: Thu Sep 27 20:05:38 2001 UTC (22 years, 7 months ago) by root
Branch: MAIN
Changes since 1.3: +12 -6 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     #define MAGIC_HI 7 /* room for one higher storable major */
28    
29     #define IN_RANGE(v,l,h) ((unsigned int)((unsigned)(v) - (unsigned)(l)) <= (unsigned)(h) - (unsigned)(l))
30    
31     static CV *storable_mstore, *storable_mretrieve;
32    
33     static SV *
34     compress_sv (SV *data, char cprepend, char uprepend)
35     {
36     STRLEN usize, csize;
37     char *src = (char *)SvPV (data, usize);
38    
39     if (usize)
40     {
41     SV *ret = NEWSV (0, usize + 1);
42     unsigned char *dst;
43     int skip = 0;
44    
45     SvPOK_only (ret);
46     dst = (unsigned char *)SvPVX (ret);
47    
48     if (cprepend)
49     dst[skip++] = cprepend;
50    
51     if (usize < 0x80)
52     {
53     dst[skip++] = usize;
54     }
55     else if (usize < 0x800)
56     {
57     dst[skip++] = (( usize >> 6) | 0xc0);
58     dst[skip++] = (( usize & 0x3f) | 0x80);
59     }
60     else if (usize < 0x10000)
61     {
62     dst[skip++] = (( usize >> 12) | 0xe0);
63     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
64     dst[skip++] = (( usize & 0x3f) | 0x80);
65     }
66     else if (usize < 0x200000)
67     {
68     dst[skip++] = (( usize >> 18) | 0xf0);
69     dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
70     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
71     dst[skip++] = (( usize & 0x3f) | 0x80);
72     }
73     else if (usize < 0x4000000)
74     {
75     dst[skip++] = (( usize >> 24) | 0xf8);
76     dst[skip++] = (((usize >> 18) & 0x3f) | 0x80);
77     dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
78     dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
79     dst[skip++] = (( usize & 0x3f) | 0x80);
80     }
81     else
82     croak ("compress can only compress up to %ld bytes", 0x4000000-1);
83    
84     /* 11 bytes is the smallest compressible string */
85     csize = usize < 11 ? 0 :
86     lzf_compress (src, usize,
87     dst + skip,
88     usize - skip);
89    
90     if (csize)
91     {
92     SvCUR_set (ret, csize + skip);
93     }
94     else if (!uprepend)
95     {
96     SvREFCNT_dec (ret);
97     ret = SvREFCNT_inc (data);
98     }
99     else
100     {
101     *dst++ = 0;
102    
103     Move ((void *)src, (void *)dst, usize, unsigned char);
104    
105     SvCUR_set (ret, usize + 1);
106     }
107    
108     return ret;
109     }
110     else
111     return newSVpv ("", 0);
112     }
113    
114     static SV *
115     decompress_sv (SV *data, int skip)
116     {
117     STRLEN usize, csize;
118     unsigned char *src = (unsigned char *)SvPV (data, csize) + skip;
119    
120     if (csize)
121     {
122     void *dst;
123     SV *ret;
124    
125     csize -= skip;
126    
127     if (src[0])
128     {
129     if (!(src[0] & 0x80))
130     {
131     csize -= 1;
132     usize = *src++ & 0xff;
133     }
134     else if (!(src[0] & 0x20))
135     {
136     csize -= 2;
137     usize = *src++ & 0x1f;
138     usize = (usize << 6) | (*src++ & 0x3f);
139     }
140     else if (!(src[0] & 0x10))
141     {
142     csize -= 3;
143     usize = *src++ & 0x0f;
144     usize = (usize << 6) | (*src++ & 0x3f);
145     usize = (usize << 6) | (*src++ & 0x3f);
146     }
147     else if (!(src[0] & 0x08))
148     {
149     csize -= 4;
150     usize = *src++ & 0x07;
151     usize = (usize << 6) | (*src++ & 0x3f);
152     usize = (usize << 6) | (*src++ & 0x3f);
153     usize = (usize << 6) | (*src++ & 0x3f);
154     }
155     else if (!(src[0] & 0x04))
156     {
157     csize -= 5;
158     usize = *src++ & 0x03;
159     usize = (usize << 6) | (*src++ & 0x3f);
160     usize = (usize << 6) | (*src++ & 0x3f);
161     usize = (usize << 6) | (*src++ & 0x3f);
162     usize = (usize << 6) | (*src++ & 0x3f);
163     }
164     else
165     croak ("compressed data corrupted");
166    
167     ret = NEWSV (0, usize);
168     SvPOK_only (ret);
169     dst = SvPVX (ret);
170    
171     if (lzf_decompress (src, csize, dst, usize) != usize)
172     croak ("compressed data corrupted", csize, skip, usize);
173     }
174     else
175     {
176     usize = csize - 1;
177     ret = NEWSV (0, usize);
178     SvPOK_only (ret);
179    
180     Move ((void *)(src + 1), (void *)SvPVX (ret), usize, unsigned char);
181     }
182    
183     SvCUR_set (ret, usize);
184    
185     return ret;
186     }
187     else
188     return newSVpvn ("", 0);
189     }
190    
191     static void
192     need_storable(void)
193     {
194 root 1.2 #if PATCHLEVEL < 6
195     perl_eval_pv ("require Storable;", 1);
196     #else
197 root 1.1 load_module (PERL_LOADMOD_NOIMPORT, newSVpv ("Storable", 0), Nullsv);
198 root 1.2 #endif
199 root 1.1
200     storable_mstore = GvCV (gv_fetchpv ("Storable::mstore" , TRUE, SVt_PVCV));
201     storable_mretrieve = GvCV (gv_fetchpv ("Storable::mretrieve", TRUE, SVt_PVCV));
202     }
203    
204     MODULE = Compress::LZF PACKAGE = Compress::LZF
205    
206     void
207     compress(data)
208     SV * data
209     PROTOTYPE: $
210     PPCODE:
211     XPUSHs (sv_2mortal (compress_sv (data, 0, 1)));
212    
213     void
214     decompress(data)
215     SV * data
216     PROTOTYPE: $
217     PPCODE:
218     XPUSHs (sv_2mortal (decompress_sv (data, 0)));
219    
220     void
221     sfreeze(sv)
222     SV * sv
223     ALIAS:
224     sfreeze_cr = 1
225     sfreeze_c = 2
226     PROTOTYPE: $
227     PPCODE:
228    
229 root 1.4 if (!SvOK (sv))
230     XPUSHs (sv_2mortal (newSVpvn ("\02", 1))); /* 02 == MAGIC_undef */
231     else if (SvTYPE(sv) != SVt_IV
232 root 1.3 && SvTYPE(sv) != SVt_NV
233     && SvTYPE(sv) != SVt_PV) /* mstore */
234 root 1.1 {
235     if (!storable_mstore)
236     need_storable ();
237    
238     PUSHMARK (SP);
239     XPUSHs (sv);
240     PUTBACK;
241    
242     if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
243     croak ("Storable::mstore didn't return a single scalar");
244    
245     SPAGAIN;
246    
247     sv = POPs;
248    
249     if (SvPVX (sv)[0] != MAGIC_R)
250     croak ("Storable format changed, need newer version of Compress::LZF");
251    
252     if (ix) /* compress */
253     XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_CR, 0)));
254     else
255     XPUSHs (sv);
256     }
257 root 1.4 else if (sv && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI))
258 root 1.1 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, 1))); /* need to prefix only */
259     else if (ix == 2) /* compress always */
260     XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, 0)));
261     else /* don't compress */
262     XPUSHs (sv_2mortal (SvREFCNT_inc (sv)));
263    
264     void
265     sthaw(sv)
266     SV * sv
267     PROTOTYPE: $
268     PPCODE:
269    
270 root 1.4 if (IN_RANGE (SvPV_nolen (sv)[0], MAGIC_LO, MAGIC_HI))
271 root 1.1 {
272     switch (SvPVX (sv)[0])
273     {
274 root 1.4 case MAGIC_undef:
275     XPUSHs (sv_2mortal (NEWSV (0, 0)));
276     break;
277    
278 root 1.1 case MAGIC_U:
279     XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
280     break;
281    
282     case MAGIC_C:
283     XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
284     break;
285    
286     case MAGIC_CR:
287     sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
288     case MAGIC_R:
289     if (!storable_mstore)
290     need_storable ();
291    
292     PUSHMARK (SP);
293     XPUSHs (sv);
294     PUTBACK;
295    
296     if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
297     croak ("Storable::mstore didn't return a single scalar");
298    
299     SPAGAIN;
300    
301 root 1.4 XPUSHs (POPs); /* this is a nop, hope the compiler also knows this */
302 root 1.1
303     break;
304    
305     default:
306     croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
307     }
308     }
309     else
310     XPUSHs (sv_2mortal (SvREFCNT_inc (sv)));