/* TZipBuilderSFX (C) 2002 -2003 - 2004
   TZipBuilderSFX is a convertion to CPP of the Delphi component TZipMasterSFX

  TZipMasterSFX is  written by markus stephany, http://delphizip.mirkes.de,   mailto:merkes@mirkes.de
  last changed: apr 21, 2003

   Convertion to CPP by Roger Aelbrecht, http://home.tiscali.be/driehoeksw
   mailto:roger.aelbrecht@tiscali.be

   this component is some kind of "snap-in" for TZipBuilder to support the new sfx

   - it uses an associated TZipBuilder component to get the SFX... properties (and
     also for ShowZipMessage and things like this

   - to convert a TZipBuilder's zip to an exe, set all properties in the associated
     TZipBuilder component and then call TZipBuilderSFX->ConvertToExe rather than
     TZipBuilder->ConvertEXE, if conversion was successfull, the TZipBuilder will
     automatically use the converted SFX as its ZipFileName (no special action
     must be taken).

   - to convert a TZipBuilder's sfx-zip to an ordinary zipfile, call
     TZipBuilderSFX->ConvertToZip instead of TZipBuilder->ConvertZip.

   - to create a new sfx-zip, you should do something like this:
     1) set the sfx's properties in the ZipBuilder component.
     2) call ZipBuilderSFX1->CreateNewSFX(FileName).
     3) if creation was successfull, the associated ZipBuilder automatically
        use the newly created SFX as its ZipFile(Name).

 	-  History is moved to file History.txt
*/


#include <vcl\vcl.h>
#pragma hdrstop

#pragma package(smart_init)
#pragma resource "*.res"

#include "ZipBuilder.h"
#include "ZipBuilderSFX.h"
#include "ZipMsg.h"
#include "Ziputils.h"
#include "zipsfxdefs.h"
#define min(x,y) ((x)<(y)?(x):(y))
//----------------------------------------------------------------------------
static inline TZipBuilderSFX *ValidCtrCheck()
{
	return new TZipBuilderSFX( NULL );
}
//----------------------------------------------------------------------------
namespace Zipbuildersfx
{
	void __fastcall PACKAGE Register()
  {
		TComponentClass classes[ 1 ] = {__classid( TZipBuilderSFX ) };
		RegisterComponents( "ZipComponents", classes, 0 );
 	}
}

// ================== changed or New functions =============================

#ifndef NO_SPAN
/*?TZipBuidlerSFX::GetLastVolume-------------------------------------------------
3.2.3 24 Nov 2004 RA added to find last volume of MV spanned sfx on hard disc
*/
AnsiString __fastcall TZipBuilderSFX::GetLastVolume(AnsiString FileName,ZipEndOfCentral& EOC)
{
  AnsiString Fname = FileName.SubString(1, FileName.Length() - 4);// remove extension
        // MV files are series with consecutive partnbrs in filename, highest number has EOC
  bool Finding = true;
  int PartNbr = -1;
  AnsiString s;
  while(Finding)
  {
    s = Fname + IntToStr(1002 + PartNbr).SubString(2, 3) + ".zip";
    if(!FileExists(s))
    {
      PartNbr = -1;
      break;
    }
    ++PartNbr;
    int InFile = FileOpen(s, fmOpenRead | fmShareDenyWrite );
    if(ReadEOC(InFile, EOC) != -1)
    {
      Finding = false;
      if(EOC.ThisDiskNo != PartNbr) PartNbr = -1; // not valid last part
    }
    FileClose(InFile);
  }
  return s;
}
//?TZipBuidlerSFX::GetLastVolume

/*?TZipBuilderSFX::ConvertToSpanSFX----------------------------------------------
3.2.3 24 Nov 2004 RA if used as InternalSFX OutFilePath is full destination filespec
3.2.3 20 Nov 2004 RA allow spannedsfx in ZipBuilder when used as internal sfx
3.2.1.2 21 July 2004 RA original value of ZipBuilder->KeepFreeOnDisk1 saved and restored
3.2.1.2 20 July 2004 RA corrected writing of CentralHeader to file
 3.2.0.1 8 April 2004 RA changed to use CentralHeader and EOC as fileslist
 added version 3.0 to support diskspanning
 starts from archive on harddisk and creates a SFX with disk spanning
 supports "spanned" disk on removable disks and "multi-volume" on non-removable
*/
int __fastcall TZipBuilderSFX::ConvertToSpanSFX(AnsiString OutFilePath)
{
  // need ZipBuilder for properties messages and actual sapnning functions etc..
  if(CheckZipBuilder() > 0) return SE_ZipBuilderError;
  TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
   // now we create a temp sfx file name
  AnsiString TempDir = "";
  if(FZipBuilder->TempDir != "") TempDir = FZipBuilder->AppendSlash(FZipBuilder->TempDir);
#ifdef INTERNAL_ZIPBUILDER_SFX
  // outfilepath is the destination FZipFileName the source file
  AnsiString TempFile = TempDir + ExtractFileName(OutFilePath);
#else
  AnsiString TempFile = TempDir + ExtractFileName(ChangeFileExt(FZipBuilder->ZipFileName, ".exe"));
#endif
  // first we make sure we have a sfx bin for spanning

  // now we create a temp sfx file
  int Result;
  Detached = true;
  if((Result = DoConvertOrCreateSFX(TempFile, true)) != 0) return Result;
  // we need to execute List again
#ifdef INTERNAL_ZIPBUILDER_SFX
   // cannot use the property zipbuilder is busy
  FZipBuilder->FZip->List();
#else
//  FZipBuilder->ZipFileName = ChangeFileExt(TempFile, ".zip");
  FZipBuilder->List();
#endif

  // calulate the size of the sfx stub
#ifdef INTERNAL_ZIPBUILDER_SFX
  // internals sfx as full file spec in outfilepath
  AnsiString FPartFileName = ChangeFileExt(OutFilePath, ".zip");
#else
  if(OutFilePath[OutFilePath.Length()] != '\\') OutFilePath += "\\"; // append backshlash if needed
  AnsiString FPartFileName	= OutFilePath + ExtractFileName(FZipBuilder->ZipFileName);
#endif
  TFileStream* OutFile = new TFileStream(TempFile, fmOpenReadWrite);
  AnsiString FDrive = ExtractFileDrive(ExpandFileName(FPartFileName)) + "\\";
  unsigned int drt = GetDriveType(FDrive.c_str());
        // we check the type of spanning used and set the Sig accordingly
  SpanSfxType Sig = stSpanSfx;
  if(drt == DRIVE_FIXED || drt == DRIVE_REMOTE || drt == DRIVE_RAMDISK ||
      FZipBuilder->SpanOptions.Contains(spNoVolumeName))
            Sig = stMVSfx; // set multi volume sig to alert the reader
  unsigned OrgKeepFree = FZipBuilder->KeepFreeOnDisk1; // save original value we will change it
  try
  {
       // we position at the end
    OutFile->Seek(0, soFromEnd);
   // prepare the header and append to file
    TSFXDetachedHeader recDet;
    AnsiString DetName = ChangeFileExt(ExtractFileName(FPartFileName), "");
    if((Sig == stMVSfx) && FUseDelphiBin)
          DetName += "BCB"; // add a part nummer to detached name for delphi SFXstub
                            // stub will remove 3 chars when creating part numbers
    AnsiString DetExt = ExtractFileExt(FPartFileName);
    if(!DetExt.IsEmpty() && DetExt[1] == '.') DetExt.Delete(1,1);
    recDet.Signature = SFX_DETACHED_HEADER_SIG;
    recDet.NameLen = DetName.Length();
    recDet.ExtLen = DetExt.Length();
    OutFile->Write(&recDet, sizeof(recDet));
    if(!DetName.IsEmpty()) OutFile->Write(DetName.c_str(), DetName.Length());
    if(!DetExt.IsEmpty()) OutFile->Write(DetExt.c_str(), DetExt.Length());
    // write an end header for backward searching
    recDet.Signature = SFX_DETACHED_HEADER_END_SIG;
    OutFile->Write(&recDet, sizeof(recDet));
    int FileListSize = OutFile->Size;
#ifdef ZipBuilderVersion180
      TZipDirEntry* DirEntry;
#else
      ZipDirEntry* DirEntry;
#endif
      // add the size of the filelist first by reading central directory
    for(int i = 0; i < FZipBuilder->Count; ++i)
    {
      DirEntry = FZipBuilder->DirEntry[i];
          // we need for each file the ZipCentralHeader + filenamelength
      FileListSize += sizeof(ZipCentralHeader) + DirEntry->FileNameLength;
    }
    FileListSize += sizeof(int) + sizeof(ZipEndOfCentral); // number of entries + sig
      // reserve this space extra on first disk
    int Keepfree =  static_cast<int>(FZipBuilder->KeepFreeOnDisk1) + FileListSize;
    DWORD	SectorsPCluster, BytesPSector, FreeClusters, TotalClusters;
    if(GetDiskFreeSpace(FDrive.c_str(), &SectorsPCluster, &BytesPSector, &FreeClusters, &TotalClusters))
    {
      if(Keepfree % BytesPSector)
#ifdef INTERNAL_ZIPBUILDER_SFX
          FZipBuilder->FZip->KeepFreeOnDisk1 = ((Keepfree / BytesPSector) + 1) * BytesPSector;
      else FZipBuilder->FZip->KeepFreeOnDisk1 = Keepfree;
#else
          FZipBuilder->KeepFreeOnDisk1 = ((Keepfree / BytesPSector) + 1) * BytesPSector;
      else FZipBuilder->KeepFreeOnDisk1 = Keepfree;
#endif
    }
    // let ZipBuilder do the spanning
    try
    {
#ifdef INTERNAL_ZIPBUILDER_SFX
     // if internal sfx call the worker writespan method directly to avoid re-entry error
      Result = FZipBuilder->FZip->WriteSpan(FZipBuilder->ZipFileName, FPartFileName, true);
#else
      Result = FZipBuilder->WriteSpan(FZipBuilder->ZipFileName, FPartFileName);
#endif
    }
    __finally
    {
      if(Result != 0)
      {
        delete OutFile;
        DeleteFile(TempFile); // remove the useless/incomplete sfx stub
        FZipBuilder->KeepFreeOnDisk1 = OrgKeepFree; // restore original value
        return Result; // writespan failed
      }
    }
       // find the last part and read the EOC
    AnsiString SourceFile = FZipBuilder->ZipFileName;
    ZipEndOfCentral EOC;
    if(drt == DRIVE_FIXED || drt == DRIVE_REMOTE || drt == DRIVE_RAMDISK)
         FPartFileName = GetLastVolume(FPartFileName, EOC);
     // if original file is on same path as resulting files then change name of original file
    if(FZipBuilder->ZipFileName == FPartFileName)
            RenameFile(FPartFileName, ChangeFileExt(FPartFileName, ".spn"));
#ifdef INTERNAL_ZIPBUILDER_SFX
    // this will execute List() to get the centraldir
    FZipBuilder->FZip->ZipFileName = FPartFileName;
#else
    FZipBuilder->ZipFileName = FPartFileName; // this will execute List() to get the centraldir
#endif
    // now that all information is collected we can set the original filename again
    RenameFile(ChangeFileExt(FPartFileName, ".spn"), FPartFileName);
    // write the central headers
    int CEHSig = CentralFileHeaderSig;
#ifdef ZipBuilderVersion180
    for(int i = 0; i < FZipBuilder->Count; ++i)
    {
      DirEntry = FZipBuilder->DirEntry[i];
      OutFile->Write(&CEHSig, sizeof(CentralFileHeaderSig));
      // write the Header
      OutFile->Write(DirEntry->Header, sizeof(ZipCentralHeader) - sizeof(CentralFileHeaderSig));
      // and the filename
      OutFile->Write(DirEntry->FileName.c_str(), DirEntry->FileNameLength);
    }
#else
    for(int i = 0; i < FZipBuilder->Count; ++i)
    {
      DirEntry = FZipBuilder->DirEntry[i];
      OutFile->Write(&CEHSig, sizeof(CentralFileHeaderSig));
      // write the Header
      OutFile->Write(DirEntry, sizeof(ZipCentralHeader) - sizeof(CentralFileHeaderSig));
      // and the filename
      OutFile->Write(DirEntry->FileName.c_str(), DirEntry->FileNameLength);
    }
#endif
    // write the EOC
    int InFile = FileOpen(SourceFile, fmOpenRead | fmShareDenyWrite );
    ReadEOC(InFile, EOC);
    FileClose(InFile);
    OutFile->Write(&EOC, sizeof(ZipEndOfCentral));
    // and copy the tempfile to its destination
    if(!(drt == DRIVE_FIXED || drt == DRIVE_REMOTE || drt == DRIVE_RAMDISK))
    { // for removable disk we need to insert the first again
      bool RightDiskInserted = false;
      do
      {   // ask to insert the first disk
        AnsiString MsgStr = LoadStr(DS_InsertAVolume) + LoadStr(DS_InDrive);
        if(MsgStr.IsEmpty()) MsgStr = "Please insert disk volume %.d in drive %s";
        MsgStr = MsgStr.Format(MsgStr,ARRAYOFCONST((1, FDrive)));
        Application->MessageBox(MsgStr.c_str(), Application->Title.c_str(), MB_OK | MB_ICONINFORMATION);
        // check if right disk is inserted
        if(Sig == stSpanSfx)
        {
          unsigned long Dummy1, Dummy2, DiskSerial;
          char VolName[MAX_PATH];
          GetVolumeInformation(FDrive.c_str(), VolName, MAX_PATH, &DiskSerial, &Dummy1, &Dummy2, NULL, 0);
          if(StrComp(VolName, "PKBACK# 001") == 0) RightDiskInserted = true;
        }
        else
        {
          AnsiString DiskFile= FPartFileName.SubString( 1, FPartFileName.Length()
                               - ExtractFileExt(FPartFileName).Length()) + "001.zip";
          if(FileExists(DiskFile)) RightDiskInserted = true;
        }
      }while(!RightDiskInserted);
    }
  }
  __finally
  {
    FZipBuilder->KeepFreeOnDisk1 = OrgKeepFree; // restore original value
    delete OutFile;  // close the file
    // finally copy the exe file to the destination if needed
    if(ExtractFilePath(OutFilePath) != ExtractFilePath(TempFile))
    {
#ifdef INTERNAL_ZIPBUILDER_SFX
      FZipBuilder->FZip->Copy_File(TempFile, OutFilePath);
#else
      FZipBuilder->Copy_File(TempFile, OutFilePath + ExtractFileName(TempFile));
#endif
      // and remove the temp file
      DeleteFile(TempFile);
    }
  }
  return Result;
}
//?TZipBuilderSFX::ConvertToSpanSFX
#endif

