ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Compress-LZF/LZF.xs
Revision: 1.31
Committed: Sun Aug 25 18:13:26 2013 UTC (10 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-3_7
Changes since 1.30: +21 -9 lines
Log Message:
3.7

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #define LZF_STANDALONE 1
6 #define LZF_STATE_ARG 1
7
8 #include "lzf_c.c"
9 #include "lzf_d.c"
10 #include "lzf_c_best.c"
11
12 /* we re-use the storable header for our purposes */
13 #define MAGIC_LO 0
14 #define MAGIC_U 0 /* uncompressed data follows */
15 #define MAGIC_C 1 /* compressed data follows */
16 #define MAGIC_undef 2 /* the special value undef */
17 #define MAGIC_CR 3 /* storable (reference, freeze), compressed */
18 #define MAGIC_R 4 /* storable (reference, freeze) */
19 #define MAGIC_CR_deref 5 /* storable (NO reference, freeze), compressed */
20 #define MAGIC_R_deref 6 /* storable (NO reference, freeze) */
21 #define MAGIC_HI 7 /* room for one higher storable major */
22 /* for historical reasons, MAGIC_undef + MAGIC_R and MAGIC_undef + MAGIC_R_deref are used, too */
23
24 #define IN_RANGE(v,l,h) ((unsigned int)((unsigned)(v) - (unsigned)(l)) <= (unsigned)(h) - (unsigned)(l))
25
26 static SV *serializer_package, *serializer_mstore, *serializer_mretrieve;
27 static CV *storable_mstore, *storable_mretrieve;
28
29 #if Size_t_size > 4
30 # define MAX_LENGTH ((Size_t)0x80000000L)
31 #else
32 # define MAX_LENGTH ((Size_t) 0x8000000L)
33 #endif
34
35 static SV *
36 compress_sv (SV *data, char cprepend, int uprepend, int best)
37 {
38 LZF_STATE *state;
39 STRLEN usize, csize;
40 char *src = (char *)SvPVbyte (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 <= 0x7f)
55 {
56 dst[skip++] = usize;
57 }
58 else if (usize <= 0x7ff)
59 {
60 dst[skip++] = (( usize >> 6) | 0xc0);
61 dst[skip++] = (( usize & 0x3f) | 0x80);
62 }
63 else if (usize <= 0xffff)
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 <= 0x1fffff)
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 <= 0x3ffffff)
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 if (usize <= 0x7fffffff)
85 {
86 dst[skip++] = (( usize >> 30) | 0xfc);
87 dst[skip++] = (((usize >> 24) & 0x3f) | 0x80);
88 dst[skip++] = (((usize >> 18) & 0x3f) | 0x80);
89 dst[skip++] = (((usize >> 12) & 0x3f) | 0x80);
90 dst[skip++] = (((usize >> 6) & 0x3f) | 0x80);
91 dst[skip++] = (( usize & 0x3f) | 0x80);
92 }
93 else
94 croak ("compress can only compress up to %ld bytes", 0x7fffffffL);
95
96 New (0, state, 1, LZF_STATE);
97 if (!state)
98 croak ("Compress::LZF unable to allocate memory for compression state");
99
100 /* 11 bytes is the smallest compressible string */
101 csize = usize < 11 ? 0 :
102 (best ? lzf_compress_best (src, usize, dst + skip, usize - skip)
103 : lzf_compress (src, usize, dst + skip, usize - skip, *state));
104
105 Safefree (state);
106
107 if (csize)
108 {
109 SvCUR_set (ret, csize + skip);
110 }
111 else if (uprepend < 0)
112 {
113 SvREFCNT_dec (ret);
114 ret = SvREFCNT_inc (data);
115 }
116 else
117 {
118 *dst++ = uprepend;
119
120 Move ((void *)src, (void *)dst, usize, unsigned char);
121
122 SvCUR_set (ret, usize + 1);
123 }
124
125 return ret;
126 }
127 else
128 return newSVpv ("", 0);
129 }
130
131 static SV *
132 decompress_sv (SV *data, int skip)
133 {
134 STRLEN usize, csize;
135 unsigned char *src = (unsigned char *)SvPVbyte (data, csize) + skip;
136
137 if (csize)
138 {
139 void *dst;
140 SV *ret;
141
142 csize -= skip;
143
144 if (src[0])
145 {
146 if (!(src[0] & 0x80) && csize >= 1)
147 {
148 csize -= 1;
149 usize = *src++ & 0xff;
150 }
151 else if (!(src[0] & 0x20) && csize >= 2)
152 {
153 csize -= 2;
154 usize = *src++ & 0x1f;
155 usize = (usize << 6) | (*src++ & 0x3f);
156 }
157 else if (!(src[0] & 0x10) && csize >= 3)
158 {
159 csize -= 3;
160 usize = *src++ & 0x0f;
161 usize = (usize << 6) | (*src++ & 0x3f);
162 usize = (usize << 6) | (*src++ & 0x3f);
163 }
164 else if (!(src[0] & 0x08) && csize >= 4)
165 {
166 csize -= 4;
167 usize = *src++ & 0x07;
168 usize = (usize << 6) | (*src++ & 0x3f);
169 usize = (usize << 6) | (*src++ & 0x3f);
170 usize = (usize << 6) | (*src++ & 0x3f);
171 }
172 else if (!(src[0] & 0x04) && csize >= 5)
173 {
174 csize -= 5;
175 usize = *src++ & 0x03;
176 usize = (usize << 6) | (*src++ & 0x3f);
177 usize = (usize << 6) | (*src++ & 0x3f);
178 usize = (usize << 6) | (*src++ & 0x3f);
179 usize = (usize << 6) | (*src++ & 0x3f);
180 }
181 else if (!(src[0] & 0x02) && csize >= 6)
182 {
183 csize -= 6;
184 usize = *src++ & 0x01;
185 usize = (usize << 6) | (*src++ & 0x3f);
186 usize = (usize << 6) | (*src++ & 0x3f);
187 usize = (usize << 6) | (*src++ & 0x3f);
188 usize = (usize << 6) | (*src++ & 0x3f);
189 usize = (usize << 6) | (*src++ & 0x3f);
190 }
191 else
192 croak ("compressed data corrupted (invalid length)");
193
194 if (!usize)
195 croak ("compressed data corrupted (invalid length)");
196
197 ret = NEWSV (0, usize);
198 SvPOK_only (ret);
199 dst = SvPVX (ret);
200
201 if (lzf_decompress (src, csize, dst, usize) != usize)
202 {
203 SvREFCNT_dec (ret);
204 croak ("compressed data corrupted (size mismatch)", csize, skip, usize);
205 }
206 }
207 else
208 {
209 usize = csize - 1;
210 ret = NEWSV (0, usize | 1);
211 SvPOK_only (ret);
212
213 Move ((void *)(src + 1), (void *)SvPVX (ret), usize, unsigned char);
214 }
215
216 SvCUR_set (ret, usize);
217
218 return ret;
219 }
220 else
221 return newSVpvn ("", 0);
222 }
223
224 static void
225 need_storable (void)
226 {
227 eval_sv (sv_2mortal (newSVpvf ("require %s", SvPVbyte_nolen (serializer_package))), G_VOID | G_DISCARD);
228
229 storable_mstore = (CV *)SvREFCNT_inc (GvCV (gv_fetchpv (SvPVbyte_nolen (serializer_mstore ), TRUE, SVt_PVCV)));
230 storable_mretrieve = (CV *)SvREFCNT_inc (GvCV (gv_fetchpv (SvPVbyte_nolen (serializer_mretrieve), TRUE, SVt_PVCV)));
231 }
232
233 MODULE = Compress::LZF PACKAGE = Compress::LZF
234
235 BOOT:
236 serializer_package = newSVpv ("Storable", 0);
237 serializer_mstore = newSVpv ("Storable::net_mstore", 0);
238 serializer_mretrieve = newSVpv ("Storable::mretrieve", 0);
239
240 void
241 set_serializer(package, mstore, mretrieve)
242 SV * package
243 SV * mstore
244 SV * mretrieve
245 PROTOTYPE: $$$
246 PPCODE:
247 SvSetSV (serializer_package , package );
248 SvSetSV (serializer_mstore , mstore );
249 SvSetSV (serializer_mretrieve, mretrieve);
250 SvREFCNT_dec (storable_mstore ); storable_mstore = 0;
251 SvREFCNT_dec (storable_mretrieve); storable_mretrieve = 0;
252
253 void
254 compress(data)
255 SV * data
256 ALIAS:
257 compress_best = 1
258 PROTOTYPE: $
259 PPCODE:
260 XPUSHs (sv_2mortal (compress_sv (data, 0, MAGIC_U, ix)));
261
262 void
263 decompress(data)
264 SV * data
265 PROTOTYPE: $
266 PPCODE:
267 XPUSHs (sv_2mortal (decompress_sv (data, 0)));
268
269 void
270 sfreeze(sv)
271 SV * sv
272 ALIAS:
273 sfreeze = 0
274 sfreeze_cr = 1
275 sfreeze_c = 2
276 sfreeze_best = 4
277 sfreeze_cr_best = 5
278 sfreeze_c_best = 6
279 PROTOTYPE: $
280 PPCODE:
281 {
282 int best = ix & 4;
283 ix &= 3;
284
285 SvGETMAGIC (sv);
286
287 if (!SvOK (sv))
288 XPUSHs (sv_2mortal (newSVpvn ("\02", 1))); /* 02 == MAGIC_undef */
289 else if (SvROK (sv)
290 || SvUTF8 (sv)
291 || (SvTYPE(sv) != SVt_IV
292 && SvTYPE(sv) != SVt_NV
293 && SvTYPE(sv) != SVt_PV
294 && SvTYPE(sv) != SVt_PVIV
295 && SvTYPE(sv) != SVt_PVNV
296 && SvTYPE(sv) != SVt_PVMG)) /* mstore */
297 {
298 int deref = !SvROK (sv);
299 char *pv;
300
301 if (!storable_mstore)
302 {
303 PUTBACK;
304 need_storable ();
305 SPAGAIN;
306 }
307
308 if (deref)
309 sv = newRV_noinc (sv);
310
311 PUSHMARK (SP);
312 XPUSHs (sv);
313 PUTBACK;
314
315 if (1 != call_sv ((SV *)storable_mstore, G_SCALAR))
316 croak ("%s didn't return a single scalar", SvPVbyte_nolen (serializer_mstore));
317
318 SPAGAIN;
319
320 sv = POPs;
321 pv = SvPV_nolen (sv);
322
323 if (*pv == MAGIC_R)
324 {
325 if (deref)
326 *pv = MAGIC_R_deref;
327 }
328 else
329 {
330 char pfx[2];
331
332 pfx[0] = MAGIC_undef;
333 pfx[1] = deref ? MAGIC_R_deref : MAGIC_R;
334
335 sv_insert (sv, 0, 0, pfx, 2);
336 }
337
338 if (ix) /* compress */
339 sv = sv_2mortal (compress_sv (sv, deref ? MAGIC_CR_deref : MAGIC_CR, -1, best));
340
341 XPUSHs (sv);
342 }
343 else if (SvPOKp (sv) && IN_RANGE (SvPVX (sv)[0], MAGIC_LO, MAGIC_HI))
344 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, MAGIC_U, best))); /* need to prefix only */
345 else if (ix == 2) /* compress always */
346 XPUSHs (sv_2mortal (compress_sv (sv, MAGIC_C, -1, best)));
347 else if (SvNIOK (sv)) /* don't compress */
348 {
349 STRLEN len;
350 char *s = SvPV (sv, len);
351 XPUSHs (sv_2mortal (newSVpvn (s, len)));
352 }
353 else /* don't compress */
354 XPUSHs (sv_2mortal (newSVsv (sv)));
355 }
356
357 void
358 sthaw(sv)
359 SV * sv
360 PROTOTYPE: $
361 PPCODE:
362 {
363 STRLEN svlen;
364 int deref = 0;
365
366 SvGETMAGIC (sv);
367 if (SvPOK (sv) && IN_RANGE (SvPVbyte (sv, svlen)[0], MAGIC_LO, MAGIC_HI))
368 {
369 redo:
370
371 switch (SvPVX (sv)[0])
372 {
373 case MAGIC_undef:
374 if (svlen <= 1)
375 XPUSHs (sv_2mortal (NEWSV (0, 0)));
376 else
377 {
378 if (SvPVX (sv)[1] == MAGIC_R_deref)
379 deref = 1;
380 else if (SvPVX (sv)[1] != MAGIC_R)
381 croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
382
383 sv_chop (sv, SvPVX (sv) + 2);
384
385 if (!storable_mstore)
386 {
387 PUTBACK;
388 need_storable ();
389 SPAGAIN;
390 }
391
392 PUSHMARK (SP);
393 XPUSHs (sv);
394 PUTBACK;
395
396 if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
397 croak ("%s didn't return a single scalar", SvPVbyte_nolen (serializer_mretrieve));
398
399 SPAGAIN;
400
401 if (deref)
402 SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
403 else
404 SETs (sv_2mortal (newSVsv (TOPs)));
405 }
406 break;
407
408 case MAGIC_U:
409 XPUSHs (sv_2mortal (decompress_sv (sv, 0)));
410 break;
411
412 case MAGIC_C:
413 XPUSHs (sv_2mortal (decompress_sv (sv, 1)));
414 break;
415
416 case MAGIC_R_deref:
417 deref = 1;
418 SvPVX (sv)[0] = MAGIC_R;
419 goto handle_MAGIC_R;
420
421 case MAGIC_CR_deref:
422 deref = 1;
423 case MAGIC_CR:
424 sv = sv_2mortal (decompress_sv (sv, 1)); /* mortal could be optimized */
425 if (deref)
426 if (SvPVX (sv)[0] == MAGIC_R_deref)
427 SvPVX (sv)[0] = MAGIC_R;
428
429 goto redo;
430
431 case MAGIC_R:
432 handle_MAGIC_R:
433 if (!storable_mstore)
434 {
435 PUTBACK;
436 need_storable ();
437 SPAGAIN;
438 }
439
440 PUSHMARK (SP);
441 XPUSHs (sv);
442 PUTBACK;
443
444 if (1 != call_sv ((SV *)storable_mretrieve, G_SCALAR))
445 croak ("%s didn't return a single scalar", SvPVbyte_nolen (serializer_mretrieve));
446
447 SPAGAIN;
448
449 if (deref)
450 {
451 SETs (sv_2mortal (SvREFCNT_inc (SvRV (TOPs))));
452
453 if (SvPVX (sv)[0] == MAGIC_R)
454 SvPVX (sv)[0] = MAGIC_R_deref;
455 }
456 else
457 SETs (sv_2mortal (newSVsv (TOPs)));
458
459 break;
460
461 default:
462 croak ("Compress::LZF::sthaw(): invalid data, maybe you need a newer version of Compress::LZF?");
463 }
464 }
465 else
466 XPUSHs (sv_2mortal (newSVsv (sv)));
467 }
468