{******************************************************************************}
{                                                                              }
{ Jazz SDK                                                                     }
{ Jazz Core Library                                                            }
{                                                                              }
{ Copyright (c) 1998-2008                                                      }
{ Cesar Romero <cesar@liws.com.br>                                             }
{                                                                              }
{******************************************************************************}
{                                                                              }
{ Jazz Zip - Version 1.0                                                       }
{ 2008, 5 march                                                                }
{******************************************************************************}
unit JazzZip;

{$I Jazz.inc}

interface

uses
  Classes, SysUtils, ZLib;

type
  TJzZipLevel = ZLib.TCompressionLevel;
  IZip = interface(IInterface)
  ['{37930CD0-F127-4C03-BE46-B4731905B2DD}']
    procedure Execute(const ZipLevel: TJzZipLevel = clMax);
  end;

  IJzUnzip = interface(IInterface)
  ['{D57C6894-BF3E-4AD6-8317-A7684F575878}']
    procedure Execute;
  end;

  TJzZipClass = class of TJzZip;
  TJzZip = class(TInterfacedObject, IZip)
  private
    FInput: TStream;
    FOutput: TStream;
    FSame: boolean;
    FTempStream: TStream;
  public
    constructor Create(const Input: string; const Output: TStream); overload;
    constructor Create(const Input, Output: TStream); overload;
    destructor Destroy; override;
    procedure Execute(const ZipLevel: TJzZipLevel = clMax); virtual;
  end;

  TJzUnzipClass = class of TJzUnzip;
  TJzUnzip = class(TInterfacedObject, IJzUnzip)
  private
    FInput: TStream;
    FOutput: TStream;
    FOutputStr: PString;
    FSame: boolean;
    FTemp: TStream;
  public
    constructor Create(const Input: TStream; var Output: string); overload;
    constructor Create(const Input, Output: TStream); overload;
    destructor Destroy; override;
    procedure Execute; virtual;
  end;

  TJzZLibZip = class(TJzZip)
  public
    procedure Execute(const ZipLevel: TJzZipLevel = clMax); override;
  end;

  TJzZLibUnzip = class(TJzUnzip)
  public
    procedure Execute; override;
  end;

  ECompression = class(Exception);

procedure ZipData(const Source: TStream; const Output: TStream = nil; ZipLevel: TJzZipLevel = clMax); overload;
procedure ZipData(const Source: string; const Output: TStream; ZipLevel: TJzZipLevel = clMax); overload;
procedure UnzipData(const Source: TStream; const Output: TStream = nil); overload;
procedure UnzipData(const Source: TStream; var Output: string); overload;

var
  ZipClass: TJzZipClass = TJzZLibZip;
  UnzipClass: TJzUnzipClass = TJzZLibUnzip;

implementation

const
  SInvalidDestination = 'Output can''t be nil with source as string .';

procedure ZipData(const Source: TStream; const Output: TStream = nil; ZipLevel: TJzZipLevel = clMax);
var
  LZip: IZip;
begin
  LZip:= ZipClass.Create(Source, Output);
  LZip.Execute(ZipLevel);
end;

procedure ZipData(const Source: string; const Output: TStream; ZipLevel: TJzZipLevel = clMax);
var
  LZip: IZip;
begin
  LZip:= ZipClass.Create(Source, Output);
  LZip.Execute(ZipLevel);
end;

procedure UnzipData(const Source: TStream; const Output: TStream = nil);
var
  LUnzip: IJzUnzip;
begin
  LUnzip:= UnzipClass.Create(Source, Output);
  LUnzip.Execute;
end;

procedure UnzipData(const Source: TStream; var Output: string); overload;
var
  LUnzip: IJzUnzip;
begin
  LUnzip:= UnzipClass.Create(Source, Output);
  LUnzip.Execute;
end;

constructor TJzZip.Create(const Input: string; const Output: TStream);
begin
  if Output = nil then
    raise ECompression.Create(SInvalidDestination);

  FTempStream:= TStringStream.Create(Input);
  Create(FTempStream, Output);
end;

{ TJzZip }

constructor TJzZip.Create(const Input, Output: TStream);
begin
  inherited Create;
  FInput:= Input;
  FOutput:= Output;
  FSame:= FOutput = nil;
  if FSame then FOutput:= TMemoryStream.Create;
  FInput.Position:= 0;
  FOutput.Position:= 0;
end;

destructor TJzZip.Destroy;
begin
  if FTempStream <> nil then FTempStream.Free;
  if FSame then FOutput.Free;
  inherited;
end;

procedure TJzZip.Execute(const ZipLevel: TJzZipLevel);
begin
  if FSame then
  begin
    FOutput.Position:= 0;
    FInput.Size:= 0;
    FInput.CopyFrom(FOutput, FOutput.Size);
  end;
end;

constructor TJzUnzip.Create(const Input: TStream; var Output: string);
begin
  FTemp:= TStringStream.Create(Output);
  FOutputStr:= @Output;
  Create(Input, FTemp);
end;

{ TJzUnzip }

constructor TJzUnzip.Create(const Input, Output: TStream);
begin
  inherited Create;
  FInput:= Input;
  FOutput:= Output;
  FSame:= FOutput = nil;
  if FSame then FOutput:= TMemoryStream.Create;
  FInput.Position:= 0;
end;

destructor TJzUnzip.Destroy;
begin
  if FTemp <> nil then FTemp.Free;
  if FSame then FOutput.Free;
  inherited;
end;

procedure TJzUnzip.Execute;
begin
  if FSame then
  begin
    FOutput.Position:= 0;
    FInput.Size:= 0;
    FInput.WriteBuffer(FOutput, FOutput.Size);
  end;

  if FOutputStr <> nil then
  begin
    FInput.Position:= 0;
    FInput.ReadBuffer(FOutputStr, FInput.Size);
  end;
end;

{ TJzZLibZip }

procedure TJzZLibZip.Execute(const ZipLevel: TJzZipLevel);
var
  LComp: TCompressionStream;
begin
  LComp:= TCompressionStream.Create(ZipLevel, FOutput);
  LComp.CopyFrom(FInput, FInput.Size);
  LComp.Free;
  inherited Execute(ZipLevel);
end;

{ TJzZLibUnzip }

procedure TJzZLibUnzip.Execute;
var
  LCount: Integer;
  LDecomp: TDecompressionStream;
  LBuffer: array[1..1024] of Byte;
begin
  LDecomp:= TDecompressionStream.Create(FInput);
  try
    repeat
      LCount:= LDecomp.Read(LBuffer, SizeOf(LBuffer));
      if LCount > 0 then FOutput.Write(LBuffer, LCount);
    until LCount < 1;
  finally
    LDecomp.Free;
  end;
  inherited Execute;
end;

end.