I have created a small wrapper for the Brotli compression format: [L1 ]
The code uses critcl:
package require Tcl 8.4 package require critcl 3.1 critcl::buildrequirement { package require critcl::class } # critcl::config language c++ critcl::license {Georgios Petasis} {BSD licensed} critcl::summary {Stack objects for Tcl.} critcl::description { This package implements stack objects for Tcl. It uses the abstract data type provided by package 'cstack' for actual storage and operations. } critcl::subject brotli ::critcl::clibraries -lbrotlidec -lbrotlienc critcl::class::define ::brotli { # include vector include brotli/decode.h include brotli/encode.h insvariable BrotliEncoderMode mode {} { instance->mode=(BrotliEncoderMode) BROTLI_DEFAULT_MODE; } insvariable int lgwin {} {instance->lgwin = BROTLI_DEFAULT_WINDOW;} insvariable int lgblock {} {instance->lgblock = -1;} insvariable int quality {} {instance->quality = BROTLI_DEFAULT_QUALITY;} method compress command {} { size_t length, out_len; const uint8_t *input; BrotliEncoderState* state; uint8_t *output; BROTLI_BOOL status; if (objc != 3) { Tcl_WrongNumArgs (interp, 2, objv, "binary_content_to_compress"); return TCL_ERROR; } Tcl_ResetResult(interp); input = Tcl_GetByteArrayFromObj(objv[2], &length); if (!length) return TCL_OK; /* Get an estimation about the output buffer... */ out_len = BrotliEncoderMaxCompressedSize(length); if (out_len == 0) { Tcl_SetResult(interp, "needed output buffer too large to encode input", TCL_STATIC); return TCL_ERROR; } output = (uint8_t *) ckalloc(sizeof(uint8_t) * out_len); if (output == NULL) { Tcl_SetResult(interp, "cannot allocate needed output buffer", TCL_STATIC); return TCL_ERROR; } /* Decode... */ status = BrotliEncoderCompress(instance->quality, instance->lgwin, instance->mode, length, input, &out_len, output); if (status) { Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(output, out_len)); ckfree((char *) output); return TCL_OK; } else { ckfree((char *) output); Tcl_SetResult(interp, "cannot compress input", TCL_STATIC); return TCL_ERROR; } #if 0 BrotliEncoderState* state = BrotliEncoderCreateInstance(0, 0, 0); if ((int) instance->mode != -1) BrotliEncoderSetParameter(state, BROTLI_PARAM_MODE, (uint32_t)instance->mode); if (instance->quality != -1) BrotliEncoderSetParameter(state, BROTLI_PARAM_QUALITY, (uint32_t)instance->quality); if (instance->lgwin != -1) BrotliEncoderSetParameter(state, BROTLI_PARAM_LGWIN, (uint32_t)instance->lgwin); if (instance->lgblock != -1) BrotliEncoderSetParameter(state, BROTLI_PARAM_LGBLOCK, (uint32_t)instance->lgblock); #endif };# compress method decompress command {} { Tcl_DString output; size_t length; const uint8_t *input; int status; if (objc != 3) { Tcl_WrongNumArgs (interp, 2, objv, "binary_content_to_decode"); return TCL_ERROR; } Tcl_ResetResult(interp); input = Tcl_GetByteArrayFromObj(objv[2], &length); if (!length) return TCL_OK; Tcl_DStringInit(&output); BrotliDecoderState* state = BrotliDecoderCreateInstance(0, 0, 0); BrotliDecoderResult result = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; while (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) { size_t available_out = 0; result = BrotliDecoderDecompressStream(state, &length, &input, &available_out, 0, 0); const uint8_t* next_out = BrotliDecoderTakeOutput(state, &available_out); if (available_out != 0) { Tcl_DStringAppend(&output, next_out, available_out); // output.insert(output.end(), next_out, next_out + available_out); } } status = result == BROTLI_DECODER_RESULT_SUCCESS; BrotliDecoderDestroyInstance(state); if (status) { Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(Tcl_DStringValue(&output), Tcl_DStringLength(&output))); status = TCL_OK; } else { BrotliDecoderErrorCode code = BrotliDecoderGetErrorCode(state); Tcl_SetResult(interp, (char *) BrotliDecoderErrorString(code), TCL_DYNAMIC); status = TCL_ERROR; } Tcl_DStringFree(&output); return status; };# decompress method decoder_version command {} { if (objc != 2) { Tcl_WrongNumArgs (interp, 2, objv, NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewWideIntObj(BrotliDecoderVersion())); return TCL_OK; };# decoder_version method encoder_version command {} { if (objc != 2) { Tcl_WrongNumArgs (interp, 2, objv, NULL); return TCL_ERROR; } Tcl_SetObjResult(interp, Tcl_NewWideIntObj(BrotliEncoderVersion())); return TCL_OK; };# encoder_version } package provide brotli 1.0
You can generate the package by saving the code in a file named "brotli.tcl" and then execute:
critcl -pkg brotli.tcl