/// low-level access to ZLib compression (1.2.5 engine version)
// - this unit is a part of the freeware Synopse framework,
// licensed under a MPL/GPL/LGPL tri-license; version 1.18
unit SynZip;

{
    This file is part of Synopse framework.

    Synopse framework. Copyright (C) 2022 Arnaud Bouchez
      Synopse Informatique - https://synopse.info

  *** BEGIN LICENSE BLOCK *****
  Version: MPL 1.1/GPL 2.0/LGPL 2.1

  The contents of this file are subject to the Mozilla Public License Version
  1.1 (the "License"); you may not use this file except in compliance with
  the License. You may obtain a copy of the License at
  http://www.mozilla.org/MPL

  Software distributed under the License is distributed on an "AS IS" basis,
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  for the specific language governing rights and limitations under the License.

  The Original Code is Synopse framework.

  The Initial Developer of the Original Code is Arnaud Bouchez.

  Portions created by the Initial Developer are Copyright (C) 2022
  the Initial Developer. All Rights Reserved.

  Contributor(s):
   - Alf
   - Andre Heider (dhewg)
   - ehansen
   - jpdk
   - Gigo

  Alternatively, the contents of this file may be used under the terms of
  either the GNU General Public License Version 2 or later (the "GPL"), or
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  in which case the provisions of the GPL or the LGPL are applicable instead
  of those above. If you wish to allow use of your version of this file only
  under the terms of either the GPL or the LGPL, and not to allow others to
  use your version of this file under the terms of the MPL, indicate your
  decision by deleting the provisions above and replace them with the notice
  and other provisions required by the GPL or the LGPL. If you do not delete
  the provisions above, a recipient may use your version of this file under
  the terms of any one of the MPL, the GPL or the LGPL.

  ***** END LICENSE BLOCK *****

  ORIGINAL LICENSE:

  zlib.h -- interface of the 'zlib' general purpose compression library
  version 1.2.5, April 19th, 2010

  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler

  This software is provided 'as-is', without any express or implied
  warranty.  In no event will the authors be held liable for any damages
  arising from the use of this software.

  Permission is granted to anyone to use this software for any purpose,
  including commercial applications, and to alter it and redistribute it
  freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not
     claim that you wrote the original software. If you use this software
     in a product, an acknowledgment in the product documentation would be
     appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be
     misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

  Jean-loup Gailly
  Mark Adler

    Cross-platform ZLib implementation
   ====================================

    Link to original C-compiled ZLib library
    - Win32: use fast obj and inline asm
    - Linux: use available system library libz.so
    Also defines .zip file structure (TFileInfo TFileHeader TLastHeader)

}

{$I Synopse.inc} // define HASINLINE CPU32 CPU64

{.$define USEZLIBSSE}
// if defined (only FPC+Win64), will link static\x86_64-win64sse\*.o static libraries
// from https://github.com/cloudflare/zlib (warning: SSE3/SSE4.2 CPUs only)

{.$define USECFZLIB} // https://github.com/cloudflare/zlib as external dll
{$ifdef USECFZLIB}
  {$define USEEXTZLIB}
{$else}

{$ifdef FPC}
  {$ifdef MSWINDOWS} // avoid link to zlib1.dll
    {.$define USEPASZLIB} // paszlib makes Z_BUF_ERROR with bits = -MAX_WBITS
    {$ifdef Win32}
      {.$define USEZLIBSSE} // SynZLibSSE static .o files for FPC + Win32 fails
    {$endif}
    {$ifdef Win64}
      {.$define USEEXTZLIB}  // use zlib-64.dll as in \fpc-win64 sub-folder
    {$endif}
  {$else}
    // will use zlib.so under Linux/Posix
    {$ifdef ANDROID}
       {$define USEPASZLIB} // Alf: problem with external zlib.so under Android
    {$else}
       {$define USEEXTZLIB}
    {$endif}
  {$endif}
{$else}
  {$undef USEZLIBSSE}  // Delphi linker is buggy as hell
  {$ifndef USEEXTZLIB} // define USEEXTZLIB for the project for better performance
    {$ifdef MSWINDOWS}
      {$ifdef Win32}
        {$define USEINLINEASM}
        // if defined, we use a special inlined asm version for uncompress:
        // seems 50% faster than BC++ generated .obj, and is 3KB smaller in code size
      {$endif}
      {$ifdef Win64}
       {$define USEDELPHIZLIB} // System.ZLib is (much) slower, but static
        {.$define USEEXTZLIB}  // use faster zlib-64.dll as in \fpc-win64 sub-folder
      {$endif}
    {$else}
      {$define USEEXTZLIB} // e.g. for Kylix
    {$endif}
  {$endif USEEXTZLIB}
{$endif}

{$endif USECFZLIB}

interface

uses
{$ifdef MSWINDOWS}
  Windows,
{$else}
  {$ifdef KYLIX3}
  LibC,
  {$else}
  {$ifndef ANDROID}
  clocale,
  {$endif}
  {$endif}
  Types,
{$endif}
{$ifdef USEPASZLIB}
  zbase,
  paszlib,
{$endif}
  SysUtils,
  Classes;

type
  /// the format used for storing data
  TSynZipCompressorFormat = (szcfRaw, szcfZip, szcfGZ);

{$ifdef DELPHI5OROLDER}
type // Delphi 5 doesn't have those base types defined :(
  PInteger = ^Integer;
  PCardinal = ^Cardinal;
  IntegerArray  = array[0..$effffff] of Integer;
const
  PathDelim  = '\';
  soCurrent = soFromCurrent;

function IncludeTrailingPathDelimiter(const FileName: TFileName): TFileName;
{$endif}

/// in-memory ZLib DEFLATE compression
// - by default, will use the deflate/.zip header-less format, but you may set
// ZlibFormat=true to add an header, as expected by zlib (and pdf)
function CompressMem(src, dst: pointer; srcLen, dstLen: integer;
  CompressionLevel: integer=6; ZlibFormat: Boolean=false) : integer;

/// in-memory ZLib INFLATE decompression
// - by default, will use the deflate/.zip header-less format, but you may set
// ZlibFormat=true to add an header, as expected by zlib (and pdf)
function UnCompressMem(src, dst: pointer; srcLen, dstLen: integer; ZlibFormat: Boolean=false) : integer;

/// ZLib DEFLATE compression from memory into a stream
// - by default, will use the deflate/.zip header-less format, but you may set
// ZlibFormat=true to add an header, as expected by zlib (and pdf)
function CompressStream(src: pointer; srcLen: integer;
  tmp: TStream; CompressionLevel: integer=6; ZlibFormat: Boolean=false;
  TempBufSize: integer=0): cardinal;

/// ZLib INFLATE decompression from memory into a stream
// - return the number of bytes written into the stream
// - if checkCRC if not nil, it will contain the crc32; if aStream is nil, it
// will only calculate the crc of the the uncompressed memory block
// - by default, will use the deflate/.zip header-less format, but you may set
// ZlibFormat=true to add an header, as expected by zlib (and pdf)
function UnCompressStream(src: pointer; srcLen: integer; tmp: TStream;
  checkCRC: PCardinal; ZlibFormat: Boolean=false; TempBufSize: integer=0): cardinal;

type
{$ifdef HASCODEPAGE}
  ZipString = type RawByteString;
{$else}
  /// define a raw storage string type, used for data buffer management
  ZipString = type AnsiString;
{$endif}
{$ifdef FPC}
  ZipPtrUInt = PtrUInt;
  ZipPtrInt = PtrInt;
{$else}
  /// as available in FPC
  ZipPtrUInt = {$ifdef CPU64}UInt64{$else}cardinal{$endif};
  ZipPtrInt = {$ifdef CPU64}Int64{$else}integer{$endif};
{$endif}

/// ZLib INFLATE decompression from memory into a AnsiString (ZipString) variable
// - return the number of bytes written into the string
// - if checkCRC if not nil, it will contain the crc32; if aStream is nil, it
// will only calculate the crc of the the uncompressed memory block
// - by default, will use the deflate/.zip header-less format, but you may set
// ZlibFormat=true to add an header, as expected by zlib (and pdf)
function UnCompressZipString(src: pointer; srcLen: integer; out data: ZipString;
  checkCRC: PCardinal; ZlibFormat: Boolean; TempBufSize: integer=0): cardinal;

/// compress some data, with a proprietary format (including CRC)
function CompressString(const data: ZipString; failIfGrow: boolean = false;
  CompressionLevel: integer=6) : ZipString;

/// uncompress some data, with a proprietary format (including CRC)
// - return '' in case of a decompression failure
function UncompressString(const data: ZipString) : ZipString;


/// (un)compress a data content using the gzip algorithm
// - as expected by THttpSocket.RegisterCompress
// - will use internaly a level compression of 1, i.e. fastest available (content
// of 4803 bytes is compressed into 700, and time is 440 us instead of 220 us)
function CompressGZip(var DataRawByteString; Compress: boolean): AnsiString;

/// (un)compress a data content using the Deflate algorithm (i.e. "raw deflate")
// - as expected by THttpSocket.RegisterCompress
// - will use internaly a level compression of 1, i.e. fastest available (content
// of 4803 bytes is compressed into 700, and time is 440 us instead of 220 us)
// - deflate content encoding is pretty inconsistent in practice, so slightly
// slower CompressGZip() is preferred - http://stackoverflow.com/a/9186091
function CompressDeflate(var DataRawByteString; Compress: boolean): AnsiString;

/// (un)compress a data content using the zlib algorithm
// - as expected by THttpSocket.RegisterCompress
// - will use internaly a level compression of 1, i.e. fastest available (content
// of 4803 bytes is compressed into 700, and time is 440 us instead of 220 us)
// - zlib content encoding is pretty inconsistent in practice, so slightly
// slower CompressGZip() is preferred - http://stackoverflow.com/a/9186091
function CompressZLib(var DataRawByteString; Compress: boolean): AnsiString;

/// low-level check of the code returned by the ZLib library
function Check(const Code: Integer; const ValidCodes: array of Integer;
  const Context: string=''): integer;

type
  PCardinalArray = ^TCardinalArray;
  TCardinalArray = array[0..(MaxLongint div SizeOf(cardinal))-1] of cardinal;

/// just hash aString with CRC32 algorithm
// - crc32 is better than adler32 for short strings
function CRC32string(const aString: ZipString): cardinal;

type
  /// exception raised internaly in case of Zip errors
  ESynZipException = class(Exception);

{$ifdef USEZLIBSSE} // statically linked with new 64-bit TZStream
type
  TZLong = ZipPtrUint;
  TZCRC = Int64;
{$else}
  {$ifdef USECFZLIB} // dynamically linked with new 64-bit TZStream
  type
    TZLong = ZipPtrUint;
    TZCRC = Int64;
  const
    {$ifdef WIN64}
    libz='zlibcf64.dll';
    {$else}
    libz='zlibcf32.dll';
    {$endif}
  {$else}
    {$ifdef USEEXTZLIB}
      {$ifdef MSWINDOWS} // dynamically linked with old 32-bit TZStream
      type
        TZLong = cardinal;
        TZCRC = cardinal;
      const
        {$ifdef WIN2}
        libz='zlib-32.dll'; // as available in \fpc-win32 sub-folder
        {$endif}
        {$ifdef WIN64}
        libz='zlib-64.dll'; // as available in \fpc-win64 sub-folder
        {$endif}
      {$endif MSWINDOWS}
      {$ifdef KYLIX3}
      type
        TZLong = cardinal;
        TZCRC = cardinal;
      const
        libz = 'libz.so.1';
      {$else}
        {$ifdef UNIX} // dynamically linked with new 64-bit TZStream
        type
          TZLong = ZipPtrUint;
          TZCRC = cardinal;
        const
          libz='z';
          {$linklib libz}
        {$endif UNIX}
      {$endif KYLIX3}
    {$else} // statically linked with old 32-bit TZStream
    type
      TZLong = cardinal;
      TZCRC = cardinal;
    {$endif USEEXTZLIB}
  {$endif USECFZLIB}
{$endif USEZLIBSSE}

type
  {$ifdef USEPASZLIB}
  TZStream = z_stream;
  {$else}
  /// the internal memory structure as expected by the ZLib library
  TZStream =  record
    next_in: PAnsiChar;
    avail_in: cardinal;
    total_in: TZLong;
    next_out: PAnsiChar;
    avail_out: cardinal;
    total_out: TZLong;
    msg: PAnsiChar;
    state: pointer;
    zalloc: pointer;
    zfree: pointer;
    opaque: pointer;
    data_type: integer;
    adler: TZLong;
    reserved: TZLong;
  end;
  {$endif USEPASZLIB}

/// initialize the internal memory structure as expected by the ZLib library
procedure StreamInit(var Stream: TZStream); overload;

/// prepare the internal memory structure as expected by the ZLib library for compression
function DeflateInit(var Stream: TZStream; CompressionLevel: integer;
  ZlibFormat: Boolean): Boolean; overload;

// don't know why using objects below produce an Internal Error DT5830
// under Delphi 2009 Update 3 !!!!!
// -> see http://qc.embarcadero.com/wc/qcmain.aspx?d=79792
// it seems that this compiler doesn't like to compile packed objects,
// but all other versions (including Delphi 2009 Update 2) did
// -> do Codegear knows about regression tests?

type
{$A-} { force packed object (not allowed under Delphi 2009) }
  PFileInfo = ^TFileInfo;
  /// generic file information structure, as used in .zip file format
  // - used in any header, contains info about following block
  {$ifndef USERECORDWITHMETHODS}TFileInfo = object
    {$else}TFileInfo = record{$endif}
    neededVersion : word;            // $14
    flags         : word;            // 0
    zzipMethod    : word;            // 0=Z_STORED 8=Z_DEFLATED 12=BZ2 14=LZMA
    zlastMod      : integer;         // time in dos format
    zcrc32        : dword;           // crc32 checksum of uncompressed data
    zzipSize      : dword;           // size of compressed data
    zfullSize     : dword;           // size of uncompressed data
    nameLen       : word;            // length(name)
    extraLen      : word;            // 0
    function SameAs(aInfo: PFileInfo): boolean;
    function AlgoID: integer; // 1..15  (1=SynLZ e.g.) from flags
    procedure SetAlgoID(Algorithm: integer);
    function GetUTF8FileName: boolean;
    procedure SetUTF8FileName;
    procedure UnSetUTF8FileName;
  end;

  /// directory file information structure, as used in .zip file format
  // - used at the end of the zip file to recap all entries
  TFileHeader = {$ifdef USERECORDWITHMETHODS}record
    {$else}object{$endif}
    signature     : dword;           // $02014b50 PK#1#2
    madeBy        : word;            // $0314 = OS + version
    fileInfo      : TFileInfo;
    commentLen    : word;            // 0
    firstDiskNo   : word;            // 0
    intFileAttr   : word;            // 0 = binary; 1 = text
    extFileAttr   : dword;           // dos file attributes
    localHeadOff  : dword;           // @TLocalFileHeader
    function IsFolder: boolean; {$ifdef HASINLINE}inline;{$endif}
    procedure Init;
  end;
  PFileHeader = ^TFileHeader;

  /// internal file information structure, as used in .zip file format
  // - used locally inside the file stream, followed by the name and then the data
  {$ifdef USERECORDWITHMETHODS}TLocalFileHeader = record
    {$else}TLocalFileHeader = object{$endif}
    signature     : dword;           // $04034b50 PK#3#4
    fileInfo      : TFileInfo;
    function LocalData: PAnsiChar;
  end;
  PLocalFileHeader = ^TLocalFileHeader;

  /// last header structure, as used in .zip file format
  // - this header ends the file and is used to find the TFileHeader entries
  TLastHeader = record
    signature     : dword;           // $06054b50 PK#5#6
    thisDisk      : word;            // 0
    headerDisk    : word;            // 0
    thisFiles     : word;            // 1
    totalFiles    : word;            // 1
    headerSize    : dword;           // sizeOf(TFileHeaders + names)
    headerOffset  : dword;           // @TFileHeader
    commentLen    : word;            // 0
  end;
  PLastHeader = ^TLastHeader;
{$A+}

const
  ZLIB_VERSION = '1.2.3';
  ZLIB_VERNUM = $1230;

  Z_NO_FLUSH = 0;
  Z_PARTIAL_FLUSH = 1;
  Z_SYNC_FLUSH = 2;
  Z_FULL_FLUSH = 3;
  Z_FINISH = 4;
  Z_BLOCK = 5;

  Z_OK = 0;
  Z_STREAM_END = 1;
  Z_NEED_DICT = 2;
  Z_ERRNO = -1;
  Z_STREAM_ERROR = -2;
  Z_DATA_ERROR = -3;
  Z_MEM_ERROR = -4;
  Z_BUF_ERROR = -5;
  Z_VERSION_ERROR = -6;

  Z_NO_COMPRESSION = 0;
  Z_BEST_SPEED = 1;
  Z_BEST_COMPRESSION = 9;
  Z_DEFAULT_COMPRESSION = -1;

  Z_FILTERED = 1;
  Z_HUFFMAN_ONLY = 2;
  Z_RLE = 3;
  Z_FIXED = 4;
  Z_DEFAULT_STRATEGY = 0;

  Z_BINARY = 0;
  Z_ASCII = 1;
  Z_UNKNOWN = 2;

  Z_STORED = 0;
  Z_DEFLATED = 8;
  MAX_WBITS   = 15; // 32K LZ77 window
  DEF_MEM_LEVEL = 8;

  Z_NULL = 0;

{$ifdef USEPASZLIB}
function deflateInit2_(var strm: TZStream;
  level, method, windowBits, memLevel, strategy: integer;
  version: PAnsiChar; stream_size: integer): integer;
function deflate(var strm: TZStream; flush: integer): integer;
function deflateEnd(var strm: TZStream): integer;
function inflateInit2_(var strm: TZStream; windowBits: integer;
  version: PAnsiChar; stream_size: integer): integer;
