Registriert seit: 19. Jan 2009
Ort: Kirchlinteln (LK Verden)
1.051 Beiträge
Delphi 2009 Professional
|
Gzip dekomprimieren
13. Nov 2017, 21:08
Habe auf Anhieb keine Gzip-Klasse für Delphi gefunden, daher habe ich selbst eine geschrieben. Sie hat volle Kompatibilität zu RFC 1952, außer dass sie nur einen Stream zur Zeit unterstützt, da ich nicht weiß, wie man die trennt.
Klasse ist unten, Verwendung wie folgt:
Delphi-Quellcode:
InputStream := TIrgendeinStream.Create();
try
Adapter := TRedeemerGzipDecompressionAdapter.Create(InputStream);
finally
InputStream.Free; // Wird nicht mehr benötigt, Daten liegen jetzt im Speicher
end;
try
Zlib := TDecompressionStream.Create(Adapter.Zlib);
try
OutputStream := TIrgendeinStream.Create();
try
OutputStream.CopyFrom( Zlib, 0);
// tue irgendwas mit OutputStream
finally
OutputStream.Free;
end;
finally
Zlib.Free;
end;
finally
Adapter.Free;
end;
Delphi-Quellcode:
unit RedeemerGzip;
// Konvertiert einen GZIP-Stream in einen ZLIB-Stream
// RFC 1952
interface
uses
Classes, SysUtils;
type TGzipOS = (osFAT = 0,
osAmiga = 1,
osVMS = 2,
osUnix = 3,
osVMCMS = 4,
osAtariTOS = 5,
osHPFS = 6,
osMac = 7,
osZ = 8,
osCPM = 9,
osTOPS20 = 10,
osNTFS = 11,
osQDOS = 12,
osAcornRISCOS = 13,
osUnknown = 255);
type
TRedeemerGzipDecompressionAdapter = class
public
constructor Create(From: TStream);
destructor Destroy(); override;
const
ID1: Byte = 31; // Header
ID2: Byte = 139; // Header
CompressionMethod: Byte = 8; // Deflate
var
IsText, HasHeaderCRC, HasExtra, HasName, HasComment: Boolean;
Timestamp: Cardinal;
CompressionLevel: Byte; // 2 = max, 4 = so lala
OS: TGzipOS;
ExtraLen: Word;
Extra: TBytes;
Name, Comment: WideString;
HeaderCRC: Word;
Zlib: TMemoryStream;
UncompressedCRC32: Cardinal;
UncompressedSize: Cardinal;
end;
implementation
{ TRedeemerGzipAdapter }
constructor TRedeemerGzipDecompressionAdapter.Create(From: TStream);
function ReadByte: Byte;
begin
From. Read(Result, 1);
end;
procedure ReadStr( out s: WideString);
var
Temp: Byte;
begin
s := ' ';
repeat
Temp := ReadByte;
if Temp = 0 then
Exit
else
s := s + WideChar(Temp); // Konvertiere ISO 8859-1 nach UTF-16
until False;
end;
var
Temp: Byte;
function ReadBool: Boolean;
begin
Result := Temp mod 2 = 1;
Temp := Temp shr 1;
end;
begin
inherited Create;
if (ReadByte <> ID1)
or (ReadByte <> ID2)
or (ReadByte <> CompressionMethod) then
raise Exception.Create(' Data error.');
// Flags
Temp := ReadByte;
IsText := ReadBool;
HasHeaderCRC := ReadBool;
HasExtra := ReadBool;
HasName := ReadBool;
HasComment := ReadBool;
// Sonstiger fixer Header
From. Read(Timestamp, 4);
CompressionLevel := ReadByte;
From. Read( OS, 1);
// Optionaler Header
if HasExtra then
begin
From. Read(ExtraLen, 2);
SetLength(Extra, ExtraLen);
From. Read(Extra[0], ExtraLen);
end;
if HasName then
ReadStr( Name);
if HasComment then
ReadStr(Comment);
if HasHeaderCRC then
From. Read(HeaderCRC, 2);
Zlib := TMemoryStream.Create;
try
// Zlib-Header erstellen
Temp := $78;
Zlib. Write(Temp, 1);
Temp := $9c; // tatsächlicher Level interessiert niemanden
Zlib. Write(Temp, 1);
// Zlib-Daten kopieren (ohne CRC32, denn das irritiert Zlib, da dessen CRC offenbar anders ist)
Zlib.CopyFrom(From, From.Size - From.Position - 8);
Zlib.Position := 0;
From. Read(UncompressedCRC32, 4);
From. Read(UncompressedSize, 4);
except
Zlib.Free;
raise;
end;
end;
destructor TRedeemerGzipDecompressionAdapter.Destroy;
begin
inherited;
Zlib.Free;
end;
end.
Janni 2005 PE, 2009 PA, XE2 PA
|