brotli Komprimierung von Streams mit Free Pascal

Komprimierte Datenübertragung

Realisierung eines Interfaces zur brotli Library von Google, aktuelle Releases auch der Windows DLL's stehen unter https://github.com/google/brotli/releases zur Verfügung.

Sicherlich ist es nur eine minimale Realisierung ohne die Klassen mit all ihren Methoden, aber zum einfachen Gebrauch reicht es schon und vor allem zum Test und für einen Vergleich mit GZip.

Ich habe den BROTLI_DEFAULT_QUALITY Wert auf 5 gesetzt nicht auf 11 wie in vielen anderen Realisierungen, dadurch ergibt sich ein Vergleichbarer Wert mit GZip, je nach Dateigröße eine etwas bessere Komprimierung in einer angemessenen Zeit.
Setzt man diesen Wert auf 11, erhält man kein brauchbares Ergenis denn die benötigte Zeit ist zumindest für eine dynamische Komprimierung unbrauchbar.

brotli.pas Pascal (5,34 kByte) 24.06.2018 10:33
// *****************************************************************************
//  Title.............. :  brotli interface library
//
//  Modulname ......... :  brotli.pas
//  Type .............. :  Unit
//  Author ............ :  Udo Schmal
//  Development Status  :  24.06.2018
//  Operating Systen    :  Windows
//
//  Library Download    :  https://github.com/google/brotli/releases
// *****************************************************************************
unit Brotli;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils;

const
  BROTLI_DEFAULT_QUALITY = 5; // my default like gzip
  BROTLI_MIN_QUALITY = 0;
  BROTLI_MAX_QUALITY = 11;
  BROTLI_DEFAULT_MODE = 0;
  BROTLI_MODE_GENERIC = 0; // Default compression mode.
  BROTLI_MODE_TEXT = 1; // Compression mode for UTF-8 formatted text input.
  BROTLI_MODE_FONT = 2; // Compression mode used in WOFF 2.0
  BROTLI_DEFAULT_WINDOW = 22;
  BROTLI_MIN_WINDOW_BITS = 10;
  BROTLI_MAX_WINDOW_BITS = 24;
  BROTLI_DECODER_RESULT_ERROR = 0;
  BROTLI_DECODER_RESULT_SUCCESS = 1;
  BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT = 2;
  BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT = 3;

  function brotliEncodeStream(inStream, outStream: TMemoryStream; mode: LongInt = BROTLI_DEFAULT_MODE): boolean;
  function brotliDecodeStream(inStream, outStream: TMemoryStream): boolean;
  function BrotliCompress(const aFile: string): boolean;
  function BrotliUncompress(const aFile: string): boolean;

implementation

const
  BROTLIENC_DLL = 'libbrotlienc.dll';
  BROTLIDEC_DLL = 'libbrotlidec.dll';

var
  BrotliEncHandle: TLibHandle = 0;
  BrotliDecHandle: TLibHandle = 0;

  function BrotliEncoderCompress(quality: longint; lgwin: longint; mode: LongInt;
    input_size: LongWord; const input_buffer: pointer; var encoded_size: LongWord; encoded_buffer: pointer): boolean;
    stdcall; external BROTLIENC_DLL name 'BrotliEncoderCompress';
  function BrotliDecoderDecompress(encoded_size: LongWord; const encoded_buffer: pointer; var decoded_size: LongWord; decoded_buffer: pointer): LongInt;
    stdcall; external BROTLIDEC_DLL name 'BrotliDecoderDecompress';

function brotliEncodeStream(inStream, outStream: TMemoryStream; mode: LongInt = BROTLI_DEFAULT_MODE): boolean;
var outSize: LongWord;
begin
  result := false;
  outStream.SetSize(inStream.Size);
  outSize := outStream.Size;
  inStream.Position := 0; // goto start of input stream
  outStream.Position := 0; // goto start of output stream
  result := BrotliEncoderCompress(BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, mode, inStream.size, inStream.Memory, outSize, outStream.Memory);
  if result then
  begin
    inStream.Position := 0; // goto start of input stream
    outStream.Position := 0; // goto start of output stream
    outStream.Size := outSize;
  end;
end;

function brotliDecodeStream(inStream, outStream: TMemoryStream): boolean;
var
  outSize: LongWord;
  btResult: LongInt;
