2370abbcef9b2df7dcfa86ded4ec306c2dea17f7
[io-compress-brotli.git] / Brotli.xs
1 #define PERL_NO_GET_CONTEXT
2 #include "EXTERN.h"
3 #include "perl.h"
4 #include "XSUB.h"
5
6 #include "ppport.h"
7
8 #include <brotli/decode.h>
9 #include <brotli/encode.h>
10
11 #define BUFFER_SIZE 1048576
12
13 typedef struct brotli_decoder {
14 BrotliDecoderState *decoder;
15 }* IO__Uncompress__Brotli;
16
17 typedef struct brotli_encoder {
18 BrotliEncoderState *encoder;
19 }* IO__Compress__Brotli;
20
21
22 MODULE = IO::Compress::Brotli PACKAGE = IO::Uncompress::Brotli
23 PROTOTYPES: ENABLE
24
25 SV*
26 unbro(buffer, decoded_size)
27 SV* buffer
28 size_t decoded_size
29 PREINIT:
30 STRLEN encoded_size;
31 uint8_t *encoded_buffer, *decoded_buffer;
32 CODE:
33 encoded_buffer = (uint8_t*) SvPV(buffer, encoded_size);
34 Newx(decoded_buffer, decoded_size, uint8_t);
35 if(!BrotliDecoderDecompress(encoded_size, encoded_buffer, &decoded_size, decoded_buffer)){
36 croak("Error in BrotliDecoderDecompress");
37 }
38 RETVAL = newSV(0);
39 sv_usepvn(RETVAL, decoded_buffer, decoded_size);
40 OUTPUT:
41 RETVAL
42
43 IO::Uncompress::Brotli
44 create(class)
45 SV* class
46 CODE:
47 Newx(RETVAL, 1, struct brotli_decoder);
48 RETVAL->decoder = BrotliDecoderCreateInstance(NULL, NULL, NULL);
49 OUTPUT:
50 RETVAL
51
52 void
53 DESTROY(self)
54 IO::Uncompress::Brotli self
55 CODE:
56 BrotliDecoderDestroyInstance(self->decoder);
57 Safefree(self);
58
59 SV*
60 decompress(self, in)
61 IO::Uncompress::Brotli self
62 SV* in
63 PREINIT:
64 uint8_t *next_in, *next_out, *buffer;
65 size_t available_in, available_out;
66 BrotliDecoderResult result;
67 CODE:
68 next_in = (uint8_t*) SvPV(in, available_in);
69 Newx(buffer, BUFFER_SIZE, uint8_t);
70 RETVAL = newSVpv("", 0);
71 result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
72 while(result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
73 next_out = buffer;
74 available_out=BUFFER_SIZE;
75 result = BrotliDecoderDecompressStream( self->decoder,
76 &available_in,
77 (const uint8_t**) &next_in,
78 &available_out,
79 &next_out,
80 NULL );
81 if(!result){
82 Safefree(buffer);
83 croak("Error in BrotliDecoderDecompressStream");
84 }
85 sv_catpvn(RETVAL, (const char*)buffer, BUFFER_SIZE-available_out);
86 }
87 Safefree(buffer);
88 OUTPUT:
89 RETVAL
90
91 void
92 set_dictionary(self, dict)
93 IO::Uncompress::Brotli self
94 SV* dict
95 PREINIT:
96 size_t size;
97 uint8_t *data;
98 CODE:
99 data = SvPV(dict, size);
100 BrotliDecoderSetCustomDictionary(self->decoder, size, data);
101
102
103 MODULE = IO::Compress::Brotli PACKAGE = IO::Compress::Brotli
104 PROTOTYPES: ENABLE
105
106 SV*
107 bro(buffer, quality=BROTLI_DEFAULT_QUALITY, lgwin=BROTLI_DEFAULT_WINDOW)
108 SV* buffer
109 U32 quality
110 U32 lgwin
111 PREINIT:
112 size_t encoded_size;
113 STRLEN decoded_size;
114 uint8_t *encoded_buffer, *decoded_buffer;
115 BROTLI_BOOL result;
116 CODE:
117 if( quality < BROTLI_MIN_QUALITY || quality > BROTLI_MAX_QUALITY ) {
118 croak("Invalid quality value");
119 }
120 if( lgwin < BROTLI_MIN_WINDOW_BITS || lgwin > BROTLI_MAX_WINDOW_BITS ) {
121 croak("Invalid window value");
122 }
123 decoded_buffer = (uint8_t*) SvPV(buffer, decoded_size);
124 encoded_size = BrotliEncoderMaxCompressedSize(decoded_size);
125 if(!encoded_size){
126 croak("Compressed size overflow");
127 }
128 Newx(encoded_buffer, encoded_size+1, uint8_t);
129 result = BrotliEncoderCompress( quality,
130 lgwin,
131 BROTLI_DEFAULT_MODE,
132 decoded_size,
133 decoded_buffer,
134 &encoded_size,
135 encoded_buffer );
136 if(!result){
137 Safefree(buffer);
138 croak("Error in BrotliEncoderCompress");
139 }
140 encoded_buffer[encoded_size]=0;
141 RETVAL = newSV(0);
142 sv_usepvn_flags(RETVAL, encoded_buffer, encoded_size, SV_SMAGIC | SV_HAS_TRAILING_NUL);
143 OUTPUT:
144 RETVAL
145
146 IO::Compress::Brotli
147 create(class)
148 SV* class
149 CODE:
150 Newx(RETVAL, 1, struct brotli_encoder);
151 RETVAL->encoder = BrotliEncoderCreateInstance(NULL, NULL, NULL);
152 OUTPUT:
153 RETVAL
154
155 bool BrotliEncoderSetParameter(self, value)
156 IO::Compress::Brotli self
157 U32 value
158 ALIAS:
159 window = 1
160 quality = 2
161 _mode = 3
162 PREINIT:
163 BrotliEncoderParameter param;
164 INIT:
165 switch(ix){
166 case 0:
167 croak("BrotliEncoderSetParameter may not be called directly");
168 break;
169 case 1:
170 if( value < BROTLI_MIN_WINDOW_BITS || value > BROTLI_MAX_WINDOW_BITS ) {
171 croak("Invalid window value");
172 }
173 param = BROTLI_PARAM_LGWIN;
174 break;
175 case 2:
176 if( value < BROTLI_MIN_QUALITY || value > BROTLI_MAX_QUALITY ) {
177 croak("Invalid quality value");
178 }
179 param = BROTLI_PARAM_QUALITY;
180 break;
181 case 3:
182 /* Validation done on Perl side */
183 param = BROTLI_PARAM_MODE;
184 break;
185 default:
186 croak("Impossible ix in BrotliEncoderSetParameter");
187 break;
188 }
189 C_ARGS:
190 self->encoder, param, value
191
192 SV*
193 _compress(self, in = &PL_sv_undef)
194 IO::Compress::Brotli self
195 SV* in
196 ALIAS:
197 compress = 1
198 flush = 2
199 finish = 3
200 PREINIT:
201 uint8_t *next_in, *next_out, *buffer;
202 size_t available_in, available_out;
203 BROTLI_BOOL result;
204 BrotliEncoderOperation op;
205 CODE:
206 switch(ix) {
207 case 0:
208 croak("_compress may not be called directly");
209 break;
210 case 1:
211 op = BROTLI_OPERATION_PROCESS;
212 break;
213 case 2:
214 op = BROTLI_OPERATION_FLUSH;
215 break;
216 case 3:
217 op = BROTLI_OPERATION_FINISH;
218 break;
219 default:
220 croak("Impossible ix in _compress");
221 break;
222 }
223
224 Newx(buffer, BUFFER_SIZE, uint8_t);
225 if(in == &PL_sv_undef)
226 next_in = (uint8_t*) buffer, available_in = 0;
227 else
228 next_in = (uint8_t*) SvPV(in, available_in);
229 RETVAL = newSVpv("", 0);
230 while(1) {
231 next_out = buffer;
232 available_out = BUFFER_SIZE;
233 result = BrotliEncoderCompressStream( self->encoder,
234 (BrotliEncoderOperation) op,
235 &available_in,
236 (const uint8_t**) &next_in,
237 &available_out,
238 &next_out,
239 NULL );
240 if(!result) {
241 Safefree(buffer);
242 croak("Error in BrotliEncoderCompressStream");
243 }
244
245 if( available_out != BUFFER_SIZE ) {
246 sv_catpvn(RETVAL, (const char*)buffer, BUFFER_SIZE-available_out);
247 }
248
249 if(
250 BrotliEncoderIsFinished(self->encoder) ||
251 (!available_in && !BrotliEncoderHasMoreOutput(self->encoder))
252 ) break;
253 }
254 Safefree(buffer);
255 OUTPUT:
256 RETVAL
257
258 void
259 DESTROY(self)
260 IO::Compress::Brotli self
261 CODE:
262 BrotliEncoderDestroyInstance(self->encoder);
263 Safefree(self);
264
265 void
266 set_dictionary(self, dict)
267 IO::Compress::Brotli self
268 SV* dict
269 PREINIT:
270 size_t size;
271 uint8_t *data;
272 CODE:
273 data = SvPV(dict, size);
274 BrotliEncoderSetCustomDictionary(self->encoder, size, data);
This page took 0.027056 seconds and 3 git commands to generate.