/*?TZipBuilderSFX::CreateSFXBinStream------------------------------------------
3.2.3 18 NOv 2004 RA zipbuilder error message usage if stub b-noit found
added version 3.1.0.0 function to create SFXBinStream from resource or from file
returns false if error*/
bool __fastcall TZipBuilderSFX::CreateSFXBinStream(void)
{
  // what type of bin will be used
  AnsiString SfxType;
  if(FUseDelphiBin) SfxType = SfxType_DZ;
  else SfxType = SfxType_BCB;
  SFXBinStream = new TMemoryStream();
  // load it either from resource (if bcsfx##.res has been linked to the executable)
  // or by loading from file in SFXPath and check both versions if available
  bool ResExist = false;
  AnsiString ResVersion = "";
  AnsiString str = SfxType + FSFXLanguage + "_BIN";
  HANDLE hFindSFX = FindResource(HInstance, str.c_str() , RT_RCDATA);
  if(hFindSFX)
  {
    str = SfxType + FSFXLanguage + "_BIN_VERSION";
    HANDLE hFindVersion = FindResource(HInstance, str.c_str(), RT_RCDATA);
    if(hFindVersion && (SizeofResource(HInstance, hFindVersion) >= sizeof(unsigned)))
    {     // load version from resource if available
      HANDLE hRes = LoadResource(HInstance, hFindVersion);
       if(hRes)
      {
        void* Dataptr = LockResource(hRes);
        if(Dataptr)
        {
          char* buff = static_cast<char*>(Dataptr);
          ResVersion =  buff;
        }
      }
    }
    str = SfxType + FSFXLanguage + "_BIN_SIZE";
    HANDLE hFindSize = FindResource(HInstance, str.c_str(), RT_RCDATA);
    if(hFindSize && (SizeofResource(HInstance, hFindSize) >= sizeof(unsigned)))
    {
      HANDLE hRes = LoadResource(HInstance, hFindSize);
      if(hRes)
      {
        void* Dataptr = LockResource(hRes);
        if(Dataptr)
        {
          unsigned Size = *static_cast<unsigned*>(Dataptr);
          if((Size > 0) && (SizeofResource(HInstance, hFindSFX) >= Size))
          {
            hRes = LoadResource(HInstance, hFindSFX);
            if(hRes)
            {
              Dataptr = LockResource(hRes);
              if(Dataptr)
              {
                SFXBinStream->Write(Dataptr, Size);
                SFXBinStream->Seek(0, soFromBeginning);
                ResExist = true;
              }
            }
          }
        }
      }
    }
  }
  AnsiString BinVersion = "";
  AnsiString BinName;
  bool BinExists = true;
  char dirbuf[MAX_PATH];
  TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
  do
  {
    if(FileExists(FSFXPath = FSFXPath + "\\" + SfxType + FSFXLanguage + ".bin")) break;
    // Try the current directory.
    if(FileExists(FSFXPath = SfxType + FSFXLanguage + ".bin")) break;
    BinName = FSFXPath;
    // Try the application directory.
    if(FileExists(FSFXPath = ExtractFilePath(ParamStr(0)) + SfxType + FSFXLanguage + ".bin")) break;
    // Try the Windows System dir.
    ::GetSystemDirectory(dirbuf, MAX_PATH);
    if(FileExists(FSFXPath = AnsiString(dirbuf) + "\\" + SfxType + FSFXLanguage + ".bin")) break;
    // Try the Windows dir.
    ::GetWindowsDirectory(dirbuf, MAX_PATH);
    if(FileExists(FSFXPath = AnsiString(dirbuf ) + "\\" + SfxType + FSFXLanguage + ".bin")) break;
    // Try the dir specified in the DLLDirectory property.
    if(FZipBuilder->DLLDirectory != "" &&
         FileExists(FSFXPath = FZipBuilder->DLLDirectory + "\\" + SfxType + FSFXLanguage + ".bin")) break;
    BinExists = false;   // bin not found
    break;
  } while(true);
  if(BinExists)
  {
    // get fileversion from the .Bin if available
    DWORD VersionHandle;
    int VersionSize = GetFileVersionInfoSize(SFXPath.c_str(), & VersionHandle);
    if(VersionSize)
    {
      char* Buffer = new char[VersionSize];
      GetFileVersionInfo(SFXPath.c_str(), VersionHandle, VersionSize, Buffer);
      char *buff;
      UINT buflen;
      char txtstr[100];
      char sbuff[30];
      struct LANGANDCODEPAGE
      {
        WORD wLanguage;
        WORD wCodePage;
      } *lpTranslate;
      UINT vsize;
      VerQueryValue(Buffer,"\\VarFileInfo\\Translation",(LPVOID *)&lpTranslate,&vsize);
      wsprintf(sbuff,"\\StringFileInfo\\%04x%04x\\",lpTranslate->wLanguage,lpTranslate->wCodePage);
      if(VerQueryValue(Buffer,strcat(strcpy(txtstr,sbuff),"FileVersion"),
                     reinterpret_cast<void **>(&buff),&buflen))
                BinVersion = buff;
      delete[] Buffer;
    }
  }
  // decide which will be used
  if(BinExists && ResExist)
  {
    if((ResVersion == "") || (BinVersion.AnsiCompare(ResVersion) > 0))
    {    // if res has no version or bin version is larger (younger) use bin
      ResExist = false;
      SFXBinStream->Clear();
    }
  }
  // not found in exe image or bin is younger, so try to load it from file
  if(!ResExist && !BinExists)
#ifdef INTERNAL_ZIPBUILDER_SFX
    throw EZipBuilder(SF_NoZipSFXBin,ARRAYOFCONST((BinName)));
#else
  {
    AnsiString msg = LoadStr(SF_NoZipSFXBin);
    if(!msg.IsEmpty()) msg = Format(msg, ARRAYOFCONST((BinName)));
    Application->MessageBox(msg.c_str(), Application->Title.c_str(), MB_OK | MB_ICONERROR);
		return false;
  }
#endif
  if(!ResExist)
  {
    SFXBinStream->LoadFromFile(FSFXPath);
    SFXBinStream->Seek(0, soFromBeginning);
  }
  return true;
}
//?TZipBuilderSFX::CreateSFXBinStream

