unit _SZip_Tools;

interface

{$WARN UNIT_PLATFORM OFF}
{$WARN SYMBOL_PLATFORM OFF}

uses
  Windows,SysUtils,Classes,ZLib;

type
  PLargeByteArray = ^TLargeByteArray;
  TLargeByteArray = array[0..65536*1000] of byte;

const SZipSuccess=0;
const SZipErrorCRC=1;
const SZipErrorFileSize=2;
const SZipErrorNoFile=3;
const SZipErrorCompress=4;
const SZipErrorDecompress=5;

function SZipGetCRC(var Data:PByteArray;const Offset,Size:integer):dword;overload;
function SZipGetCRC(var Data:array of byte;const Offset,Size:integer):dword;overload;
function SZipCompress(const Data:PLargeByteArray;const DataSize:integer;var EncData:PLargeByteArray;var EncDataSize:integer):integer;overload;
function SZipCompress(const Data:PByteArray;const DataSize:integer;var EncData:PByteArray;var EncDataSize:integer):integer;overload;
function SZipCompress(SrcFilename,DstFilename:string):integer;overload;
function SZipDecompress(const Data:PLargeByteArray;const DataSize:integer;var DecData:PLargeByteArray;var DecDataSize:integer):integer;overload;
function SZipDecompress(const Data:PByteArray;const DataSize:integer;var DecData:PByteArray;var DecDataSize:integer):integer;overload;
function SZipDecompress(const Data:PByteArray;const DataSize:integer;const DstFilename:string):integer;overload;
function SZipDecompress(const Data:array of byte;const DataSize:integer;const DstFilename:string):integer;overload;
function SZipDecompress(SrcFilename,DstFilename:string):integer;overload;

implementation

function SZipGetCRC(var Data:PByteArray;const Offset,Size:integer):dword;
var
  TempData:array of byte;
begin
  SetLength(TempData,Size+1);
  MoveMemory(@TempData[0],@Data[0],Size);
  Result:=SZipGetCRC(TempData,Offset,Size);
end;

function SZipGetCRC(var Data:array of byte;const Offset,Size:integer):dword;
var
  cnt:integer;
begin
  Result:=0;
  for cnt:=0 to Size-1 do begin
    Result:=((Result xor dword(Data[Offset+cnt])) shl 1) and $7fffffff;
  end;
end;

function SZipCompress(const Data:PLargeByteArray;const DataSize:integer;var EncData:PLargeByteArray;var EncDataSize:integer):integer;overload;
var
  tmpData,tmpEncData:PByteArray;
begin
  tmpData:=@Data[0];
  tmpEncData:=@EncData[0];

  Result:=SZipCompress(tmpData,DataSize,tmpEncData,EncDataSize);

  EncData:=@tmpEncData[0];
end;

function SZipCompress(const Data:PByteArray;const DataSize:integer;var EncData:PByteArray;var EncDataSize:integer):integer;overload;
var
  _EncData:PByteArray;
  _EncDataSize:integer;
  procedure WriteDWord(pos:integer;const dw:dword);
  begin
    MoveMemory(@EncData[pos],@dw,4);
  end;
begin
  if DataSize<=0 then begin
    Result:=SZipErrorCompress;
    exit;
  end;

  ZLib.CompressBuf(pointer(Data),DataSize,pointer(_EncData),_EncDataSize);

  if (_EncData=nil) or (_EncDataSize=0) then begin
    Result:=SZipErrorCompress;
    exit;
  end;

  EncDataSize:=_EncDataSize+8;
  GetMem(EncData,EncDataSize);

  WriteDWord(0,_EncDataSize);
  WriteDWord(4,SZipGetCRC(_EncData,0,_EncDataSize));
  MoveMemory(@EncData[8],@_EncData[0],_EncDataSize);

  Result:=SZipSuccess;
end;

function SZipCompress(SrcFilename,DstFilename:string):integer;
var
  Srcfs,Dstfs:TFileStream;
  DecData,EncData:PByteArray;
  DecDataSize,EncDataSize:integer;
  procedure WriteDWord(var fs:TFileStream;const dw:dword);
  begin
    fs.Write(dw,4);
  end;
begin
  if FileExists(SrcFilename)=False then begin
    Result:=SZipErrorNoFile;
    exit;
  end;

  ForceDirectories(ExtractFilePath(DstFilename));

  Srcfs:=TFileStream.Create(SrcFilename,fmOpenRead or fmShareExclusive);
  Dstfs:=TFileStream.Create(DstFilename,fmCreate or fmShareExclusive);

  DecDataSize:=Srcfs.Size;
  GetMem(DecData,DecDataSize+1);
  Srcfs.ReadBuffer(DecData[0],DecDataSize);

  ZLib.CompressBuf(pointer(DecData),DecDataSize,pointer(EncData),EncDataSize);

  if (EncData=nil) or (EncDataSize=0) then begin
    Result:=SZipErrorCompress;
    FreeMem(DecData);
    Srcfs.Free;
    Dstfs.Free;
    exit;
  end;

  WriteDWord(Dstfs,EncDataSize);
  WriteDWord(Dstfs,SZipGetCRC(EncData,0,EncDataSize));

  Dstfs.Write(EncData[0],EncDataSize);

  FreeMem(DecData);
  FreeMem(EncData);

  Srcfs.Free;
  Dstfs.Free;

  Result:=SZipSuccess;