function inflate(var strm: TZStream; flush: integer): integer;
function inflateEnd(var strm: TZStream): integer;
function adler32(adler: cardinal; buf: PAnsiChar; len: cardinal): cardinal;
function crc32(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal;
function get_crc_table: pointer;
{$else}
{ our very own short implementation of ZLibH }
{$ifdef USEINLINEASM}
function deflateInit2_(var strm: TZStream;
  level, method, windowBits, memLevel, strategy: integer;
  version: PAnsiChar; stream_size: integer): integer;
function deflate(var strm: TZStream; flush: integer): integer;
function deflateEnd(var strm: TZStream): integer;
function inflateInit2_(var strm: TZStream; windowBits: integer;
  version: PAnsiChar; stream_size: integer): integer; stdcall;
function inflate(var strm: TZStream; flush: integer): integer; stdcall;
function inflateEnd(var strm: TZStream): integer; stdcall;
function adler32(adler: cardinal; buf: PAnsiChar; len: cardinal): cardinal;
function crc32(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal;
function get_crc_table: pointer;
{$else USEINLINEASM}
function deflate(var strm: TZStream; flush: integer): integer; cdecl;
function deflateEnd(var strm: TZStream): integer; cdecl;
function inflate(var strm: TZStream; flush: integer): integer; cdecl;
function inflateEnd(var strm: TZStream): integer; cdecl;
function adler32(adler: TZCRC; buf: PAnsiChar; len: cardinal): TZCRC; cdecl;
function crc32(crc: TZCRC; buf: PAnsiChar; len: cardinal): TZCRC; cdecl;
function deflateInit_(var strm: TZStream; level: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
function inflateInit_(var strm: TZStream;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
function deflateInit2_(var strm: TZStream;
  level, method, windowBits, memLevel, strategy: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
function inflateInit2_(var strm: TZStream; windowBits: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
{$endif USEINLINEASM}
{$endif USEPASZLIB}

type
  /// simple wrapper class to decompress a .gz file into memory or stream/file
  {$ifdef USERECORDWITHMETHODS}TGZRead = record
    {$else}TGZRead = object{$endif}
  private
    comp, zsdest: pointer;
    zscrc: cardinal;
    zssize, zscode: integer;
    zs: TZStream;
  public
    complen: ZipPtrInt;
    uncomplen32: cardinal; // modulo 2^32 by gzip design
    crc32: cardinal;
    unixmodtime: cardinal;
    fname, fcomment, extra: PAnsiChar;
    /// read and validate the .gz header
    // - on success, return true and fill complen/uncomplen/crc32c properties
    function Init(gz: PAnsiChar; gzLen: ZipPtrInt): boolean;
    /// uncompress the .gz content into a memory buffer
    // - warning: won't work as expected if uncomplen32 was truncated to 2^32
    function ToMem: ZipString;
    /// uncompress the .gz content into a stream
    function ToStream(stream: TStream; tempBufSize: integer=0): boolean;
    /// uncompress the .gz content into a file
    function ToFile(const filename: TFileName; tempBufSize: integer=0): boolean;
    /// allow low level iterative decompression using an internal TZStream structure
    function ZStreamStart(dest: pointer; destsize: integer): boolean;
    /// return true if ZStreamStart() has been successfully called
    function ZStreamStarted: boolean; {$ifdef HASINLINE}inline;{$endif}
    /// will uncompress into dest/destsize buffer as supplied to ZStreamStart
    // - return the number of bytes uncompressed (<=destsize)
    // - return 0 if the input stream is finished
    function ZStreamNext: integer;
    /// any successfull call to ZStreamStart should always run ZStreamDone
    // - return true if the crc and the uncompressed size are ok
    function ZStreamDone: boolean;
  end;


/// uncompress a .gz file content
// - return '' if the .gz content is invalid (e.g. bad crc)
function GZRead(gz: PAnsiChar; gzLen: integer): ZipString;

/// compress a file content into a new .gz file
// - will use TSynZipCompressor for minimal memory use during file compression
function GZFile(const orig, destgz: TFileName; CompressionLevel: Integer=6): boolean;

const
  /// operating-system dependent wildchar to match all files in a folder
  ZIP_FILES_ALL = {$ifdef MSWINDOWS}'*.*'{$else}'*'{$endif};

type
  /// a simple TStream descendant for compressing data into a stream
  // - this simple version don't use any internal buffer, but rely
  // on Zip library buffering system
  // - the version in SynZipFiles is much more powerfull, but this one
  // is sufficient for most common cases (e.g. for on the fly .gz backup)
  TSynZipCompressor = class(TStream)
  private
    fInitialized: Boolean;
    fDestStream: TStream;
    fStrm: TZStream;
    fCRC: Cardinal;
    fGZFormat: boolean;
    fBufferOut: array[word] of byte; // a 64 KB buffer
    function FlushBufferOut: integer;
  public
    /// create a compression stream, writting the compressed data into
    // the specified stream (e.g. a file stream)
    constructor Create(outStream: TStream; CompressionLevel: Integer;
      Format: TSynZipCompressorFormat = szcfRaw);
    /// release memory
    destructor Destroy; override;
    /// this method will raise an error: it's a compression-only stream
    function Read(var Buffer; Count: Longint): Longint; override;
    /// add some data to be compressed
    function Write(const Buffer; Count: Longint): Longint; override;
    /// used to return the current position, i.e. the real byte written count
    // - for real seek, this method will raise an error: it's a compression-only stream
    function Seek(Offset: Longint; Origin: Word): Longint; override;
    /// the number of byte written, i.e. the current uncompressed size
    function SizeIn: cardinal;
    /// the number of byte sent to the destination stream, i.e. the current
    // compressed size
    function SizeOut: cardinal;
    /// write all pending compressed data into outStream
    procedure Flush;
    /// the current CRC of the written data, i.e. the uncompressed data CRC
    property CRC: cardinal read fCRC;
  end;

  /// stores an entry of a file inside a .zip archive
  TZipEntry = record
    /// the information of this file, as stored locally in the .zip archive
    // - note that infoLocal^.zzipSize/zfullSize/zcrc32 may be 0 if the info
    // was stored in a "data descriptor" block after the data: in this case,
    // you should use TZipRead.RetrieveFileInfo() instead of this structure
    infoLocal: PFileInfo;
    /// the information of this file, as stored at the end of the .zip archive
    // - may differ from infoLocal^ content, depending of the zipper tool used
    infoDirectory: PFileHeader;
    /// points to the compressed data in the .zip archive, mapped in memory
    data: PAnsiChar;
    /// name of the file inside the .zip archive
    // - not ASCIIZ: length = infoLocal.nameLen
    storedName: PAnsiChar;
    /// name of the file inside the .zip archive
    // - converted from DOS/OEM or UTF-8 into generic (Unicode) string
    zipName: TFileName;
  end;

  /// read-only access to a .zip archive file
  // - can open directly a specified .zip file (will be memory mapped for fast access)
  // - can open a .zip archive file content from a resource (embedded in the executable)
  // - can open a .zip archive file content from memory
  TZipRead = class
  private
    buf: PByteArray;
    FirstFileHeader: PFileHeader;
    ReadOffset: cardinal;
    {$ifdef MSWINDOWS}
    file_, map: ZipPtrUint;
    {$else}
    file_: THandle;
    mapSize: cardinal;
    {$endif}
    procedure UnMap;
    function UnZipStream(aIndex: integer; const aInfo: TFileInfo; aDest: TStream): boolean;
  public
    /// the number of files inside a .zip archive
    Count: integer;
    /// the files inside the .zip archive
    Entry: array of TZipEntry;

    /// open a .zip archive file as Read Only
    constructor Create(const aFileName: TFileName; ZipStartOffset: cardinal=0;
      Size: cardinal=0); overload;
    /// open a .zip archive file directly from a resource
    constructor Create(Instance: THandle; const ResName: string; ResType: PChar); overload;
    /// open a .zip archive file from its File Handle
    constructor Create(aFile: THandle; ZipStartOffset: cardinal=0;
      Size: cardinal=0); overload;
    /// open a .zip archive file directly from memory
    constructor Create(BufZip: PByteArray; Size: cardinal); overload;
    /// release associated memory
    destructor  Destroy; override;

    /// get the index of a file inside the .zip archive
    function NameToIndex(const aName: TFileName): integer;
    /// uncompress a file stored inside the .zip archive into memory
    function UnZip(aIndex: integer): ZipString; overload;
    /// uncompress a file stored inside the .zip archive into a stream
    function UnZip(aIndex: integer; aDest: TStream): boolean; overload;
    /// uncompress a file stored inside the .zip archive into a destination directory
    function UnZip(aIndex: integer; const DestDir: TFileName;
      DestDirIsFileName: boolean=false): boolean; overload;
    /// uncompress a file stored inside the .zip archive into memory
    function UnZip(const aName: TFileName): ZipString; overload;
    /// uncompress a file stored inside the .zip archive into a destination directory
    function UnZip(const aName, DestDir: TFileName;
      DestDirIsFileName: boolean=false): boolean; overload;
    /// uncompress all fields stored inside the .zip archive into the supplied
    // destination directory
    // - returns -1 on success, or the index in Entry[] of the failing file
    function UnZipAll(DestDir: TFileName): integer;
    /// retrieve information about a file
    // - in some cases (e.g. for a .zip created by latest Java JRE),
    // infoLocal^.zzipSize/zfullSize/zcrc32 may equal 0: this method is able
    // to retrieve the information either from the ending "central directory",
    // or by searching the "data descriptor" block
    // - returns TRUE if the Index is correct and the info was retrieved
    // - returns FALSE if the information was not successfully retrieved
    function RetrieveFileInfo(Index: integer; var Info: TFileInfo): boolean;
  end;

  /// abstract write-only access for creating a .zip archive
  // - update can be done manualy by using a TZipRead instance and the
  // AddFromZip() method
  TZipWriteAbstract = class
  protected
    fAppendOffset: cardinal;
    fMagic: cardinal;
    function InternalAdd(const zipName: TFileName; Buf: pointer; Size: integer): cardinal;
    function InternalWritePosition: cardinal; virtual; abstract;
    procedure InternalWrite(const buf; len: cardinal); virtual; abstract;
  public
    /// the total number of entries
    Count: integer;
    /// the resulting file entries, ready to be written as a .zip catalog
    // - those will be appended after the data blocks at the end of the .zip file
    Entry: array of record
      /// the file name, as stored in the .zip internal directory
      intName: ZipString;
      /// the corresponding file header
      fhr: TFileHeader;
    end;
    /// initialize the .zip archive
    // - a new .zip file content is prepared
    constructor Create;
    /// compress (using the deflate method) a memory buffer, and add it to the zip file
    // - by default, the 1st of January, 2010 is used if not date is supplied
    procedure AddDeflated(const aZipName: TFileName; Buf: pointer; Size: integer;
      CompressLevel: integer=6; FileAge: integer=1+1 shl 5+30 shl 9); overload;
    /// add a memory buffer to the zip file, without compression
    // - content is stored, not deflated
    // (in that case, no deflate code is added to the executable)
    // - by default, the 1st of January, 2010 is used if not date is supplied
    procedure AddStored(const aZipName: TFileName; Buf: pointer; Size: integer;
      FileAge: integer=1+1 shl 5+30 shl 9);
    /// add a file from an already compressed zip entry
    procedure AddFromZip(Source: TZipRead; EntryIndex: integer);
    /// append a file content into the destination file
    // - useful to add the initial Setup.exe file, e.g.
    procedure Append(const Content: ZipString);
    /// release associated memory, and close destination archive
    destructor Destroy; override;
  end;

  /// write-only access for creating a .zip archive file
  // - not to be used to update a .zip file, but to create a new one
  TZipWrite = class(TZipWriteAbstract)
  protected
    fFileName: TFileName;
    function InternalWritePosition: cardinal; override;
    procedure InternalWrite(const buf; len: cardinal); override;
  public
    /// the associated file handle
    Handle: integer;
    /// initialize the .zip file
    // - a new .zip file content is created
    constructor Create(const aFileName: TFileName); overload;
    /// initialize an existing .zip file in order to add some content to it
    // - warning: AddStored/AddDeflated() won't check for duplicate zip entries
    // - this method is very fast, and will increase the .zip file in-place
    // (the old content is not copied, new data is appended at the file end)
    // - "dummy" parameter exists only to disambiguate constructors for C++
    constructor CreateFrom(const aFileName: TFileName; dummy: integer=0);
    /// compress (using the deflate method) a file, and add it to the zip file
    procedure AddDeflated(const aFileName: TFileName; RemovePath: boolean=true;
      CompressLevel: integer=6; ZipName: TFileName=''); overload;
    /// compress (using the deflate method) all files within a folder, and
    // add it to the zip file
    // - if Recursive is TRUE, would include files from nested sub-folders
    procedure AddFolder(const FolderName: TFileName; const Mask: TFileName=ZIP_FILES_ALL;
      Recursive: boolean=true; CompressLevel: integer=6);
    /// release associated memory, and close destination file
    destructor Destroy; override;
  end;

  /// write-only access for creating a .zip archive into a stream
  TZipWriteToStream = class(TZipWriteAbstract)
  protected
    fDest: TStream;
    function InternalWritePosition: cardinal; override;
    procedure InternalWrite(const buf; len: cardinal); override;
  public
    /// initialize the .zip archive
    // - a new .zip file content is prepared
    constructor Create(aDest: TStream);
  end;

/// a TSynLogArchiveEvent handler which will compress older .log files
// into .zip archive files
// - resulting file will be named YYYYMM.zip and will be located in the
// aDestinationPath directory, i.e. TSynLogFamily.ArchivePath+'\log\YYYYMM.zip'
function EventArchiveZip(const aOldLogFileName, aDestinationPath: TFileName): boolean;

implementation

{$ifdef USEDELPHIZLIB}
uses
  ZLib;
{$endif USEDELPHIZLIB}
{$ifdef Linux}
uses
  {$ifdef FPC}
  SynFPCLinux,
  BaseUnix;
  {$else}
  SynKylix;
  {$endif}
{$endif Linux}

{$ifdef DELPHI5OROLDER}
function IncludeTrailingPathDelimiter(const FileName: TFileName): TFileName;
begin
  result := IncludeTrailingBackslash(FileName);
end;
{$endif}

const
  // those constants have +1 to avoid finding it in the exe
  FIRSTHEADER_SIGNATURE_INC = $04034b50+1;  // PK#3#4
  LASTHEADER_SIGNATURE_INC  = $06054b50+1;  // PK#5#6
  ENTRY_SIGNATURE_INC = $02014b50+1; // PK#1#2


{ TZipWrite }

var
  EventArchiveZipWrite: TZipWrite = nil;

function EventArchiveZip(const aOldLogFileName, aDestinationPath: TFileName): boolean;
var n: integer;
begin
  result := false;
  if aOldLogFileName='' then
    FreeAndNil(EventArchiveZipWrite) else begin
    if not FileExists(aOldLogFileName) then
      exit;
    if EventArchiveZipWrite=nil then
      EventArchiveZipWrite := TZipWrite.CreateFrom(
        system.copy(aDestinationPath,1,length(aDestinationPath)-1)+'.zip');
    n := EventArchiveZipWrite.Count;
    EventArchiveZipWrite.AddDeflated(aOldLogFileName,True);
    if (EventArchiveZipWrite.Count=n+1) and DeleteFile(aOldLogFileName) then
      result := True;
  end;
end;

function Is7BitAnsi(P: PChar): boolean;
begin
  if P<>nil then
    while true do
      if ord(P^)=0 then
        break else
      if ord(P^)<=126 then
        inc(P) else begin
        result := false;
        exit;
      end;
  result := true;
end;


{ TZipWriteAbstract }

constructor TZipWriteAbstract.Create;
begin
  fMagic := FIRSTHEADER_SIGNATURE_INC; // +1 to avoid finding it in the exe generated code
  dec(fMagic);
end;

function TZipWriteAbstract.InternalAdd(const zipName: TFileName; Buf: pointer; Size: integer): cardinal;
begin
  with Entry[Count] do begin
    fHr.signature := ENTRY_SIGNATURE_INC; // +1 to avoid finding it in the exe
    dec(fHr.signature);
    fHr.madeBy := $0314; // where $03=Unix (for proper UTF8 filenames) and $14=version
    fHr.fileInfo.neededVersion := $14;
    result := InternalWritePosition;
    fHr.localHeadOff := result-fAppendOffset;
    {$ifndef DELPHI5OROLDER}
    // Delphi 5 doesn't have UTF8Decode/UTF8Encode functions -> make 7 bit version
    if Is7BitAnsi(pointer(zipName)) then begin
    {$endif}
      {$ifdef UNICODE}
      intName := AnsiString(zipName);
      {$else}  // intName := zipName -> error reference count under Delphi 6
      SetString(intName,PAnsiChar(pointer(zipName)),length(zipName));
      {$endif}
      fHr.fileInfo.UnSetUTF8FileName;
    {$ifndef DELPHI5OROLDER}
    end else begin
      intName := UTF8Encode(WideString(zipName));
      fHr.fileInfo.SetUTF8FileName;
    end;
    {$endif}
    fHr.fileInfo.nameLen := length(intName);
    fhr.fileInfo.extraLen := 0; // source may have something here
    InternalWrite(fMagic,sizeof(fMagic));
    InternalWrite(fhr.fileInfo,sizeof(fhr.fileInfo));
    InternalWrite(pointer(intName)^,fhr.fileInfo.nameLen);
  end;
  if Buf<>nil then begin
    InternalWrite(Buf^,Size); // write stored data
    inc(Count);
  end;
end;

procedure TZipWriteAbstract.AddDeflated(const aZipName: TFileName; Buf: pointer;
  Size, CompressLevel, FileAge: integer);
var tmp: pointer;
    tmpsize: integer;
begin
  if self=nil then
    exit;
  if Count>=length(Entry) then
    SetLength(Entry,length(Entry)+20);
  with Entry[Count] do begin
    with fhr.fileInfo do begin
      zcrc32 := SynZip.crc32(0,Buf,Size);
      zfullSize := Size;
      zzipMethod := Z_DEFLATED;
      zlastMod := FileAge;
      tmpsize := (Int64(Size)*11) div 10+12;
      Getmem(tmp,tmpSize);
      zzipSize := CompressMem(Buf,tmp,Size,tmpSize,CompressLevel);
      InternalAdd(aZipName,tmp,zzipSize); // write deflated data and inc(Count)
      Freemem(tmp);
    end;
  end;
end;

procedure TZipWriteAbstract.AddStored(const aZipName: TFileName; Buf: pointer;
  Size, FileAge: integer);
begin
  if self=nil then
    exit;
  if Count>=length(Entry) then
    SetLength(Entry,length(Entry)+20);
  with Entry[Count], fhr.fileInfo do begin
    zcrc32 := SynZip.crc32(0,Buf,Size);
    zfullSize := Size;
    zzipSize := Size;
    zlastMod := FileAge;
    InternalAdd(aZipName,Buf,Size); // write stored data and inc(Count)
  end;
end;

procedure TZipWriteAbstract.AddFromZip(Source: TZipRead; EntryIndex: integer);
var s: ^TZipEntry;
    origZipName: TFileName;
begin
  if (self=nil) or (Source=nil) then
    exit;
  if Count>=length(Entry) then
    SetLength(Entry,length(Entry)+20);
  with Entry[Count] do
    if Source.RetrieveFileInfo(EntryIndex, fhr.FileInfo) then begin
      s := @Source.Entry[EntryIndex];
      // backslash in s^.storedName are replaced to '\' by TZipRead.Create,
      // accoding to ZIP file format "All slashes MUST be forward slashes '/' as opposed to
      //  backwards slashes '\'"
      SetString(origZipName,s^.storedName,s^.infoLocal.nameLen);
      InternalAdd(origZipName,s^.data,fhr.fileInfo.zzipSize);
    end;
end;

procedure TZipWriteAbstract.Append(const Content: ZipString);
begin
  if (self=nil) or (fAppendOffset<>0) then
    exit;
  fAppendOffset := length(Content);
  InternalWrite(pointer(Content)^,fAppendOffset);
end;

destructor TZipWriteAbstract.Destroy;
var lhr: TLastHeader;
    i: integer;
begin
  fillchar(lhr,sizeof(lhr),0);
  lhr.signature := LASTHEADER_SIGNATURE_INC;
  dec(lhr.signature); // +1 to avoid finding it in the exe
  lhr.thisFiles := Count;
  lhr.totalFiles := Count;
  lhr.headerOffset := InternalWritePosition-fAppendOffset;
  for i := 0 to Count-1 do
  with Entry[i] do begin
    assert(fhr.fileInfo.nameLen=length(intName));
    inc(lhr.headerSize,sizeof(TFileHeader)+fhr.fileInfo.nameLen);
    InternalWrite(fhr,sizeof(fhr));
    InternalWrite(pointer(IntName)^,fhr.fileInfo.nameLen);
  end;
  InternalWrite(lhr,sizeof(lhr));
  inherited Destroy;
end;


{ TZipWrite }

function TZipWrite.InternalWritePosition: cardinal;
begin
  result := SetFilePointer(Handle,0,nil,{$ifdef Linux}SEEK_CUR{$else}FILE_CURRENT{$endif});
end;

procedure TZipWrite.InternalWrite(const buf; len: cardinal);
begin
  FileWrite(Handle,buf,len);
end;

procedure TZipWrite.AddFolder(const FolderName: TFileName; const Mask: TFileName;
  Recursive: boolean; CompressLevel: integer);
procedure RecursiveAdd(const fileDir,zipDir: TFileName);
var f: TSearchRec;
begin
  if Recursive then
    if FindFirst(fileDir+ZIP_FILES_ALL,faDirectory,f)=0 then begin
      repeat
        if f.Name[1]<>'.' then
          RecursiveAdd(fileDir+f.Name+PathDelim,zipDir+f.Name+'\');
      until FindNext(f)<>0;
      FindClose(f);
    end;
  if FindFirst(fileDir+Mask,faAnyfile-faDirectory,f)=0 then begin
    repeat
      if f.Name[1]<>'.' then
        {$ifndef DELPHI5OROLDER}
        {$WARN SYMBOL_DEPRECATED OFF} // for faVolumeID
        {$endif}
        if f.Attr and (faDirectory+faVolumeID+faSysFile+faHidden)=0 then
          AddDeflated(fileDir+f.Name,false,CompressLevel,zipDir+f.Name)
        {$ifndef DELPHI5OROLDER}
        {$WARN SYMBOL_DEPRECATED ON}
        {$endif}
    until FindNext(f)<>0;
    FindClose(f);
  end;
end;
begin
  RecursiveAdd(IncludeTrailingPathDelimiter(FolderName),'');
end;

procedure TZipWrite.AddDeflated(const aFileName: TFileName; RemovePath: boolean=true;
  CompressLevel: integer=6; ZipName: TFileName='');
var {$ifdef MSWINDOWS}
    Time: TFileTime;
    FileTime: LongRec;
    {$endif}
    Size: Int64;
    Size64: Int64Rec absolute Size;
    OffsHead, OffsEnd: cardinal;
    S: TFileStream;
    D: THandleStream;
    Z: TSynZipCompressor;
begin
  S := TFileStream.Create(aFileName,fmOpenRead or fmShareDenyNone);
  try
    if ZipName='' then
      if RemovePath then
        ZipName := ExtractFileName(aFileName) else
    {$ifdef MSWINDOWS}
        ZipName := aFileName;
    GetFileTime(S.Handle,nil,nil,@Time);
    FileTimeToLocalFileTime(Time,Time);
    FileTimeToDosDateTime(Time,FileTime.Hi,FileTime.Lo);
    {$else}
        ZipName := StringReplace(aFileName,'/','\',[rfReplaceAll]);
    {$endif}
    Size := S.Size;
    if Size64.Hi<>0 then
      raise ESynZipException.CreateFmt('%s file too big for .zip',[aFileName]);
    if Count>=length(Entry) then
      SetLength(Entry,length(Entry)+20);
    OffsHead := InternalAdd(ZipName,nil,0); // write data and inc(Count)
    D := THandleStream.Create(Handle);
    Z := TSynZipCompressor.Create(D,CompressLevel);
    try
      Z.CopyFrom(S,Size64.Lo);
      Z.Flush;
      assert(Z.SizeIn=Size64.Lo);
      with Entry[Count] do begin
        with fhr.fileInfo do begin
          zcrc32 := Z.CRC;
          zfullSize := Z.SizeIn;
          zzipSize := Z.SizeOut;
          zzipMethod := Z_DEFLATED;
          {$ifdef MSWINDOWS}
          zlastMod := integer(FileTime);
          {$else}
          zlastMod := FileAge(ZipName);
          {$endif}
        end;
        OffsEnd := D.Position;
        D.Position := OffsHead+sizeof(fMagic);
        D.WriteBuffer(fhr.fileInfo,sizeof(fhr.fileInfo));
        D.Position := OffsEnd;
      end;
      inc(Count);
    finally
      Z.Free;
      D.Free;
    end;
  finally
    S.Free;
  end;
end;

constructor TZipWrite.Create(const aFileName: TFileName);
begin
  Create;
  fFileName := aFileName;
  if Handle=0 then
    Handle := FileCreate(aFileName);
end;

constructor TZipWrite.CreateFrom(const aFileName: TFileName; dummy: integer);
var R: TZipRead;
    i: Integer;
begin
  Handle := FileOpen(aFileName,fmOpenReadWrite or fmShareDenyNone);
  if Handle<0 then begin
    R := nil;
    Handle := 0;
  end else
    R := TZipRead.Create(Handle);
  Create(aFileName);
  if R<>nil then
  try
    Count := R.Count;
    SetLength(Entry,Count+10);
    for i := 0 to Count-1 do
    with Entry[i], R.Entry[i] do begin
      fhr.Init;
      fhr.localHeadOff := ZipPtrUint(infoLocal)-ZipPtrUint(R.Entry[0].infoLocal);
      R.RetrieveFileInfo(i,fhr.fileInfo);
      SetString(intName,storedName,infoLocal^.nameLen);
    end;
    {$ifdef MSWINDOWS}
    SetFilePointer(Handle,R.ReadOffset,nil,FILE_BEGIN);
    {$else}
    FileSeek(Handle,R.ReadOffset,soFromBeginning);
    {$endif}
  finally
    R.Free;
  end;
end;

destructor TZipWrite.Destroy;
begin
  inherited Destroy; // will write TLastHeader content
  SetEndOfFile(Handle);
  FileClose(Handle);
end;


{ TZipWriteToStream }

constructor TZipWriteToStream.Create(aDest: TStream);
begin
  fDest := aDest;
  inherited Create;
end;

function TZipWriteToStream.InternalWritePosition: cardinal;
begin
  result := fDest.Seek(0,soCurrent);
end;

procedure TZipWriteToStream.InternalWrite(const buf; len: cardinal);
begin
  fDest.WriteBuffer(buf,len);
end;


{ TZipRead }

procedure TZipRead.UnMap;
begin
  Count := 0;
  {$ifdef MSWINDOWS}
  if map<>0 then begin
    UnmapViewOfFile(Buf);
    CloseHandle(map);
    map := 0;
  end;
  {$else}
  if (mapSize<>0) and (buf<>nil) then begin
    {$ifdef KYLIX3}munmap{$else}fpmunmap{$endif}(buf,mapSize);
    mapSize := 0;
  end;
  {$endif MSWINDOWS}
  if file_>0 then begin
    FileClose(file_);
    file_ := 0;
  end;
end;

{$ifdef UNICODE}
function UTF8Decode(const tmp: UTF8String): TFileName;
begin
  result := TFileName(tmp);
end;
{$endif}

constructor TZipRead.Create(BufZip: PByteArray; Size: cardinal);
var lhr: PLastHeader;
    H: PFileHeader;
    lfhr: PLocalFileHeader;
    i,j: integer;
    {$ifndef DELPHI5OROLDER}
    tmp: UTF8String;
    {$else}
    tmp: ZipString;
    {$endif}
begin
  for i := 0 to 127 do begin // resources size may be rounded up to alignment
    lhr := @BufZip[Size-sizeof(TLastHeader)];
    if lhr^.signature+1=LASTHEADER_SIGNATURE_INC then
      break;
    dec(Size);
    if Size<=sizeof(lhr^) then
      break;
  end;
  if lhr^.signature+1<>LASTHEADER_SIGNATURE_INC then begin
    UnMap;
    raise ESynZipException.Create('ZIP format');
  end;
  SetLength(Entry,lhr^.totalFiles); // fill Entry[] with the Zip headers
  ReadOffset := lhr^.headerOffset;
  FirstFileHeader := @BufZip[lhr^.headerOffset];
  H := FirstFileHeader;
  for i := 1 to lhr^.totalFiles do begin
    if H^.signature+1<>ENTRY_SIGNATURE_INC then begin // +1 to avoid match in exe
      UnMap;
      raise ESynZipException.Create('ZIP format');
    end;
    lfhr := @BufZip[H^.localHeadOff];
    with lfhr^.fileInfo do
    if flags and (1 shl 3)<>0 then begin // crc+sizes in "data descriptor"
      if (zcrc32<>0) or (zzipSize<>0) or (zfullSize<>0) then
        raise ESynZipException.Create('ZIP extended format');
      // UnZip() will call RetrieveFileInfo()
    end else
      if (zzipSize=cardinal(-1)) or (zfullSize=cardinal(-1)) then
        raise ESynZipException.Create('ZIP64 format not supported - use mORMot 2');
    with Entry[Count] do begin
      infoLocal := @lfhr^.fileInfo;
      infoDirectory := H;
      storedName := PAnsiChar(lfhr)+sizeof(lfhr^);
      data := storedName+infoLocal^.NameLen+infoLocal^.extraLen; // data mapped in memory
      SetString(tmp,storedName,infoLocal^.nameLen);
      for j := 0 to infoLocal^.nameLen-1 do
        if storedName[j]='/' then // normalize path delimiter
          PAnsiChar(Pointer(tmp))[j] := '\';
      {$ifndef DELPHI5OROLDER} // Delphi 5 lacks UTF-8 functions -> 7 bit
      if infoLocal^.GetUTF8FileName then
        // decode UTF-8 file name into native string/TFileName type
        zipName := TFileName(UTF8Decode(tmp)) else
      {$endif DELPHI5OROLDER}
      begin
        {$ifdef MSWINDOWS} // decode OEM/DOS file name into native encoding
        SetLength(zipName,infoLocal^.nameLen);
        OemToChar(Pointer(tmp),Pointer(zipName)); // OemToCharW/OemToCharA
        {$else}
        zipName := TFileName(UTF8Decode(tmp)); // let's assume UTF-8 under Linux
        {$endif MSWINDOWS}
      end;
      inc(PByte(H),sizeof(H^)+infoLocal^.NameLen+H^.fileInfo.extraLen+H^.commentLen);
      if not(infoLocal^.zZipMethod in [Z_STORED,Z_DEFLATED]) then
        raise ESynZipException.CreateFmt(
          'Unsupported compression method %d for %s',[infoLocal^.zZipMethod,zipName]);
      if (zipName='') or (zipName[length(zipName)]='\') then
        continue; // ignore folder
      inc(Count); // add file to Entry[]
    end;
  end;
end;

constructor TZipRead.Create(Instance: THandle; const ResName: string; ResType: PChar);
// locked resources are memory map of the executable -> direct access is easy
var HResInfo: THandle;
    HGlobal: THandle;
begin
  if Instance=0 then
    Instance := HInstance;
  HResInfo := FindResource(Instance,PChar(ResName),ResType);
  if HResInfo=0 then
    exit;
  HGlobal := LoadResource(Instance, HResInfo);
  if HGlobal<>0 then
    // warning: resources size may be rounded up to alignment -> handled in Create()
    Create(LockResource(HGlobal),SizeofResource(Instance, HResInfo));
end;

constructor TZipRead.Create(aFile: THandle; ZipStartOffset,Size: cardinal);
var i, ExeOffset: integer;
begin
  if aFile<=0 then
    exit;
  if Size=0 then
    Size := GetFileSize(aFile, nil);
  {$ifdef MSWINDOWS}
  map := CreateFileMapping(aFile, nil, PAGE_READONLY, 0, 0, nil);
  if map=0 then begin
    Unmap;
    raise ESynZipException.Create('Missing File');
  end;
  buf := MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
  {$else}
  mapSize := Size;
  buf := {$ifdef KYLIX3}mmap{$else}fpmmap{$endif}(nil,Size,PROT_READ,MAP_SHARED,aFile,0);
  if buf=MAP_FAILED then
    buf := nil;
  {$endif}
  if buf=nil then begin
    Unmap;
    raise ESynZipException.Create('FileMap failed');
  end;
  ExeOffset := -1;
  for i := ZipStartOffset to Size-5 do // search for first local header
    if PCardinal(@buf[i])^+1=FIRSTHEADER_SIGNATURE_INC then begin
      // +1 above to avoid finding it in the exe part
      ExeOffset := i;
      break;
    end;
  if ExeOffset<0 then // try if adding files to an empty archive
    for i := ZipStartOffset to Size-5 do
      if PCardinal(@buf[i])^+1=LASTHEADER_SIGNATURE_INC then begin
        // +1 avoids false positive
        ExeOffset := i;
        break;
      end;
  if ExeOffset<0 then begin
    Unmap;
    raise ESynZipException.Create('No ZIP header found');
  end;
  Create(@Buf[ExeOffset],integer(Size)-ExeOffset);
end;

constructor TZipRead.Create(const aFileName: TFileName; ZipStartOffset, Size: cardinal);
begin
  {$ifdef MSWINDOWS}
  file_ := CreateFile(pointer(aFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  {$else}
  file_ := FileOpen(aFileName,fmOpenRead or fmShareDenyNone);
  {$endif}
  Create(file_,ZipStartOffset, Size);
end;

destructor TZipRead.Destroy;
begin
  UnMap;
  inherited Destroy;
end;

function TZipRead.NameToIndex(const aName: TFileName): integer;
begin
  if (self<>nil) and (aName<>'') then
    for result := 0 to Count-1 do
      if SameText(Entry[result].zipName,aName) then
        exit;
  result := -1;
end;

type
  TDataDescriptor = packed record
    signature: dword;
    crc32: dword;
    zipSize: dword;
    fullSize: dword;
  end;

function TZipRead.RetrieveFileInfo(Index: integer; var Info: TFileInfo): boolean;
var P: ^TDataDescriptor;
    PDataStart: ZipPtrUint;
begin
  if (self=nil) or (cardinal(Index)>=cardinal(Count)) then begin
    result := false;
    exit;
  end;
  // copy information from "local file header"
  Info := Entry[Index].infoLocal^;
  if Info.flags and (1 shl 3)=0 then begin
    result := true; // local information is correct
    exit;
  end;
  // get info from ending "central directory" (faster than "data descriptor")
  with Entry[Index].infoDirectory^.fileInfo do
    if (zzipSize<>dword(-1)) and (zfullSize<>dword(-1)) then begin
      // ZIP64 format not supported yet (sizes=-1)
      Info.zcrc32 := zcrc32;
      Info.zzipSize := zzipSize;
      Info.zfullSize := zfullSize;
      result := true;
      exit;
    end;
  // search manually the "data descriptor" from the binary local data
  if Index<Count-2 then
    P := Pointer(Entry[Index+1].infoLocal) else
    P := Pointer(FirstFileHeader);
  dec(P);
  PDataStart := ZipPtrUint(Entry[Index].data);
  repeat
    // same pattern as ReadLocalItemDescriptor() in 7-Zip's ZipIn.cpp
    // but here, search is done backwards (much faster than 7-Zip algorithm)
    if P^.signature<>$08074b50 then
      if ZipPtrUint(P)>PDataStart then
        dec(PByte(P)) else
        break else
      if P^.zipSize=ZipPtrUint(P)-PDataStart then begin
        if (P^.zipSize=0) or (P^.fullSize=0) or
           (P^.zipSize=dword(-1)) or (P^.fullSize=dword(-1)) then
          break; // we expect sizes to be there!
        Info.zcrc32 := P^.crc32;
        Info.zzipSize := P^.zipSize;
        Info.zfullSize := P^.fullSize;
        result := true;
        exit;
      end else
      if ZipPtrUint(P)>PDataStart then
        dec(PByte(P)) else
        break;
  until false;
  result := false; // data descriptor block not found
end;

function TZipRead.UnZip(aIndex: integer): ZipString;
var len: cardinal;
    info: TFileInfo;
begin
  result := ''; // somewhat faster if memory is reallocated each time
  if not RetrieveFileInfo(aIndex,info) then
    exit;
  SetString(result,nil,info.zfullSize);
  case info.zZipMethod of
  Z_STORED: begin
    len := info.zfullsize;
    move(Entry[aIndex].data^,pointer(result)^,len);
  end;
  Z_DEFLATED:
    len := UnCompressMem(Entry[aIndex].data,pointer(result),info.zzipsize,info.zfullsize);
  else raise ESynZipException.CreateFmt('Unsupported method %d for %s',
    [info.zZipMethod,Entry[aIndex].zipName]);
  end;
  if (len<>info.zfullsize) or
     (info.zcrc32<>SynZip.crc32(0,pointer(result),info.zfullSize)) then
    raise ESynZipException.CreateFmt('Error decompressing %s',[Entry[aIndex].zipName]);
end;

{$ifdef DELPHI5OROLDER}
/// DirectoryExists returns a boolean value that indicates whether the
//  specified directory exists (and is actually a directory)
function DirectoryExists(const Directory: string): boolean;
var res: Integer;
begin
  res := GetFileAttributes(PChar(Directory));
  result := (res<>-1) and (FILE_ATTRIBUTE_DIRECTORY and res<> 0);
end;
{$endif}

function EnsurePath(var Path: TFileName): boolean;
var Parent: TFileName;
begin
  result := false;
  if Path='' then exit;
  {$IFDEF FPC}
  Path := IncludeTrailingPathDelimiter(SetDirSeparators(Path));
  {$ELSE} // We assume Delphi for Windows here
  if Path[length(Path)]<>'\' then
    Path := Path+'\';
  {$ENDIF}
  if DirectoryExists(Path) then
    result := true else begin
    Parent := ExtractFilePath(system.copy(Path,1,length(Path)-1));
    if (Parent<>'') and not DirectoryExists(Parent) then
      if not EnsurePath(Parent) then exit;
    if CreateDir(path) then
      result := true;
  end;
end;

function TZipRead.UnZipStream(aIndex: integer; const aInfo: TFileInfo; aDest: TStream): boolean;
var crc: cardinal;
begin
  result := false;
  case aInfo.zZipMethod of
  Z_STORED: begin
    aDest.WriteBuffer(Entry[aIndex].data^,aInfo.zfullsize);
    crc := SynZip.crc32(0,Entry[aIndex].data,aInfo.zfullSize);
  end;
  Z_DEFLATED:
    if UnCompressStream(Entry[aIndex].data,aInfo.zzipsize,aDest,@crc)<>aInfo.zfullsize then
      exit;
  else raise ESynZipException.CreateFmt('Unsupported method %d for %s',
    [aInfo.zZipMethod,Entry[aIndex].zipName]);
  end;
  result := crc=aInfo.zcrc32;
end;

function TZipRead.UnZip(aIndex: integer; aDest: TStream): boolean;
var info: TFileInfo;
begin
  if not RetrieveFileInfo(aIndex,info) then
    result := false else
    result := UnZipStream(aIndex,info,aDest);
end;

function TZipRead.UnZip(aIndex: integer; const DestDir: TFileName;
  DestDirIsFileName: boolean): boolean;
var FS: TFileStream;
    Path: TFileName;
    info: TFileInfo;
begin
  result := false;
  if not RetrieveFileInfo(aIndex,info) then
    exit;
  with Entry[aIndex] do
    if DestDirIsFileName then
      Path := DestDir else begin
      Path := DestDir+ExtractFilePath(zipName); // include sub directories
      if not EnsurePath(Path) then
        exit;
      Path := Path+ExtractFileName(zipName);
    end;
  FS := TFileStream.Create(Path,fmCreate);
  try
    result := UnZipStream(aIndex,info,FS);
    {$ifdef MSWINDOWS}
    {$ifdef CONDITIONALEXPRESSIONS}
      {$WARN SYMBOL_PLATFORM OFF} // zip expects a Windows timestamp
    {$endif}
    if result and (info.zlastMod<>0) then
      FileSetDate(FS.Handle,info.zlastMod);
    {$ifdef CONDITIONALEXPRESSIONS}
      {$WARN SYMBOL_PLATFORM ON}
    {$endif}
    {$endif MSWINDOWS}
  finally
    FS.Free;
  end;
end;

function TZipRead.UnZipAll(DestDir: TFileName): integer;
begin
  if DestDir<>'' then
    {$ifdef DELPHI5OROLDER}
    DestDir := IncludeTrailingBackslash(DestDir);
    {$else}
    DestDir := IncludeTrailingPathDelimiter(DestDir);
    {$endif}
  for result := 0 to Count-1 do
    if not UnZip(result,DestDir) then
      exit;
  result := -1;
end;

function TZipRead.UnZip(const aName, DestDir: TFileName;
  DestDirIsFileName: boolean): boolean;
var aIndex: integer;
begin
  aIndex := NameToIndex(aName);
  if aIndex<0 then
    result := false else
    result := UnZip(aIndex,DestDir,DestDirIsFileName);
end;

function TZipRead.UnZip(const aName: TFileName): ZipString;
var aIndex: integer;
begin
  aIndex := NameToIndex(aName);
  if aIndex<0 then
    result := '' else
    result := UnZip(aIndex);
end;

const
  GZHEAD: array [0..2] of cardinal = ($088B1F,0,0);
  GZHEAD_SIZE = 10;

type
  TGZFlags = set of (gzfText, gzfHCRC, gzfExtra, gzfName, gzfComment);

{ TGZRead }

function TGZRead.Init(gz: PAnsiChar; gzLen: ZipPtrInt): boolean;
var offset: ZipPtrInt;
    flags: TGZFlags;
begin // see https://www.ietf.org/rfc/rfc1952.txt
  comp := nil;
  complen := 0;
  uncomplen32 := 0;
  zsdest := nil;
  result := false;
  extra := nil;
  fname := nil;
  fcomment := nil;
  if (gz=nil) or (gzLen<=18) or (PCardinal(gz)^ and $ffffff<>GZHEAD[0]) then
    exit; // .gz file as header + compressed + crc32 + len32 format
  flags := TGZFlags(gz[3]);
  unixmodtime := PCardinal(gz+4)^;
  offset := GZHEAD_SIZE;
  if gzfExtra in flags then begin
    extra := gz+offset;
    inc(offset,PWord(extra)^+SizeOf(word));
  end;
  if gzfName in flags then begin // FNAME flag (as created e.g. by 7Zip)
    fname := gz+offset;
    while (offset<gzlen) and (gz[offset]<>#0) do
      inc(offset);
    inc(offset);
  end;
  if gzfComment in flags then begin
    fcomment := gz+offset;
    while (offset<gzlen) and (gz[offset]<>#0) do
      inc(offset);
    inc(offset);
  end;
  if gzfHCRC in flags then
    if PWord(gz+offset)^<>SynZip.crc32(0,gz,offset) and $ffff then
      exit
    else
      inc(offset,SizeOf(word));
  if offset>=gzlen-8 then
    exit;
  uncomplen32 := PCardinal(@gz[gzLen-4])^; // modulo 2^32 by design (may be 0)
  comp := gz+offset;
  complen := gzLen-offset-8;
  crc32 := PCardinal(@gz[gzLen-8])^;
  result := true;
end;

function TGZRead.ToMem: ZipString;
begin
  result := '';
  if (comp=nil) or ((uncomplen32=0) and (crc32=0){0 length stream}) then
    exit;
  SetLength(result,uncomplen32);
  if (UnCompressMem(comp,pointer(result),complen,uncomplen32)<>integer(uncomplen32)) or
     (SynZip.crc32(0,pointer(result),uncomplen32)<>crc32) then
    result := ''; // invalid CRC
end;

function TGZRead.ToStream(stream: TStream; tempBufSize: integer): boolean;
var crc: cardinal;
begin
  crc := 0;
  result := (comp<>nil) and (stream<>nil) and
    (UnCompressStream(comp,complen,stream,@crc,{zlib=}false,tempBufSize)=uncomplen32) and
    (crc=crc32);
end;

function TGZRead.ToFile(const filename: TFileName; tempBufSize: integer): boolean;
var f: TStream;
begin
  result := false;
  if (comp=nil) or (filename='') then
    exit;
  f := TFileStream.Create(filename,fmCreate);
  try
    result := ToStream(f,tempBufSize);
  finally
    f.Free;
  end;
end;

function TGZRead.ZStreamStart(dest: pointer; destsize: integer): boolean;
begin
  result := false;
  zscode := Z_STREAM_ERROR;
  if (comp=nil) or (dest=nil) or (destsize<=0) then
    exit;
  StreamInit(zs);
  zs.next_in := comp;
  zs.avail_in := complen;
  zs.next_out := dest;
  zs.avail_out := destsize;
  zscode := inflateInit2_(zs, -MAX_WBITS, ZLIB_VERSION, sizeof(zs));
  if zscode>=0 then begin
    zscrc := 0;
    zsdest := dest;
    zssize := destsize;
    result := true;
  end;
end;

function TGZRead.ZStreamStarted: boolean;
begin
  result := zsdest<>nil;
end;

function TGZRead.ZStreamNext: integer;
begin
  result := 0;
  if (comp=nil) or (zsdest=nil) or
     not ((zscode=Z_OK) or (zscode=Z_STREAM_END) or (zscode=Z_BUF_ERROR)) then
    exit;
  if zscode<>Z_STREAM_END then begin
    zscode := Check(inflate(zs, Z_FINISH),[Z_OK,Z_STREAM_END,Z_BUF_ERROR],'ZStreamNext');
    result := zssize-integer(zs.avail_out);
    if result=0 then
      exit;
    zscrc := SynZip.crc32(zscrc,zsdest,result);
    zs.next_out := zsdest;
    zs.avail_out := zssize;
  end;
end;

function TGZRead.ZStreamDone: boolean;
begin
  result := false;
  if (comp<>nil) and (zsdest<>nil) then begin
    inflateEnd(zs);
    zsdest := nil;
    result := (zscrc=crc32) and (cardinal(zs.total_out)=uncomplen32);
  end;
end;


function GZRead(gz: PAnsiChar; gzLen: integer): ZipString;
var gzr: TGZRead;
begin
  if gzr.Init(gz,gzlen) then
    result := gzr.ToMem else
    result := '';
end;

function GZFile(const orig, destgz: TFileName; CompressionLevel: Integer=6): boolean;
var gz: TSynZipCompressor;
    s,d: TFileStream;
begin
  try
    s := TFileStream.Create(orig,fmOpenRead or fmShareDenyNone);
    try
      d := TFileStream.Create(destgz,fmCreate);
      try
        gz := TSynZipCompressor.Create(d,CompressionLevel,szcfGZ);
        try
          gz.CopyFrom(s,0);  // Count=0 for whole stream copy
          result := true;
        finally
          gz.Free;
        end;
      finally
        d.Free;
      end;
    finally
      s.Free;
    end;
  except
    result := false;
  end;
end;

{$ifdef USEEXTZLIB}
function deflate(var strm: TZStream; flush: integer): integer; cdecl;
  external libz name 'deflate';
function deflateEnd(var strm: TZStream): integer; cdecl;
  external libz name 'deflateEnd';
function inflate(var strm: TZStream; flush: integer): integer; cdecl;
  external libz name 'inflate';
function inflateEnd(var strm: TZStream): integer; cdecl;
  external libz name 'inflateEnd';
function adler32(adler: TZCRC; buf: PAnsiChar; len: cardinal): TZCRC; cdecl;
  external libz name 'adler32';
function crc32(crc: TZCRC; buf: PAnsiChar; len: cardinal): TZCRC; cdecl;
  external libz name 'crc32';
function deflateInit_(var strm: TZStream; level: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
  external libz name 'deflateInit_';
function inflateInit_(var strm: TZStream;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
  external libz name 'inflateInit_';
function deflateInit2_(var strm: TZStream;
  level, method, windowBits, memLevel, strategy: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
  external libz name 'deflateInit2_';
function inflateInit2_(var strm: TZStream; windowBits: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
  external libz name 'inflateInit2_';
function get_crc_table: pointer; cdecl;
  external libz name 'get_crc_table';
{$else USEEXTZLIB}

{$ifdef USEPASZLIB}

function adler32(adler: cardinal; buf: PAnsiChar; len: cardinal): cardinal;
begin
  result := paszlib.adler32(adler,pointer(buf),len);
end;

function crc32(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal;
begin
  result := paszlib.crc32(crc,pointer(buf),len);
end;

function deflateInit2_(var strm: TZStream; level: integer; method: integer;
  windowBits: integer; memLevel: integer;strategy: integer; version: PAnsiChar; stream_size: integer): integer;
begin
  result := paszlib.deflateInit2_(strm,level,method,windowBits,memLevel,strategy,version,stream_size);
end;

function deflate(var strm: TZStream; flush: integer): integer;
begin
  result := paszlib.deflate(strm,flush);
end;

function deflateEnd(var strm: TZStream): integer;
begin
  result := paszlib.deflateEnd(strm);
end;

function inflateInit2_(var strm: TZStream; windowBits: integer; version: PAnsiChar; stream_size: integer): integer;
begin
  result := paszlib.inflateInit2_(strm,windowBits,version,stream_size);
end;

function inflate(var strm: TZStream; flush: integer): integer;
begin
  result := paszlib.inflate(strm,flush);
end;

function inflateEnd(var strm: TZStream): integer;
begin
  result := paszlib.inflateEnd(strm);
end;

function get_crc_table: pointer;
begin
  result := paszlib.get_crc_table;
end;

{$else USEPASZLIB}

{$ifdef USEINLINEASM}
// some small functions (adler32.obj, zutil.obj, compress.obj, uncompress.obj,
// crc32.obj) are coded directly in this unit, not as external .obj files

// this external obj code was compiled with pascal register call conventions
{$LINK deflate.obj}
{$LINK trees.obj}

function deflateInit2_(var strm: TZStream; level: integer; method: integer;
  windowBits: integer; memLevel: integer;strategy: integer; version: PAnsiChar;
  stream_size: integer): integer; external;
function deflate(var strm: TZStream; flush: integer): integer; external;
function deflateEnd(var strm: TZStream): integer; external;

const
  _z_errmsg: array[0..9] of PAnsiChar = (
  'need dictionary',     // Z_NEED_DICT       2
  'stream end',          // Z_STREAM_END      1
  '',                    // Z_OK              0
  'file error',          // Z_ERRNO         (-1)
  'stream error',        // Z_STREAM_ERROR  (-2)
  'data error',          // Z_DATA_ERROR    (-3)
  'insufficient memory', // Z_MEM_ERROR     (-4)
  'buffer error',        // Z_BUF_ERROR     (-5)
  'incompatible version',// Z_VERSION_ERROR (-6)
  '');
  Err246: array[0..3] of AnsiChar = 'lit';
  Err247: array[0..3] of AnsiChar = 'dst';
  Err248: array[0..3] of AnsiChar = 'inv';

procedure Inline018;
asm
        sub     esp, 60
        push    ebx
        push    ebp
        push    esi
        push    edi
        mov     eax, dword ptr [esp + 50H]
        mov     edx, dword ptr [eax]
        mov     ecx, dword ptr [eax + 04H]
        mov     ebx, dword ptr [esp + 54H]
        dec     edx
        lea     ecx, [ecx + edx - 05H]
        mov     ebp, dword ptr [eax + 1CH]
        mov     dword ptr [esp + 30H], ecx
        mov     esi, dword ptr [eax + 0CH]
        mov     eax, dword ptr [eax + 10H]
        mov     ecx, eax
        sub     ecx, ebx
        dec     esi
        lea     eax, [eax + esi - 00000101H]
        add     ecx, esi
        mov     dword ptr [esp + 34H], eax
        mov     eax, dword ptr [ebp + 2CH]
        mov     dword ptr [esp + 44H], ecx
        mov     ecx, dword ptr [ebp + 28H]
        mov     dword ptr [esp + 48H], eax
        mov     eax, dword ptr [ebp + 34H]
        mov     ebx, dword ptr [ebp + 3CH]
        mov     dword ptr [esp + 28H], ecx
        mov     ecx, dword ptr [ebp + 30H]
        mov     dword ptr [esp + 2CH], eax
        mov     eax, dword ptr [ebp + 50H]
        mov     dword ptr [esp + 1CH], ecx
        mov     ecx, dword ptr [ebp + 4CH]
        mov     dword ptr [esp + 24H], eax
        mov     dword ptr [esp + 20H], ecx
        mov     ecx, dword ptr [ebp + 54H]
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [ebp + 58H]
        mov     edi, dword ptr [ebp + 38H]
        dec     eax
        mov     dword ptr [esp + 38H], eax
        mov     eax, 1
        shl     eax, cl
        mov     dword ptr [esp + 18H], ebp
        mov     dword ptr [esp + 14H], edx
        dec     eax
        mov     dword ptr [esp + 3CH], eax
@@019:  cmp     ebx, 15
        jnc     @@020
        movzx   eax, byte ptr [edx + 01H]
        inc     edx
        mov     ecx, ebx
        shl     eax, cl
        add     ebx, 8
        mov     ecx, ebx
        add     edi, eax
        movzx   eax, byte ptr [edx + 01H]
        inc     edx
        shl     eax, cl
        mov     dword ptr [esp + 14H], edx
        add     edi, eax
        add     ebx, 8
@@020:  mov     ecx, dword ptr [esp + 38H]
        mov     eax, dword ptr [esp + 20H]
        and     ecx, edi
        mov     eax, dword ptr [eax + ecx*4]
        movzx   ecx, ah
        mov     dword ptr [esp + 10H], eax
        movzx   eax, al
        shr     edi, cl
        sub     ebx, ecx
        test    eax, eax
        jz      @@022
@@021:  test    al, 10H
        jnz     @@023
        test    al, 40H
        jne     @@046
        mov     ecx, 1
        mov     dword ptr [esp + 54H], ecx
        mov     ecx, eax
        mov     eax, dword ptr [esp + 54H]
        shl     eax, cl
        mov     ecx, dword ptr [esp + 10H]
        shr     ecx, 16
        dec     eax
        and     eax, edi
        add     eax, ecx
        mov     ecx, dword ptr [esp + 20H]
        mov     eax, dword ptr [ecx + eax*4]
        movzx   ecx, ah
        mov     dword ptr [esp + 10H], eax
        movzx   eax, al
        shr     edi, cl
        sub     ebx, ecx
        test    eax, eax
        jnz     @@021
@@022:  mov     eax, dword ptr [esp + 10H]
        inc     esi
        shr     eax, 16
        mov     byte ptr [esi], al
        jmp     @@043

@@023:  mov     ecx, dword ptr [esp + 10H]
        shr     ecx, 16
        and     eax, 0000000FH
        mov     dword ptr [esp + 54H], ecx
        jz      @@025
        cmp     ebx, eax
        jnc     @@024
        movzx   ebp, byte ptr [edx + 01H]
        inc     edx
        mov     ecx, ebx
        shl     ebp, cl
        mov     dword ptr [esp + 14H], edx
        add     edi, ebp
        add     ebx, 8
@@024:  mov     ecx, eax
        mov     ebp, 1
        shl     ebp, cl
        mov     ecx, dword ptr [esp + 54H]
        dec     ebp
        and     ebp, edi
        add     ecx, ebp
        mov     ebp, dword ptr [esp + 18H]
        mov     dword ptr [esp + 54H], ecx
        mov     ecx, eax
        shr     edi, cl
        sub     ebx, eax
@@025:  cmp     ebx, 15
        jnc     @@026
        movzx   eax, byte ptr [edx + 01H]
        inc     edx
        mov     ecx, ebx
        shl     eax, cl
        add     ebx, 8
        mov     ecx, ebx
        add     edi, eax
        movzx   eax, byte ptr [edx + 01H]
        inc     edx
        shl     eax, cl
        mov     dword ptr [esp + 14H], edx
        add     edi, eax
        add     ebx, 8
@@026:  mov     ecx, dword ptr [esp + 3CH]
        mov     eax, dword ptr [esp + 24H]
        and     ecx, edi
        mov     eax, dword ptr [eax + ecx*4]
        movzx   ecx, ah
        mov     dword ptr [esp + 10H], eax
        movzx   eax, al
        shr     edi, cl
        sub     ebx, ecx
        test    al, 10H
        jnz     @@028
@@027:  test    al, 40H
        jne     @@045
        mov     ecx, 1
        mov     dword ptr [esp + 40H], ecx
        mov     ecx, eax
        mov     eax, dword ptr [esp + 40H]
        shl     eax, cl
        mov     ecx, dword ptr [esp + 10H]
        shr     ecx, 16
        dec     eax
        and     eax, edi
        add     eax, ecx
        mov     ecx, dword ptr [esp + 24H]
        mov     eax, dword ptr [ecx + eax*4]
        movzx   ecx, ah
        mov     dword ptr [esp + 10H], eax
        movzx   eax, al
        shr     edi, cl
        sub     ebx, ecx
        test    al, 10H
        jz      @@027
@@028:  mov     ecx, dword ptr [esp + 10H]
        shr     ecx, 16
        and     eax, 0000000FH
        cmp     ebx, eax
        mov     dword ptr [esp + 10H], ecx
        jnc     @@029
        movzx   ebp, byte ptr [edx + 01H]
        inc     edx
        mov     ecx, ebx
        shl     ebp, cl
        add     ebx, 8
        mov     dword ptr [esp + 14H], edx
        add     edi, ebp
        cmp     ebx, eax
        jnc     @@029
        movzx   ebp, byte ptr [edx + 01H]
        inc     edx
        mov     ecx, ebx
        shl     ebp, cl
        mov     dword ptr [esp + 14H], edx
        add     edi, ebp
        add     ebx, 8
@@029:  mov     ecx, 1
        mov     ebp, ecx
        mov     ecx, eax
        shl     ebp, cl
        sub     ebx, eax
        dec     ebp
        and     ebp, edi
        mov     ecx, ebp
        mov     ebp, dword ptr [esp + 10H]
        add     ebp, ecx
        mov     ecx, eax
        shr     edi, cl
        mov     ecx, dword ptr [esp + 44H]
        mov     eax, esi
        sub     eax, ecx
        cmp     ebp, eax
        mov     dword ptr [esp + 10H], ebp
        jbe     @@040
        sub     ebp, eax
        cmp     ebp, dword ptr [esp + 48H]
        ja      @@044
        mov     ecx, dword ptr [esp + 2CH]
        mov     eax, dword ptr [esp + 1CH]
        dec     ecx
        test    eax, eax
        jnz     @@031
        mov     eax, dword ptr [esp + 28H]
        sub     eax, ebp
        add     ecx, eax
        mov     eax, dword ptr [esp + 54H]
        cmp     ebp, eax
        jae     @@037
        sub     eax, ebp
        mov     dword ptr [esp + 54H], eax

@@030:  mov     al, byte ptr [ecx + 01H]
        inc     ecx
        inc     esi
        dec     ebp
        mov     byte ptr [esi], al
        jnz     @@030
        jmp     @@036

@@031:  cmp     eax, ebp
        jnc     @@034
        sub     eax, ebp
        add     eax, dword ptr [esp + 28H]
        add     ecx, eax
        sub     ebp, dword ptr [esp + 1CH]
        mov     eax, dword ptr [esp + 54H]
        cmp     ebp, eax
        jnc     @@037
        sub     eax, ebp
        mov     dword ptr [esp + 54H], eax

@@032:  mov     al, byte ptr [ecx + 01H]
        inc     ecx
        inc     esi
        dec     ebp
        mov     byte ptr [esi], al
        jnz     @@032
        mov     ecx, dword ptr [esp + 2CH]
        mov     eax, dword ptr [esp + 1CH]
        mov     ebp, dword ptr [esp + 54H]
        dec     ecx
        cmp     eax, ebp
        jnc     @@037
        sub     ebp, eax
        mov     dword ptr [esp + 54H], ebp
        mov     dword ptr [esp + 40H], eax
        mov     ebp, eax
@@033:  mov     al, byte ptr [ecx + 01H]
        inc     ecx
        inc     esi
        dec     ebp
        mov     byte ptr [esi], al
        jnz     @@033
        jmp     @@036

@@034:  sub     eax, ebp
        add     ecx, eax
        mov     eax, dword ptr [esp + 54H]
        cmp     ebp, eax
        jnc     @@037
        sub     eax, ebp
        mov     dword ptr [esp + 54H], eax
@@035:  mov     al, byte ptr [ecx + 01H]
        inc     ecx
        inc     esi
        dec     ebp
        mov     byte ptr [esi], al
        jnz     @@035
@@036:  mov     eax, dword ptr [esp + 10H]
        mov     ecx, esi
        sub     ecx, eax
@@037:  mov     eax, dword ptr [esp + 54H]
        cmp     eax, 2
        jbe     @@039
        lea     edx, [eax - 03H]
        mov     eax, -1431655765
        mul     edx
        mov     ebp, edx
        shr     ebp, 1
        inc     ebp
        nop
@@038:  mov     al, byte ptr [ecx + 01H]
        inc     ecx
        inc     esi
        mov     byte ptr [esi], al
        mov     dl, byte ptr [ecx + 01H]
        inc     ecx
        inc     esi
        mov     byte ptr [esi], dl
        mov     edx, dword ptr [esp + 54H]
        mov     al, byte ptr [ecx + 01H]
        inc     ecx
        inc     esi
        sub     edx, 3
        dec     ebp
        mov     byte ptr [esi], al
        mov     dword ptr [esp + 54H], edx
        jnz     @@038
        mov     edx, dword ptr [esp + 14H]
@@039:  mov     eax, dword ptr [esp + 54H]
        test    eax, eax
        jz      @@042
        mov     al, byte ptr [ecx + 01H]
        inc     ecx
        inc     esi
        mov     byte ptr [esi], al
        cmp     dword ptr [esp + 54H], 1
        jbe     @@042
        mov     cl, byte ptr [ecx + 01H]
        inc     esi
        mov     byte ptr [esi], cl
        jmp     @@042

@@040:  mov     eax, esi
        sub     eax, ebp

@@041:  mov     cl, byte ptr [eax + 01H]
        inc     eax
        inc     esi
        mov     byte ptr [esi], cl
        mov     cl, byte ptr [eax + 01H]
        inc     eax
        inc     esi
        mov     byte ptr [esi], cl
        mov     cl, byte ptr [eax + 01H]
        inc     eax
        inc     esi
        mov     byte ptr [esi], cl
        mov     ecx, dword ptr [esp + 54H]
        sub     ecx, 3
        cmp     ecx, 2
        mov     dword ptr [esp + 54H], ecx
        ja      @@041
        test    ecx, ecx
        jz      @@042
        mov     cl, byte ptr [eax + 01H]
        inc     eax
        inc     esi
        mov     byte ptr [esi], cl
        cmp     dword ptr [esp + 54H], 1
        jbe     @@042
        mov     al, byte ptr [eax + 01H]
        inc     esi
        mov     byte ptr [esi], al
@@042:  mov     ebp, dword ptr [esp + 18H]
@@043:  cmp     edx, dword ptr [esp + 30H]
        jnc     @@049
        cmp     esi, dword ptr [esp + 34H]
        jb      @@019
        jmp     @@049

@@044:  mov     ecx, dword ptr [esp + 50H]
        mov     eax, dword ptr [esp + 18H]
        mov     dword ptr [ecx + 18H],offset Err248
        mov     dword ptr [eax], 27
        mov     ebp, eax
        jmp     @@049

@@045:  mov     ecx, dword ptr [esp + 50H]
        mov     dword ptr [ecx + 18H], offset Err247
        jmp     @@048

@@046:  test    al, 20H
        jz      @@047
        mov     dword ptr [ebp], 11
        jmp     @@049

@@047:  mov     eax, dword ptr [esp + 50H]
        mov     dword ptr [eax + 18H], offset Err246
@@048:  mov     dword ptr [ebp], 27
@@049:  mov     eax, ebx
        shr     eax, 3
        lea     ecx, [eax*8]
        sub     edx, eax
        sub     ebx, ecx
        mov     ecx, ebx
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [esp + 50H]
        dec     eax
        and     edi, eax
        lea     eax, [edx + 01H]
        mov     dword ptr [ecx], eax
        lea     eax, [esi + 01H]
        mov     dword ptr [ecx + 0CH], eax
        mov     eax, dword ptr [esp + 30H]
        sub     eax, edx
        add     eax, 5
        mov     dword ptr [ecx + 04H], eax
        mov     eax, dword ptr [esp + 34H]
        sub     eax, esi
        add     eax, 257
        mov     dword ptr [ecx + 10H], eax
        mov     dword ptr [ebp + 38H], edi
        pop     edi
        pop     esi
        mov     dword ptr [ebp + 3CH], ebx
        pop     ebp
        pop     ebx
        add     esp, 60
        ret     8
end;

procedure inflateReset;
asm
        mov     edx, dword ptr [esp + 04H]
        xor     ecx, ecx
        cmp     edx, ecx
        jz      @@050
        mov     eax, dword ptr [edx + 1CH]
        cmp     eax, ecx
        jz      @@050
        mov     dword ptr [eax + 1CH], ecx
        mov     dword ptr [edx + 14H], ecx
        mov     dword ptr [edx + 08H], ecx
        mov     dword ptr [edx + 18H], ecx
        mov     dword ptr [edx + 30H], 1
        mov     dword ptr [eax], ecx
        mov     dword ptr [eax + 04H], ecx
        mov     dword ptr [eax + 0CH], ecx
        mov     dword ptr [eax + 20H], ecx
        mov     dword ptr [eax + 28H], ecx
        mov     dword ptr [eax + 2CH], ecx
        mov     dword ptr [eax + 30H], ecx
        mov     dword ptr [eax + 38H], ecx
        mov     dword ptr [eax + 3CH], ecx
        lea     ecx, [eax + 00000530H]
        mov     dword ptr [eax + 14H], 32768
        mov     dword ptr [eax + 6CH], ecx
        mov     dword ptr [eax + 50H], ecx
        mov     dword ptr [eax + 4CH], ecx
        xor     eax, eax
        ret     4

@@050:  mov     eax, -2
        ret     4
end;

function zsalloc(AppData: Pointer; Items, Size: cardinal): Pointer; stdcall;
begin // direct use of the (FastMM4) delphi heap for all inflate memory allocation
  Getmem(result,Items * Size);
end;

procedure zsfree(AppData, Block: Pointer); stdcall;
begin // direct use of the (FastMM4) delphi heap for all inflate memory allocation
  FreeMem(Block);
end;

function inflateInit2_;
asm  pop ebp  // auto-generated push ebp; mov ebp,esp
        mov     eax, dword ptr [esp + 0CH]
        push    edi
        xor     edi, edi
        cmp     eax, edi
        je      @@058
        cmp     byte ptr [eax], 49
        jne     @@058
        cmp     dword ptr [esp + 14H], 56
        jnz     @@058
        push    esi
        mov     esi, dword ptr [esp + 0CH]
        cmp     esi, edi
        jz      @@057
        mov [esi].TZStream.zFree,offset zsfree
        mov [esi].TZStream.zAlloc,offset zsalloc
        mov     dword ptr [esi + 18H], edi
        mov eax,9520
        call System.@GetMem
        mov [esi].TZStream.State,eax
        mov     ecx, dword ptr [esp + 10H]
        cmp     ecx, edi
        jge     @@054
        mov     dword ptr [eax + 08H], edi
        neg     ecx
        jmp     @@055

@@054:  mov     edx, ecx
        sar     edx, 4
        inc     edx
        mov     dword ptr [eax + 08H], edx
@@055:  cmp     ecx, 8
        jl      @@056
        cmp     ecx, 15
        jg      @@056
        push    esi
        mov     dword ptr [eax + 24H], ecx
        mov     dword ptr [eax + 34H], edi
        call    inflateReset
        pop     esi
        pop     edi
        ret     16

@@056:  push    eax
        mov     eax, dword ptr [esi + 28H]
        push    eax
        call    dword ptr [esi + 24H]
        mov     dword ptr [esi + 1CH], edi
@@057:  pop     esi
        mov     eax, -2
        pop     edi
        ret     16

@@058:  mov     eax, -6
        pop     edi
        ret     16
end;


procedure Inline059;
asm
        push    ebx
        push    ebp
        mov     ebp, dword ptr [esp + 0CH]
        mov     ebx, dword ptr [ebp + 1CH]
        push    esi
        push    edi
        mov     esi, eax
        mov     eax, dword ptr [ebx + 34H]
        xor     edi, edi
        cmp     eax, edi
        jnz     @@060
        mov     ecx, dword ptr [ebx + 24H]
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [ebp + 28H]
        push    1
        push    eax
        push    ecx
        call    dword ptr [ebp + 20H]
        cmp     eax, edi
        mov     dword ptr [ebx + 34H], eax
        jnz     @@060
        pop     edi
        pop     esi
        pop     ebp
        mov     eax, 1
        pop     ebx
        ret     4

@@060:  cmp     dword ptr [ebx + 28H], edi
        jnz     @@061
        mov     ecx, dword ptr [ebx + 24H]
        mov     edx, 1
        shl     edx, cl
        mov     dword ptr [ebx + 30H], edi
        mov     dword ptr [ebx + 2CH], edi
        mov     dword ptr [ebx + 28H], edx
@@061:  mov     edi, dword ptr [ebp + 10H]
        mov     ecx, dword ptr [ebx + 28H]
        sub     esi, edi
        mov     eax, esi
        cmp     eax, ecx
        jc      @@062
        mov     esi, dword ptr [ebp + 0CH]
        mov     edi, dword ptr [ebx + 34H]
        sub     esi, ecx
        mov     eax, ecx
        shr     ecx, 2
        rep movsd
        mov     ecx, eax
        and     ecx, 00000003H
        rep movsb
        mov     ecx, dword ptr [ebx + 28H]
        pop     edi
        pop     esi
        pop     ebp
        mov     dword ptr [ebx + 30H], 0
        mov     dword ptr [ebx + 2CH], ecx
        xor     eax, eax
        pop     ebx
        ret     4

@@062:  sub     ecx, dword ptr [ebx + 30H]
        cmp     ecx, eax
        mov     dword ptr [esp + 14H], ecx
        jbe     @@063
        mov     ecx, eax
        mov     dword ptr [esp + 14H], ecx
@@063:  mov     edx, dword ptr [ebx + 30H]
        mov     edi, dword ptr [ebx + 34H]
        mov     esi, dword ptr [ebp + 0CH]
        add     edi, edx
        mov     edx, ecx
        shr     ecx, 2
        sub     esi, eax
        rep movsd
        mov     ecx, edx
        and     ecx, 00000003H
        rep movsb
        mov     ecx, dword ptr [esp + 14H]
        sub     eax, ecx
        jz      @@064
        mov     esi, dword ptr [ebp + 0CH]
        mov     edi, dword ptr [ebx + 34H]
        mov     ecx, eax
        mov     edx, ecx
        sub     esi, eax
        shr     ecx, 2
        rep movsd
        mov     ecx, edx
        and     ecx, 00000003H
        rep movsb
        pop     edi
        mov     dword ptr [ebx + 30H], eax
        mov     eax, dword ptr [ebx + 28H]
        pop     esi
        mov     dword ptr [ebx + 2CH], eax
        pop     ebp
        xor     eax, eax
        pop     ebx
        ret     4

@@064:  mov     edi, dword ptr [ebx + 30H]
        mov     eax, dword ptr [ebx + 28H]
        add     edi, ecx
        mov     edx, edi
        cmp     edx, eax
        mov     dword ptr [ebx + 30H], edi
        jnz     @@065
        mov     dword ptr [ebx + 30H], 0
@@065:  mov     edx, dword ptr [ebx + 2CH]
        cmp     edx, eax
        jnc     @@066
        add     edx, ecx
        mov     dword ptr [ebx + 2CH], edx
@@066:  pop     edi
        pop     esi
        pop     ebp
        xor     eax, eax
        pop     ebx
        ret     4
end;

function inflate;
asm  pop ebp  // auto-generated push ebp; mov ebp,esp
        mov     eax, dword ptr [esp + 04H]
        sub     esp, 52
        test    eax, eax
        push    ebx
        je      @@191
        mov     ebx, dword ptr [eax + 1CH]
        test    ebx, ebx
        je      @@191
        mov     ecx, dword ptr [eax + 0CH]
        test    ecx, ecx
        je      @@191
        cmp     dword ptr [eax], 0
        jnz     @@067
        mov     ecx, dword ptr [eax + 04H]
        test    ecx, ecx
        jne     @@191
@@067:  cmp     dword ptr [ebx], 11
        jnz     @@068
        mov     dword ptr [ebx], 12
@@068:  mov     ecx, dword ptr [eax + 0CH]
        mov     edx, dword ptr [ebx + 38H]
        push    ebp
        mov     ebp, dword ptr [ebx + 3CH]
        push    esi
        mov     esi, dword ptr [eax]
        push    edi
        mov     edi, dword ptr [eax + 04H]
        mov     dword ptr [esp + 24H], ecx
        mov     ecx, dword ptr [eax + 10H]
        mov     eax, dword ptr [ebx]
        cmp     eax, 28
        mov     dword ptr [esp + 1CH], ecx
        mov     dword ptr [esp + 14H], esi
        mov     dword ptr [esp + 18H], edi
        mov     dword ptr [esp + 10H], edx
        mov     dword ptr [esp + 38H], edi
        mov     dword ptr [esp + 28H], ecx
        mov     dword ptr [esp + 2CH], 0
        ja      @@176
@@069:  jmp     dword ptr [@@192 + eax*4]

@@070:  mov     eax, dword ptr [ebx + 08H]
        test    eax, eax
        jnz     @@071
        mov     dword ptr [ebx], 12
        jmp     @@175

@@071:  cmp     ebp, 16
        jnc     @@073
@@072:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        dec     edi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     edx, eax
        inc     esi
        cmp     ebp, 16
        mov     dword ptr [esp + 10H], edx
        mov     dword ptr [esp + 14H], esi
        jc      @@072
@@073:  mov     eax, edx
        and     eax, 000000FFH
        shr     edx, 8
        shl     eax, 8
        add     eax, edx
        xor     edx, edx
        mov     ecx, 31
        div     ecx
        test    edx, edx
        jz      @@074
        mov     edx, dword ptr [esp + 48H]
        mov     dword ptr [edx + 18H], offset Err248
        mov     edx, dword ptr [esp + 10H]
        jmp     @@174

@@074:  mov     ecx, dword ptr [esp + 10H]
        mov     eax, ecx
        and     al, 0FH
        cmp     al, 8
        jz      @@075
        mov     ecx, dword ptr [esp + 48H]
        mov     edx, dword ptr [esp + 10H]
        mov     dword ptr [ecx + 18H], offset Err248
        jmp     @@174

@@075:  mov     eax, dword ptr [ebx + 24H]
        shr     ecx, 4
        mov     dword ptr [esp + 10H], ecx
        and     ecx, 0000000FH
        add     ecx, 8
        sub     ebp, 4
        cmp     ecx, eax
        jbe     @@076
        mov     edx, dword ptr [esp + 48H]
        mov     dword ptr [edx + 18H], offset Err248
        mov     edx, dword ptr [esp + 10H]
        jmp     @@174

@@076:  mov     eax, 1
        shl     eax, cl
        mov     dword ptr [ebx + 14H], eax
        xor eax,eax
        xor ecx,ecx
        xor edx,edx
        xor ebp,ebp
        call    Adler32
        mov     edx, dword ptr [esp + 10H]
        mov     ecx, dword ptr [esp + 48H]
        shr     edx, 8
        not     edx
        and     edx, 00000002H
        or      edx, 00000009H
        mov     dword ptr [ebx + 18H], eax
        mov     dword ptr [ecx + 30H], eax
        mov     dword ptr [ebx], edx
        mov     dword ptr [esp + 10H], ebp
        mov     edx, ebp
        jmp     @@175

@@077:  cmp     ebp, 32
        jnc     @@079
@@078:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        dec     edi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     edx, eax
        inc     esi
        cmp     ebp, 32
        mov     dword ptr [esp + 10H], edx
        mov     dword ptr [esp + 14H], esi
        jc      @@078
@@079:  mov     ecx, edx
        and     ecx, 0000FF00H
        mov     eax, edx
        shl     eax, 16
        add     ecx, eax
        xor     eax, eax
        mov     ah, byte ptr [esp + 12H]
        shl     ecx, 8
        shr     edx, 24
        add     ecx, eax
        lea     eax, [ecx + edx]
        mov     ecx, dword ptr [esp + 48H]
        xor     ebp, ebp
        mov     dword ptr [ebx + 18H], eax
        mov     dword ptr [ecx + 30H], eax
        mov     dword ptr [esp + 10H], ebp
        mov     dword ptr [ebx], 10
        mov     edx, ebp

@@080:  mov     eax, dword ptr [ebx + 0CH]
        test    eax, eax
        je      @@178
        xor eax,eax
        xor ecx,ecx
        xor edx,edx
        call    Adler32
        mov     edx, dword ptr [esp + 48H]
        mov     dword ptr [ebx + 18H], eax
        mov     dword ptr [edx + 30H], eax
        mov     edx, dword ptr [esp + 10H]
        mov     dword ptr [ebx], 11

@@081:  cmp     dword ptr [esp + 4CH], 5
        je      @@183

@@082:  mov     eax, dword ptr [ebx + 04H]
        test    eax, eax
        jz      @@083
        mov     ecx, ebp
        and     ecx, 00000007H
        shr     edx, cl
        sub     ebp, ecx
        mov     dword ptr [ebx], 24
        mov     dword ptr [esp + 10H], edx
        jmp     @@175

@@083:  cmp     ebp, 3
        jnc     @@085

@@084:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        dec     edi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     edx, eax
        inc     esi
        cmp     ebp, 3
        mov     dword ptr [esp + 14H], esi
        jc      @@084
@@085:  mov     ecx, edx
        shr     edx, 1
        and     ecx, 00000001H
        mov     eax, edx
        and     eax, 00000003H
        dec     ebp
        cmp     eax, 3
        mov     dword ptr [ebx + 04H], ecx
        ja      @@090
        jmp     dword ptr [@@193 + eax*4]

@@086:  shr     edx, 2
        mov     dword ptr [ebx], 13
        mov     dword ptr [esp + 10H], edx
        sub     ebp, 2
        jmp     @@175

@@087:  shr     edx, 2
        mov     dword ptr [ebx + 4CH], offset @@249
        mov     dword ptr [ebx + 54H], 9
        mov     dword ptr [ebx + 50H], offset @@250
        mov     dword ptr [ebx + 58H], 5
        mov     dword ptr [ebx], 18
        mov     dword ptr [esp + 10H], edx
        sub     ebp, 2
        jmp     @@175

@@088:  shr     edx, 2
        mov     dword ptr [ebx], 15
        mov     dword ptr [esp + 10H], edx
        sub     ebp, 2
        jmp     @@175

@@089:  mov     eax, dword ptr [esp + 48H]
        mov     dword ptr [eax + 18H], offset Err248
        mov     dword ptr [ebx], 27
@@090:  shr     edx, 2
        mov     dword ptr [esp + 10H], edx
        sub     ebp, 2
        jmp     @@175

@@091:  mov     ecx, ebp
        and     ecx, 00000007H
        shr     edx, cl
        sub     ebp, ecx
        cmp     ebp, 32
        mov     dword ptr [esp + 10H], edx
        jnc     @@093

@@092:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        dec     edi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     edx, eax
        inc     esi
        cmp     ebp, 32
        mov     dword ptr [esp + 10H], edx
        mov     dword ptr [esp + 14H], esi
        jc      @@092
@@093:  mov     ecx, edx
        mov     eax, edx
        not     ecx
        and     eax, 0000FFFFH
        shr     ecx, 16
        cmp     eax, ecx
        jz      @@094
        mov     eax, dword ptr [esp + 48H]
        mov     dword ptr [eax + 18H], offset Err248
        jmp     @@174

@@094:  xor     ebp, ebp
        mov     dword ptr [ebx + 40H], eax
        mov     dword ptr [esp + 10H], ebp
        mov     dword ptr [ebx], 14
        mov     edx, ebp

@@095:  mov     ecx, dword ptr [ebx + 40H]
        test    ecx, ecx
        mov     dword ptr [esp + 20H], ecx
        je      @@142
        cmp     ecx, edi
        jbe     @@096
        mov     ecx, edi
        mov     dword ptr [esp + 20H], ecx
@@096:  mov     eax, dword ptr [esp + 1CH]
        cmp     ecx, eax
        jbe     @@097
        mov     ecx, eax
        mov     dword ptr [esp + 20H], ecx
@@097:  test    ecx, ecx
        je      @@183
        mov     esi, dword ptr [esp + 14H]
        mov     edi, dword ptr [esp + 24H]
        mov     eax, ecx
        shr     ecx, 2
        rep movsd
        mov     ecx, eax
        mov     eax, dword ptr [esp + 20H]
        and     ecx, 00000003H
        rep movsb
        mov     esi, dword ptr [esp + 18H]
        mov     ecx, dword ptr [esp + 14H]
        mov     edi, dword ptr [esp + 1CH]
        sub     esi, eax
        mov     dword ptr [esp + 18H], esi
        mov     esi, dword ptr [esp + 24H]
        add     ecx, eax
        mov     dword ptr [esp + 14H], ecx
        mov     ecx, dword ptr [ebx + 40H]
        sub     edi, eax
        add     esi, eax
        sub     ecx, eax
        mov     dword ptr [esp + 1CH], edi
        mov     edi, dword ptr [esp + 18H]
        mov     dword ptr [esp + 24H], esi
        mov     esi, dword ptr [esp + 14H]
        mov     dword ptr [ebx + 40H], ecx
        jmp     @@175

@@098:  cmp     ebp, 14
        jnc     @@100
@@099:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        dec     edi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     edx, eax
        inc     esi
        cmp     ebp, 14
        mov     dword ptr [esp + 14H], esi
        jc      @@099
@@100:  mov     ecx, edx
        and     ecx, 0000001FH
        shr     edx, 5
        add     ecx, 257
        mov     eax, edx
        mov     dword ptr [ebx + 60H], ecx
        and     eax, 0000001FH
        shr     edx, 5
        inc     eax
        mov     ecx, edx
        and     ecx, 0000000FH
        mov     dword ptr [ebx + 64H], eax
        mov     eax, dword ptr [ebx + 60H]
        add     ecx, 4
        shr     edx, 4
        sub     ebp, 14
        cmp     eax, 286
        mov     dword ptr [ebx + 5CH], ecx
        mov     dword ptr [esp + 10H], edx
        ja      @@108
        cmp     dword ptr [ebx + 64H], 30
        ja      @@108
        mov     dword ptr [ebx + 68H], 0
        mov     dword ptr [ebx], 16

@@101:  mov     ecx, dword ptr [ebx + 68H]
        cmp     ecx, dword ptr [ebx + 5CH]
        jnc     @@105
@@102:  cmp     ebp, 3
        jnc     @@104

@@103:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        dec     edi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     edx, eax
        inc     esi
        cmp     ebp, 3
        mov     dword ptr [esp + 14H], esi
        jc      @@103
@@104:  mov     eax, dword ptr [ebx + 68H]
        movzx   eax, word ptr [@@251 + eax*2]
        xor     ecx, ecx
        mov     cl, dl
        shr     edx, 3
        sub     ebp, 3
        mov     dword ptr [esp + 10H], edx
        and     ecx, 00000007H
        mov     word ptr [ebx + eax*2 + 70H], cx
        mov     ecx, dword ptr [ebx + 68H]
        inc     ecx
        mov     dword ptr [ebx + 68H], ecx
        cmp     ecx, dword ptr [ebx + 5CH]
        jc      @@102
@@105:  mov     ecx, dword ptr [ebx + 68H]
        mov     eax, 19
        cmp     ecx, eax
        jnc     @@107
        xor     ecx, ecx

@@106:  mov     edx, dword ptr [ebx + 68H]
        movzx   edx, word ptr [@@251 + edx*2]
        mov     word ptr [ebx + edx*2 + 70H], cx
        mov     edx, dword ptr [ebx + 68H]
        inc     edx
        cmp     edx, eax
        mov     dword ptr [ebx + 68H], edx
        jc      @@106
@@107:  lea     eax, [ebx + 00000530H]
        lea     ecx, [ebx + 6CH]
        mov     dword ptr [ecx], eax
        mov     dword ptr [ebx + 4CH], eax
        lea     edx, [ebx + 000002F0H]
        push    edx
        lea     eax, [ebx + 54H]
        push    eax
        push    ecx
        mov     dword ptr [eax], 7
        push    19
        lea     eax, [ebx + 70H]
        push    eax
        push    0
        call    @@196
        test    eax, eax
        mov     edx, dword ptr [esp + 10H]
        mov     dword ptr [esp + 2CH], eax
        jz      @@109
        mov     ecx, dword ptr [esp + 48H]
        mov     dword ptr [ecx + 18H], offset Err248
        jmp     @@174

@@108:  mov     eax, dword ptr [esp + 48H]
        mov     dword ptr [eax + 18H], offset Err248
        jmp     @@174

@@109:  mov     dword ptr [ebx + 68H], 0
        mov     dword ptr [ebx], 17

@@110:  mov     ecx, dword ptr [ebx + 60H]
        mov     eax, dword ptr [ebx + 64H]
        add     eax, ecx
        cmp     dword ptr [ebx + 68H], eax
        jae     @@129
@@111:  mov     ecx, dword ptr [ebx + 54H]
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [ebx + 4CH]
        dec     eax
        and     eax, edx
        mov     eax, dword ptr [ecx + eax*4]
        movzx   ecx, ah
        cmp     ecx, ebp
        mov     dword ptr [esp + 3CH], eax
        jbe     @@113
@@112:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        mov     ecx, dword ptr [ebx + 54H]
        dec     edi
        add     ebp, 8
        add     edx, eax
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [ebx + 4CH]
        inc     esi
        mov     dword ptr [esp + 18H], edi
        dec     eax
        and     eax, edx
        mov     eax, dword ptr [ecx + eax*4]
        movzx   ecx, ah
        cmp     ecx, ebp
        mov     dword ptr [esp + 14H], esi
        mov     dword ptr [esp + 3CH], eax
        ja      @@112
@@113:  mov     ecx, dword ptr [esp + 3CH]
        shr     ecx, 16
        cmp     cx, 16
        jnc     @@116
        movzx   ecx, ah
        cmp     ebp, ecx
        mov     dword ptr [esp + 20H], ecx
        jnc     @@115
@@114:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        mov     ecx, dword ptr [esp + 20H]
        dec     edi
        add     ebp, 8
        add     edx, eax
        inc     esi
        cmp     ebp, ecx
        mov     dword ptr [esp + 18H], edi
        mov     dword ptr [esp + 14H], esi
        jc      @@114
@@115:  mov     ax, word ptr [esp + 3EH]
        shr     edx, cl
        sub     ebp, ecx
        mov     ecx, dword ptr [ebx + 68H]
        mov     word ptr [ebx + ecx*2 + 70H], ax
        mov     eax, dword ptr [ebx + 68H]
        inc     eax
        mov     dword ptr [esp + 10H], edx
        mov     dword ptr [ebx + 68H], eax
        jmp     @@128

@@116:  jnz     @@119
        movzx   ecx, ah
        lea     eax, [ecx + 02H]
        cmp     ebp, eax
        mov     dword ptr [esp + 20H], ecx
        jnc     @@118

@@117:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        mov     ecx, dword ptr [esp + 20H]
        dec     edi
        add     ebp, 8
        add     edx, eax
        inc     esi
        lea     eax, [ecx + 02H]
        cmp     ebp, eax
        mov     dword ptr [esp + 18H], edi
        mov     dword ptr [esp + 14H], esi
        jc      @@117
@@118:  mov     eax, dword ptr [ebx + 68H]
        shr     edx, cl
        sub     ebp, ecx
        test    eax, eax
        mov     dword ptr [esp + 10H], edx
        je      @@130
        movzx   ecx, word ptr [ebx + eax*2 + 6EH]
        mov     eax, edx
        and     eax, 00000003H
        add     eax, 3
        shr     edx, 2
        mov     dword ptr [esp + 30H], ecx
        mov     dword ptr [esp + 20H], eax
        sub     ebp, 2
        jmp     @@126

@@119:  cmp     cx, 17
        movzx   ecx, ah
        mov     dword ptr [esp + 20H], ecx
        jnz     @@122
        lea     eax, [ecx + 03H]
        cmp     ebp, eax
        jnc     @@121
@@120:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        mov     ecx, dword ptr [esp + 20H]
        dec     edi
        add     ebp, 8
        add     edx, eax
        inc     esi
        lea     eax, [ecx + 03H]
        cmp     ebp, eax
        mov     dword ptr [esp + 18H], edi
        mov     dword ptr [esp + 14H], esi
        jc      @@120
@@121:  shr     edx, cl
        mov     eax, edx
        and     eax, 00000007H
        add     eax, 3
        mov     dword ptr [esp + 20H], eax
        shr     edx, 3
        mov     eax, -3
        jmp     @@125

@@122:  lea     eax, [ecx + 07H]
        cmp     ebp, eax
        jnc     @@124
@@123:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        mov     ecx, dword ptr [esp + 20H]
        dec     edi
        add     ebp, 8
        add     edx, eax
        inc     esi
        lea     eax, [ecx + 07H]
        cmp     ebp, eax
        mov     dword ptr [esp + 18H], edi
        mov     dword ptr [esp + 14H], esi
        jc      @@123
@@124:  shr     edx, cl
        mov     eax, edx
        and     eax, 0000007FH
        add     eax, 11
        mov     dword ptr [esp + 20H], eax
        shr     edx, 7
        mov     eax, -7
@@125:  sub     eax, ecx
        mov     dword ptr [esp + 30H], 0
        add     ebp, eax
@@126:  mov     eax, dword ptr [ebx + 60H]
        mov     ecx, dword ptr [ebx + 64H]
        add     ecx, eax
        mov     eax, dword ptr [ebx + 68H]
        add     eax, dword ptr [esp + 20H]
        mov     dword ptr [esp + 10H], edx
        cmp     eax, ecx
        ja      @@131
        mov     eax, dword ptr [esp + 20H]
        test    eax, eax
        jz      @@128
        mov     dword ptr [esp + 20H], eax
        mov     eax, dword ptr [esp + 30H]

@@127:  mov     ecx, dword ptr [ebx + 68H]
        mov     word ptr [ebx + ecx*2 + 70H], ax
        inc     dword ptr [ebx + 68H]
        dec     dword ptr [esp + 20H]
        jnz     @@127
@@128:  mov     ecx, dword ptr [ebx + 60H]
        mov     eax, dword ptr [ebx + 64H]
        add     eax, ecx
        cmp     dword ptr [ebx + 68H], eax
        jb      @@111
@@129:  cmp     dword ptr [ebx], 27
        je      @@175
        lea     eax, [ebx + 00000530H]
        lea     ecx, [ebx + 6CH]
        mov     dword ptr [ecx], eax
        lea     edx, [ebx + 000002F0H]
        push    edx
        mov     dword ptr [ebx + 4CH], eax
        lea     eax, [ebx + 54H]
        push    eax
        push    ecx
        mov     ecx, dword ptr [ebx + 60H]
        push    ecx
        lea     edx, [ebx + 70H]
        push    edx
        push    1
        mov     dword ptr [eax], 9
        call    @@196
        test    eax, eax
        mov     dword ptr [esp + 2CH], eax
        jz      @@132
        mov     eax, dword ptr [esp + 48H]
        mov     edx, dword ptr [esp + 10H]
        mov     dword ptr [eax + 18H], offset Err248
        jmp     @@174

@@130:  mov     ecx, dword ptr [esp + 48H]
        mov     dword ptr [ecx + 18H], offset Err248
        jmp     @@174

@@131:  mov     eax, dword ptr [esp + 48H]
        mov     dword ptr [eax + 18H], offset Err248
        jmp     @@174

@@132:  mov     edx, dword ptr [ebx + 6CH]
        lea     ecx, [ebx + 6CH]
        mov     dword ptr [ebx + 50H], edx
        lea     edx, [ebx + 000002F0H]
        push    edx
        lea     eax, [ebx + 58H]
        push    eax
        push    ecx
        mov     ecx, dword ptr [ebx + 60H]
        mov     dword ptr [eax], 6
        mov     eax, dword ptr [ebx + 64H]
        push    eax
        lea     edx, [ebx + ecx*2 + 70H]
        push    edx
        push    2
        call    @@196
        test    eax, eax
        mov     edx, dword ptr [esp + 10H]
        mov     dword ptr [esp + 2CH], eax
        jz      @@133
        mov     eax, dword ptr [esp + 48H]
        mov     dword ptr [eax + 18H], offset Err248
        jmp     @@174

@@133:  mov     dword ptr [ebx], 18

@@134:  cmp     edi, 6
        jc      @@135
        cmp     dword ptr [esp + 1CH], 258
        jc      @@135
        mov     eax, dword ptr [esp + 48H]
        mov     ecx, dword ptr [esp + 24H]
        mov     dword ptr [eax + 0CH], ecx
        mov     ecx, dword ptr [esp + 1CH]
        mov     dword ptr [eax + 10H], ecx
        mov     dword ptr [eax], esi
        mov     dword ptr [eax + 04H], edi
        mov     dword ptr [ebx + 38H], edx
        mov     edx, dword ptr [esp + 28H]
        push    edx
        push    eax
        mov     dword ptr [ebx + 3CH], ebp
        call    Inline018
        mov     eax, dword ptr [esp + 48H]
        mov     edx, dword ptr [eax + 10H]
        mov     ecx, dword ptr [eax + 0CH]
        mov     esi, dword ptr [eax]
        mov     edi, dword ptr [eax + 04H]
        mov     eax, dword ptr [ebx + 38H]
        mov     ebp, dword ptr [ebx + 3CH]
        mov     dword ptr [esp + 1CH], edx
        mov     dword ptr [esp + 24H], ecx
        mov     dword ptr [esp + 14H], esi
        mov     dword ptr [esp + 18H], edi
        mov     dword ptr [esp + 10H], eax
        mov     edx, eax
        jmp     @@175

@@135:  mov     ecx, dword ptr [ebx + 54H]
        mov     eax, 1
        shl     eax, cl
        dec     eax
        and     eax, edx
        mov     ecx, eax
        mov     eax, dword ptr [ebx + 4CH]
        mov     eax, dword ptr [eax + ecx*4]
        movzx   ecx, ah
        cmp     ecx, ebp
        mov     dword ptr [esp + 3CH], eax
        jbe     @@137

@@136:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        mov     ecx, dword ptr [ebx + 54H]
        dec     edi
        add     ebp, 8
        add     edx, eax
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [ebx + 4CH]
        inc     esi
        mov     dword ptr [esp + 18H], edi
        dec     eax
        and     eax, edx
        mov     eax, dword ptr [ecx + eax*4]
        movzx   ecx, ah
        cmp     ecx, ebp
        mov     dword ptr [esp + 14H], esi
        mov     dword ptr [esp + 3CH], eax
        ja      @@136
@@137:  test    al, al
        je      @@140
        test    al, 0F0H
        jne     @@140
        movzx   ecx, ah
        mov     dword ptr [esp + 20H], ecx
        xor     ecx, ecx
        mov     cl, al
        mov     dword ptr [esp + 10H], eax
        add     ecx, dword ptr [esp + 20H]
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [esp + 20H]
        dec     eax
        and     eax, edx
        shr     eax, cl
        mov     ecx, dword ptr [esp + 3CH]
        shr     ecx, 16
        add     eax, ecx
        mov     ecx, eax
        mov     eax, dword ptr [ebx + 4CH]
        mov     eax, dword ptr [eax + ecx*4]
        mov     ecx, dword ptr [esp + 10H]
        shr     ecx, 8
        mov     dword ptr [esp + 3CH], eax
        movzx   ecx, cl
        movzx   eax, ah
        add     eax, ecx
        cmp     eax, ebp
        mov     dword ptr [esp + 20H], ecx
        jbe     @@139

@@138:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        xor     ecx, ecx
        mov     cl, byte ptr [esp + 10H]
        dec     edi
        add     edx, eax
        mov     eax, dword ptr [esp + 20H]
        inc     esi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     ecx, eax
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [esp + 20H]
        mov     dword ptr [esp + 14H], esi
        dec     eax
        and     eax, edx
        shr     eax, cl
        movzx   ecx, word ptr [esp + 12H]
        add     eax, ecx
        mov     ecx, dword ptr [ebx + 4CH]
        mov     eax, dword ptr [ecx + eax*4]
        mov     ecx, dword ptr [esp + 20H]
        mov     dword ptr [esp + 3CH], eax
        movzx   eax, ah
        add     eax, ecx
        cmp     eax, ebp
        ja      @@138
@@139:  mov     eax, dword ptr [esp + 3CH]
        shr     edx, cl
        sub     ebp, ecx
@@140:  movzx   ecx, ah
        shr     edx, cl
        movzx   ecx, ah
        sub     ebp, ecx
        mov     ecx, dword ptr [esp + 3CH]
        shr     ecx, 16
        test    al, al
        mov     dword ptr [esp + 10H], edx
        mov     dword ptr [ebx + 40H], ecx
        jnz     @@141
        mov     dword ptr [ebx], 23
        jmp     @@175

@@141:  test    al, 20H
        jz      @@143
@@142:  mov     dword ptr [ebx], 11
        jmp     @@175

@@143:  test    al, 40H
        jz      @@144
        mov     eax, dword ptr [esp + 48H]
        mov     dword ptr [eax + 18H], offset Err248
        jmp     @@174

@@144:  and     eax, 0000000FH
        mov     dword ptr [ebx + 48H], eax
        mov     dword ptr [ebx], 19

@@145:  mov     eax, dword ptr [ebx + 48H]
        test    eax, eax
        jz      @@148
        cmp     ebp, eax
        jnc     @@147
@@146:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        dec     edi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     edx, eax
        mov     eax, dword ptr [ebx + 48H]
        inc     esi
        cmp     ebp, eax
        mov     dword ptr [esp + 14H], esi
        jc      @@146
@@147:  mov     ecx, dword ptr [ebx + 48H]
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [ebx + 40H]
        dec     eax
        and     eax, edx
        add     ecx, eax
        mov     dword ptr [ebx + 40H], ecx
        mov     ecx, dword ptr [ebx + 48H]
        shr     edx, cl
        sub     ebp, ecx
@@148:  mov     dword ptr [ebx], 20

@@149:  mov     ecx, dword ptr [ebx + 58H]
        mov     eax, 1
        shl     eax, cl
        dec     eax
        and     eax, edx
        mov     ecx, eax
        mov     eax, dword ptr [ebx + 50H]
        mov     eax, dword ptr [eax + ecx*4]
        movzx   ecx, ah
        cmp     ecx, ebp
        mov     dword ptr [esp + 3CH], eax
        jbe     @@151
@@150:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        mov     ecx, dword ptr [ebx + 58H]
        dec     edi
        add     ebp, 8
        add     edx, eax
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [ebx + 50H]
        inc     esi
        mov     dword ptr [esp + 18H], edi
        dec     eax
        and     eax, edx
        mov     eax, dword ptr [ecx + eax*4]
        movzx   ecx, ah
        cmp     ecx, ebp
        mov     dword ptr [esp + 14H], esi
        mov     dword ptr [esp + 3CH], eax
        ja      @@150
@@151:  test    al, 0F0H
        jne     @@154
        movzx   ecx, ah
        mov     dword ptr [esp + 20H], ecx
        xor     ecx, ecx
        mov     cl, al
        mov     dword ptr [esp + 10H], eax
        add     ecx, dword ptr [esp + 20H]
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [esp + 20H]
        dec     eax
        and     eax, edx
        shr     eax, cl
        mov     ecx, dword ptr [esp + 3CH]
        shr     ecx, 16
        add     eax, ecx
        mov     ecx, eax
        mov     eax, dword ptr [ebx + 50H]
        mov     eax, dword ptr [eax + ecx*4]
        mov     ecx, dword ptr [esp + 10H]
        shr     ecx, 8
        mov     dword ptr [esp + 3CH], eax
        movzx   ecx, cl
        movzx   eax, ah
        add     eax, ecx
        cmp     eax, ebp
        mov     dword ptr [esp + 20H], ecx
        jbe     @@153

@@152:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        xor     ecx, ecx
        mov     cl, byte ptr [esp + 10H]
        dec     edi
        add     edx, eax
        mov     eax, dword ptr [esp + 20H]
        inc     esi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     ecx, eax
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [esp + 20H]
        mov     dword ptr [esp + 14H], esi
        dec     eax
        and     eax, edx
        shr     eax, cl
        movzx   ecx, word ptr [esp + 12H]
        add     eax, ecx
        mov     ecx, dword ptr [ebx + 50H]
        mov     eax, dword ptr [ecx + eax*4]
        mov     ecx, dword ptr [esp + 20H]
        mov     dword ptr [esp + 3CH], eax
        movzx   eax, ah
        add     eax, ecx
        cmp     eax, ebp
        ja      @@152
@@153:  mov     eax, dword ptr [esp + 3CH]
        shr     edx, cl
        sub     ebp, ecx
@@154:  movzx   ecx, ah
        shr     edx, cl
        movzx   ecx, ah
        sub     ebp, ecx
        test    al, 40H
        mov     dword ptr [esp + 10H], edx
        jz      @@155
        mov     ecx, dword ptr [esp + 48H]
        mov     dword ptr [ecx + 18H], offset Err248
        jmp     @@174

@@155:  mov     ecx, dword ptr [esp + 3CH]
        shr     ecx, 16
        and     eax, 0000000FH
        mov     dword ptr [ebx + 44H], ecx
        mov     dword ptr [ebx + 48H], eax
        mov     dword ptr [ebx], 21

@@156:  mov     eax, dword ptr [ebx + 48H]
        test    eax, eax
        jz      @@159
        cmp     ebp, eax
        jnc     @@158
@@157:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        dec     edi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     edx, eax
        mov     eax, dword ptr [ebx + 48H]
        inc     esi
        cmp     ebp, eax
        mov     dword ptr [esp + 14H], esi
        jc      @@157
@@158:  mov     ecx, dword ptr [ebx + 48H]
        mov     eax, 1
        shl     eax, cl
        mov     ecx, dword ptr [ebx + 44H]
        dec     eax
        and     eax, edx
        add     ecx, eax
        mov     dword ptr [ebx + 44H], ecx
        mov     ecx, dword ptr [ebx + 48H]
        shr     edx, cl
        sub     ebp, ecx
        mov     dword ptr [esp + 10H], edx
@@159:  mov     eax, dword ptr [esp + 1CH]
        mov     ecx, dword ptr [ebx + 2CH]
        sub     ecx, eax
        add     ecx, dword ptr [esp + 28H]
        cmp     dword ptr [ebx + 44H], ecx
        jbe     @@160
        mov     eax, dword ptr [esp + 48H]
        mov     dword ptr [eax + 18H], offset Err248
        jmp     @@174

@@160:  mov     dword ptr [ebx], 22

@@161:  mov     eax, dword ptr [esp + 1CH]
        test    eax, eax
        je      @@183
        mov     ecx, dword ptr [esp + 28H]
        sub     ecx, eax
        mov     eax, dword ptr [ebx + 44H]
        cmp     eax, ecx
        jbe     @@164
        sub     eax, ecx
        mov     ecx, dword ptr [ebx + 30H]
        cmp     eax, ecx
        mov     dword ptr [esp + 20H], eax
        jbe     @@162
        sub     eax, ecx
        mov     ecx, dword ptr [ebx + 34H]
        add     ecx, dword ptr [ebx + 28H]
        mov     dword ptr [esp + 20H], eax
        sub     ecx, eax
        jmp     @@163

@@162:  mov     ecx, dword ptr [ebx + 34H]
        sub     ecx, eax
        add     ecx, dword ptr [ebx + 30H]
        mov     eax, dword ptr [esp + 20H]
@@163:  mov     dword ptr [esp + 30H], ecx
        mov     ecx, dword ptr [ebx + 40H]
        cmp     eax, ecx
        mov     dword ptr [esp + 34H], ecx
        jbe     @@166
        mov     eax, ecx
        jmp     @@165

@@164:  mov     ecx, dword ptr [esp + 24H]
        sub     ecx, eax
        mov     eax, dword ptr [ebx + 40H]
        mov     dword ptr [esp + 30H], ecx
        mov     dword ptr [esp + 34H], eax
@@165:  mov     dword ptr [esp + 20H], eax
@@166:  mov     ecx, dword ptr [esp + 1CH]
        cmp     eax, ecx
        jbe     @@167
        mov     eax, ecx
        mov     dword ptr [esp + 20H], eax
@@167:  sub     ecx, eax
        mov     dword ptr [esp + 1CH], ecx
        mov     ecx, dword ptr [esp + 34H]
        sub     ecx, eax
        mov     eax, dword ptr [esp + 24H]
        mov     dword ptr [ebx + 40H], ecx

@@168:  mov     ecx, dword ptr [esp + 30H]
        mov     cl, byte ptr [ecx]
        mov     byte ptr [eax], cl
        mov     ecx, dword ptr [esp + 30H]
        inc     eax
        inc     ecx
        mov     dword ptr [esp + 30H], ecx
        dec     dword ptr [esp + 20H]
        jnz     @@168
        mov     dword ptr [esp + 24H], eax
        mov     eax, dword ptr [ebx + 40H]
        test    eax, eax
        jne     @@175
        mov     dword ptr [ebx], 18
        jmp     @@175

@@169:  mov     eax, dword ptr [esp + 1CH]
        test    eax, eax
        je      @@183
        mov     eax, dword ptr [esp + 24H]
        mov     cl, byte ptr [ebx + 40H]
        mov     byte ptr [eax], cl
        inc     eax
        mov     dword ptr [esp + 24H], eax
        dec     dword ptr [esp + 1CH]
        mov     dword ptr [ebx], 18
        jmp     @@175

@@170:  mov     eax, dword ptr [ebx + 08H]
        test    eax, eax
        je      @@180
        cmp     ebp, 32
        jnc     @@172

@@171:  test    edi, edi
        je      @@183
        movzx   eax, byte ptr [esi]
        mov     ecx, ebp
        shl     eax, cl
        dec     edi
        add     ebp, 8
        mov     dword ptr [esp + 18H], edi
        add     edx, eax
        inc     esi
        cmp     ebp, 32
        mov     dword ptr [esp + 10H], edx
        mov     dword ptr [esp + 14H], esi
        jc      @@171
@@172:  mov     eax, dword ptr [esp + 28H]
        sub     eax, dword ptr [esp + 1CH]
        mov     ecx, dword ptr [esp + 48H]
        add     dword ptr [ecx + 14H], eax
        mov     ecx, dword ptr [ebx + 1CH]
        add     ecx, eax
        test    eax, eax
        mov     dword ptr [esp + 28H], eax
        mov     dword ptr [ebx + 1CH], ecx
        jz      @@173
        mov     ecx, dword ptr [esp + 24H]
        mov     edx, dword ptr [ebx + 18H]
        push    eax
        sub     ecx, eax
        push    ecx
        push    edx // parameters on stack
        pop eax
        pop edx
        pop ecx // register calling convention
        call    Adler32
        mov     ecx, dword ptr [esp + 48H]
        mov     edx, dword ptr [esp + 10H]
        mov     dword ptr [ebx + 18H], eax
        mov     dword ptr [ecx + 30H], eax
@@173:  mov     eax, dword ptr [esp + 1CH]
        mov     dword ptr [esp + 28H], eax
        mov     ecx, edx
        and     ecx, 0000FF00H
        mov     eax, edx
        shl     eax, 16
        add     ecx, eax
        xor     eax, eax
        mov     ah, byte ptr [esp + 12H]
        shl     ecx, 8
        add     ecx, eax
        mov     eax, edx
        shr     eax, 24
        add     ecx, eax
        cmp     ecx, dword ptr [ebx + 18H]
        jz      @@179
        mov     ecx, dword ptr [esp + 48H]
        mov     dword ptr [ecx + 18H], offset Err248
@@174:  mov     dword ptr [ebx], 27
@@175:  mov     eax, dword ptr [ebx]
        cmp     eax, 28
        jbe     @@069

@@176:  mov     eax, -2
@@177:  pop     edi
        pop     esi
        pop     ebp
        pop     ebx
        add     esp, 52
        ret     8

@@178:  mov     eax, dword ptr [esp + 48H]
        mov     ecx, dword ptr [esp + 24H]
        mov     dword ptr [eax + 0CH], ecx
        mov     ecx, dword ptr [esp + 1CH]
        mov     dword ptr [eax + 04H], edi
        mov     dword ptr [eax], esi
        pop     edi
        mov     dword ptr [eax + 10H], ecx
        pop     esi
        mov     dword ptr [ebx + 3CH], ebp
        pop     ebp
        mov     dword ptr [ebx + 38H], edx
        mov     eax, 2
        pop     ebx
        add     esp, 52
        ret     8

@@179:  xor     ebp, ebp
        mov     dword ptr [esp + 10H], ebp
        mov     edx, ebp
@@180:  mov     dword ptr [ebx], 26

@@181:  mov     dword ptr [esp + 2CH], 1
        jmp     @@183

@@182:  mov     dword ptr [esp + 2CH], -3
@@183:  mov     eax, dword ptr [esp + 48H]
        mov     ecx, dword ptr [esp + 24H]
        mov     dword ptr [eax + 0CH], ecx
        mov     ecx, dword ptr [esp + 1CH]
        mov     dword ptr [eax + 10H], ecx
        mov     dword ptr [eax], esi
        mov     dword ptr [eax + 04H], edi
        mov     eax, dword ptr [ebx + 28H]
        test    eax, eax
        mov     dword ptr [ebx + 38H], edx
        mov     dword ptr [ebx + 3CH], ebp
        jnz     @@184
        cmp     dword ptr [ebx], 24
        jge     @@186
        mov     eax, dword ptr [esp + 48H]
        mov     edx, dword ptr [esp + 28H]
        cmp     edx, dword ptr [eax + 10H]
        jz      @@186
@@184:  mov     ecx, dword ptr [esp + 48H]
        mov     eax, dword ptr [esp + 28H]
        push    ecx
        call    Inline059;
        test    eax, eax
        jz      @@186
        mov     dword ptr [ebx], 28

@@185:  pop     edi
        pop     esi
        pop     ebp
        mov     eax, -4
        pop     ebx
        add     esp, 52
        ret     8

@@186:  mov     esi, dword ptr [esp + 48H]
        mov     edx, dword ptr [esi + 04H]
        mov     ecx, dword ptr [esi + 10H]
        mov     ebp, dword ptr [esp + 38H]
        mov     edi, dword ptr [esp + 28H]
        mov     eax, dword ptr [esi + 08H]
        sub     ebp, edx
        mov     edx, dword ptr [esi + 14H]
        sub     edi, ecx
        add     eax, ebp
        add     edx, edi
        mov     dword ptr [esi + 08H], eax
        mov     dword ptr [esi + 14H], edx
        mov     ecx, dword ptr [ebx + 1CH]
        mov     eax, dword ptr [ebx + 08H]
        add     ecx, edi
        test    eax, eax
        mov     dword ptr [ebx + 1CH], ecx
        jz      @@187
        test    edi, edi
        jz      @@187
        mov     edx, dword ptr [esi + 0CH]
        mov     eax, dword ptr [ebx + 18H]
        mov ecx,edi
        sub     edx, edi
        call    Adler32 // register calling convention
        mov     dword ptr [ebx + 18H], eax
        mov     dword ptr [esi + 30H], eax
@@187:  mov     ecx, dword ptr [ebx + 04H]
        mov     eax, dword ptr [ebx]
        neg     ecx
        sbb     ecx, ecx
        xor     edx, edx
        and     ecx, 00000040H
        cmp     eax, 11
        setne   dl
        dec     edx
        and     edx, 00000080H
        add     ecx, edx
        add     ecx, dword ptr [ebx + 3CH]
        test    ebp, ebp
        mov     dword ptr [esi + 2CH], ecx
        jnz     @@188
        test    edi, edi
        jz      @@189
@@188:  cmp     dword ptr [esp + 4CH], 4
        jnz     @@190
@@189:  mov     eax, dword ptr [esp + 2CH]
        test    eax, eax
        jne     @@177
        pop     edi
        pop     esi
        pop     ebp
        mov     eax, -5
        pop     ebx
        add     esp, 52
        ret     8

@@190:  mov     eax, dword ptr [esp + 2CH]
        pop     edi
        pop     esi
        pop     ebp
        pop     ebx
        add     esp, 52
        ret     8

@@191:  mov     eax, -2
        pop     ebx
        add     esp, 52
        ret     8

@@196:  sub     esp, 124
        mov     edx, dword ptr [esp + 00000088H]
        xor     eax, eax
        test    edx, edx
        mov     dword ptr [esp + 3CH], eax
        mov     dword ptr [esp + 40H], eax
        mov     dword ptr [esp + 44H], eax
        mov     dword ptr [esp + 48H], eax
        mov     dword ptr [esp + 4CH], eax
        push    ebx
        mov     dword ptr [esp + 54H], eax
        push    ebp
        mov     ebp, dword ptr [esp + 0000008CH]
        mov     dword ptr [esp + 5CH], eax
        push    esi
        mov     dword ptr [esp + 64H], eax
        jbe     @@198

@@197:  movzx   ecx, word ptr [ebp + eax*2]
        inc     word ptr [esp + ecx*2 + 48H]
        lea     ecx, [esp + ecx*2 + 48H]
        inc     eax
        cmp     eax, edx
        jc      @@197
@@198:  mov     esi, dword ptr [esp + 0000009CH]
        mov     eax, dword ptr [esi]
        mov     ebx, 15
        mov     dword ptr [esp + 10H], eax
        mov     dword ptr [esp + 18H], ebx

@@199:  cmp     word ptr [esp + ebx*2 + 48H], 0
        jnz     @@200
        dec     ebx
        cmp     ebx, 1
        jnc     @@199
@@200:  cmp     eax, ebx
        mov     dword ptr [esp + 18H], ebx
        jbe     @@201
        mov     dword ptr [esp + 10H], ebx
@@201:  test    ebx, ebx
        jnz     @@202
        mov     eax, dword ptr [esp + 00000098H]
        mov     edx, dword ptr [eax]
        mov     word ptr [esp + 0EH], bx
        mov     byte ptr [esp + 0CH], 64
        mov     byte ptr [esp + 0DH], 1
        mov     ecx, dword ptr [esp + 0CH]
        mov     dword ptr [edx], ecx
        mov     edx, dword ptr [eax]
        add     edx, 4
        mov     dword ptr [eax], edx
        mov     dword ptr [edx], ecx
        add     dword ptr [eax], 4
        mov     dword ptr [esi], 1
        pop     esi
        pop     ebp
        xor     eax, eax
        pop     ebx
        add     esp, 124
        ret     24

@@202:  mov     esi, 1

@@203:  cmp     word ptr [esp + esi*2 + 48H], 0
        jnz     @@208
        cmp     word ptr [esp + esi*2 + 4AH], 0
        jnz     @@204
        cmp     word ptr [esp + esi*2 + 4CH], 0
        jnz     @@205
        cmp     word ptr [esp + esi*2 + 4EH], 0
        jnz     @@206
        cmp     word ptr [esp + esi*2 + 50H], 0
        jnz     @@207
        add     esi, 5
        cmp     esi, 15
        jbe     @@203
        jmp     @@208

@@204:  inc     esi
        jmp     @@208

@@205:  add     esi, 2
        jmp     @@208

@@206:  add     esi, 3
        jmp     @@208

@@207:  add     esi, 4
@@208:  cmp     dword ptr [esp + 10H], esi
        jnc     @@209
        mov     dword ptr [esp + 10H], esi
@@209:  mov     edx, 1
        mov     eax, edx
@@210:  movzx   ecx, word ptr [esp + eax*2 + 48H]
        add     edx, edx
        sub     edx, ecx
        js      @@212
        inc     eax
        cmp     eax, 15
        jbe     @@210
        test    edx, edx
        push    edi
        mov     edi, dword ptr [esp + 00000090H]
        jle     @@213
        test    edi, edi
        jz      @@211
        cmp     ebx, 1
        jz      @@213
@@211:  pop     edi
        pop     esi
        pop     ebp
        or      eax, 0FFFFFFFFH
        pop     ebx
        add     esp, 124
        ret     24

@@212:  pop     esi
        pop     ebp
        or      eax, 0FFFFFFFFH
        pop     ebx
        add     esp, 124
        ret     24

@@213:
        mov     word ptr [esp + 6EH], 0
        mov     eax, 2

@@214:  mov     dx, word ptr [esp + eax + 6CH]
        add     dx, word ptr [esp + eax + 4CH]
        mov     cx, word ptr [esp + eax + 4EH]
        add     cx, dx
        mov     word ptr [esp + eax + 6EH], dx
        mov     word ptr [esp + eax + 70H], cx
        add     eax, 4
        cmp     eax, 30
        jc      @@214
        mov     ebx, dword ptr [esp + 00000098H]
        xor     eax, eax
        test    ebx, ebx
        jbe     @@217
@@215:  cmp     word ptr [ebp + eax*2], 0
        jz      @@216
        movzx   edx, word ptr [ebp + eax*2]
        movzx   ecx, word ptr [esp + edx*2 + 6CH]
        mov     edx, dword ptr [esp + 000000A4H]
        mov     word ptr [edx + ecx*2], ax
        movzx   edx, word ptr [ebp + eax*2]
        inc     word ptr [esp + edx*2 + 6CH]
        lea     edx, [esp + edx*2 + 6CH]
@@216:  inc     eax
        cmp     eax, ebx
        jc      @@215
@@217:  mov     eax, edi
        sub     eax, 0
        mov     edx, -1
        jz      @@219
        dec     eax
        jz      @@218
        mov     dword ptr [esp + 34H], offset @@265
        mov     dword ptr [esp + 30H], offset @@266
        mov     dword ptr [esp + 2CH], edx
        jmp     @@221

@@218:  mov     eax, offset @@263
        sub     eax, 514
        mov     dword ptr [esp + 34H], eax
        mov     eax, offset @@264
        sub     eax, 514
        mov     dword ptr [esp + 2CH], 256
        jmp     @@220

@@219:  mov     eax, dword ptr [esp + 000000A4H]
        mov     dword ptr [esp + 34H], eax
        mov     dword ptr [esp + 2CH], 19
@@220:  mov     dword ptr [esp + 30H], eax
@@221:  mov     eax, dword ptr [esp + 0000009CH]
        mov     ecx, dword ptr [eax]
        mov     dword ptr [esp + 20H], ecx
        mov     ecx, dword ptr [esp + 14H]
        mov     eax, 1
        shl     eax, cl
        mov     dword ptr [esp + 38H], edx
        xor     ebp, ebp
        xor     ebx, ebx
        cmp     edi, 1
        lea     edx, [eax - 01H]
        mov     dword ptr [esp + 18H], esi
        mov     dword ptr [esp + 3CH], eax
        mov     dword ptr [esp + 28H], eax
        mov     dword ptr [esp + 40H], edx
        jnz     @@222
        cmp     eax, 1456
        jae     @@244
@@222:  mov     eax, dword ptr [esp + 000000A4H]
        mov     dword ptr [esp + 24H], eax

@@223:  mov     cl, byte ptr [esp + 18H]
        mov     esi, dword ptr [esp + 24H]
        mov     ax, word ptr [esi]
        mov     edx, dword ptr [esp + 2CH]
        sub     cl, bl
        mov     byte ptr [esp + 11H], cl
        movzx   ecx, ax
        cmp     ecx, edx
        jge     @@224
        mov     byte ptr [esp + 10H], 0
        mov     word ptr [esp + 12H], ax
        jmp     @@226

@@224:  jle     @@225
        movzx   eax, word ptr [esi]
        mov     edx, dword ptr [esp + 30H]
        shl     eax, 1
        mov     cl, byte ptr [eax + edx]
        mov     edx, dword ptr [esp + 34H]
        mov     ax, word ptr [eax + edx]
        mov     byte ptr [esp + 10H], cl
        mov     word ptr [esp + 12H], ax
        jmp     @@226

@@225:  mov     byte ptr [esp + 10H], 96
        mov     word ptr [esp + 12H], 0
@@226:  mov     ecx, dword ptr [esp + 18H]
        mov     eax, dword ptr [esp + 3CH]
        sub     ecx, ebx
        mov     edx, 1
        shl     edx, cl
        mov     ecx, ebx
        mov     edi, ebp
        shr     edi, cl
        mov     ecx, dword ptr [esp + 20H]
        mov     dword ptr [esp + 44H], eax
        lea     esi, [edx*4]
        add     edi, eax
        lea     ecx, [ecx + edi*4]
        mov     edi, dword ptr [esp + 10H]
@@227:  sub     eax, edx
        sub     ecx, esi
        test    eax, eax
        mov     dword ptr [ecx], edi
        jnz     @@227
        mov     edx, dword ptr [esp + 18H]
        lea     ecx, [edx - 01H]
        mov     eax, 1
        shl     eax, cl
        test    ebp, eax
        jz      @@229
@@228:  shr     eax, 1
        test    ebp, eax
        jnz     @@228
@@229:  test    eax, eax
        jz      @@230
        lea     ecx, [eax - 01H]
        and     ecx, ebp
        add     ecx, eax
        mov     ebp, ecx
        jmp     @@231

@@230:  xor     ebp, ebp
@@231:  mov     esi, dword ptr [esp + 24H]
        add     esi, 2
        dec     word ptr [esp + edx*2 + 4CH]
        cmp     word ptr [esp + edx*2 + 4CH], 0
        mov     dword ptr [esp + 24H], esi
        jnz     @@232
        cmp     edx, dword ptr [esp + 1CH]
        je      @@238
        mov     ecx, dword ptr [esp + 00000094H]
        mov     edx, esi
        movzx   eax, word ptr [edx]
        movzx   edx, word ptr [ecx + eax*2]
        mov     dword ptr [esp + 18H], edx
@@232:  cmp     edx, dword ptr [esp + 14H]
        jbe     @@223
        mov     esi, dword ptr [esp + 40H]
        mov     eax, dword ptr [esp + 38H]
        and     esi, ebp
        cmp     esi, eax
        mov     dword ptr [esp + 48H], esi
        je      @@223
        test    ebx, ebx
        jnz     @@233
        mov     ebx, dword ptr [esp + 14H]
@@233:  mov     eax, dword ptr [esp + 20H]
        mov     ecx, dword ptr [esp + 44H]
        mov     edi, dword ptr [esp + 1CH]
        lea     edx, [eax + ecx*4]
        mov     ecx, dword ptr [esp + 18H]
        sub     ecx, ebx
        mov     dword ptr [esp + 20H], edx
        mov     eax, 1
        lea     edx, [ebx + ecx]
        shl     eax, cl
        cmp     edx, edi
        jnc     @@236
        lea     esi, [esp + edx*2 + 4CH]
@@234:  movzx   edi, word ptr [esi]
        sub     eax, edi
        test    eax, eax
        jle     @@235
        mov     edi, dword ptr [esp + 1CH]
        inc     ecx
        inc     edx
        add     esi, 2
        shl     eax, 1
        cmp     edx, edi
        jc      @@234
@@235:  mov     esi, dword ptr [esp + 48H]
@@236:  mov     edx, dword ptr [esp + 28H]
        mov     eax, 1
        shl     eax, cl
        add     edx, eax
        mov     dword ptr [esp + 3CH], eax
        cmp     dword ptr [esp + 00000090H], 1
        mov     dword ptr [esp + 28H], edx
        jnz     @@237
        mov     eax, edx
        cmp     eax, 1456
        jae     @@244
@@237:  mov     edx, esi
        mov     esi, dword ptr [esp + 0000009CH]
        mov     eax, dword ptr [esi]
        mov     byte ptr [eax + edx*4], cl
        mov     ecx, dword ptr [esi]
        mov     al, byte ptr [esp + 14H]
        mov     byte ptr [ecx + edx*4 + 01H], al
        mov     eax, dword ptr [esi]
        mov     ecx, dword ptr [esp + 20H]
        sub     ecx, eax
        sar     ecx, 2
        mov     dword ptr [esp + 38H], edx
        mov     word ptr [eax + edx*4 + 02H], cx
        jmp     @@223

@@238:  mov     edi, dword ptr [esp + 0000009CH]
        mov     al, dl
        sub     al, bl
        test    ebp, ebp
        mov     byte ptr [esp + 10H], 64
        mov     byte ptr [esp + 11H], al
        mov     word ptr [esp + 12H], 0
        jz      @@243
        mov     esi, dword ptr [esp + 20H]

@@239:  test    ebx, ebx
        jz      @@240
        mov     ecx, dword ptr [esp + 40H]
        mov     eax, dword ptr [esp + 38H]
        and     ecx, ebp
        cmp     ecx, eax
        jz      @@240
        mov     eax, dword ptr [esp + 14H]
        mov     esi, dword ptr [edi]
        xor     ebx, ebx
        mov     dword ptr [esp + 18H], eax
        mov     byte ptr [esp + 11H], al
        mov     edx, eax
@@240:  mov     ecx, ebx
        mov     eax, ebp
        shr     eax, cl
        mov     ecx, dword ptr [esp + 10H]
        mov     dword ptr [esi + eax*4], ecx
        lea     ecx, [edx - 01H]
        mov     eax, 1
        shl     eax, cl
        test    ebp, eax
        jz      @@242

@@241:  shr     eax, 1
        test    ebp, eax
        jnz     @@241
@@242:  test    eax, eax
        jz      @@243
        lea     ecx, [eax - 01H]
        and     ecx, ebp
        add     ecx, eax
        mov     ebp, ecx
        jnz     @@239
@@243:  mov     edx, dword ptr [esp + 28H]
        mov     ecx, dword ptr [edi]
        lea     eax, [edx*4]
        mov     edx, dword ptr [esp + 14H]
        add     ecx, eax
        mov     dword ptr [edi], ecx
        mov     ecx, dword ptr [esp + 000000A0H]
        pop     edi
        pop     esi
        pop     ebp
        mov     dword ptr [ecx], edx
        xor     eax, eax
        pop     ebx
        add     esp, 124
        ret     24

@@244:  pop     edi
        pop     esi
        pop     ebp
        mov     eax, 1
        pop     ebx
        add     esp, 124
        ret     24

        nop; nop

@@192:  dd @@070 // buffer is 8 bytes aligned
        dd @@176
        dd @@176
        dd @@176
        dd @@176
        dd @@176
        dd @@176
        dd @@176
        dd @@176
        dd @@077
        dd @@080
        dd @@081
        dd @@082
        dd @@091
        dd @@095
        dd @@098
        dd @@101
        dd @@110
        dd @@134
        dd @@145
        dd @@149
        dd @@156
        dd @@161
        dd @@169
        dd @@170
        dd @@176
        dd @@181
        dd @@182
        dd @@185

@@193:  dd @@086
        dd @@087
        dd @@088
        dd @@089

@@251:  dw 0010H, 0011H, 0012H, 0000H
        dw 0008H, 0007H, 0009H, 0006H
        dw 000AH, 0005H, 000BH, 0004H
        dw 000CH, 0003H, 000DH, 0002H
        dw 000EH, 0001H, 000FH, 0000H

@@249:  db 60H, 07H, 00H, 00H, 00H, 08H, 50H, 00H
        db 00H, 08H, 10H, 00H, 14H, 08H, 73H, 00H
        db 12H, 07H, 1FH, 00H, 00H, 08H, 70H, 00H
        db 00H, 08H, 30H, 00H, 00H, 09H, 0C0H, 00H
        db 10H, 07H, 0AH, 00H, 00H, 08H, 60H, 00H
        db 00H, 08H, 20H, 00H, 00H, 09H, 0A0H, 00H
        db 00H, 08H, 00H, 00H, 00H, 08H, 80H, 00H
        db 00H, 08H, 40H, 00H, 00H, 09H, 0E0H, 00H
        db 10H, 07H, 06H, 00H, 00H, 08H, 58H, 00H
        db 00H, 08H, 18H, 00H, 00H, 09H, 90H, 00H
        db 13H, 07H, 3BH, 00H, 00H, 08H, 78H, 00H
        db 00H, 08H, 38H, 00H, 00H, 09H, 0D0H, 00H
        db 11H, 07H, 11H, 00H, 00H, 08H, 68H, 00H
        db 00H, 08H, 28H, 00H, 00H, 09H, 0B0H, 00H
        db 00H, 08H, 08H, 00H, 00H, 08H, 88H, 00H
        db 00H, 08H, 48H, 00H, 00H, 09H, 0F0H, 00H
        db 10H, 07H, 04H, 00H, 00H, 08H, 54H, 00H
        db 00H, 08H, 14H, 00H, 15H, 08H, 0E3H, 00H
        db 13H, 07H, 2BH, 00H, 00H, 08H, 74H, 00H
        db 00H, 08H, 34H, 00H, 00H, 09H, 0C8H, 00H
        db 11H, 07H, 0DH, 00H, 00H, 08H, 64H, 00H
        db 00H, 08H, 24H, 00H, 00H, 09H, 0A8H, 00H
        db 00H, 08H, 04H, 00H, 00H, 08H, 84H, 00H
        db 00H, 08H, 44H, 00H, 00H, 09H, 0E8H, 00H
        db 10H, 07H, 08H, 00H, 00H, 08H, 5CH, 00H
        db 00H, 08H, 1CH, 00H, 00H, 09H, 98H, 00H
        db 14H, 07H, 53H, 00H, 00H, 08H, 7CH, 00H
        db 00H, 08H, 3CH, 00H, 00H, 09H, 0D8H, 00H
        db 12H, 07H, 17H, 00H, 00H, 08H, 6CH, 00H
        db 00H, 08H, 2CH, 00H, 00H, 09H, 0B8H, 00H
        db 00H, 08H, 0CH, 00H, 00H, 08H, 8CH, 00H
        db 00H, 08H, 4CH, 00H, 00H, 09H, 0F8H, 00H
        db 10H, 07H, 03H, 00H, 00H, 08H, 52H, 00H
        db 00H, 08H, 12H, 00H, 15H, 08H, 0A3H, 00H
        db 13H, 07H, 23H, 00H, 00H, 08H, 72H, 00H
        db 00H, 08H, 32H, 00H, 00H, 09H, 0C4H, 00H
        db 11H, 07H, 0BH, 00H, 00H, 08H, 62H, 00H
        db 00H, 08H, 22H, 00H, 00H, 09H, 0A4H, 00H
        db 00H, 08H, 02H, 00H, 00H, 08H, 82H, 00H
        db 00H, 08H, 42H, 00H, 00H, 09H, 0E4H, 00H
        db 10H, 07H, 07H, 00H, 00H, 08H, 5AH, 00H
        db 00H, 08H, 1AH, 00H, 00H, 09H, 94H, 00H
        db 14H, 07H, 43H, 00H, 00H, 08H, 7AH, 00H
        db 00H, 08H, 3AH, 00H, 00H, 09H, 0D4H, 00H
        db 12H, 07H, 13H, 00H, 00H, 08H, 6AH, 00H
        db 00H, 08H, 2AH, 00H, 00H, 09H, 0B4H, 00H
        db 00H, 08H, 0AH, 00H, 00H, 08H, 8AH, 00H
        db 00H, 08H, 4AH, 00H, 00H, 09H, 0F4H, 00H
        db 10H, 07H, 05H, 00H, 00H, 08H, 56H, 00H
        db 00H, 08H, 16H, 00H, 40H, 08H, 00H, 00H
        db 13H, 07H, 33H, 00H, 00H, 08H, 76H, 00H
        db 00H, 08H, 36H, 00H, 00H, 09H, 0CCH, 00H
        db 11H, 07H, 0FH, 00H, 00H, 08H, 66H, 00H
        db 00H, 08H, 26H, 00H, 00H, 09H, 0ACH, 00H
        db 00H, 08H, 06H, 00H, 00H, 08H, 86H, 00H
        db 00H, 08H, 46H, 00H, 00H, 09H, 0ECH, 00H
        db 10H, 07H, 09H, 00H, 00H, 08H, 5EH, 00H
        db 00H, 08H, 1EH, 00H, 00H, 09H, 9CH, 00H
        db 14H, 07H, 63H, 00H, 00H, 08H, 7EH, 00H
        db 00H, 08H, 3EH, 00H, 00H, 09H, 0DCH, 00H
        db 12H, 07H, 1BH, 00H, 00H, 08H, 6EH, 00H
        db 00H, 08H, 2EH, 00H, 00H, 09H, 0BCH, 00H
        db 00H, 08H, 0EH, 00H, 00H, 08H, 8EH, 00H
        db 00H, 08H, 4EH, 00H, 00H, 09H, 0FCH, 00H
        db 60H, 07H, 00H, 00H, 00H, 08H, 51H, 00H
        db 00H, 08H, 11H, 00H, 15H, 08H, 83H, 00H
        db 12H, 07H, 1FH, 00H, 00H, 08H, 71H, 00H
        db 00H, 08H, 31H, 00H, 00H, 09H, 0C2H, 00H
        db 10H, 07H, 0AH, 00H, 00H, 08H, 61H, 00H
        db 00H, 08H, 21H, 00H, 00H, 09H, 0A2H, 00H
        db 00H, 08H, 01H, 00H, 00H, 08H, 81H, 00H
        db 00H, 08H, 41H, 00H, 00H, 09H, 0E2H, 00H
        db 10H, 07H, 06H, 00H, 00H, 08H, 59H, 00H
        db 00H, 08H, 19H, 00H, 00H, 09H, 92H, 00H
        db 13H, 07H, 3BH, 00H, 00H, 08H, 79H, 00H
        db 00H, 08H, 39H, 00H, 00H, 09H, 0D2H, 00H
        db 11H, 07H, 11H, 00H, 00H, 08H, 69H, 00H
        db 00H, 08H, 29H, 00H, 00H, 09H, 0B2H, 00H
        db 00H, 08H, 09H, 00H, 00H, 08H, 89H, 00H
        db 00H, 08H, 49H, 00H, 00H, 09H, 0F2H, 00H
        db 10H, 07H, 04H, 00H, 00H, 08H, 55H, 00H
        db 00H, 08H, 15H, 00H, 10H, 08H, 02H, 01H
        db 13H, 07H, 2BH, 00H, 00H, 08H, 75H, 00H
        db 00H, 08H, 35H, 00H, 00H, 09H, 0CAH, 00H
        db 11H, 07H, 0DH, 00H, 00H, 08H, 65H, 00H
        db 00H, 08H, 25H, 00H, 00H, 09H, 0AAH, 00H
        db 00H, 08H, 05H, 00H, 00H, 08H, 85H, 00H
        db 00H, 08H, 45H, 00H, 00H, 09H, 0EAH, 00H
        db 10H, 07H, 08H, 00H, 00H, 08H, 5DH, 00H
        db 00H, 08H, 1DH, 00H, 00H, 09H, 9AH, 00H
        db 14H, 07H, 53H, 00H, 00H, 08H, 7DH, 00H
        db 00H, 08H, 3DH, 00H, 00H, 09H, 0DAH, 00H
        db 12H, 07H, 17H, 00H, 00H, 08H, 6DH, 00H
        db 00H, 08H, 2DH, 00H, 00H, 09H, 0BAH, 00H
        db 00H, 08H, 0DH, 00H, 00H, 08H, 8DH, 00H
        db 00H, 08H, 4DH, 00H, 00H, 09H, 0FAH, 00H
        db 10H, 07H, 03H, 00H, 00H, 08H, 53H, 00H
        db 00H, 08H, 13H, 00H, 15H, 08H, 0C3H, 00H
        db 13H, 07H, 23H, 00H, 00H, 08H, 73H, 00H
        db 00H, 08H, 33H, 00H, 00H, 09H, 0C6H, 00H
        db 11H, 07H, 0BH, 00H, 00H, 08H, 63H, 00H
        db 00H, 08H, 23H, 00H, 00H, 09H, 0A6H, 00H
        db 00H, 08H, 03H, 00H, 00H, 08H, 83H, 00H
        db 00H, 08H, 43H, 00H, 00H, 09H, 0E6H, 00H
        db 10H, 07H, 07H, 00H, 00H, 08H, 5BH, 00H
        db 00H, 08H, 1BH, 00H, 00H, 09H, 96H, 00H
        db 14H, 07H, 43H, 00H, 00H, 08H, 7BH, 00H
        db 00H, 08H, 3BH, 00H, 00H, 09H, 0D6H, 00H
        db 12H, 07H, 13H, 00H, 00H, 08H, 6BH, 00H
        db 00H, 08H, 2BH, 00H, 00H, 09H, 0B6H, 00H
        db 00H, 08H, 0BH, 00H, 00H, 08H, 8BH, 00H
        db 00H, 08H, 4BH, 00H, 00H, 09H, 0F6H, 00H
        db 10H, 07H, 05H, 00H, 00H, 08H, 57H, 00H
        db 00H, 08H, 17H, 00H, 40H, 08H, 00H, 00H
        db 13H, 07H, 33H, 00H, 00H, 08H, 77H, 00H
        db 00H, 08H, 37H, 00H, 00H, 09H, 0CEH, 00H
        db 11H, 07H, 0FH, 00H, 00H, 08H, 67H, 00H
        db 00H, 08H, 27H, 00H, 00H, 09H, 0AEH, 00H
        db 00H, 08H, 07H, 00H, 00H, 08H, 87H, 00H
        db 00H, 08H, 47H, 00H, 00H, 09H, 0EEH, 00H
        db 10H, 07H, 09H, 00H, 00H, 08H, 5FH, 00H
        db 00H, 08H, 1FH, 00H, 00H, 09H, 9EH, 00H
        db 14H, 07H, 63H, 00H, 00H, 08H, 7FH, 00H
        db 00H, 08H, 3FH, 00H, 00H, 09H, 0DEH, 00H
        db 12H, 07H, 1BH, 00H, 00H, 08H, 6FH, 00H
        db 00H, 08H, 2FH, 00H, 00H, 09H, 0BEH, 00H
        db 00H, 08H, 0FH, 00H, 00H, 08H, 8FH, 00H
        db 00H, 08H, 4FH, 00H, 00H, 09H, 0FEH, 00H
        db 60H, 07H, 00H, 00H, 00H, 08H, 50H, 00H
        db 00H, 08H, 10H, 00H, 14H, 08H, 73H, 00H
        db 12H, 07H, 1FH, 00H, 00H, 08H, 70H, 00H
        db 00H, 08H, 30H, 00H, 00H, 09H, 0C1H, 00H
        db 10H, 07H, 0AH, 00H, 00H, 08H, 60H, 00H
        db 00H, 08H, 20H, 00H, 00H, 09H, 0A1H, 00H
        db 00H, 08H, 00H, 00H, 00H, 08H, 80H, 00H
        db 00H, 08H, 40H, 00H, 00H, 09H, 0E1H, 00H
        db 10H, 07H, 06H, 00H, 00H, 08H, 58H, 00H
        db 00H, 08H, 18H, 00H, 00H, 09H, 91H, 00H
        db 13H, 07H, 3BH, 00H, 00H, 08H, 78H, 00H
        db 00H, 08H, 38H, 00H, 00H, 09H, 0D1H, 00H
        db 11H, 07H, 11H, 00H, 00H, 08H, 68H, 00H
        db 00H, 08H, 28H, 00H, 00H, 09H, 0B1H, 00H
        db 00H, 08H, 08H, 00H, 00H, 08H, 88H, 00H
        db 00H, 08H, 48H, 00H, 00H, 09H, 0F1H, 00H
        db 10H, 07H, 04H, 00H, 00H, 08H, 54H, 00H
        db 00H, 08H, 14H, 00H, 15H, 08H, 0E3H, 00H
        db 13H, 07H, 2BH, 00H, 00H, 08H, 74H, 00H
        db 00H, 08H, 34H, 00H, 00H, 09H, 0C9H, 00H
        db 11H, 07H, 0DH, 00H, 00H, 08H, 64H, 00H
        db 00H, 08H, 24H, 00H, 00H, 09H, 0A9H, 00H
        db 00H, 08H, 04H, 00H, 00H, 08H, 84H, 00H
        db 00H, 08H, 44H, 00H, 00H, 09H, 0E9H, 00H
        db 10H, 07H, 08H, 00H, 00H, 08H, 5CH, 00H
        db 00H, 08H, 1CH, 00H, 00H, 09H, 99H, 00H
        db 14H, 07H, 53H, 00H, 00H, 08H, 7CH, 00H
        db 00H, 08H, 3CH, 00H, 00H, 09H, 0D9H, 00H
        db 12H, 07H, 17H, 00H, 00H, 08H, 6CH, 00H
        db 00H, 08H, 2CH, 00H, 00H, 09H, 0B9H, 00H
        db 00H, 08H, 0CH, 00H, 00H, 08H, 8CH, 00H
        db 00H, 08H, 4CH, 00H, 00H, 09H, 0F9H, 00H
        db 10H, 07H, 03H, 00H, 00H, 08H, 52H, 00H
        db 00H, 08H, 12H, 00H, 15H, 08H, 0A3H, 00H
        db 13H, 07H, 23H, 00H, 00H, 08H, 72H, 00H
        db 00H, 08H, 32H, 00H, 00H, 09H, 0C5H, 00H
        db 11H, 07H, 0BH, 00H, 00H, 08H, 62H, 00H
        db 00H, 08H, 22H, 00H, 00H, 09H, 0A5H, 00H
        db 00H, 08H, 02H, 00H, 00H, 08H, 82H, 00H
        db 00H, 08H, 42H, 00H, 00H, 09H, 0E5H, 00H
        db 10H, 07H, 07H, 00H, 00H, 08H, 5AH, 00H
        db 00H, 08H, 1AH, 00H, 00H, 09H, 95H, 00H
        db 14H, 07H, 43H, 00H, 00H, 08H, 7AH, 00H
        db 00H, 08H, 3AH, 00H, 00H, 09H, 0D5H, 00H
        db 12H, 07H, 13H, 00H, 00H, 08H, 6AH, 00H
        db 00H, 08H, 2AH, 00H, 00H, 09H, 0B5H, 00H
        db 00H, 08H, 0AH, 00H, 00H, 08H, 8AH, 00H
        db 00H, 08H, 4AH, 00H, 00H, 09H, 0F5H, 00H
        db 10H, 07H, 05H, 00H, 00H, 08H, 56H, 00H
        db 00H, 08H, 16H, 00H, 40H, 08H, 00H, 00H
        db 13H, 07H, 33H, 00H, 00H, 08H, 76H, 00H
        db 00H, 08H, 36H, 00H, 00H, 09H, 0CDH, 00H
        db 11H, 07H, 0FH, 00H, 00H, 08H, 66H, 00H
        db 00H, 08H, 26H, 00H, 00H, 09H, 0ADH, 00H
        db 00H, 08H, 06H, 00H, 00H, 08H, 86H, 00H
        db 00H, 08H, 46H, 00H, 00H, 09H, 0EDH, 00H
        db 10H, 07H, 09H, 00H, 00H, 08H, 5EH, 00H
        db 00H, 08H, 1EH, 00H, 00H, 09H, 9DH, 00H
        db 14H, 07H, 63H, 00H, 00H, 08H, 7EH, 00H
        db 00H, 08H, 3EH, 00H, 00H, 09H, 0DDH, 00H
        db 12H, 07H, 1BH, 00H, 00H, 08H, 6EH, 00H
        db 00H, 08H, 2EH, 00H, 00H, 09H, 0BDH, 00H
        db 00H, 08H, 0EH, 00H, 00H, 08H, 8EH, 00H
        db 00H, 08H, 4EH, 00H, 00H, 09H, 0FDH, 00H
        db 60H, 07H, 00H, 00H, 00H, 08H, 51H, 00H
        db 00H, 08H, 11H, 00H, 15H, 08H, 83H, 00H
        db 12H, 07H, 1FH, 00H, 00H, 08H, 71H, 00H
        db 00H, 08H, 31H, 00H, 00H, 09H, 0C3H, 00H
        db 10H, 07H, 0AH, 00H, 00H, 08H, 61H, 00H
        db 00H, 08H, 21H, 00H, 00H, 09H, 0A3H, 00H
        db 00H, 08H, 01H, 00H, 00H, 08H, 81H, 00H
        db 00H, 08H, 41H, 00H, 00H, 09H, 0E3H, 00H
        db 10H, 07H, 06H, 00H, 00H, 08H, 59H, 00H
        db 00H, 08H, 19H, 00H, 00H, 09H, 93H, 00H
        db 13H, 07H, 3BH, 00H, 00H, 08H, 79H, 00H
        db 00H, 08H, 39H, 00H, 00H, 09H, 0D3H, 00H
        db 11H, 07H, 11H, 00H, 00H, 08H, 69H, 00H
        db 00H, 08H, 29H, 00H, 00H, 09H, 0B3H, 00H
        db 00H, 08H, 09H, 00H, 00H, 08H, 89H, 00H
        db 00H, 08H, 49H, 00H, 00H, 09H, 0F3H, 00H
        db 10H, 07H, 04H, 00H, 00H, 08H, 55H, 00H
        db 00H, 08H, 15H, 00H, 10H, 08H, 02H, 01H
        db 13H, 07H, 2BH, 00H, 00H, 08H, 75H, 00H
        db 00H, 08H, 35H, 00H, 00H, 09H, 0CBH, 00H
        db 11H, 07H, 0DH, 00H, 00H, 08H, 65H, 00H
        db 00H, 08H, 25H, 00H, 00H, 09H, 0ABH, 00H
        db 00H, 08H, 05H, 00H, 00H, 08H, 85H, 00H
        db 00H, 08H, 45H, 00H, 00H, 09H, 0EBH, 00H
        db 10H, 07H, 08H, 00H, 00H, 08H, 5DH, 00H
        db 00H, 08H, 1DH, 00H, 00H, 09H, 9BH, 00H
        db 14H, 07H, 53H, 00H, 00H, 08H, 7DH, 00H
        db 00H, 08H, 3DH, 00H, 00H, 09H, 0DBH, 00H
        db 12H, 07H, 17H, 00H, 00H, 08H, 6DH, 00H
        db 00H, 08H, 2DH, 00H, 00H, 09H, 0BBH, 00H
        db 00H, 08H, 0DH, 00H, 00H, 08H, 8DH, 00H
        db 00H, 08H, 4DH, 00H, 00H, 09H, 0FBH, 00H
        db 10H, 07H, 03H, 00H, 00H, 08H, 53H, 00H
        db 00H, 08H, 13H, 00H, 15H, 08H, 0C3H, 00H
        db 13H, 07H, 23H, 00H, 00H, 08H, 73H, 00H
        db 00H, 08H, 33H, 00H, 00H, 09H, 0C7H, 00H
        db 11H, 07H, 0BH, 00H, 00H, 08H, 63H, 00H
        db 00H, 08H, 23H, 00H, 00H, 09H, 0A7H, 00H
        db 00H, 08H, 03H, 00H, 00H, 08H, 83H, 00H
        db 00H, 08H, 43H, 00H, 00H, 09H, 0E7H, 00H
        db 10H, 07H, 07H, 00H, 00H, 08H, 5BH, 00H
        db 00H, 08H, 1BH, 00H, 00H, 09H, 97H, 00H
        db 14H, 07H, 43H, 00H, 00H, 08H, 7BH, 00H
        db 00H, 08H, 3BH, 00H, 00H, 09H, 0D7H, 00H
        db 12H, 07H, 13H, 00H, 00H, 08H, 6BH, 00H
        db 00H, 08H, 2BH, 00H, 00H, 09H, 0B7H, 00H
        db 00H, 08H, 0BH, 00H, 00H, 08H, 8BH, 00H
        db 00H, 08H, 4BH, 00H, 00H, 09H, 0F7H, 00H
        db 10H, 07H, 05H, 00H, 00H, 08H, 57H, 00H
        db 00H, 08H, 17H, 00H, 40H, 08H, 00H, 00H
        db 13H, 07H, 33H, 00H, 00H, 08H, 77H, 00H
        db 00H, 08H, 37H, 00H, 00H, 09H, 0CFH, 00H
        db 11H, 07H, 0FH, 00H, 00H, 08H, 67H, 00H
        db 00H, 08H, 27H, 00H, 00H, 09H, 0AFH, 00H
        db 00H, 08H, 07H, 00H, 00H, 08H, 87H, 00H
        db 00H, 08H, 47H, 00H, 00H, 09H, 0EFH, 00H
        db 10H, 07H, 09H, 00H, 00H, 08H, 5FH, 00H
        db 00H, 08H, 1FH, 00H, 00H, 09H, 9FH, 00H
        db 14H, 07H, 63H, 00H, 00H, 08H, 7FH, 00H
        db 00H, 08H, 3FH, 00H, 00H, 09H, 0DFH, 00H
        db 12H, 07H, 1BH, 00H, 00H, 08H, 6FH, 00H
        db 00H, 08H, 2FH, 00H, 00H, 09H, 0BFH, 00H
        db 00H, 08H, 0FH, 00H, 00H, 08H, 8FH, 00H
        db 00H, 08H, 4FH, 00H, 00H, 09H, 0FFH, 00H

@@250:  db 10H, 05H, 01H, 00H, 17H, 05H, 01H, 01H
        db 13H, 05H, 11H, 00H, 1BH, 05H, 01H, 10H
        db 11H, 05H, 05H, 00H, 19H, 05H, 01H, 04H
        db 15H, 05H, 41H, 00H, 1DH, 05H, 01H, 40H
        db 10H, 05H, 03H, 00H, 18H, 05H, 01H, 02H
        db 14H, 05H, 21H, 00H, 1CH, 05H, 01H, 20H
        db 12H, 05H, 09H, 00H, 1AH, 05H, 01H, 08H
        db 16H, 05H, 81H, 00H, 40H, 05H, 00H, 00H
        db 10H, 05H, 02H, 00H, 17H, 05H, 81H, 01H
        db 13H, 05H, 19H, 00H, 1BH, 05H, 01H, 18H
        db 11H, 05H, 07H, 00H, 19H, 05H, 01H, 06H
        db 15H, 05H, 61H, 00H, 1DH, 05H, 01H, 60H
        db 10H, 05H, 04H, 00H, 18H, 05H, 01H, 03H
        db 14H, 05H, 31H, 00H, 1CH, 05H, 01H, 30H
        db 12H, 05H, 0DH, 00H, 1AH, 05H, 01H, 0CH
        db 16H, 05H, 0C1H, 00H, 40H, 05H, 00H, 00H

@@263:  db 03H, 00H, 04H, 00H, 05H, 00H, 06H, 00H
        db 07H, 00H, 08H, 00H, 09H, 00H, 0AH, 00H
        db 0BH, 00H, 0DH, 00H, 0FH, 00H, 11H, 00H
        db 13H, 00H, 17H, 00H, 1BH, 00H, 1FH, 00H
        db 23H, 00H, 2BH, 00H, 33H, 00H, 3BH, 00H
        db 43H, 00H, 53H, 00H, 63H, 00H, 73H, 00H
        db 83H, 00H, 0A3H, 00H, 0C3H, 00H, 0E3H, 00H
        db 02H, 01H, 00H, 00H, 00H, 00H, 00H, 00H

@@264:  db 10H, 00H, 10H, 00H, 10H, 00H, 10H, 00H
        db 10H, 00H, 10H, 00H, 10H, 00H, 10H, 00H
        db 11H, 00H, 11H, 00H, 11H, 00H, 11H, 00H
        db 12H, 00H, 12H, 00H, 12H, 00H, 12H, 00H
        db 13H, 00H, 13H, 00H, 13H, 00H, 13H, 00H
        db 14H, 00H, 14H, 00H, 14H, 00H, 14H, 00H
        db 15H, 00H, 15H, 00H, 15H, 00H, 15H, 00H
        db 10H, 00H, 0C9H, 00H, 0C4H, 00H, 00H, 00H

@@265:  db 01H, 00H, 02H, 00H, 03H, 00H, 04H, 00H
        db 05H, 00H, 07H, 00H, 09H, 00H, 0DH, 00H
        db 11H, 00H, 19H, 00H, 21H, 00H, 31H, 00H
        db 41H, 00H, 61H, 00H, 81H, 00H, 0C1H, 00H
        db 01H, 01H, 81H, 01H, 01H, 02H, 01H, 03H
        db 01H, 04H, 01H, 06H, 01H, 08H, 01H, 0CH
        db 01H, 10H, 01H, 18H, 01H, 20H, 01H, 30H
        db 01H, 40H, 01H, 60H, 00H, 00H, 00H, 00H

@@266:  db 10H, 00H, 10H, 00H, 10H, 00H, 10H, 00H
        db 11H, 00H, 11H, 00H, 12H, 00H, 12H, 00H
        db 13H, 00H, 13H, 00H, 14H, 00H, 14H, 00H
        db 15H, 00H, 15H, 00H, 16H, 00H, 16H, 00H
        db 17H, 00H, 17H, 00H, 18H, 00H, 18H, 00H
        db 19H, 00H, 19H, 00H, 1AH, 00H, 1AH, 00H
        db 1BH, 00H, 1BH, 00H, 1CH, 00H, 1CH, 00H
        db 1DH, 00H, 1DH, 00H, 40H, 00H, 40H, 00H
end;

function inflateEnd;
asm  pop ebp  // auto-generated push ebp; mov ebp,esp
        push    esi
        mov     esi, dword ptr [esp + 08H]
        test    esi, esi
        jz      @@195
        mov     eax, dword ptr [esi + 1CH]
        test    eax, eax
        jz      @@195
        mov     ecx, dword ptr [esi + 24H]
        test    ecx, ecx
        jz      @@195
        mov     eax, dword ptr [eax + 34H]
        test    eax, eax
        jz      @@194
        push    eax
        mov     eax, dword ptr [esi + 28H]
        push    eax
        call    ecx
@@194:  mov     ecx, dword ptr [esi + 1CH]
        mov     edx, dword ptr [esi + 28H]
        push    ecx
        push    edx
        call    dword ptr [esi + 24H]
        mov     dword ptr [esi + 1CH], 0
        xor     eax, eax
        pop     esi
        ret     4
@@195:  mov     eax, -2
        pop     esi
        ret     4
end;

function adler32;
// our optimized asm version, faster than the original zlib C implementation
asm
	push      ebx
	push      esi
	push      edi
	mov       edi,eax
	shr       edi,16
	movzx     ebx,ax
	push      ebp
	mov       esi,edx
	test      esi,esi
	mov       ebp,ecx
	jne       @31
	mov       eax,1
	jmp       @32
@31:    test      ebp,ebp
	jbe       @34
@33:    cmp       ebp,5552
	jae        @35
	mov       eax,ebp
	jmp        @36
        nop; nop
@35:    mov       eax,5552
@36:    sub       ebp,eax
	cmp       eax,16
	jl        @38
	xor       edx,edx
	xor       ecx,ecx
@39:    sub       eax,16
	mov       dl,[esi]
	mov       cl,[esi+1]
	add       ebx,edx
	add       edi,ebx
	add       ebx,ecx
	mov       dl,[esi+2]
	add       edi,ebx
	add       ebx,edx
	mov       cl,[esi+3]
	add       edi,ebx
	add       ebx,ecx
	mov       dl,[esi+4]
	add       edi,ebx
	add       ebx,edx
	mov       cl,[esi+5]
	add       edi,ebx
	add       ebx,ecx
	mov       dl,[esi+6]
	add       edi,ebx
	add       ebx,edx
	mov       cl,[esi+7]
	add       edi,ebx
	add       ebx,ecx
	mov       dl,[esi+8]
	add       edi,ebx
	add       ebx,edx
	mov       cl,[esi+9]
	add       edi,ebx
	add       ebx,ecx
	mov       dl,[esi+10]
	add       edi,ebx
	add       ebx,edx
	mov       cl,[esi+11]
	add       edi,ebx
	add       ebx,ecx
	mov       dl,[esi+12]
	add       edi,ebx
	add       ebx,edx
	mov       cl,[esi+13]
	add       edi,ebx
	add       ebx,ecx
	mov       dl,[esi+14]
	add       edi,ebx
	add       ebx,edx
	mov       cl,[esi+15]
	add       edi,ebx
	add       ebx,ecx
	cmp       eax,16
	lea       esi,[esi+16]
	lea       edi,[edi+ebx]
	jge       @39
@38:    test      eax,eax
	je        @42
@43:    xor       edx,edx
	mov       dl,[esi]
	add       ebx,edx
	dec       eax
	lea       esi,[esi+1]
        lea       edi,[edi+ebx]
	jg        @43
@42:    mov       ecx,65521
	mov       eax,ebx
	xor       edx,edx
	div       ecx
	mov       ebx,edx
	mov       ecx,65521
	mov       eax,edi
	xor       edx,edx
	div       ecx
	test      ebp,ebp
	mov       edi,edx
	ja        @33
@34:    mov       eax,edi
	shl       eax,16
	or        eax,ebx
@45:
@32:    pop       ebp
	pop       edi
	pop       esi
	pop       ebx
end;

{$define BYFOUR}
// if defined, the crc32 hashing is performed using 8 tables, for better
// CPU pipelining and faster execution

var
  // tables content is created from code in initialization section below
  // (save 8 KB of code size from standard crc32.obj, with no speed penalty)
  crc32tab: array[0..{$ifdef BYFOUR}7{$else}0{$endif},byte] of cardinal;

function crc32(crc: cardinal; buf: PAnsiChar; len: cardinal): cardinal;
// adapted from fast Aleksandr Sharahov version
asm
  test edx, edx
  jz   @ret
  neg  ecx
  jz   @ret
  not eax
  push ebx
{$ifdef BYFOUR}
@head:
  test dl, 3
  jz   @bodyinit
  movzx ebx, byte [edx]
  inc  edx
  xor  bl, al
  shr  eax, 8
  xor  eax,dword ptr [ebx*4 + crc32tab]
  inc  ecx
  jnz  @head
  pop  ebx
  not eax
  ret
@ret:
  rep ret
@bodyinit:
  sub  edx, ecx
  add  ecx, 8
  jg   @bodydone
  push esi
  push edi
  mov  edi, edx
  mov  edx, eax
@bodyloop:
  mov ebx, [edi + ecx - 4]
  xor edx, [edi + ecx - 8]
  movzx esi, bl
  mov eax,dword ptr [esi*4 + crc32tab + 1024*3]
  movzx esi, bh
  xor eax,dword ptr [esi*4 + crc32tab + 1024*2]
  shr ebx, 16
  movzx esi, bl
  xor eax,dword ptr [esi*4 + crc32tab + 1024*1]
  movzx esi, bh
  xor eax,dword ptr [esi*4 + crc32tab + 1024*0]
  movzx esi, dl
  xor eax,dword ptr [esi*4 + crc32tab + 1024*7]
  movzx esi, dh
  xor eax,dword ptr [esi*4 + crc32tab + 1024*6]
  shr edx, 16
  movzx esi, dl
  xor eax,dword ptr [esi*4 + crc32tab + 1024*5]
  movzx esi, dh
  xor eax,dword ptr [esi*4 + crc32tab + 1024*4]
  add ecx, 8
  jg  @done
  mov ebx, [edi + ecx - 4]
  xor eax, [edi + ecx - 8]
  movzx esi, bl
  mov edx,dword ptr [esi*4 + crc32tab + 1024*3]
  movzx esi, bh
  xor edx,dword ptr [esi*4 + crc32tab + 1024*2]
  shr ebx, 16
  movzx esi, bl
  xor edx,dword ptr [esi*4 + crc32tab + 1024*1]
  movzx esi, bh
  xor edx,dword ptr [esi*4 + crc32tab + 1024*0]
  movzx esi, al
  xor edx,dword ptr [esi*4 + crc32tab + 1024*7]
  movzx esi, ah
  xor edx,dword ptr [esi*4 + crc32tab + 1024*6]
  shr eax, 16
  movzx esi, al
  xor edx,dword ptr [esi*4 + crc32tab + 1024*5]
  movzx esi, ah
  xor edx,dword ptr [esi*4 + crc32tab + 1024*4]
  add ecx, 8
  jle @bodyloop
  mov eax, edx
@done:
  mov edx, edi
  pop edi
  pop esi
@bodydone:
  sub ecx, 8
  jl @tail
  pop ebx
  not eax
  ret
@tail:
  movzx ebx,byte ptr [edx + ecx]
  xor bl,al
  shr eax,8
  xor eax,dword ptr [ebx*4 + crc32tab]
  inc ecx
  jnz @tail
  pop ebx
  not eax
{$else}
  sub edx,ecx
@next:
  movzx ebx,byte ptr [edx + ecx]
  xor bl, al
  shr eax, 8
  xor eax, [ebx*4 + crc32tab]
  add ecx, 1
  jnz @next
  pop ebx
  not eax
  ret
@ret:
  db $f3 // rep ret
{$endif BYFOUR}
end;

function get_crc_table: pointer;
begin
  result := @crc32tab;
end;

function zcalloc(AppData: Pointer; Items, Size: cardinal): Pointer;
begin // direct use of the (FastMM4) delphi heap for all zip memory allocation
  Getmem(result,Items * Size);
end;

procedure zcfree(AppData, Block: Pointer);
begin // direct use of the (FastMM4) delphi heap for all zip memory allocation
  FreeMem(Block);
end;

procedure _memcpy(dest, src: Pointer; count: integer); cdecl;
begin // will use fastcode if compiled within
  Move(src^, dest^, count);
end;

procedure _memset(dest: Pointer; val: Integer; count: integer); cdecl;
begin // will use fastcode if compiled within
  FillChar(dest^, count, val);
end;

{$else}

{$ifdef USEDELPHIZLIB} // Delphi linker is really bugged -> use slow ZLib.dcu
function deflate(var strm: TZStream; flush: integer): integer; cdecl;
begin
  result := ZLib.deflate(z_stream(strm),flush);
end;
function deflateEnd(var strm: TZStream): integer; cdecl;
begin
  result := ZLib.deflateEnd(z_stream(strm));
end;
function inflate(var strm: TZStream; flush: integer): integer; cdecl;
begin
  result := ZLib.inflate(z_stream(strm),flush);
end;
function inflateEnd(var strm: TZStream): integer; cdecl;
begin
  result := ZLib.inflateEnd(z_stream(strm));
end;
function adler32(adler: TZCRC; buf: PAnsiChar; len: cardinal): TZCRC; cdecl;
begin
  result := ZLib.adler32(adler,pointer(buf),len);
end;
function crc32(crc: TZCRC; buf: PAnsiChar; len: cardinal): TZCRC; cdecl;
begin
  result := ZLib.crc32(crc,pointer(buf),len);
end;
function deflateInit_(var strm: TZStream; level: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
begin
  result := ZLib.deflateInit_(z_stream(strm),level,version,stream_size);
end;
function inflateInit_(var strm: TZStream;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
begin
  result := ZLib.inflateInit_(z_stream(strm),version,stream_size);
end;
function deflateInit2_(var strm: TZStream;
  level, method, windowBits, memLevel, strategy: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
begin
  result := ZLib.deflateInit2_(z_stream(strm),level,method,windowBits,memLevel,
    strategy,version,stream_size);
end;
function inflateInit2_(var strm: TZStream; windowBits: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl;
begin
  result := ZLib.inflateInit2_(z_stream(strm),windowBits,version,stream_size);
end;
function get_crc_table: pointer; cdecl;
begin
  result := ZLib.get_crc_table;
end;
{$endif USEDELPHIZLIB}

{$ifdef FPC} // we supply our own static zlib files in coff format for Windows
  {$ifdef WIN32}
    {$LINK static\i386-win32\deflate.o}
    {$LINK static\i386-win32\trees.o}
    {$LINK static\i386-win32\zutil.o}
    {$LINK static\i386-win32\inffast.o}
    {$LINK static\i386-win32\inflate.o}
    {$LINK static\i386-win32\inftrees.o}
    {$LINK static\i386-win32\adler32.o}
    {$LINK static\i386-win32\crc32.o}
    {$linklib static\i386-win32\libmsvcrt.a}
  {$endif}
  {$ifdef WIN64}
    {$ifdef USEZLIBSSE}
    {$L static\x86_64-win64\sse\inffast.o}
    {$L static\x86_64-win64\sse\inftrees.o}
    {$L static\x86_64-win64\sse\inflate.o}
    {$L static\x86_64-win64\sse\deflate.o}
    {$L static\x86_64-win64\sse\trees.o}
    {$L static\x86_64-win64\sse\adler32.o}
    {$L static\x86_64-win64\sse\crc32.o}
    {$L static\x86_64-win64\sse\zutil.o}
    {$else USEZLIBSSE}
    {$L static\x86_64-win64\inffast.o}
    {$L static\x86_64-win64\inftrees.o}
    {$L static\x86_64-win64\inflate.o}
    {$L static\x86_64-win64\deflate.o}
    {$L static\x86_64-win64\trees.o}
    {$L static\x86_64-win64\adler32.o}
    {$L static\x86_64-win64\crc32.o}
    {$L static\x86_64-win64\zutil.o}
    {$endif USEZLIBSSE}
    {$linklib static\x86_64-win64\libmsvcrt.a}
  {$endif}

function deflate(var strm: TZStream; flush: integer): integer; cdecl; external;
function deflateEnd(var strm: TZStream): integer; cdecl; external;
function inflate(var strm: TZStream; flush: integer): integer; cdecl; external;
function inflateEnd(var strm: TZStream): integer; cdecl; external;
function adler32(adler: TZCRC; buf: PAnsiChar; len: cardinal): TZCRC; cdecl; external;
function crc32(crc: TZCRC; buf: PAnsiChar; len: cardinal): TZCRC; cdecl; external;
function deflateInit_(var strm: TZStream; level: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl; external;
function inflateInit_(var strm: TZStream;
  version: PAnsiChar; stream_size: integer): integer; cdecl; external;
function deflateInit2_(var strm: TZStream;
  level, method, windowBits, memLevel, strategy: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl; external;
function inflateInit2_(var strm: TZStream; windowBits: integer;
  version: PAnsiChar; stream_size: integer): integer; cdecl; external;

{$endif FPC}

{$endif USEINLINEASM}
{$endif USEPASZLIB}
{$endif USEEXTZLIB}

function compressBound(sourceLen: cardinal): cardinal;
begin
  result := sourceLen + (sourceLen shr 12) + (sourceLen shr 14) + 11;
end;

function zlibAllocMem(AppData: Pointer; Items, Size: cardinal): Pointer; cdecl;
begin
  Getmem(result,Items * Size);
end;

procedure zlibFreeMem(AppData, Block: Pointer);  cdecl;
begin
  FreeMem(Block);
end;

procedure StreamInit(var Stream: TZStream);
begin
  fillchar(Stream,sizeof(Stream),0);
  {$ifndef USEINLINEASM}
  {$ifndef USEPASZLIB}
  Stream.zalloc := @zlibAllocMem; // even under Linux, use program heap
  Stream.zfree := @zlibFreeMem;
  {$endif}
  {$endif}
end;

function DeflateInit(var Stream: TZStream;
  CompressionLevel: integer; ZlibFormat: Boolean): Boolean;
var Bits: integer;
begin
  if ZlibFormat then
    Bits := MAX_WBITS else
    Bits := -MAX_WBITS;
  result := deflateInit2_(Stream, CompressionLevel, Z_DEFLATED, Bits, DEF_MEM_LEVEL,
    Z_DEFAULT_STRATEGY, ZLIB_VERSION, sizeof(Stream))>=0
end;

function ZLibError(Code: integer): shortstring;
begin
  case Code of
    Z_ERRNO:
      result := 'Z_ERRNO';
    Z_STREAM_ERROR:
      result := 'Z_STREAM_ERROR';
    Z_DATA_ERROR:
      result := 'Z_DATA_ERROR';
    Z_MEM_ERROR:
      result := 'Z_MEM_ERROR';
    Z_BUF_ERROR:
      result := 'Z_BUF_ERROR';
    Z_VERSION_ERROR:
      result := 'Z_VERSION_ERROR';
  else
    str(Code,result);
  end;
end;

function Check(const Code: Integer; const ValidCodes: array of Integer;
  const Context: string): integer;
var i: Integer;
begin
  if Code=Z_MEM_ERROR then
    OutOfMemoryError;
  result := code;
  for i := Low(ValidCodes) to High(ValidCodes) do
    if ValidCodes[i]=Code then
      Exit;
  raise ESynZipException.CreateFmt('Error %s during %s process',[ZLibError(Code),Context]);
end;

function CompressString(const data: ZipString; failIfGrow: boolean = false;
  CompressionLevel: integer=6) : ZipString;
var i1 : integer;
begin
  result := '';
  SetLength(result, 12 + (Int64(length(data)) * 11) div 10 + 12);
  pInt64(result)^ := length(data);
  PCardinalArray(result)^[2] := adler32(0, pointer(data), length(data));
  i1 := CompressMem(pointer(data), @PByteArray(result)[12], length(data),
    length(result) - 12, CompressionLevel);
  if (i1 > 0) and ( (12 + i1 < length(data)) or not failIfGrow ) then
       SetLength(result, 12 + i1)
  else result := '';
end;

function UncompressString(const data: ZipString) : ZipString;
begin
  result := '';
  if Length(data) > 12 then begin
    SetLength(result, PCardinal(data)^);
    SetLength(result, UncompressMem(@PByteArray(data)[12], pointer(result),
      length(data) - 12, length(result)));
    if (result <> '') and
     ((Adler32(0, pointer(result), length(result))) <> PCardinalArray(data)^[2]) then
      result := '';
  end;
end;

function CompressMem(src, dst: pointer; srcLen, dstLen: integer;
  CompressionLevel: integer=6; ZlibFormat: Boolean=false) : integer;
var strm: TZStream;
begin
  StreamInit(strm);
  strm.next_in := src;
  strm.avail_in := srcLen;
  strm.next_out := dst;
  strm.avail_out := dstLen;
  if DeflateInit(strm,CompressionLevel,ZlibFormat) then
  try
    Check(deflate(strm,Z_FINISH),[Z_STREAM_END,Z_OK],'CompressMem');
  finally
    deflateEnd(strm);
  end;
  result := strm.total_out;
end;

type
  TTempBuf = record
    buf: pointer;
    temp: AnsiString;
    buf128k: array[0..32767] of cardinal; // IIS allows 256KB of stack size -> 128KB
  end;

procedure InitTempBuf(var tempbuf: TTempBuf; var TempBufSize: integer);
begin
  if TempBufSize<=sizeof(tempbuf.buf128k) then begin
    TempBufSize := sizeof(tempbuf.buf128k);
    tempbuf.buf := @tempbuf.buf128k;
  end else begin
    SetLength(tempbuf.temp,TempBufSize);
    tempbuf.buf := pointer(tempbuf.temp);
  end;
end;

function CompressStream(src: pointer; srcLen: integer;
  tmp: TStream; CompressionLevel: integer; ZlibFormat: Boolean;
  TempBufSize: integer): cardinal;
var strm: TZStream;
    code: integer;
    temp: TTempBuf;
  procedure FlushBuf;
  var Count: integer;
  begin
    Count := TempBufSize - integer(strm.avail_out);
    if Count=0 then exit;
    tmp.WriteBuffer(temp.buf^,Count);
    strm.next_out := temp.buf;
    strm.avail_out := TempBufSize;
  end;
begin
  InitTempBuf(temp,TempBufSize);
  StreamInit(strm);
  strm.next_in := src;
  strm.avail_in := srcLen;
  strm.next_out := temp.buf;
  strm.avail_out := TempBufSize;
  if DeflateInit(strm,CompressionLevel,ZlibFormat) then
  try
    repeat
      code := Check(deflate(strm, Z_FINISH),[Z_OK,Z_STREAM_END,Z_BUF_ERROR],'CompressStream');
      FlushBuf;
    until code=Z_STREAM_END;
    FlushBuf;
  finally
    deflateEnd(strm);
  end;
  result := strm.total_out;
end;

function UnCompressMem(src, dst: pointer; srcLen, dstLen: integer;
  ZlibFormat: Boolean) : integer;
var strm: TZStream;
    Bits: integer;
begin
  StreamInit(strm);
  strm.next_in := src;
  strm.avail_in := srcLen;
  strm.next_out := dst;
  strm.avail_out := dstLen;
  if ZlibFormat then
    Bits := MAX_WBITS else
    Bits := -MAX_WBITS; // -MAX_WBITS -> no zLib header => .zip compatible !
  if inflateInit2_(strm, Bits, ZLIB_VERSION, sizeof(strm))>=0 then
  try
    Check(inflate(strm, Z_FINISH),[Z_OK,Z_STREAM_END],'UnCompressMem');
  finally
    inflateEnd(strm);
  end;
  result := strm.total_out;
end;

function UnCompressStream(src: pointer; srcLen: integer; tmp: TStream;
  checkCRC: PCardinal; ZlibFormat: Boolean; TempBufSize: integer): cardinal;
var strm: TZStream;
    code, Bits: integer;
    temp: TTempBuf;
  procedure FlushBuf;
  var Count: integer;
  begin
    Count := TempBufSize - integer(strm.avail_out);
    if Count=0 then exit;
    if CheckCRC<>nil then
      CheckCRC^ := SynZip.crc32(CheckCRC^,temp.buf,Count);
    if tmp<>nil then
      tmp.WriteBuffer(temp.buf^,Count);
    strm.next_out := temp.buf;
    strm.avail_out := TempBufSize;
  end;
begin
  InitTempBuf(temp,TempBufSize);
  StreamInit(strm);
  strm.next_in := src;
  strm.avail_in := srcLen;
  strm.next_out := temp.buf;
  strm.avail_out := TempBufSize;
  if checkCRC<>nil then
    CheckCRC^ := 0;
  if ZlibFormat then
    Bits := MAX_WBITS else
    Bits := -MAX_WBITS; // -MAX_WBITS -> no zLib header => .zip compatible !
  if inflateInit2_(strm, Bits, ZLIB_VERSION, sizeof(strm))>=0 then
  try
    repeat
      code := Check(inflate(strm, Z_FINISH),[Z_OK,Z_STREAM_END,Z_BUF_ERROR],'UnCompressStream');
      if (code=Z_BUF_ERROR) and (TempBufSize=integer(strm.avail_out)) then
        Check(code,[],'UnCompressStream'); // occur on invalid input
      FlushBuf;
    until code=Z_STREAM_END;
    FlushBuf;
  finally
    inflateEnd(strm);
  end;
  result := strm.total_out;
end;

function UnCompressZipString(src: pointer; srcLen: integer; out data: ZipString;
  checkCRC: PCardinal; ZlibFormat: Boolean; TempBufSize: integer): cardinal;
// result:=dstLen  checkCRC(<>nil)^:=crc32  (if aStream=nil -> fast crc calc)
var strm: TZStream;
    len, code, Bits: integer;
    temp: TTempBuf;
  procedure FlushBuf;
  var Count: integer;
  begin
    Count := TempBufSize - integer(strm.avail_out);
    if Count=0 then exit;
    if CheckCRC<>nil then
      CheckCRC^ := SynZip.crc32(CheckCRC^,temp.buf,Count);
    SetLength(data,len+Count);
    Move(temp.buf^,PByteArray(data)[len],Count);
    inc(len,Count);
    strm.next_out := temp.buf;
    strm.avail_out := TempBufSize;
  end;
begin
  InitTempBuf(temp,TempBufSize);
  len := 0;
  StreamInit(strm);
  strm.next_in := src;
  strm.avail_in := srcLen;
  strm.next_out := temp.buf;
  strm.avail_out := TempBufSize;
  if checkCRC<>nil then
    CheckCRC^ := 0;
  if ZlibFormat then
    Bits := MAX_WBITS else
    Bits := -MAX_WBITS; // -MAX_WBITS -> no zLib header => .zip compatible !
  if inflateInit2_(strm, Bits, ZLIB_VERSION, sizeof(strm))>=0 then
  try
    repeat
      code := Check(inflate(strm, Z_FINISH),[Z_OK,Z_STREAM_END,Z_BUF_ERROR],'UnCompressZipString');
      FlushBuf;
    until code=Z_STREAM_END;
    FlushBuf;
  finally
    inflateEnd(strm);
  end;
  result := strm.total_out;
end;

const
  HTTP_LEVEL = 1; // 6 is standard, but 1 is enough and faster

function CompressGZip(var DataRawByteString; Compress: boolean): AnsiString;
var L: integer;
    P: PAnsiChar;
    Data: ZipString absolute DataRawByteString;
begin
  L := length(Data);
  if Compress then begin
    SetString(result,nil,L+128+L shr 3); // maximum possible memory required
    P := pointer(result);
    move(GZHEAD,P^,GZHEAD_SIZE);
    inc(P,GZHEAD_SIZE);
    inc(P,CompressMem(pointer(Data),P,L,length(result)-(GZHEAD_SIZE+8),HTTP_LEVEL));
    PCardinal(P)^ := SynZip.crc32(0,pointer(Data),L);
    inc(P,4);
    PCardinal(P)^ := L;
    inc(P,4);
    SetString(Data,PAnsiChar(pointer(result)),P-pointer(result));
  end else
    Data := gzread(pointer(Data),length(Data));
  result := 'gzip';
end;

procedure CompressInternal(var Data: ZipString; Compress, ZLib: boolean);
var tmp: ZipString;
    DataLen: integer;
begin
  tmp := Data;
  DataLen := length(Data);
  if Compress then begin
    SetString(Data,nil,DataLen+256+DataLen shr 3); // max mem required
    DataLen := CompressMem(pointer(tmp),pointer(Data),DataLen,length(Data),
      HTTP_LEVEL,ZLib);
    if DataLen<=0 then
      Data := '' else
      SetLength(Data,DataLen);
  end else
    UnCompressZipString(pointer(tmp),DataLen,Data,nil,ZLib,0);
end;

function CompressDeflate(var DataRawByteString; Compress: boolean): AnsiString;
var Data: ZipString absolute DataRawByteString;
begin
  CompressInternal(Data,Compress,false);
  result := 'deflate';
end;

function CompressZLib(var DataRawByteString; Compress: boolean): AnsiString;
var Data: ZipString absolute DataRawByteString;
begin
  CompressInternal(Data,Compress,true);
  result := 'zlib';
end;


{ TLocalFileHeader }

function TLocalFileHeader.LocalData: PAnsiChar;
begin
  result := @Self;
  inc(result,sizeof(TLocalFileHeader)+fileInfo.extraLen+fileInfo.nameLen);
end;


{ TFileHeader }

function TFileHeader.IsFolder: boolean;
begin
  result := extFileAttr and $00000010<>0;
end;

procedure TFileHeader.Init;
begin
  fillchar(self,sizeof(TFileHeader),0);
  signature := ENTRY_SIGNATURE_INC; // +1 to avoid finding it in the exe
  dec(signature);
  madeBy := $14;
  extFileAttr := $A0; // archive, normal
  fileInfo.neededVersion := $14;
end;

{ TFileInfo }

function TFileInfo.AlgoID: integer;
// 1..15  (1=SynLZ e.g.) from flags bits 7..10
begin
  // in PKware appnote, bits 7..10 of general purpose bit flag are not used
  result := (flags shr 7) and 15; // proprietary flag for SynZipFiles.pas
end;

function TFileInfo.SameAs(aInfo: PFileInfo): boolean;
begin // tolerate a time change through a network: zcrc32 is accurate enough
  if (zzipSize=0) or (aInfo.zzipSize=0) then
    raise ESynZipException.Create('SameAs() with crc+sizes in "data descriptor"');
  result := (zzipMethod=aInfo.zzipMethod) and (flags=aInfo.flags) and
    (zzipSize=aInfo.zzipSize) and (zfullSize=aInfo.zfullSize) and (zcrc32=aInfo.zcrc32);
end;

procedure TFileInfo.SetAlgoID(Algorithm: integer);
begin
  zzipMethod := Z_STORED; // file is stored, accorging to .ZIP standard
  // in PKware appnote, bits 7..10 of general purpose bit flag are not used
  flags := (flags and $F87F) or
    (Algorithm and 15) shl 7; // proprietary flag for SynZipFiles.pas
end;

function TFileInfo.GetUTF8FileName: boolean;
begin // from PKware appnote, Bit 11: Language encoding flag (EFS)
  result := (flags and (1 shl 11))<>0;
end;

procedure TFileInfo.SetUTF8FileName;
begin
  flags := flags or (1 shl 11);
end;

procedure TFileInfo.UnSetUTF8FileName;
begin
  flags := flags and not(1 shl 11);
end;

function CRC32string(const aString: ZipString): cardinal;
// crc32 is better than adler32 for short strings, and fast enough in zlib 1.2.5
begin
  result := length(aString);
  if result<>0 then
    result := SynZip.crc32(0,pointer(aString),result);
end;


{ TSynZipCompressor }

constructor TSynZipCompressor.Create(outStream: TStream; CompressionLevel: Integer;
  Format: TSynZipCompressorFormat = szcfRaw);
begin
  fDestStream := outStream;
  fGZFormat := (Format=szcfGZ);
  if fGZFormat then
    fDestStream.WriteBuffer(GZHEAD,GZHEAD_SIZE);
  StreamInit(FStrm);
  FStrm.next_out := @FBufferOut;
  FStrm.avail_out := SizeOf(FBufferOut);
  fInitialized := DeflateInit(FStrm,CompressionLevel,Format=szcfZip);
end;

procedure TSynZipCompressor.Flush;
begin
  if FInitialized then begin
    while (Check(deflate(FStrm, Z_FINISH),[Z_OK, Z_STREAM_END],'Flush')<>Z_STREAM_END) and
          (FStrm.avail_out=0) do
      FlushBufferOut;
    FlushBufferOut;
  end;
end;

destructor TSynZipCompressor.Destroy;
begin
  if FInitialized then begin
    Flush;
    FStrm.next_out := nil;
    FStrm.avail_out := 0;
    deflateEnd(FStrm);
  end;
  if fGZFormat then begin
    fDestStream.WriteBuffer(fCRC,4);
    fDestStream.WriteBuffer(FStrm.total_in,4);
  end;
  inherited;
end;

function TSynZipCompressor.SizeIn: cardinal;
begin // FStrm.total_in may be integer, cardinal or ulong -> use function
  result := FStrm.total_in;
end;

function TSynZipCompressor.SizeOut: cardinal;
begin // FStrm.total_out may be integer, cardinal or ulong -> use function
  result := FStrm.total_out;
end;

function TSynZipCompressor.FlushBufferOut: integer;
begin
  result := 0;
  if not FInitialized then
    exit;
  if FStrm.avail_out < SizeOf(FBufferOut) then begin
    result := SizeOf(FBufferOut) - FStrm.avail_out;
    FDestStream.WriteBuffer(FBufferOut, result);
    FStrm.next_out := @FBufferOut;
    FStrm.avail_out := SizeOf(FBufferOut);
  end;
end;

function TSynZipCompressor.Read(var Buffer; Count: Integer): Longint;
begin
  assert(false);
  result := 0;
end;

function TSynZipCompressor.Seek(Offset: Integer; Origin: Word): Longint;
begin
  if not FInitialized then
    result := 0 else
  if (Offset = 0) and (Origin = soFromCurrent) then // for TStream.Position
    result := FStrm.total_in else begin
    result := 0;
    assert((Offset = 0) and (Origin = soFromBeginning) and (FStrm.total_in = 0));
  end;
end;

function TSynZipCompressor.Write(const Buffer; Count: Integer): Longint;
begin
  if (self=nil) or not FInitialized or (Count<=0) then begin
    result := 0;
    exit;
  end;
  result := Count;
  fCRC := SynZip.crc32(fCRC,@Buffer,Count);
  FStrm.next_in := pointer(@Buffer);
  FStrm.avail_in := Count;
  while FStrm.avail_in > 0 do begin // compress pending data
    if Check(deflate(FStrm, Z_NO_FLUSH), [Z_OK], 'Write')<>Z_OK then
      raise ESynZipException.Create('ZCompress');
    if FStrm.avail_out = 0 then
      FlushBufferOut;
  end;
  FStrm.next_in := nil;
  FStrm.avail_in := 0;
end;

{$ifdef USEINLINEASM}
{
  Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
  x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.

  Polynomials over GF(2) are represented in binary, one bit per coefficient,
  with the lowest powers in the most significant bit.  Then adding polynomials
  is just exclusive-or, and multiplying a polynomial by x is a right shift by
  one.  If we call the above polynomial p, and represent a byte as the
  polynomial q, also with the lowest power in the most significant bit (so the
  byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
  where a mod b means the remainder after dividing a by b.

  This calculation is done using the shift-register method of multiplying and
  taking the remainder.  The register is initialized to zero, and for each
  incoming bit, x^32 is added mod p to the register if the bit is a one (where
  x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
  x (which is shifting right by one and adding x^32 mod p if the bit shifted
  out is a one).  We start with the highest power (least significant bit) of
  q and repeat for all eight bits of q.

  The table is simply the CRC of all possible eight bit values.  This is all
  the information needed to generate CRC's on data a byte at a time for all
  combinations of CRC register values and incoming bytes.
}
procedure InitCrc32Tab;
var i,n: integer;
    crc: cardinal;
begin // this code size is only 105 bytes, generating 8 KB table content
  for i := 0 to 255 do begin
    crc := i;
    for n := 1 to 8 do
      if (crc and 1)<>0 then
        // $edb88320 from polynomial p=(0,1,2,4,5,7,8,10,11,12,16,22,23,26)
        crc := (crc shr 1) xor $edb88320 else
        crc := crc shr 1;
    crc32tab[0,i] := crc;
  end;
{$ifdef BYFOUR}
  for i := 0 to 255 do begin
    crc := crc32tab[0,i];
    for n := 1 to 7 do begin
      crc := (crc shr 8) xor crc32tab[0,byte(crc)];
      crc32tab[n,i] := crc;
    end;
  end;
{$endif}
end;

initialization
  // crc32 tables content is created from code in initialization section below
  // (save 8 KB of code size from standard crc32.obj, with no speed penalty)
  InitCrc32Tab;
{$endif USEINLINEASM}
end.