/*?TZipBuilderSFX::CheckZipBuilder---------------------------------------------
3.2.3 18 Nov 2004 RA If used as internal sfx
3.2.0.2 16 July 2004 added testing if zipbuilder busy
returns 0 : OK
        1 : no zipbuilder assigned
        2 : zipbuilder assigned and busy
*/
int __fastcall TZipBuilderSFX::CheckZipBuilder(void)
// returns true if FZipBuilder is present else false
{
  // need ZipBuilder component for messages, properties etc..
  TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
  if(!FZipBuilder)
  {
#ifdef INTERNAL_ZIPBUILDER_SFX
    throw EZipBuilder(AD_AutoSFXWrong, SE_ZipBuilderError);
#else
    AnsiString Messg = "No TZipBuilder component assigned";
    Application->MessageBox(Messg.c_str(), Application->Title.c_str(), MB_OK | MB_ICONERROR);
    return 1;
#endif
  }
#ifndef INTERNAL_ZIPBUILDER_SFX
  if(FZipBuilder->Busy) return 2;
#endif
  return 0;
}
//?TZipBuilderSFX::CheckZipBuilder

/*?TZipBuilderSFX::CreateNewSFX------------------------------------------------
3.2.3 18 Nov 2004 RA if used as InternalSFx then error raises exception and do not display message
3.2.1.2 20 July 2004 RA added detached = false;
  Creates a new, empty SFX archive (according to the sfx related options of the
  ZipBuilder component) and updates the ZipBuilder component to use this newly created file.*/
int __fastcall TZipBuilderSFX::CreateNewSFX(const AnsiString File)
{
  Detached = false;
  // need ZipBuilder
  if(CheckZipBuilder() > 0) return SE_ZipBuilderError;
  // file must be an EXE
  if(UpperCase(ExtractFileExt(File)) != ".EXE")
	{
#ifdef INTERNAL_ZIPBUILDER_SFX
    throw EZipBuilder(CZ_InputNotExe);
#else
		dynamic_cast<TZipBuilder*>(FBuilder)->ShowZipMessage(CZ_InputNotExe);
		return SE_GeneralError;
#endif
	}
  else return DoConvertOrCreateSFX(File, true);
}
//?TZipBuilderSFX::CreateNewSFX

/*?TZipBuilderSFX::ConvertToZip------------------------------------------------
3.2.3 18 Nov 2004 RA if used as InternalSFx then error raises exception and do not display message
3.2.1.2 20 July 2004 RA added detached = false;
30 March 2004 RA allow SFX with bad length as query result
  Converts the SFX archive (in the ZipBuilder property's ZipFileName) to a ZIP archive
   and updates the ZipBuilder component to use the newly created file.*/
int __fastcall TZipBuilderSFX::ConvertToZip(void)
{
  int InFile, OutFile, InSize = -1, OutSize = -1, Result = SE_GeneralError;
  __int64 PosofEOC, Delta, SFXSize;
	ZipEndOfCentral EOC;
  Detached = false;
  //zipbuilder must exist;
  if(CheckZipBuilder() > 0) return SE_ZipBuilderError;
  // get sfx options from zipbuilder
  GetPropertiesFromZipBuilder();
  //file must exist
  TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
  if(!FileExists(FZipBuilder->ZipFileName))
  {
#ifdef INTERNAL_ZIPBUILDER_SFX
    throw EZipBuilder(CZ_NoExeSpecified);
#else
    FZipBuilder->ShowZipMessage(CZ_NoExeSpecified);
    return SE_OpenReadError;
#endif
  }
  int QueryRes = QueryZip(FZipBuilder->ZipFileName);
  if(!(QueryRes == 241 || QueryRes == 225))// test if it is an SFX 241 is SFX 225 is SFX with bad length
  {
#ifdef INTERNAL_ZIPBUILDER_SFX
    throw EZipBuilder(CZ_InputNotExe);
#else
    FZipBuilder->ShowZipMessage(CZ_InputNotExe);
    return SE_OpenReadError;
#endif
  }
  // rename to zip
  AnsiString OutFileName = ChangeFileExt(FZipBuilder->ZipFileName, ".zip");
  TCursor SaveCursor = Screen->Cursor;
  Screen->Cursor = crHourGlass;
  try
  {
    // open in file
    if((InFile = FileOpen(FZipBuilder->ZipFileName, fmOpenRead | fmShareDenyWrite )) == -1)
                  Result = SE_OpenReadError;
    else
    {
      //read the EOC
      if((PosofEOC = ReadEOC(InFile, EOC)) == 0) Result = SE_ErrorInCentral;
      else
      {
        //calculate delta ( if wrong offsets are stored in zip-file
        Delta = PosofEOC - (EOC.CentralOffset + EOC.CentralSize);
        //now find the first local header
        if((SFXSize = GetFirstLocalHeader(InFile, EOC.CentralEntries,
                                static_cast<int>(EOC.ThisDiskNo),
                                static_cast<int>(EOC.CentralOffset + Delta))) < 0)
                Result = SE_ErrorInCentral; //no local file header found
        else
        {
          SFXSize += Delta;
          //delete an existing output file
          if(FileExists(OutFileName)) EraseFile(OutFileName, FZipBuilder->HowToDelete);
          // open output file
          if((OutFile = FileCreate(OutFileName)) == -1) Result = SE_CreateError;
          else
          {
            FileSeek(InFile, SFXSize, soFromBeginning);
            // write local data
            Result = CopyBuffer(InFile, OutFile,
                                static_cast<int>(EOC.CentralOffset - SFXSize + Delta));
            if(!Result)
            {
              if((Result = CopyAndAdjustCentralDir(InFile, OutFile,
                                                 EOC.CentralEntries,
                            static_cast<int>(EOC.ThisDiskNo),
                            static_cast<int>(Delta - SFXSize))) == 0)
                    OutSize = FileSeek(OutFile, 0, soFromEnd);
            }
            FileClose(OutFile);
          }
        }
      }
      if(!Result)
      {
        // read headers etc from input file
        Result = ReadSFXProperties(InFile, static_cast<int>(SFXSize));
        if(!Result)
        {
          // get the icon from the sfx
          ReadSFXIcon(FZipBuilder->ZipFileName);
          InSize = FileSeek(InFile, 0, soFromEnd);
        }
      }
      FileClose(InFile);
    }
    //extra check
    if(!Result && (SFXSize == -1 || OutSize == -1 || InSize == -1)) Result = SE_GeneralError;
    if(!Result)
    {
      TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
      EraseFile(FZipBuilder->ZipFileName, FZipBuilder->HowToDelete);
      FZipBuilder->ZipFileName = OutFileName;
    }
    else if(FileExists(OutFileName)) DeleteFile(OutFileName);
  }
  __finally
  {
    Screen->Cursor = SaveCursor;
  }
  return Result;
}
//?TZipBuilderSFX::ConvertToZip

/*?TZipBuilderSFX::ConvertToSFX------------------------------------------------
3.2.3 18 Nov 2004 RA if used as InternalSFx then error raises exception and do not display message
3.2.1.2 20 July 2004 RA added detached = false;
  Converts the ZIP archive (according to the sfx related options of the ZipBuilder component)
   to a SFX archive and updates the ZipBuilder component to use the newly created file.
*/
int __fastcall TZipBuilderSFX::ConvertToSFX(void)
{
  Detached = false;
  // need ZipBuilder for properties messages etc..
  if(CheckZipBuilder() > 0) return SE_ZipBuilderError;
  int Result = DoConvertOrCreateSFX(dynamic_cast<TZipBuilder*>(FBuilder)->ZipFileName, false);
  return Result;
}
//?TZipBuilderSFX::ConvertToSFX

