Whitespace
[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 <dec/decode.h>
9 #include <enc/encode.h>
10 #include <common/dictionary.h>
11
12 #define BUFFER_SIZE 1048576
13
14 typedef struct brotli_decoder {
15 BrotliDecoderState *decoder;
16 }* IO__Uncompress__Brotli;
17
18 typedef struct brotli_encoder {
19 BrotliEncoderState *encoder;
20 }* IO__Compress__Brotli;
21
22
23 MODULE = IO::Compress::Brotli PACKAGE = IO::Uncompress::Brotli
24 PROTOTYPES: ENABLE
25
26 SV*
27 unbro(buffer)
28 SV* buffer
29 PREINIT:
30 size_t decoded_size;
31 STRLEN encoded_size;
32 uint8_t *encoded_buffer, *decoded_buffer;
33 CODE:
34 encoded_buffer = (uint8_t*) SvPV(buffer, encoded_size);
35 if(!BrotliDecompressedSize(encoded_size, encoded_buffer, &decoded_size)){
36 croak("Error in BrotliDecompressedSize");
37 }
38 Newx(decoded_buffer, decoded_size+1, uint8_t);
39 decoded_buffer[decoded_size]=0;
40 if(!BrotliDecoderDecompress(encoded_size, encoded_buffer, &decoded_size, decoded_buffer)){
41 croak("Error in BrotliDecoderDecompress");
42 }
43 RETVAL = newSV(0);
44 sv_usepvn_flags(RETVAL, decoded_buffer, decoded_size, SV_HAS_TRAILING_NUL);
45 OUTPUT:
46 RETVAL
47
48 IO::Uncompress::Brotli
49 create(class)
50 SV* class
51 CODE:
52 Newx(RETVAL, 1, struct brotli_decoder);
53 RETVAL->decoder = BrotliDecoderCreateInstance(NULL, NULL, NULL);
54 OUTPUT:
55 RETVAL
56
57 void
58 DESTROY(self)
59 IO::Uncompress::Brotli self
60 CODE:
61 BrotliDecoderDestroyInstance(self->decoder);
62 Safefree(self);
63
64 SV*
65 decompress(self, in)
66 IO::Uncompress::Brotli self
67 SV* in
68 PREINIT:
69 uint8_t *next_in, *next_out, *buffer;
70 size_t available_in, available_out;
71 BrotliDecoderResult result;
72 CODE:
73 next_in = (uint8_t*) SvPV(in, available_in);
74 Newx(buffer, BUFFER_SIZE, uint8_t);
75 RETVAL = newSVpv("", 0);
76 result = BROTLI_RESULT_NEEDS_MORE_OUTPUT;
77 while(result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
78 next_out = buffer;
79 available_out=BUFFER_SIZE;
80 result = BrotliDecoderDecompressStream( self->decoder,
81 &available_in,
82 (const uint8_t**) &next_in,
83 &available_out,
84 &next_out,
85 NULL );
86 if(!result){
87 Safefree(buffer);
88 croak("Error in BrotliDecoderDecompressStream");
89 }
90 sv_catpvn(RETVAL, (const char*)buffer, BUFFER_SIZE-available_out);
91 }
92 Safefree(buffer);
93 OUTPUT:
94 RETVAL
95
96 void
97 set_dictionary(self, dict)
98 IO::Uncompress::Brotli self
99 SV* dict
100 PREINIT:
101 size_t size;
102 uint8_t *data;
103 CODE:
104 data = SvPV(dict, size);
105 BrotliDecoderSetCustomDictionary(self->decoder, size, data);
106
107
108 MODULE = IO::Compress::Brotli PACKAGE = IO::Compress::Brotli
109 PROTOTYPES: ENABLE
110
111 SV*
112 bro(buffer, quality=BROTLI_DEFAULT_QUALITY, lgwin=BROTLI_DEFAULT_WINDOW)
113 SV* buffer
114 U32 quality
115 U32 lgwin
116 PREINIT:
117 size_t encoded_size;
118 STRLEN decoded_size;
119 uint8_t *encoded_buffer, *decoded_buffer;
120 BROTLI_BOOL result;
121 CODE:
122 if( quality < BROTLI_MIN_QUALITY || quality > BROTLI_MAX_QUALITY ) {
123 croak("Invalid quality value");
124 }
125 if( lgwin < kBrotliMinWindowBits || lgwin > kBrotliMaxWindowBits ) {
126 croak("Invalid window value");
127 }
128 decoded_buffer = (uint8_t*) SvPV(buffer, decoded_size);
129 encoded_size = BrotliEncoderMaxCompressedSize(decoded_size);
130 if(!encoded_size){
131 croak("Compressed size overflow");
132 }
133 Newx(encoded_buffer, encoded_size+1, uint8_t);
134 result = BrotliEncoderCompress( quality,
135 lgwin,
136 BROTLI_DEFAULT_MODE,
137 decoded_size,
138 decoded_buffer,
139 &encoded_size,
140 encoded_buffer );
141 if(!result){
142 Safefree(buffer);
143 croak("Error in BrotliEncoderCompress");
144 }
145 encoded_buffer[encoded_size]=0;
146 RETVAL = newSV(0);
147 sv_usepvn_flags(RETVAL, encoded_buffer, encoded_size, SV_SMAGIC | SV_HAS_TRAILING_NUL);
148 OUTPUT:
149 RETVAL
150
151 IO::Compress::Brotli
152 create(class)
153 SV* class
154 CODE:
155 Newx(RETVAL, 1, struct brotli_encoder);
156 RETVAL->encoder = BrotliEncoderCreateInstance(NULL, NULL, NULL);
157 OUTPUT:
158 RETVAL
159
160 SV*
161 window(self, window)
162 IO::Compress::Brotli self
163 U32 window
164 CODE:
165 if( window < kBrotliMinWindowBits || window > kBrotliMaxWindowBits ) {
166 croak("Invalid window value");
167 }
168 if( BrotliEncoderSetParameter(self->encoder, BROTLI_PARAM_LGWIN, window) )
169 RETVAL = newSVuv(1);
170 else
171 RETVAL = newSVuv(0);
172 OUTPUT:
173 RETVAL
174
175 SV*
176 quality(self, quality)
177 IO::Compress::Brotli self
178 U32 quality
179 CODE:
180 if( quality < BROTLI_MIN_QUALITY || quality > BROTLI_MAX_QUALITY ) {
181 croak("Invalid quality value");
182 }
183 if( BrotliEncoderSetParameter(self->encoder, BROTLI_PARAM_QUALITY, quality) )
184 RETVAL = newSVuv(1);
185 else
186 RETVAL = newSVuv(0);
187 OUTPUT:
188 RETVAL
189
190 SV*
191 _mode(self, mode)
192 IO::Compress::Brotli self
193 U32 mode
194 CODE:
195 if( BrotliEncoderSetParameter(self->encoder, BROTLI_PARAM_MODE, mode) )
196 RETVAL = newSVuv(1);
197 else
198 RETVAL = newSVuv(0);
199 OUTPUT:
200 RETVAL
201
202 SV*
203 compress(self, in)
204 IO::Compress::Brotli self
205 SV* in
206 CODE:
207 ENTER;
208 SAVETMPS;
209
210 PUSHMARK(SP);
211 XPUSHs(ST(0));
212 XPUSHs(in);
213 XPUSHs(newSVuv(BROTLI_OPERATION_PROCESS));
214 PUTBACK;
215
216 call_method("_compress", G_SCALAR);
217
218 SPAGAIN;
219
220 RETVAL = POPs;
221 SvREFCNT_inc(RETVAL);
222
223 PUTBACK;
224 FREETMPS;
225 LEAVE;
226 OUTPUT:
227 RETVAL
228
229 SV*
230 flush(self)
231 IO::Compress::Brotli self
232 CODE:
233 ENTER;
234 SAVETMPS;
235
236 PUSHMARK(SP);
237 XPUSHs(ST(0));
238 XPUSHs(newSVpv("", 0));
239 XPUSHs(newSVuv(BROTLI_OPERATION_FLUSH));
240 PUTBACK;
241
242 call_method("_compress", G_SCALAR);
243
244 SPAGAIN;
245
246 RETVAL = POPs;
247 SvREFCNT_inc(RETVAL);
248
249 PUTBACK;
250 FREETMPS;
251 LEAVE;
252 OUTPUT:
253 RETVAL
254
255 SV*
256 finish(self)
257 IO::Compress::Brotli self
258 CODE:
259 ENTER;
260 SAVETMPS;
261
262 PUSHMARK(SP);
263 XPUSHs(ST(0));
264 XPUSHs(newSVpv("", 0));
265 XPUSHs(newSVuv(BROTLI_OPERATION_FINISH));
266 PUTBACK;
267
268 call_method("_compress", G_SCALAR);
269
270 SPAGAIN;
271
272 RETVAL = POPs;
273 SvREFCNT_inc(RETVAL);
274
275 PUTBACK;
276 FREETMPS;
277 LEAVE;
278 OUTPUT:
279 RETVAL
280
281 SV*
282 _compress(self, in, op)
283 IO::Compress::Brotli self
284 SV* in
285 U8 op
286 PREINIT:
287 uint8_t *next_in, *next_out, *buffer;
288 size_t available_in, available_out;
289 BROTLI_BOOL result;
290 CODE:
291 next_in = (uint8_t*) SvPV(in, available_in);
292 Newx(buffer, BUFFER_SIZE, uint8_t);
293 RETVAL = newSVpv("", 0);
294 while(1) {
295 next_out = buffer;
296 available_out = BUFFER_SIZE;
297 result = BrotliEncoderCompressStream( self->encoder,
298 (BrotliEncoderOperation) op,
299 &available_in,
300 (const uint8_t**) &next_in,
301 &available_out,
302 &next_out,
303 NULL );
304 if(!result) {
305 Safefree(buffer);
306 croak("Error in BrotliEncoderCompressStream");
307 }
308
309 if( available_out != BUFFER_SIZE ) {
310 sv_catpvn(RETVAL, (const char*)buffer, BUFFER_SIZE-available_out);
311 }
312
313 if(
314 BrotliEncoderIsFinished(self->encoder) ||
315 (!available_in && !BrotliEncoderHasMoreOutput(self->encoder))
316 ) break;
317 }
318 Safefree(buffer);
319 OUTPUT:
320 RETVAL
321
322 void
323 DESTROY(self)
324 IO::Compress::Brotli self
325 CODE:
326 BrotliEncoderDestroyInstance(self->encoder);
327
328 void
329 set_dictionary(self, dict)
330 IO::Compress::Brotli self
331 SV* dict
332 PREINIT:
333 size_t size;
334 uint8_t *data;
335 CODE:
336 data = SvPV(dict, size);
337 BrotliEncoderSetCustomDictionary(self->encoder, size, data);
This page took 0.031748 seconds and 5 git commands to generate.