unbro should not require maximum buffer size (RT #129480)
[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_given_size(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
92 MODULE = IO::Compress::Brotli PACKAGE = IO::Compress::Brotli
93 PROTOTYPES: ENABLE
94
95 SV*
96 bro(buffer, quality=BROTLI_DEFAULT_QUALITY, lgwin=BROTLI_DEFAULT_WINDOW)
97 SV* buffer
98 U32 quality
99 U32 lgwin
100 PREINIT:
101 size_t encoded_size;
102 STRLEN decoded_size;
103 uint8_t *encoded_buffer, *decoded_buffer;
104 BROTLI_BOOL result;
105 CODE:
106 if( quality < BROTLI_MIN_QUALITY || quality > BROTLI_MAX_QUALITY ) {
107 croak("Invalid quality value");
108 }
109 if( lgwin < BROTLI_MIN_WINDOW_BITS || lgwin > BROTLI_MAX_WINDOW_BITS ) {
110 croak("Invalid window value");
111 }
112 decoded_buffer = (uint8_t*) SvPV(buffer, decoded_size);
113 encoded_size = BrotliEncoderMaxCompressedSize(decoded_size);
114 if(!encoded_size){
115 croak("Compressed size overflow");
116 }
117 Newx(encoded_buffer, encoded_size+1, uint8_t);
118 result = BrotliEncoderCompress( quality,
119 lgwin,
120 BROTLI_DEFAULT_MODE,
121 decoded_size,
122 decoded_buffer,
123 &encoded_size,
124 encoded_buffer );
125 if(!result){
126 Safefree(buffer);
127 croak("Error in BrotliEncoderCompress");
128 }
129 encoded_buffer[encoded_size]=0;
130 RETVAL = newSV(0);
131 sv_usepvn_flags(RETVAL, encoded_buffer, encoded_size, SV_SMAGIC | SV_HAS_TRAILING_NUL);
132 OUTPUT:
133 RETVAL
134
135 IO::Compress::Brotli
136 create(class)
137 SV* class
138 CODE:
139 Newx(RETVAL, 1, struct brotli_encoder);
140 RETVAL->encoder = BrotliEncoderCreateInstance(NULL, NULL, NULL);
141 OUTPUT:
142 RETVAL
143
144 bool BrotliEncoderSetParameter(self, value)
145 IO::Compress::Brotli self
146 U32 value
147 ALIAS:
148 window = 1
149 quality = 2
150 _mode = 3
151 PREINIT:
152 BrotliEncoderParameter param;
153 INIT:
154 switch(ix){
155 case 0:
156 croak("BrotliEncoderSetParameter may not be called directly");
157 break;
158 case 1:
159 if( value < BROTLI_MIN_WINDOW_BITS || value > BROTLI_MAX_WINDOW_BITS ) {
160 croak("Invalid window value");
161 }
162 param = BROTLI_PARAM_LGWIN;
163 break;
164 case 2:
165 if( value < BROTLI_MIN_QUALITY || value > BROTLI_MAX_QUALITY ) {
166 croak("Invalid quality value");
167 }
168 param = BROTLI_PARAM_QUALITY;
169 break;
170 case 3:
171 /* Validation done on Perl side */
172 param = BROTLI_PARAM_MODE;
173 break;
174 default:
175 croak("Impossible ix in BrotliEncoderSetParameter");
176 break;
177 }
178 C_ARGS:
179 self->encoder, param, value
180
181 SV*
182 _compress(self, in = &PL_sv_undef)
183 IO::Compress::Brotli self
184 SV* in
185 ALIAS:
186 compress = 1
187 flush = 2
188 finish = 3
189 PREINIT:
190 uint8_t *next_in, *next_out, *buffer;
191 size_t available_in, available_out;
192 BROTLI_BOOL result;
193 BrotliEncoderOperation op;
194 CODE:
195 switch(ix) {
196 case 0:
197 croak("_compress may not be called directly");
198 break;
199 case 1:
200 op = BROTLI_OPERATION_PROCESS;
201 break;
202 case 2:
203 op = BROTLI_OPERATION_FLUSH;
204 break;
205 case 3:
206 op = BROTLI_OPERATION_FINISH;
207 break;
208 default:
209 croak("Impossible ix in _compress");
210 break;
211 }
212
213 Newx(buffer, BUFFER_SIZE, uint8_t);
214 if(in == &PL_sv_undef)
215 next_in = (uint8_t*) buffer, available_in = 0;
216 else
217 next_in = (uint8_t*) SvPV(in, available_in);
218 RETVAL = newSVpv("", 0);
219 while(1) {
220 next_out = buffer;
221 available_out = BUFFER_SIZE;
222 result = BrotliEncoderCompressStream( self->encoder,
223 (BrotliEncoderOperation) op,
224 &available_in,
225 (const uint8_t**) &next_in,
226 &available_out,
227 &next_out,
228 NULL );
229 if(!result) {
230 Safefree(buffer);
231 croak("Error in BrotliEncoderCompressStream");
232 }
233
234 if( available_out != BUFFER_SIZE ) {
235 sv_catpvn(RETVAL, (const char*)buffer, BUFFER_SIZE-available_out);
236 }
237
238 if(
239 BrotliEncoderIsFinished(self->encoder) ||
240 (!available_in && !BrotliEncoderHasMoreOutput(self->encoder))
241 ) break;
242 }
243 Safefree(buffer);
244 OUTPUT:
245 RETVAL
246
247 void
248 DESTROY(self)
249 IO::Compress::Brotli self
250 CODE:
251 BrotliEncoderDestroyInstance(self->encoder);
252 Safefree(self);
This page took 0.027625 seconds and 4 git commands to generate.