/*?TZipBuilderSFX::DoConvertOrCreateSFX----------------------------------------
3.2.3 18 Nov 2004 RA if used as InternalSFx then error raises exception and do not display message
17 May 2004 Corrected code for writing EOC to file
10 May 2004 Changed tests on string lengths and used error messages
1 April2004 Ra allow zip with bad comment length
*/
int __fastcall TZipBuilderSFX::DoConvertOrCreateSFX(const AnsiString File, const bool CreateNew)
{
  AnsiString OutFileName;
  int InFile, OutFile, Result = SE_GeneralError;
	int SFXSize = -1, OutSize = -1, SFXBlkSize;
  __int64 ZipSize = -1;
  char* sfxblk;
  ZipEndOfCentral EOC;

  GetPropertiesFromZipBuilder();
  TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
  if(!CreateNew)
  {
    // file must exist
    if(!FileExists(File))
    {
#ifdef INTERNAL_ZIPBUILDER_SFX
      throw EZipBuilder(GE_NoZipSpecified);
#else
      FZipBuilder->ShowZipMessage(GE_NoZipSpecified);
      return Result;
#endif
    }
    //file must be a zip
    int QueryRes = QueryZip(File);
    if(QueryRes != 242 && QueryRes != 226)// test if it is a zip 242 is zip 226 is zip with bad length
    {
#ifdef INTERNAL_ZIPBUILDER_SFX
      throw EZipBuilder(SF_InputIsNoZip);
#else
      FZipBuilder->ShowZipMessage(SF_InputIsNoZip);
      return Result;
#endif
    }
    //rename to exe
    OutFileName = ChangeFileExt(File, ".exe");
  }
  else OutFileName = File;
  // try to find fsfxpath
  // remove file name if given by user or remnant from previous call
  if(ExtractFileExt(ExtractFileName(FSFXPath)) != "") FSFXPath = ExtractFilePath(FSFXPath);
  int PathLen = FSFXPath.Length();
		// If there is a trailing '\' in path, cut it off:
  if(PathLen && (FSFXPath[PathLen] == '\\'))  FSFXPath.SetLength(PathLen - 1);
  if(!CreateSFXBinStream()) return Result;
  //check string lengths
#ifndef INTERNAL_ZIPBUILDER_SFX
  try
  {
#endif
#ifndef NO_SFX_IN_ZIPBUILDER
    if(FZipBuilder->SFXCaption.Length() > 255)
          throw EZipBuilder(SF_DlgTitleTooLong);
    if(FZipBuilder->SFXCommandLine.Length() > 255)
           throw EZipBuilder(SF_CmdLineTooLong);
    if(FZipBuilder->SFXDefaultDir.Length() > 255)
           throw EZipBuilder(SF_DefPathTooLong);
    if(FZipBuilder->SFXMessage.Length() > 255)
           throw EZipBuilder(SF_MsgTooLong);
#else
    // NO_SFX in zipbuilder is set we use our own properties
    if(SFXCaption.Length() > 255)
          throw EZipBuilder(SF_DlgTitleTooLong);
    if(SFXCommandLine.Length() > 255)
           throw EZipBuilder(SF_CmdLineTooLong);
    if(SFXDefaultDir.Length() > 255)
           throw EZipBuilder(SF_DefPathTooLong);
    if(SFXMessage.Length() > 255)
           throw EZipBuilder(SF_MsgTooLong);
#endif
    if(RegFailPath.Length() > 255)
            throw EZipBuilder(SF_FBkPathTooLong);
#ifndef INTERNAL_ZIPBUILDER_SFX
  }
  catch (EZipBuilder &ers)
  {
			// All SFX creation errors will be catched and returned in this one message.
    FZipBuilder->ShowExceptionError(ers);
    return Result;
  }
#endif
  //calculate overall headersize
#ifndef NO_SFX_IN_ZIPBUILDER
  int L = FZipBuilder->SFXCaption.Length() + FZipBuilder->SFXDefaultDir.Length() +
	        FZipBuilder->SFXCommandLine.Length() + FZipBuilder->SFXMessage.Length() +
          RegFailPath.Length();
#else
  int L = SFXCaption.Length() + SFXDefaultDir.Length() +
	        SFXCommandLine.Length() + SFXMessage.Length() + RegFailPath.Length();
#endif
	SFXBlkSize = ((sizeof(TSFXFileHeader) + L + 3) / 4)* 4;	// DWord Alignment.
#ifndef INTERNAL_ZIPBUILDER_SFX
  try
	{
#endif
		sfxblk = new char[SFXBlkSize + 1];
    memset(sfxblk,0,SFXBlkSize + 1); // fill all bytes with 0 first
#ifndef INTERNAL_ZIPBUILDER_SFX
	}
	catch( ... )
	{
		FZipBuilder->ShowZipMessage(GE_NoMem);
		return Result;
	}
#endif
  //save cursor and show wait
  TCursor SaveCursor = Screen->Cursor;
  Screen->Cursor = crHourGlass;
  try
  {
    // create header
    TSFXFileHeader SFXHead;
    SFXHead.Signature = SFX_HEADER_SIG;
    SFXHead.Size = static_cast<Word>(SFXBlkSize);
    SFXHead.Options = FMySFXOptions;
    SFXHead.DefOVW = FMySFXOverWriteMode;
#ifndef NO_SFX_IN_ZIPBUILDER
    SFXHead.CaptionSize = static_cast<Byte>(FZipBuilder->SFXCaption.Length());
    SFXHead.PathSize = static_cast<Byte>(FZipBuilder->SFXDefaultDir.Length());
    SFXHead.CmdLineSize = static_cast<Byte>(FZipBuilder->SFXCommandLine.Length());
#else
    SFXHead.CaptionSize = static_cast<Byte>(SFXCaption.Length());
    SFXHead.PathSize = static_cast<Byte>(SFXDefaultDir.Length());
    SFXHead.CmdLineSize = static_cast<Byte>(SFXCommandLine.Length());
#endif
    SFXHead.RegFailPathSize = static_cast<Byte>(RegFailPath.Length());
    SFXHead.StartMsgSize = static_cast<Byte>(FMySFXMessage.Length());
    SFXHead.StartMsgType = FMySFXMessageFlags;
    // copy header to sfxblk
    memcpy(&sfxblk[0], &SFXHead, sizeof(TSFXFileHeader));
    //set end of fileheader
    TSFXFileEndOfHeader RecEnd;
    RecEnd.Signature = SFX_HEADER_END_SIG;
    RecEnd.HeaderSize = SFXBlkSize;
    // store strings
    int i =sizeof(TSFXFileHeader);
#ifndef NO_SFX_IN_ZIPBUILDER
    if(FZipBuilder->SFXCaption.Length())
    {
      StrPCopy(sfxblk +i, FZipBuilder->SFXCaption);
      i += FZipBuilder->SFXCaption.Length();
    }
    if(FZipBuilder->SFXDefaultDir.Length())
    {
      StrPCopy(sfxblk +i, FZipBuilder->SFXDefaultDir);
      i += FZipBuilder->SFXDefaultDir.Length();
    }
    if(FZipBuilder->SFXCommandLine.Length())
    {
      StrPCopy(sfxblk +i, FZipBuilder->SFXCommandLine);
      i += FZipBuilder->SFXCommandLine.Length();
    }
#else
    if(SFXCaption.Length())
    {
      StrPCopy(sfxblk +i, SFXCaption);
      i += SFXCaption.Length();
    }
    if(SFXDefaultDir.Length())
    {
      StrPCopy(sfxblk +i, SFXDefaultDir);
      i += SFXDefaultDir.Length();
    }
    if(SFXCommandLine.Length())
    {
      StrPCopy(sfxblk +i, SFXCommandLine);
      i += SFXCommandLine.Length();
    }
#endif
    if(RegFailPath.Length())
    {
      StrPCopy(sfxblk +i, RegFailPath);
      i += RegFailPath.Length();
    }
    if(FMySFXMessage.Length())
    {
      StrPCopy(sfxblk +i, FMySFXMessage);
      i += FMySFXMessage.Length();
    }

    //deleting existing file
    if(FileExists(OutFileName)) EraseFile(OutFileName, FZipBuilder->HowToDelete);
    Application->ProcessMessages(); // allow OS to effectively remove the file
    Sleep(20);
     // open and start writing
    if((OutFile = FileCreate(OutFileName)) != -1)
	  {
      // copy the SFX code from the memorystream in the outfile
      SFXSize = SFXBinStream->Size;
      char* buff = new char[SFXBinStream->Size];
      try
      {
        Result = 0; // OK
        SFXBinStream->ReadBuffer(buff, SFXBinStream->Size);
			  if(FileWrite(OutFile, buff, SFXSize) != SFXSize) Result = SE_CopyError;
      }
      __finally
      {
        delete[] buff;
        delete SFXBinStream;
      }

#ifndef NO_SFX_IN_ZIPBUILDER
      if(!Result && !FZipBuilder->SFXIcon->Empty)
                 Result = ReplaceIcon(OutFile, SFXSize, FZipBuilder->SFXIcon);
#else
      if(!Result && !SFXIcon->Empty)
                 Result = ReplaceIcon(OutFile, SFXSize, SFXIcon);
#endif
      // Copy the special SFX block to the destination.
      if(!Result)
      {
        if((FileWrite(OutFile, sfxblk, SFXBlkSize) != SFXBlkSize) ||
           (FileWrite(OutFile, &RecEnd, sizeof(RecEnd)) != sizeof(RecEnd)))
               Result = SE_CopyError;
        else
        {
          if(!CreateNew)
          { //if conversion
            if((InFile = FileOpen(File, fmOpenRead | fmShareDenyWrite )) == -1)
                Result = SE_OpenReadError;
            else
            {
              //read end of central from file
              __int64 PosofEOC;
              if((PosofEOC = ReadEOC(InFile, EOC)) < 0) Result = SE_ErrorInCentral;
              else
              { //calculate delta (if wrong ofsets are stored in zip-file)
                __int64 Delta = PosofEOC - (EOC.CentralOffset + EOC.CentralSize);
                //currently , only nonspanned archives are supported
                if((EOC.ThisDiskNo != EOC.CentralDiskNo) ||
                   (EOC.CentralEntries != EOC.TotalEntries)) Result = SE_NoSpanningSupport;
                else
                { //write zipfile
                  ZipSize = PosofEOC + sizeof(EOC) + EOC.ZipCommentLen;
                  FileSeek(InFile, 0, soFromBeginning);
                  //copy local data
                  Result = CopyBuffer(InFile, OutFile,
                                     static_cast<int>(EOC.CentralOffset + Delta));
                  //copy and adjust central dir
                  if(!Result) Result = CopyAndAdjustCentralDir(InFile, OutFile, EOC.CentralEntries,
                                                             EOC.ThisDiskNo,
                                       static_cast<int>(Delta + SFXSize + SFXBlkSize + sizeof(RecEnd)));
                  OutSize = FileSeek(OutFile, 0, soFromEnd);
                }
              }
              FileClose(InFile);
            }
          }
          else
          { //create a new file
            if(!Detached)
            {
              // fill in the EOC
              memset(&EOC, '\0', sizeof(EOC));
              EOC.HeaderSig = EndCentralDirSig;
              EOC.CentralOffset = SFXSize + SFXBlkSize + sizeof(RecEnd);
              //write it to the file
              if(FileWrite(OutFile, &EOC, sizeof(EOC)) != sizeof(EOC))	Result = SE_CopyError;
              else Result = 0;
            }
            else Result = 0;
            OutSize = FileSeek(OutFile, 0, soFromEnd);
            ZipSize = 0;
          }
        }
      }
    FileClose(OutFile);
    }
    else Result = SE_CreateError;
    //extra check
    if(!Result && (SFXSize == -1 || ZipSize == -1 || OutSize == -1)) Result = SE_GeneralError;

    if(!Result && !CreateNew) EraseFile(File, FZipBuilder->HowToDelete);
    if(Result)
    {
      if(FileExists(OutFileName)) DeleteFile(OutFileName);
    }
#ifndef INTERNAL_ZIPBUILDER_SFX
    else if(!Detached) FZipBuilder->ZipFileName = OutFileName;
#endif
  }
  __finally
  {
    Screen->Cursor = SaveCursor;
    delete[] sfxblk;
  }
return Result;
}
//?TZipBuilderSFX::DoConvertOrCreateSFX

