1 #define PERL_NO_GET_CONTEXT
2 
3 #include "EXTERN.h"
4 #include "perl.h"
5 #include "XSUB.h"
6 
7 #define NEED_sv_2pvbyte
8 #include "ppport.h"
9 
10 #include <lz4.h>
11 #include <lz4hc.h>
12 
13 MODULE = Compress::LZ4    PACKAGE = Compress::LZ4
14 
15 PROTOTYPES: ENABLE
16 
17 SV *
18 compress (sv, level=0)
19     SV *sv
20     IV level
21 ALIAS:
22     compress_hc = 1
23     lz4_compress = 2
24     lz4_compress_hc = 3
25 PREINIT:
26     char *src, *dest;
27     STRLEN src_len, dest_len;
28     int hc;
29 CODE:
30     SvGETMAGIC(sv);
31     if (SvROK(sv) && ! SvAMAGIC(sv)) {
32         sv = SvRV(sv);
33         SvGETMAGIC(sv);
34     }
35     if (! SvOK(sv))
36         XSRETURN_NO;
37     src = SvPVbyte(sv, src_len);
38     if (! src_len)
39         XSRETURN_NO;
40     dest_len = LZ4_compressBound(src_len);
41     if (2 > ix)
42         dest_len += 4;
43     RETVAL = newSV(dest_len);
44     dest = SvPVX(RETVAL);
45     if (! dest)
46         XSRETURN_UNDEF;
47 
48     hc = ix & 1;
49     if (2 > ix) {
50         /* Add the length header as 4 bytes in little endian. */
51         dest[0] = src_len       & 0xff;
52         dest[1] = (src_len>> 8) & 0xff;
53         dest[2] = (src_len>>16) & 0xff;
54         dest[3] = (src_len>>24) & 0xff;
55 
56         dest_len = hc ? LZ4_compress_HC(src, dest + 4, src_len, dest_len, level)
57                     : LZ4_compress_fast(src, dest + 4, src_len, dest_len, level);
58         dest_len += 4;
59     }
60     else {
61         dest_len = hc ? LZ4_compress_HC(src, dest, src_len, dest_len, level)
62                     : LZ4_compress_fast(src, dest, src_len, dest_len, level);
63     }
64 
65     if (! dest_len) {
66         SvREFCNT_dec(RETVAL);
67         XSRETURN_UNDEF;
68     }
69     SvCUR_set(RETVAL, dest_len);
70     SvPOK_on(RETVAL);
71 OUTPUT:
72     RETVAL
73 
74 SV *
75 decompress (sv, len=0)
76     SV *sv
77     int len
78 ALIAS:
79     uncompress = 1
80     lz4_decompress = 2
81     lz4_uncompress = 3
82 PREINIT:
83     char *src, *dest;
84     STRLEN src_len, dest_len;
85     int ret;
86 CODE:
87     PERL_UNUSED_VAR(ix);  /* -W */
88     SvGETMAGIC(sv);
89     if (SvROK(sv) && ! SvAMAGIC(sv)) {
90         sv = SvRV(sv);
91         SvGETMAGIC(sv);
92     }
93     if (! SvOK(sv))
94         XSRETURN_NO;
95     src = SvPVbyte(sv, src_len);
96     if (! src_len )
97         XSRETURN_NO;
98 
99     if (1 == items) {
100         if (src_len < 5)
101             XSRETURN_NO;
102 
103         /* Decode the length header. */
104         dest_len = (src[0] & 0xff) | (src[1] & 0xff) << 8 | (src[2] & 0xff) << 16
105                                 | (src[3] & 0xff) << 24;
106     }
107     else
108         dest_len = len;
109 
110     if (0 >= dest_len)
111         XSRETURN_NO;
112 
113     RETVAL = newSV(dest_len);
114     dest = SvPVX(RETVAL);
115     if (! dest)
116         XSRETURN_UNDEF;
117 
118     if (1 == items)
119         ret = LZ4_decompress_safe(src + 4, dest, src_len - 4, dest_len);
120     else
121         ret = LZ4_decompress_safe(src, dest, src_len, dest_len);
122 
123     if (0 > ret) {
124         SvREFCNT_dec(RETVAL);
125         XSRETURN_UNDEF;
126     }
127     SvCUR_set(RETVAL, ret);
128     SvPOK_on(RETVAL);
129 OUTPUT:
130     RETVAL
131