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