/*?TZipBuilderSFX::EraseFile--------------------------------------------------
3.2.2 16 Nov 2004 RA added to avoid version problems with TZipBuilder
*/
int __fastcall TZipBuilderSFX::EraseFile(const String Fname, DeleteOpts How)
{
  SHFILEOPSTRUCT SHF = {0};
	char* FromStr = NULL;
	int	Result  = -1;
	String DelFileName = Fname;
	// If we do not have a full path then FOF_ALLOWUNDO does not work!?
	if(ExtractFilePath(Fname) == "" )
		DelFileName = GetCurrentDir() + '\\' + Fname;
	// We need to be able to 'Delete' without getting an error
	// if the file does not exists as in ReadSpan() can occur
	if(!FileExists(DelFileName)) return Result;
	try {
		int dfnLen = DelFileName.Length() + 2;
		FromStr    = new char[dfnLen];
		SHF.hwnd   = Application->Handle;
		SHF.wFunc  = FO_DELETE;
		SHF.pFrom  = FromStr;
		SHF.pTo    = NULL;
		SHF.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI;
    if(How == htdAllowUndo) SHF.fFlags |= FOF_ALLOWUNDO;
		StrPLCopy(FromStr, DelFileName, dfnLen);
		FromStr[dfnLen - 1] = '\0';
		Result = SHFileOperation(&SHF);
	}
	catch( ... ) { }
	delete[] FromStr;
	return Result;
}
//?TZipBuilderSFX::EraseFile

//----------------------------------------------------------------------------
//added version 3.1.0.0 callback function for EnumResourceNames
bool CALLBACK ResEnumFunc(HANDLE Handle, char* /*Type*/, char* Name, TStrings* lParam)
{
  AnsiString str1;
  char Buf[255];
  AnsiString SfxType;
  AnsiString str = Name;
  str = str.UpperCase();
  // determine sfxtype for this resource
  if(str.Pos(SfxType_BCB) == 1) SfxType = SfxType_BCB;
  if(str.Pos(SfxType_DZ) == 1) SfxType = SfxType_DZ;
  if(SfxType.Length()) // it is an sfxtype
  {
    if(str.Pos("_BIN_LANG\0") > 0)
    {
      str1 = "";
      // found resource, now read language id
      HANDLE h1 = FindResource(Handle, Name, RT_RCDATA);
      if(h1)
      {
        HANDLE h2 = LoadResource(Handle, h1);
        if(h2)
        {
          char* ptr = static_cast<char*>(LockResource(h2));
          if(ptr)
          {
            // get local info
            GetLocaleInfo(MAKELCID(*ptr, SORT_DEFAULT), LOCALE_SNATIVELANGNAME, Buf, sizeof(Buf));
            str1 = Buf;
            UnlockResource(h2);
          }
          FreeResource(h2);
        }
      }
      str = str.SubString(str.Pos(SfxType) + SfxType.Length(), MaxInt);
      str.Delete(str.Pos("_BIN_LANG"), MaxInt);
      if(str1 == "") str1 = str + "=" + str.UpperCase();
      else str1 = str1 + "="+ str.UpperCase();
      if(str1 != "")
        if(lParam->IndexOf(str1) == -1) lParam->Add(str1);
    }
  }
  return true;
}
//---------------------------------------------------------------------------
// added version 3.1.0.0
void __fastcall TZipBuilderSFX::SetSFXLanguage(const AnsiString Value)
{
  if(FSFXLanguage.UpperCase() != Value.UpperCase())
  {
    FSFXLanguage = Value.UpperCase();
    if(Included_Languages->IndexOfName(FSFXLanguage) > -1)
      FSFXLanguage = Included_Languages->Values[FSFXLanguage];
  }
}
//---------------------------------------------------------------------------
// added version 3.1.0.0
AnsiString __fastcall TZipBuilderSFX::GetSFXLanguage(void)
{
  AnsiString Result = FSFXLanguage.UpperCase();
  for(int i = 0; i < Included_Languages->Count; ++i)
  {
    if(Included_Languages->Values[Included_Languages->Names[i]] == FSFXLanguage)
    {
      Result = Included_Languages->Names[i];
      break;
    }
  }
 return Result;
}

//---------------------------------------------------------------------------
__fastcall TZipBuilderSFX::TZipBuilderSFX(Classes::TComponent *AOwner) : TComponent(AOwner)
{
  Included_Languages = new TStringList();
  EnumResourceNames(0, RT_RCDATA, reinterpret_cast<ENUMRESNAMEPROC>(ResEnumFunc), int(Included_Languages));
  Detached = false;
#ifdef NO_SFX_IN_ZIPBUILDER
  FSFXIcon = new TIcon();
  FSFXOverWriteMode		= somAsk;
	FSFXCaption				= "Self-extracting Archive";
	FSFXDefaultDir			= "";
	FSFXCommandLine			= "";
#endif
}
//---------------------------------------------------------------------------
__fastcall TZipBuilderSFX::~TZipBuilderSFX(void)
{
  delete Included_Languages;
#ifdef NO_SFX_IN_ZIPBUILDER
  delete SFXIcon;
#endif
}