end;

function SZipDecompress(const Data:PLargeByteArray;const DataSize:integer;var DecData:PLargeByteArray;var DecDataSize:integer):integer;
var
  tmpData,tmpDecData:PByteArray;
begin
  tmpData:=@Data[0];
  tmpDecData:=@DecData[0];

  Result:=SZipDecompress(tmpData,DataSize,tmpDecData,DecDataSize);

  DecData:=@tmpDecData[0];
end;

function SZipDecompress(const Data:PByteArray;const DataSize:integer;var DecData:PByteArray;var DecDataSize:integer):integer;
var
  EncData:PByteArray;
  EncDataSize:integer;
  function ReadDWord(const Data:PByteArray;const Offset:integer):dword;
  begin
    Result:=Data[Offset+0];
    Result:=Result+(Data[Offset+1] shl 8);
    Result:=Result+(Data[Offset+2] shl 16);
    Result:=Result+(Data[Offset+3] shl 24);
  end;
begin
  EncDataSize:=DataSize-8;
  if EncDataSize<>integer(ReadDWord(Data,0)) then begin
    Result:=SZipErrorFileSize;
    exit;
  end;
  GetMem(EncData,EncDataSize+1);
  MoveMemory(@EncData[0],@Data[8],EncDataSize);
  if SZipGetCRC(EncData,0,EncDataSize)<>ReadDWord(Data,4) then begin
    FreeMem(EncData);
    Result:=SZipErrorCRC;
    exit;
  end;

  ZLib.DecompressBuf(pointer(EncData),EncDataSize,0,pointer(DecData),DecDataSize);

  if (DecData=nil) or (DecDataSize=0) then begin
    Result:=SZipErrorDecompress;
    end else begin
    Result:=SZipSuccess;
  end;
  FreeMem(EncData);
end;

function SZipDecompress(const Data:PByteArray;const DataSize:integer;const DstFilename:string):integer;
var
  DecData:PByteArray;
  DecDataSize:integer;
  Dstfs:TFileStream;
begin
  Result:=SZipDecompress(Data,DataSize,DecData,DecDataSize);
  if Result<>SZipSuccess then exit;

  if DstFilename<>'' then begin
    Dstfs:=TFileStream.Create(DstFilename,fmCreate or fmShareExclusive);
    Dstfs.Write(DecData[0],DecDataSize);
    Dstfs.Free;
  end;

  FreeMem(DecData);
end;

function SZipDecompress(const Data:array of byte;const DataSize:integer;const DstFilename:string):integer;
var
  DataPtr:PByteArray;
  DecData:PByteArray;
  DecDataSize:integer;
  Dstfs:TFileStream;
begin
  GetMem(DataPtr,DataSize);
  MoveMemory(DataPtr,@Data[0],DataSize);
  Result:=SZipDecompress(DataPtr,DataSize,DecData,DecDataSize);
  FreeMem(DataPtr);
  if Result<>SZipSuccess then exit;

  if DstFilename<>'' then begin
    ForceDirectories(ExtractFilePath(DstFilename));
    Dstfs:=TFileStream.Create(DstFilename,fmCreate or fmShareExclusive);
    Dstfs.Write(DecData[0],DecDataSize);
    Dstfs.Free;
  end;

  FreeMem(DecData);
end;

function SZipDecompress(SrcFilename,DstFilename:string):integer;
var
  Data,DecData:PByteArray;
  DataSize,DecDataSize:integer;
  Srcfs,Dstfs:TFileStream;
begin
  if FileExists(SrcFilename)=False then begin
    Result:=SZipErrorNoFile;
    exit;
  end;

  Srcfs:=TFileStream.Create(SrcFilename,fmOpenRead or fmShareExclusive);
  DataSize:=Srcfs.Size;
  GetMem(Data,DataSize+1);
  Srcfs.ReadBuffer(Data[0],DataSize);
  Srcfs.Free;

  Result:=SZipDecompress(Data,DataSize,DecData,DecDataSize);
  if Result<>SZipSuccess then begin
    FreeMem(Data);
    exit;
  end;

  if DstFilename<>'' then begin
    Dstfs:=TFileStream.Create(DstFilename,fmCreate or fmShareExclusive);
    Dstfs.Write(DecData[0],DecDataSize);
    Dstfs.Free;
  end;

  FreeMem(Data);
  FreeMem(DecData);
end;

end.

