#include "ppport.h"
-#include <dec/decode.h>
-#include <common/dictionary.h>
+#include <brotli/decode.h>
+#include <brotli/encode.h>
#define BUFFER_SIZE 1048576
-static uint8_t buffer[BUFFER_SIZE]; /* It's almost 2016, is anyone still using ithreads? */
+
+typedef struct brotli_decoder {
+ BrotliDecoderState *decoder;
+}* IO__Uncompress__Brotli;
+
+typedef struct brotli_encoder {
+ BrotliEncoderState *encoder;
+}* IO__Compress__Brotli;
+
MODULE = IO::Compress::Brotli PACKAGE = IO::Uncompress::Brotli
PROTOTYPES: ENABLE
-SV* unbro(buffer)
+SV*
+unbro_given_size(buffer, decoded_size)
SV* buffer
+ size_t decoded_size
PREINIT:
- size_t decoded_size;
STRLEN encoded_size;
uint8_t *encoded_buffer, *decoded_buffer;
CODE:
encoded_buffer = (uint8_t*) SvPV(buffer, encoded_size);
- if(!BrotliDecompressedSize(encoded_size, encoded_buffer, &decoded_size)){
- croak("Error in BrotliDecompressedSize");
- }
- Newx(decoded_buffer, decoded_size+1, uint8_t);
- decoded_buffer[decoded_size]=0;
+ Newx(decoded_buffer, decoded_size, uint8_t);
if(!BrotliDecoderDecompress(encoded_size, encoded_buffer, &decoded_size, decoded_buffer)){
croak("Error in BrotliDecoderDecompress");
}
RETVAL = newSV(0);
- sv_usepvn_flags(RETVAL, decoded_buffer, decoded_size, SV_HAS_TRAILING_NUL);
+ sv_usepvn(RETVAL, decoded_buffer, decoded_size);
OUTPUT:
RETVAL
-SV* BrotliDecoderCreateInstance()
+IO::Uncompress::Brotli
+create(class)
+ SV* class
CODE:
- RETVAL = newSViv((IV)BrotliDecoderCreateInstance(NULL, NULL, NULL));
+ Newx(RETVAL, 1, struct brotli_decoder);
+ RETVAL->decoder = BrotliDecoderCreateInstance(NULL, NULL, NULL);
OUTPUT:
RETVAL
-void BrotliDecoderDestroyInstance(state)
- SV* state
+void
+DESTROY(self)
+ IO::Uncompress::Brotli self
CODE:
- BrotliDecoderDestroyInstance((BrotliDecoderState*)SvIV(state));
+ BrotliDecoderDestroyInstance(self->decoder);
+ Safefree(self);
-SV* BrotliDecoderDecompressStream(state, in)
- SV* state
+SV*
+decompress(self, in)
+ IO::Uncompress::Brotli self
SV* in
PREINIT:
- uint8_t *next_in, *next_out;
- size_t available_in, available_out, total_out;
+ uint8_t *next_in, *next_out, *buffer;
+ size_t available_in, available_out;
BrotliDecoderResult result;
CODE:
next_in = (uint8_t*) SvPV(in, available_in);
+ Newx(buffer, BUFFER_SIZE, uint8_t);
RETVAL = newSVpv("", 0);
- result = BROTLI_RESULT_NEEDS_MORE_OUTPUT;
- while(result == BROTLI_RESULT_NEEDS_MORE_OUTPUT) {
+ result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
+ while(result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
next_out = buffer;
available_out=BUFFER_SIZE;
- result = BrotliDecoderDecompressStream( (BrotliDecoderState*) SvIV(state),
+ result = BrotliDecoderDecompressStream( self->decoder,
&available_in,
(const uint8_t**) &next_in,
&available_out,
&next_out,
- &total_out );
+ NULL );
if(!result){
- croak("Error in BrotliDecoderDecompressStream");
+ Safefree(buffer);
+ croak("Error in BrotliDecoderDecompressStream");
}
sv_catpvn(RETVAL, (const char*)buffer, BUFFER_SIZE-available_out);
}
+ Safefree(buffer);
+ OUTPUT:
+ RETVAL
+
+
+MODULE = IO::Compress::Brotli PACKAGE = IO::Compress::Brotli
+PROTOTYPES: ENABLE
+
+SV*
+bro(buffer, quality=BROTLI_DEFAULT_QUALITY, lgwin=BROTLI_DEFAULT_WINDOW)
+ SV* buffer
+ U32 quality
+ U32 lgwin
+ PREINIT:
+ size_t encoded_size;
+ STRLEN decoded_size;
+ uint8_t *encoded_buffer, *decoded_buffer;
+ BROTLI_BOOL result;
+ CODE:
+ if( quality < BROTLI_MIN_QUALITY || quality > BROTLI_MAX_QUALITY ) {
+ croak("Invalid quality value");
+ }
+ if( lgwin < BROTLI_MIN_WINDOW_BITS || lgwin > BROTLI_MAX_WINDOW_BITS ) {
+ croak("Invalid window value");
+ }
+ decoded_buffer = (uint8_t*) SvPV(buffer, decoded_size);
+ encoded_size = BrotliEncoderMaxCompressedSize(decoded_size);
+ if(!encoded_size){
+ croak("Compressed size overflow");
+ }
+ Newx(encoded_buffer, encoded_size+1, uint8_t);
+ result = BrotliEncoderCompress( quality,
+ lgwin,
+ BROTLI_DEFAULT_MODE,
+ decoded_size,
+ decoded_buffer,
+ &encoded_size,
+ encoded_buffer );
+ if(!result){
+ Safefree(buffer);
+ croak("Error in BrotliEncoderCompress");
+ }
+ encoded_buffer[encoded_size]=0;
+ RETVAL = newSV(0);
+ sv_usepvn_flags(RETVAL, encoded_buffer, encoded_size, SV_SMAGIC | SV_HAS_TRAILING_NUL);
+ OUTPUT:
+ RETVAL
+
+IO::Compress::Brotli
+create(class)
+ SV* class
+ CODE:
+ Newx(RETVAL, 1, struct brotli_encoder);
+ RETVAL->encoder = BrotliEncoderCreateInstance(NULL, NULL, NULL);
OUTPUT:
RETVAL
-void BrotliDecoderSetCustomDictionary(state, dict)
- SV* state
- SV* dict
+bool BrotliEncoderSetParameter(self, value)
+ IO::Compress::Brotli self
+ U32 value
+ ALIAS:
+ window = 1
+ quality = 2
+ _mode = 3
PREINIT:
- size_t size;
- uint8_t *data;
+ BrotliEncoderParameter param;
+ INIT:
+ switch(ix){
+ case 0:
+ croak("BrotliEncoderSetParameter may not be called directly");
+ break;
+ case 1:
+ if( value < BROTLI_MIN_WINDOW_BITS || value > BROTLI_MAX_WINDOW_BITS ) {
+ croak("Invalid window value");
+ }
+ param = BROTLI_PARAM_LGWIN;
+ break;
+ case 2:
+ if( value < BROTLI_MIN_QUALITY || value > BROTLI_MAX_QUALITY ) {
+ croak("Invalid quality value");
+ }
+ param = BROTLI_PARAM_QUALITY;
+ break;
+ case 3:
+ /* Validation done on Perl side */
+ param = BROTLI_PARAM_MODE;
+ break;
+ default:
+ croak("Impossible ix in BrotliEncoderSetParameter");
+ break;
+ }
+ C_ARGS:
+ self->encoder, param, value
+
+SV*
+_compress(self, in = &PL_sv_undef)
+ IO::Compress::Brotli self
+ SV* in
+ ALIAS:
+ compress = 1
+ flush = 2
+ finish = 3
+ PREINIT:
+ uint8_t *next_in, *next_out, *buffer;
+ size_t available_in, available_out;
+ BROTLI_BOOL result;
+ BrotliEncoderOperation op;
+ CODE:
+ switch(ix) {
+ case 0:
+ croak("_compress may not be called directly");
+ break;
+ case 1:
+ op = BROTLI_OPERATION_PROCESS;
+ break;
+ case 2:
+ op = BROTLI_OPERATION_FLUSH;
+ break;
+ case 3:
+ op = BROTLI_OPERATION_FINISH;
+ break;
+ default:
+ croak("Impossible ix in _compress");
+ break;
+ }
+
+ Newx(buffer, BUFFER_SIZE, uint8_t);
+ if(in == &PL_sv_undef)
+ next_in = (uint8_t*) buffer, available_in = 0;
+ else
+ next_in = (uint8_t*) SvPV(in, available_in);
+ RETVAL = newSVpv("", 0);
+ while(1) {
+ next_out = buffer;
+ available_out = BUFFER_SIZE;
+ result = BrotliEncoderCompressStream( self->encoder,
+ (BrotliEncoderOperation) op,
+ &available_in,
+ (const uint8_t**) &next_in,
+ &available_out,
+ &next_out,
+ NULL );
+ if(!result) {
+ Safefree(buffer);
+ croak("Error in BrotliEncoderCompressStream");
+ }
+
+ if( available_out != BUFFER_SIZE ) {
+ sv_catpvn(RETVAL, (const char*)buffer, BUFFER_SIZE-available_out);
+ }
+
+ if(
+ BrotliEncoderIsFinished(self->encoder) ||
+ (!available_in && !BrotliEncoderHasMoreOutput(self->encoder))
+ ) break;
+ }
+ Safefree(buffer);
+ OUTPUT:
+ RETVAL
+
+void
+DESTROY(self)
+ IO::Compress::Brotli self
CODE:
- data = SvPV(dict, size);
- BrotliDecoderSetCustomDictionary((BrotliDecoderState*) SvIV(state), size, data);
+ BrotliEncoderDestroyInstance(self->encoder);
+ Safefree(self);