//---------------------------------------------------------------------------
AnsiString __fastcall TZipBuilderSFX::GetVersion(void)
{
  return SFX_RELEASE;
}
//---------------------------------------------------------------------------
void __fastcall TZipBuilderSFX::SetVersion(const AnsiString Value)
{
 // no action but we want it to be shown in the object inspector
}
//---------------------------------------------------------------------------
// copy a buffer from a file to another, returns 0 on ok
// iReadLen: amount of data to copy, if -1, then up to eof
int __fastcall TZipBuilderSFX::CopyBuffer(const int InFile, const int OutFile,
                                          int ReadLen)
{
	int  SizeR, ToRead = SFXBufSize, Result = SE_CopyError;
	char *Buffer = NULL;

	try
	{
		Buffer = new char[SFXBufSize];
		Result = 0;					// No memory error!
		do
		{
			if(ReadLen >= 0) ToRead = min(ReadLen, SFXBufSize);
			SizeR = FileRead(InFile, Buffer, ToRead);
			if(FileWrite(OutFile, Buffer, SizeR) != SizeR)
			{
				Result = SE_CopyError;
				break;
			}
			if(ReadLen > 0) ReadLen -= SizeR;
			Application->ProcessMessages();	// Mostly for winsock.
		}
		while(SizeR == ToRead && ReadLen);
	}
	catch ( ... ) { }
	delete[] Buffer;
	return Result;
}
//---------------------------------------------------------------------------
// replace an icon in the given file
int __fastcall TZipBuilderSFX::ReplaceIcon(const int &ExeFile, const int MaxPos,
                                           Graphics::TIcon* NewIcon)
{
	char *SFXBuffer = NULL;
	TMemoryStream *IconStream = NULL;
	IMAGE_DOS_HEADER *DOSHead;
	PEheader *Header;
	DWord  FoundAddr = 0;
	pISH SectionHeader;
	int Result = SE_NoFoundError;
	try
	{
  	for(;;)
  	{
  		try
  		{
  			// Put the SFX file into a buffer.
  			SFXBuffer = new char[MaxPos];
  			FileSeek(ExeFile, 0, soFromBeginning);
  			FileRead(ExeFile, SFXBuffer, MaxPos);
  			// Read and check the ZipSFX.bin file for an icon resource.
  			DOSHead = (IMAGE_DOS_HEADER *)SFXBuffer;
  			if(DOSHead->e_magic != IMAGE_DOS_SIGNATURE) break;
  			Header = (PEheader *)((char *)DOSHead + DOSHead->e_lfanew);
  			if(Header->signature != IMAGE_NT_SIGNATURE) break;
  			SectionHeader = &Header->section_header;
  			for(int Section = 0; Section < Header->_head.NumberOfSections; Section++)
  			{	// Walk through sections.
  				if(!StrComp((char *)&SectionHeader->Name[0], ".rsrc"))
  				{	// Found the resource section.
  					FoundAddr = LookForDirs(SFXBuffer + SectionHeader->PointerToRawData,
  					                        SectionHeader->VirtualAddress,
  							                    SectionHeader->SizeOfRawData,
  							                    &Header->opt_head.DataDirectory[0]);
  					if(!FoundAddr) break;
  					// Change memory offset to file offset.
  					FoundAddr = FoundAddr - SectionHeader->VirtualAddress +
  					                        SectionHeader->PointerToRawData;
  					break;
  				}
  				SectionHeader++;
  			}
  			if(!FoundAddr) break;
  			// Save the icon data to a stream.
  			IconStream = new TMemoryStream();
  			NewIcon->SaveToStream(IconStream);
  			// Only handle icons with this size.
  			if(IconStream->Size == 766)
  			{
  				// Reposition to the actual data and put it into a buffer.
  				IconStream->Seek(22, soFromBeginning);
  				IconStream->ReadBuffer(SFXBuffer, 744);
  				// Go to start of the icon resource in the new created file.
  				FileSeek(ExeFile, static_cast<__int64>(FoundAddr), soFromBeginning);
  				// And write the changed icon data from the buffer.
  				FileWrite(ExeFile, SFXBuffer, 744);
  				Result = 0;
  			}
  			else Result = SE_IconSizeError;
  		}
  		catch( ... )
  		{
  			Result = SE_MemStreamError;
  		}
  		break;
  	}
  }
  __finally
  {
		delete[] SFXBuffer;
		delete IconStream;
		FileSeek(ExeFile, 0, soFromEnd);
	}
	return Result;
}
//---------------------------------------------------------------------------
// read end of central record from iInFile and return its position
__int64 __fastcall TZipBuilderSFX::ReadEOC(const int InFile,
                                      ZipEndOfCentral &EOC)
{
  char *Buf;
  __int64 Result;
  bool OK = false;
  int FileSize = FileSeek(InFile,0, soFromEnd);
  int BufferSize = min(FileSize, (long)(65535 + sizeof(EOC)));
  // We do a check at the end of the file to speed things up if
	// there isn't a Zip archive comment.
  if((Result = FileSeek(InFile, -static_cast<__int64>(sizeof(EOC)), soFromEnd)) != -1)
	{
		FileRead(InFile, &EOC, sizeof(EOC));
    if(EOC.HeaderSig != EndCentralDirSig)
		{  //not found at the end read in a buffer
      if(BufferSize > sizeof(EOC))
      {
        if((Result = FileSeek(InFile,-static_cast<__int64>(BufferSize), soFromEnd)) != -1)
        {
          Buf = new char[BufferSize + 1];
          try
          {
            if(FileRead(InFile, Buf, BufferSize) == BufferSize)
            { //now search from the start
              for(int i = BufferSize - sizeof(EOC)- 1; i >= 0; i--)
              if(Buf[i] == 'P' && Buf[i + 1] == 'K' &&
                 Buf[i + 2] == '\x05' && Buf[i + 3] == '\x06')
			        {
                if(EOC.ZipCommentLen + Result + i + (signed)sizeof(EOC) <= FileSize)
                {
				          memcpy(&EOC, Buf + i, sizeof(EOC));
                  Result +=i;
                  OK = true;
                  break;
                 }
               }
             }
          }
          __finally
          {
            delete[] Buf;
          }
        }
      }
		}
    else OK = true;
	}
return OK ? Result : -1;
}
//---------------------------------------------------------------------------
 // copy and adjust central dirs and end of central dir
int __fastcall TZipBuilderSFX::CopyAndAdjustCentralDir(const int InFile, const int OutFile,
                                       const int NumEntries, const int DiskToAdjust,
                                       const int Offset)
{
  ZipCentralHeader CEH;
  ZipEndOfCentral EOC;
  int Result = SE_ErrorInCentral;
  char* Buf = new char[65536 * 3]; // filename + extrafield + filecomment
  try
  {
    for(int Cur = 0; Cur < NumEntries; Cur++)
    { // write all central directory entries
      if(FileRead(InFile, &CEH, sizeof(CEH)) != sizeof(CEH) || CEH.HeaderSig != CentralFileHeaderSig)
          return Result;  //invalid record
      if(CEH.DiskStart == DiskToAdjust) CEH.RelOffLocal += Offset;
      if(FileWrite(OutFile, &CEH, sizeof(CEH)) != sizeof(CEH)) return Result = SE_CopyError;
      //copy extra data
      if(CopyBuffer(InFile, OutFile, CEH.FileNameLen + CEH.ExtraLen + CEH.FileComLen))
            return SE_CopyError;
    }
    // read, adjust and write end of central
    if(FileRead(InFile, &EOC, sizeof(EOC)) != sizeof(EOC) || EOC.HeaderSig != EndCentralDirSig)
          return Result;
    EOC.CentralOffset += Offset;
    if(FileWrite(OutFile, &EOC, sizeof(EOC)) != sizeof(EOC)) return SE_CopyError;
    // copy eventually existing comment
    if(CopyBuffer(InFile, OutFile, EOC.ZipCommentLen)) return Result = SE_CopyError;
    else Result = 0;
  }
  __finally
  {
    delete[] Buf;
  }
  return Result;
}
//---------------------------------------------------------------------------
//// return the position of the first local file header in the file
  // -1 on error, else not the absolute file position is read but the value from the central directory
int __fastcall TZipBuilderSFX::GetFirstLocalHeader(const int InFile, const int NumEntries,
                                   const int WhichDisk, const int Position)
{
  ZipCentralHeader CEH;
  int Result = SE_ErrorInCentral;
  if((NumEntries < 1) || (FileSeek(InFile, Position, soFromBeginning) != Position))
      return Result;
  for(int i = 0; i < NumEntries; i++)
  {
    //read central dir
    if(FileRead(InFile, &CEH, sizeof(CEH)) != sizeof(CEH) || CEH.HeaderSig != CentralFileHeaderSig)
        return SE_ErrorInCentral;
    // first ?
    if(((Result < 0) || ((signed)CEH.RelOffLocal < Result)) && (CEH.DiskStart == WhichDisk))
                       Result = CEH.RelOffLocal; //store
      //read over extra data
    if(CEH.FileNameLen + CEH.ExtraLen + CEH.FileComLen)
            FileSeek(InFile, CEH.FileNameLen + CEH.ExtraLen + CEH.FileComLen, soFromCurrent);
  }
  return Result;
}
//---------------------------------------------------------------------------
void __fastcall TZipBuilderSFX::GetPropertiesFromZipBuilder(void)
{
  if(CheckZipBuilder() > 0) return;
#ifndef NO_SFX_IN_ZIPBUILDER
  // use ZipBuilder properties, so convert them to our own properties
  TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
  if(FZipBuilder)
  {
    // convert message
    FMySFXMessageFlags = MB_OK;
    AnsiString Msg = FZipBuilder->SFXMessage;
    if(Msg != "")
    {
      switch(Msg[1])
      {
        case 1:
          FMySFXMessageFlags = MB_OKCANCEL | MB_ICONINFORMATION;
          Msg.Delete(1,1);
        break;
        case 2:
          FMySFXMessageFlags = MB_YESNO | MB_ICONQUESTION;
          Msg.Delete(1,1);
        break;
      }
    }
    FMySFXMessage = Msg;
    // translate overwrite
    switch(FZipBuilder->SFXOverWriteMode)
    {
      case OvrConfirm: FMySFXOverWriteMode = somAsk; break;
      case OvrAlways:  FMySFXOverWriteMode = somOverwrite; break;
      case OvrNever:   FMySFXOverWriteMode = somSkip;
    }
    // translate options
    FMySFXOptions.Clear();
//    FMySFXOptions = FMySFXOptions << soCheckAutoRunFileName; // compatibility

    if(FZipBuilder->SFXOptions.Contains(SFXAskCmdLine)) FMySFXOptions = FMySFXOptions << soAskCmdLine;
    if(FZipBuilder->SFXOptions.Contains(SFXAskFiles)) FMySFXOptions = FMySFXOptions << soAskFiles;
    if(FZipBuilder->SFXOptions.Contains(SFXAutoRun)) FMySFXOptions = FMySFXOptions << soAutoRun;
    if(FZipBuilder->SFXOptions.Contains(SFXHideOverWriteBox)) FMySFXOptions = FMySFXOptions << soHideOverWriteBox;
    if(FZipBuilder->SFXOptions.Contains(SFXNoSuccessMsg)) FMySFXOptions = FMySFXOptions << soNoSuccessMsg;
    if(Detached) FMySFXOptions = FMySFXOptions << soDetached;
  }
#else
  // NO_SFX set in zipbuilder we use are own properties
  // convert message
  FMySFXMessageFlags = MB_OK;
  AnsiString Msg = SFXMessage;
  if(Msg != "")
  {
    switch(Msg[1])
    {
      case 1:
        FMySFXMessageFlags = MB_OKCANCEL | MB_ICONINFORMATION;
        Msg.Delete(1,1);
      break;
      case 2:
        FMySFXMessageFlags = MB_YESNO | MB_ICONQUESTION;
        Msg.Delete(1,1);
      break;
    }
  }
  FMySFXMessage = Msg;
  // translate overwrite
  switch(SFXOverWriteMode)
  {
    case somAsk: FMySFXOverWriteMode = somAsk; break;
    case somOverwrite:  FMySFXOverWriteMode = somOverwrite; break;
    case somSkip:   FMySFXOverWriteMode = somSkip;
  }
  // translate options
  FMySFXOptions.Clear();
//  FMySFXOptions = FMySFXOptions << soCheckAutoRunFileName; // compatibility

  if(SFXOptions.Contains(soAskCmdLine)) FMySFXOptions = FMySFXOptions << soAskCmdLine;
  if(SFXOptions.Contains(soAskFiles)) FMySFXOptions = FMySFXOptions << soAskFiles;
  if(SFXOptions.Contains(soAutoRun)) FMySFXOptions = FMySFXOptions << soAutoRun;
  if(SFXOptions.Contains(soHideOverWriteBox)) FMySFXOptions = FMySFXOptions << soHideOverWriteBox;
  if(SFXOptions.Contains(soNoSuccessMsg)) FMySFXOptions = FMySFXOptions << soNoSuccessMsg;
  if(Detached) FMySFXOptions = FMySFXOptions << soDetached;
#endif
    // add extra options not available in ZipBuilder
  if(SFXOptionsExt.Contains(soExpandVariables)) FMySFXOptions = FMySFXOptions << soExpandVariables;
  if(SFXOptionsExt.Contains(soInitiallyHideFiles)) FMySFXOptions = FMySFXOptions << soInitiallyHideFiles;
  if(SFXOptionsExt.Contains(soForceHideFiles)) FMySFXOptions = FMySFXOptions << soForceHideFiles;
  if(SFXOptionsExt.Contains(soCheckAutoRunFileName)) FMySFXOptions = FMySFXOptions << soCheckAutoRunFileName;
  if(SFXOptionsExt.Contains(soCanBeCancelled)) FMySFXOptions = FMySFXOptions << soCanBeCancelled;
}