begin
  result := false;
  outStream.SetSize(inStream.Size*10);
  outSize := outStream.Size;
  inStream.Position := 0; // goto start of input stream
  outStream.Position := 0; // goto start of output stream
  btResult := BrotliDecoderDecompress(inStream.size, inStream.Memory, outSize, outStream.Memory);
//  case btResult of
//    BROTLI_DECODER_RESULT_ERROR: writeln('BROTLI_DECODER_RESULT_ERROR');
//    BROTLI_DECODER_RESULT_SUCCESS: writeln('BROTLI_DECODER_RESULT_SUCCESS');
//    BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: writeln('BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT');
//    BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: writeln('BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT');
//  end;
  result := btResult = BROTLI_DECODER_RESULT_SUCCESS;
  if result then
  begin
    inStream.Position := 0; // goto start of input stream
    outStream.Position := 0; // goto start of output stream
    outStream.Size := outSize;
  end;
end;

function BrotliCompress(const aFile: string): boolean;
var inStream, outStream: TMemoryStream;
begin
  result := false;
  if FileExists(aFile) then
  begin
    inStream := TMemoryStream.Create;
    try
      inStream.LoadFromFile(aFile);
      outStream := TMemoryStream.Create;
      try
        if brotliEncodeStream(inStream, outStream, BROTLI_MODE_TEXT) then
        begin
          outStream.SaveToFile(aFile + '.br');
          result := true;
        end;
      finally
        outStream.Free;
      end;
    finally
      inStream.Free;
    end;
  end;
end;

function BrotliUncompress(const aFile: string): boolean;
var inStream, outStream: TMemoryStream;
begin
  result := false;
  if FileExists(aFile) then
  begin
    inStream := TMemoryStream.Create;
    try
      inStream.LoadFromFile(aFile);
      outStream := TMemoryStream.Create;
      try
        if brotliDecodeStream(inStream, outStream) then
        begin
          outStream.SaveToFile(ChangeFileExt(aFile, ''));
          result := true;
        end;
      finally
        outStream.Free;
      end;
    finally
      inStream.Free;
    end;
  end;
end;

initialization
  BrotliEncHandle := LoadLibrary(PChar(BROTLIENC_DLL));
  BrotliDecHandle := LoadLibrary(PChar(BROTLIDEC_DLL));
finalization
  if BrotliEncHandle <> 0 then
  begin
    FreeLibrary(BrotliEncHandle);
    BrotliEncHandle := 0;
  end;
  if BrotliDecHandle <> 0 then
  begin
    FreeLibrary(BrotliDecHandle);
    BrotliDecHandle := 0;
  end;
end.

Beispiel:

brotliExample.lpr Pascal (578 bytes) 24.06.2018 10:33
program brotli_example;

{$mode objfpc}{$H+}

uses
  Classes, SysUtils, brotli;

var
  StartTime, EndTime: QWord;
begin
  StartTime := GetTickCount64();
  BrotliCompress(ExtractFilePath(ParamStr(0)) + 'test.dat');
  EndTime := GetTickCount64();
  WriteLn('Brotli compress TickCount: ' + IntToStr(EndTime - StartTime) + ' ms');
  StartTime := GetTickCount64();
  BrotliUncompress(ExtractFilePath(ParamStr(0)) + 'test.dat.br');
  EndTime := GetTickCount64();
  WriteLn('Brotli uncompress TickCount: ' + IntToStr(EndTime - StartTime) + ' ms');
  ReadLn();
end.

Autor: , veröffentlicht: , letzte Änderung:

Kontakt

Copyright / License of sources

Copyright (c) 2007-2018, Udo Schmal <udo.schmal@t-online.de>

Permission to use, copy, modify, and/or distribute the software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

Service Infos

CMS Info Product Name:
UDOs Webserver
Version:
0.3.2.223
Description:
All in one Webserver
Copyright:
Udo Schmal
Compilation:
Mo, 16 Jul 2018 22:06:26
Development Info IDE:
Lazarus LCL 1.9.0.0
Compiler:
Free Pascal FPC 3.3.1
compiled for:
OS:Win64, CPU:x86_64
Hardware Info Model:
Precision WorkStation T3500
CPU Name:
Intel(R) Xeon(R) CPU W3530 @ 2.80GHz
CPU Type:
x86_64, 1 physical CPU(s), 4 Core(s), 8 logical CPU(s), 2800 MHz