//---------------------------------------------------------------------------
int __fastcall TZipBuilderSFX::ReadSFXProperties(const int InFile, const int MaxPos)
{
  int Result;
  if(CheckZipBuilder() > 0) return SE_ZipBuilderError;
  if((Result = ReadNewSFXProperties(InFile, MaxPos)) != 0)
  {
    int Max = min(1032, MaxPos);
    char* Data = new char[Max + 1];
    try
    {
      // goto MaxPos-Max and read a complete buffer
      if((FileSeek(InFile, MaxPos - Max, soFromBeginning) == -1) ||
         (FileRead(InFile, Data, Max) != Max)) Result = SE_OpenReadError;
      else
      {
        Result = 0; // OK, also if no header found( could be winzipsfx or something like this)
        // ok, blok read, now try to find MPV or MPU
        for(int i = 0; i <= Max - 3; i++)
				{
	 				if((Data[i] == 'M') && (Data[i + 1] == 'P') && ((Data[i + 2] == 'U') ||
		 			   (Data[i + 2] == 'V')))
					{
            // read back the orginal values from the MPU block
#ifndef NO_SFX_IN_ZIPBUILDER
            TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
            FZipBuilder->SFXOptions.Clear();
            FZipBuilder->SFXOverWriteMode = OvrConfirm;
            char cll = Data[i + 3];
						if(cll & 1)	 FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXAskCmdLine;
						if(cll & 2)	 FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXAskFiles;
						if(cll & 4)	 FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXHideOverWriteBox;
						if(cll & 8)	 FZipBuilder->SFXOverWriteMode = OvrAlways;
						if(cll & 16)	 FZipBuilder->SFXOverWriteMode = OvrNever;
						if(!(cll & 32)) FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXCheckSize;
						if(cll & 64)	 FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXAutoRun;
            if(Data[i + 2] == 'U')
            {
							FZipBuilder->SFXCaption = AnsiString(&Data[i+7], Data[i+4]);
							FZipBuilder->SFXDefaultDir = AnsiString(&Data[Data[i+4] + i+7], Data[i+5]);
							FZipBuilder->SFXCommandLine = AnsiString(&Data[Data[i+4] + Data[i+5] + i+7], Data[i+6]);
						}
						else
						{
							if(cll & 128)	 FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXNoSuccessMsg;
							char *Datastr = &Data[i + 8];
							FZipBuilder->SFXCaption = AnsiString(&Datastr[1], Datastr[0]);
							Datastr = Datastr + Datastr[0] + 1;
							FZipBuilder->SFXDefaultDir = AnsiString(&Datastr[1], Datastr[0]);
							Datastr = Datastr + Datastr[0] + 1;
							FZipBuilder->SFXCommandLine = AnsiString(&Datastr[1], Datastr[0]);
							Datastr = Datastr + Datastr[0] + 1;
							FZipBuilder->SFXMessage = AnsiString(&Datastr[1], Datastr[0]);
#else
            SFXOptions.Clear();
            SFXOverWriteMode = somAsk;
            char cll = Data[i + 3];
						if(cll & 1)	 SFXOptions = SFXOptions << soAskCmdLine;
						if(cll & 2)	 SFXOptions = SFXOptions << soAskFiles;
						if(cll & 4)	 SFXOptions = SFXOptions << soHideOverWriteBox;
						if(cll & 8)	 SFXOverWriteMode = somOverwrite;
						if(cll & 16)	 SFXOverWriteMode = somSkip;
						if(cll & 64)	 SFXOptions = SFXOptions << soAutoRun;
            if(Data[i + 2] == 'U')
            {
							SFXCaption = AnsiString(&Data[i+7], Data[i+4]);
							SFXDefaultDir = AnsiString(&Data[Data[i+4] + i+7], Data[i+5]);
							SFXCommandLine = AnsiString(&Data[Data[i+4] + Data[i+5] + i+7], Data[i+6]);
						}
						else
						{
							if(cll & 128)	 SFXOptions = SFXOptions << soNoSuccessMsg;
							char *Datastr = &Data[i + 8];
							SFXCaption = AnsiString(&Datastr[1], Datastr[0]);
							Datastr = Datastr + Datastr[0] + 1;
							SFXDefaultDir = AnsiString(&Datastr[1], Datastr[0]);
							Datastr = Datastr + Datastr[0] + 1;
							SFXCommandLine = AnsiString(&Datastr[1], Datastr[0]);
							Datastr = Datastr + Datastr[0] + 1;
							SFXMessage = AnsiString(&Datastr[1], Datastr[0]);
#endif
						}
            break;
          }
         }
      }
    }
    __finally
    {
      delete[] Data;
    }
  }
  return Result;
}
//---------------------------------------------------------------------------
int __fastcall TZipBuilderSFX::ReadNewSFXProperties(const int InFile, const int MaxPos)
{
  TSFXFileEndOfHeader FEOF;
  TSFXFileHeader  SFH;

  if(CheckZipBuilder() > 0) return SE_ZipBuilderError;
  if((FileSeek(InFile,(int)(MaxPos - sizeof(FEOF)), soFromBeginning) == -1) ||
     (FileRead(InFile, &FEOF, sizeof(FEOF)) != sizeof(FEOF)) ||
     (FEOF.Signature != SFX_HEADER_END_SIG) ||
     (FileSeek(InFile, (int)(0 - sizeof(FEOF) - FEOF.HeaderSize), soFromCurrent) == -1) ||
     (FileRead(InFile, &SFH, sizeof(SFH)) != sizeof(SFH)) ||
     (SFH.Size != (int)(FEOF.HeaderSize)) ||
     (SFH.Signature != SFX_HEADER_SIG)) return SE_GeneralError;
  // new sfx header found now parse it
#ifndef NO_SFX_IN_ZIPBUILDER
  TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
#endif
  switch(SFH.DefOVW)
  {
#ifndef NO_SFX_IN_ZIPBUILDER
    case somOverwrite: FZipBuilder->SFXOverWriteMode = OvrConfirm; break;
    case somSkip:      FZipBuilder->SFXOverWriteMode = OvrAlways ;  break;
    default: FZipBuilder->SFXOverWriteMode = OvrConfirm;
  }
  FZipBuilder->SFXOptions.Clear();
  FZipBuilder->SFXOptions << SFXCheckSize; // compatibility
  if(SFH.Options.Contains(soAskCmdLine)) FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXAskCmdLine;
  if(SFH.Options.Contains(soAskFiles)) FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXAskFiles;
  if(SFH.Options.Contains(soAutoRun)) FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXAutoRun;
  if(SFH.Options.Contains(soHideOverWriteBox)) FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXHideOverWriteBox;
  if(SFH.Options.Contains(soNoSuccessMsg)) FZipBuilder->SFXOptions = FZipBuilder->SFXOptions << SFXNoSuccessMsg;
  AnsiString Read;
  if(SFH.CaptionSize)
  {
    Read.SetLength(SFH.CaptionSize);
    if((FileRead(InFile, &Read[1], SFH.CaptionSize)) != SFH.CaptionSize) return SE_OpenReadError;
    FZipBuilder->SFXCaption = Read;
  }
  else  FZipBuilder->SFXCaption = "";
  if(SFH.PathSize)
  {
    Read.SetLength(SFH.PathSize);
    if((FileRead(InFile, &Read[1], SFH.PathSize)) != SFH.PathSize) return SE_OpenReadError;
    FZipBuilder->SFXDefaultDir = Read;
  }
  else  FZipBuilder->SFXDefaultDir = "";
  if(SFH.CmdLineSize)
  {
    Read.SetLength(SFH.CmdLineSize);
    if((FileRead(InFile, &Read[1], SFH.CmdLineSize)) != SFH.CmdLineSize) return SE_OpenReadError;
    FZipBuilder->SFXCommandLine = Read;
  }
  else  FZipBuilder->SFXCommandLine = "";
  if(SFH.RegFailPathSize)
  {
    Read.SetLength(SFH.RegFailPathSize);
    if((FileRead(InFile, &Read[1], SFH.RegFailPathSize)) != SFH.RegFailPathSize) return SE_OpenReadError;
    RegFailPath = Read;
  }
  else RegFailPath = "";
  if(SFH.StartMsgSize)
  {
    Read.SetLength(SFH.StartMsgSize);
    if((FileRead(InFile, &Read[1], SFH.StartMsgSize)) != SFH.StartMsgSize) return SE_OpenReadError;
    FZipBuilder->SFXMessage = Read;
  }
  else  FZipBuilder->SFXMessage = "";
  switch(SFH.StartMsgType)
  {
    case MB_OKCANCEL | MB_ICONINFORMATION: FZipBuilder->SFXMessage = "\1" + FZipBuilder->SFXMessage;
    break;
    case MB_YESNO | MB_ICONQUESTION: FZipBuilder->SFXMessage = "\2" + FZipBuilder->SFXMessage;
    break;
  }
#else
    case somOverwrite: SFXOverWriteMode = somOverwrite; break;
    case somSkip:      SFXOverWriteMode = somSkip;  break;
    default: SFXOverWriteMode = somAsk;
  }
  SFXOptions.Clear();
  if(SFH.Options.Contains(soAskCmdLine)) SFXOptions = SFXOptions << soAskCmdLine;
  if(SFH.Options.Contains(soAskFiles)) SFXOptions = SFXOptions << soAskFiles;
  if(SFH.Options.Contains(soAutoRun)) SFXOptions = SFXOptions << soAutoRun;
  if(SFH.Options.Contains(soHideOverWriteBox)) SFXOptions = SFXOptions << soHideOverWriteBox;
  if(SFH.Options.Contains(soNoSuccessMsg)) SFXOptions = SFXOptions << soNoSuccessMsg;
  AnsiString Read;
  if(SFH.CaptionSize)
  {
    Read.SetLength(SFH.CaptionSize);
    if((FileRead(InFile, &Read[1], SFH.CaptionSize)) != SFH.CaptionSize) return SE_OpenReadError;
    SFXCaption = Read;
  }
  else  SFXCaption = "";
  if(SFH.PathSize)
  {
    Read.SetLength(SFH.PathSize);
    if((FileRead(InFile, &Read[1], SFH.PathSize)) != SFH.PathSize) return SE_OpenReadError;
    SFXDefaultDir = Read;
  }
  else  SFXDefaultDir = "";
  if(SFH.CmdLineSize)
   {
    Read.SetLength(SFH.CaptionSize);
    if((FileRead(InFile, &Read[1], SFH.CaptionSize)) != SFH.CaptionSize) return SE_OpenReadError;
    SFXCaption = Read;
  }
  else  SFXCaption = "";
  if(SFH.PathSize)
  {
    Read.SetLength(SFH.PathSize);
    if((FileRead(InFile, &Read[1], SFH.PathSize)) != SFH.PathSize) return SE_OpenReadError;
    SFXDefaultDir = Read;
  }
  else  SFXDefaultDir = "";
  if(SFH.CmdLineSize)
  {
    Read.SetLength(SFH.CmdLineSize);
    if((FileRead(InFile, &Read[1], SFH.CmdLineSize)) != SFH.CmdLineSize) return SE_OpenReadError;
    SFXCommandLine = Read;
  }
  else SFXCommandLine = "";
  if(SFH.RegFailPathSize)
  {
    Read.SetLength(SFH.RegFailPathSize);
    if((FileRead(InFile, &Read[1], SFH.RegFailPathSize)) != SFH.RegFailPathSize) return SE_OpenReadError;
    RegFailPath = Read;
  }
  else RegFailPath = "";
  if(SFH.StartMsgSize)
    {
    Read.SetLength(SFH.StartMsgSize);
    if((FileRead(InFile, &Read[1], SFH.StartMsgSize)) != SFH.StartMsgSize) return SE_OpenReadError;
    SFXMessage = Read;
  }
  else SFXMessage = "";
  switch(SFH.StartMsgType)
  {
    case MB_OKCANCEL | MB_ICONINFORMATION: SFXMessage = "\1" + SFXMessage;
    break;
    case MB_YESNO | MB_ICONQUESTION: SFXMessage = "\2" + SFXMessage;
    break;
  }
#endif
  SFXOptionsExt.Clear();
  if(SFH.Options.Contains(soExpandVariables)) SFXOptionsExt = SFXOptionsExt << soExpandVariables;
  if(SFH.Options.Contains(soInitiallyHideFiles)) SFXOptionsExt = SFXOptionsExt << soInitiallyHideFiles;
  if(SFH.Options.Contains(soForceHideFiles)) SFXOptionsExt = SFXOptionsExt << soForceHideFiles;
  if(SFH.Options.Contains(soCheckAutoRunFileName)) SFXOptionsExt = SFXOptionsExt << soCheckAutoRunFileName;
  if(SFH.Options.Contains(soCanBeCancelled)) SFXOptionsExt = SFXOptionsExt << soCanBeCancelled;
  return 0;
}
//---------------------------------------------------------------------------
int __fastcall TZipBuilderSFX::ReadSFXIcon(AnsiString File)
{
  if(CheckZipBuilder() > 0) return SE_ZipBuilderError;
  // read the 'custom' icon back from the executable
  HICON hico = ExtractIcon(HInstance, File.c_str(), 0);
  if(hico && (hico != INVALID_HANDLE_VALUE))
  {
#ifndef NO_SFX_IN_ZIPBUILDER
    TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
    if(FZipBuilder->SFXIcon->Handle) FZipBuilder->SFXIcon->ReleaseHandle();
    FZipBuilder->SFXIcon->Handle = hico;
#else
    if(SFXIcon->Handle) SFXIcon->ReleaseHandle();
    SFXIcon->Handle = hico;
#endif
  }
  return 0;
}

//---------------------------------------------------------------------------
void __fastcall TZipBuilderSFX::Notification(Classes::TComponent* aComponent,
                                                     Classes::TOperation Operation)
{
  TZipBuilder* FZipBuilder = dynamic_cast<TZipBuilder*>(FBuilder);
  if(Operation == opRemove && aComponent == FZipBuilder) FZipBuilder = NULL;
}
//---------------------------------------------------------------------------
// Search for the right(with our icon) resource directory entry.
DWord __fastcall TZipBuilderSFX::SearchResDirEntry(pIRD ResStart, pIRDirE entry, int Depth)
{
	pIRDatE data;
	if(entry->NameIsString) return 0;				// No named resources.
	if(!Depth && entry->Id != 3) return 0;			// Only icon resources.
	if(Depth == 1 && entry->Id != 1) return 0;	// Only icon with ID 0x1.
	if(!entry->DataIsDirectory)
	{
		data = (pIRDatE)((char *)ResStart + entry->OffsetToData);
		if(data->Size == 744)	return data->OffsetToData;
	} else
		return BrowseResDir(ResStart, (pIRD)((char *)ResStart + entry->OffsetToDirectory ), Depth + 1);
	return 0;
}
//-----------------------------------------------------------------------------------
// Browse through all resource Directories.
DWord __fastcall TZipBuilderSFX::BrowseResDir(pIRD ResStart, pIRD dir, int Depth)
{
	pIRDirE SingleRes = (pIRDirE)((char *)dir + sizeof(IMAGE_RESOURCE_DIRECTORY));
	DWord	Result = 0;

	for(int i = 0; i < dir->NumberOfNamedEntries + dir->NumberOfIdEntries; i++)
	{
		Result = SearchResDirEntry(ResStart, SingleRes, Depth);
		if(Result) break;   // Found the one w're looking for.
		SingleRes++;
	}
	return Result;
}
//----------------------------------------------------------------------------------------
// Find Resource directory entry.
DWord __fastcall TZipBuilderSFX::LookForDirs(const void *SectionData,
                                          const DWord SectionVirtualStart,
															            const int SectionLen, pIDD directories)
{
	pIRD  ResStart;
	DWord Result = 0;
	pIDD  dirs = directories;

	dirs += IMAGE_DIRECTORY_ENTRY_RESOURCE;
	if(dirs->VirtualAddress && ((char *)dirs->VirtualAddress >= (char *)SectionVirtualStart) &&
		(char *)dirs->VirtualAddress < ((char *)SectionVirtualStart + SectionLen))
	{
		ResStart = (pIRD)((char *)SectionData + (dirs->VirtualAddress - SectionVirtualStart));
		Result = BrowseResDir( ResStart, ResStart, 0);
	}
	return Result;
}
//----------------------------------------------------------------------------------------
// NOTE: we will allow a dir to be specified that doesn't exist,
// since this is not the only way to locate the DLLs.
void __fastcall TZipBuilderSFX::SetSFXPath(AnsiString Value )
{
	if(Value != SFXPath)
	{
		int ValLen = Value.Length();
		// If there is a trailing '\' in path, cut it off:
    if(ValLen && (Value[ValLen] == '\\'))  Value.SetLength(ValLen - 1);
    FSFXPath = Value;
	}
}
//----------------------------------------------------------------------------------------
void __fastcall TZipBuilderSFX::SetRegFailPath(AnsiString Value )
{
	if(Value != FRegFailPath)
	{
    FRegFailPath = Value;
	}
}
//---------------------------------------------------------------------------
#ifdef NO_SFX_IN_ZIPBUILDER
void __fastcall TZipBuilderSFX::SetSFXIcon(TIcon *aIcon)
{
	FSFXIcon->Assign(aIcon);
}
#endif


