⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zipbuilder.cpp

📁 zip算法的源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/* TZipBuilder component v1.60 by Chris Vleghert
 * a C++ Builder 1, 3, 4 , 5 and 6 wrapper for the freeware ZIP and UNZIP DLL's
 * from Chris Vleghert and E.W. Engler.
 *	 e-mail: englere@abraxis.com
 *  www:    http://www.geocities.com/SiliconValley/Network/2114
 *  v1.72 by Roger Aelbrecht Februari 18, 2003.
 *          http://web.wanadoo.be/driehoeksw
 */



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

#pragma package(smart_init)	// Used in BCB 3,4,5 ignored in BCB 1
#pragma resource "*.res"

#include "ZIPBuilder.h"
#include "ZipMsg.h"
#include "ZipBuildDefs.h"

//USEUNIT("CallBack.cpp");
//USEUNIT("ZipDLL.cpp");
//USEUNIT("UnZipDLL.cpp");

// Added by Russell Peters to compile/build under BCB6
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#if __BORLANDC__ > 0x0550
#define STRMSIZ(x) __int64(x)
#else
#define STRMSIZ(x) x
#endif
//end of add

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

// TZipBuilder::GetZipComment---------------------------------------------------
// 1.73.3.2 11 Oct 2003 RP comment now converted when read
// 1.73 (2 June 2003) RA use ConvertOEM
String __fastcall TZipBuilder::GetZipComment(void)
{
//  return ConvertOEM(FZipComment, cpdOEM2ISO);
  return FZipComment;
}
// TZipBuilder::GetZipComment

// TZipBuilder::SetZipComment---------------------------------------------------
// 1.73.3.2 11 Oct 2003 RP allow preset comment
// 1.73 (10 June 2003) RA bugfix
// changed 1.73 (22 May 2003) RA use of ReadJoin
void __fastcall TZipBuilder::SetZipComment(String zComment)
{
	struct ZipEndOfCentral  EOC;
	bool Fatal = false;
	FInFileHandle = -1;
	try
  {
    if(!FZipFileName.Length() ) throw EZipBuilder(GE_NoZipSpecified);
#ifndef NO_SPAN
    // for multi volume find last volume and allow that file does not exists
    GetLastVolume(FZipFileName, EOC, true); // wil read existing comment
#else
    OpenEOC(EOC,false);
#endif
    FZipComment = zComment;
    if(FInFileHandle != -1)
    {
      FileClose(FInFileHandle);  // must reopen for read/write
      AnsiString CommentBuf = ConvertOEM(zComment, cpdISO2OEM);
      if(CommentBuf == FEOCComment) return; // same - nothing to do
      int len = CommentBuf.Length();
      FInFileHandle = FileOpen( FInFileName, fmShareDenyWrite | fmOpenReadWrite );
      if(FInFileHandle == -1)
          throw EZipBuilder(DS_FileOpen);
      if(FileSeek(FInFileHandle, (SeekInt)FZipEOC, 0 ) == -1)
          throw EZipBuilder(DS_FailedSeek);
      ReadJoin( &EOC, sizeof(EOC), DS_EOCBadRead);
      EOC.ZipCommentLen = len;
      if(FileSeek(FInFileHandle, -(SeekInt)(signed)sizeof(EOC), 1) == -1)
        throw EZipBuilder(DS_FailedSeek);
      Fatal = true;
      if(FileWrite(FInFileHandle, &EOC, sizeof(EOC)) != sizeof(EOC))
        throw EZipBuilder(DS_EOCBadWrite);
      if(FileWrite( FInFileHandle, FZipComment.c_str(), len ) != len )
        throw EZipBuilder(DS_NoWrite);
      Fatal = false;
    // if SetEOF fails we get garbage at the end of the file, not nice but
    // also not important.
      SetEndOfFile((HANDLE)FInFileHandle);
    }
  }
	catch (const EZipBuilder &ezl)
  {
		ShowExceptionError(ezl);
		FZipComment = "";
	}
	catch (const MEMEXCEPT &me)
  {
		ShowZipMessage(GE_NoMem);
		FZipComment = "";
  }
	if(FInFileHandle != -1)	FileClose(FInFileHandle);
	if(Fatal)	// Try to read the zipfile, maybe it still works.
		_List();
}
// TZipBuilder::SetZipComment

// TZipBuilder::OpenEOC--------------------------------------------------------
// 1.73.3.2 8 Oct 2003 RA RP allow max 512 whitespace chars at end of file and save comment
// changed 1.73 (22 May 2003) RA use ReadJoin
// Function to find the EOC record at the end of the archive (on the last disk.)
// We can get a return value( true::Found, false::Not Found ) or an exception if not found.
bool __fastcall TZipBuilder::OpenEOC(struct ZipEndOfCentral &EOC, bool DoExcept)
{
	unsigned long  Sig;
	int			   DiskNo = 0;
	bool			   First = false;
	AnsiString ZipBuf;

	FZipComment = "";
	FZipEOC     =  0;
  FEOCComment = "";
	// Open the input archive, presumably the last disk.
	if((FInFileHandle = FileOpen(FInFileName, fmShareDenyWrite | fmOpenRead )) == -1)
	{
		if(DoExcept) throw EZipBuilder(DS_NoInFile);
		ShowZipMessage(DS_FileOpen);
		return false;
	}
	// First a check for the first disk of a spanned archive,
	// could also be the last so we don't issue a warning yet.
	if(FileRead(FInFileHandle, &Sig, 4) == 4 && Sig == ExtLocalSig &&
		 FileRead(FInFileHandle, &Sig, 4) == 4 && Sig == LocalFileHeaderSig)
	{
		First = true;
		FIsSpanned = true;
	}
	// Next we do a check at the end of the file to speed things up if
	// there isn't a Zip archive comment.
	if((FFileSize = (long)FileSeek(FInFileHandle, -(SeekInt)(signed)sizeof(EOC), 2 )) != -1 )
	{
		FFileSize += sizeof(EOC);	// Save the archive size as a side effect.
		FRealFileSize = FFileSize;		// There could follow a correction on FFileSize.
		if(FileRead(FInFileHandle, &EOC, sizeof(EOC)) == sizeof(EOC) &&
				EOC.HeaderSig == EndCentralDirSig)
		{
			FZipEOC = FFileSize - sizeof(EOC);
      return true;
		}
	}
	// Now we try to find the EOC record within the last 65535 + sizeof( EOC ) bytes
	// of this file because we don't know the Zip archive comment length at this time.
	try
	{
		int Size = min(FFileSize, (long)(65535 + sizeof(EOC)));
		ZipBuf.SetLength(Size);
		if(FileSeek(FInFileHandle, (SeekInt)(-Size), 2) == -1) throw EZipBuilder(DS_FailedSeek);
    ReadJoin(ZipBuf.c_str(), Size,DS_EOCBadRead);
		for(int i = Size - sizeof(EOC)- 1; i >= 0; i--)
    {
      ZipEndOfCentral* pEOC = reinterpret_cast<ZipEndOfCentral*>(ZipBuf.c_str() + i);
      if(pEOC->HeaderSig == EndCentralDirSig)
			{
				FZipEOC = FFileSize - Size + i;
				memcpy(&EOC, ZipBuf.c_str() + i, sizeof(EOC));
        //If we have ZipComment: Save it,No codepage translation yet, wait for CEH read.
        if(EOC.ZipCommentLen)
					FEOCComment = ZipBuf.SubString(i + sizeof(EOC) + 1 , EOC.ZipCommentLen);
				// Check if we really are at the end of the file, if not correct the filesize
				// and give a warning. (It should be an error but we are nice.)
				if(i + sizeof(EOC) + EOC.ZipCommentLen - Size)
				{
					FFileSize += (i + sizeof(EOC) + (unsigned)EOC.ZipCommentLen - Size);
					// Now we need a check for WinZip Self Extractor which makes SFX files which
					// allmost always have garbage at the end (Zero filled at 512 byte boundary!)
					// In this special case 'we' don't give a warning.
					bool ShowGarbageMsg = true;
//					if(FRealFileSize - (unsigned)FFileSize < 512 && (FRealFileSize % 512) == 0)
          if(FRealFileSize - (unsigned)FFileSize < 512)
					{
						int j = i + sizeof(EOC) + EOC.ZipCommentLen;
//						while(ZipBuf[j] == '\0' && j <= Size) j++;
            while(ZipBuf[j] < '/' && j <= Size) j++;
						if(j == Size + 1) ShowGarbageMsg = false;
					}
					if(ShowGarbageMsg) ShowZipMessage(LI_GarbageAtEOF);
				}
				// If we have a ZipComment save it, must be after Garbage check because a '\0' is set!
/*				if(EOC.ZipCommentLen)
				{
					ZipBuf[i + sizeof(EOC) + EOC.ZipCommentLen] = '\0';
					FZipComment = AnsiString(ZipBuf + i + sizeof(EOC));  // No codepage translation yet, wait for CEH read.
				}   */
//				delete[] ZipBuf;
				return true;
      }
		}
//		delete[] ZipBuf;
	}
	catch ( ... )
	{
//		delete[] ZipBuf;
		if(DoExcept) throw;
	}
	if(DoExcept)
	{ // Get the volume number if it's disk from a set. - 1.72 moved
    if(FVolumeName.SubString(1, 8) == "PKBACK# ")
		      DiskNo = StrToIntDef(FVolumeName.SubString(9, 3), 0);
    else
    {
      AnsiString	ext = UpperCase(ExtractFileExt(FInFileName));
			DiskNo = 0;
      if(ext.SubString(1,2) == ".Z")
           DiskNo = StrToIntDef(ext.SubString(2,2),0);
      if(DiskNo <= 0)
           DiskNo = StrToIntDef(FInFileName.SubString(FInFileName.Length() -
                                                   ext.Length() - 3 +1, 3),0);

    }
		if(!First && DiskNo) throw EZipBuilder(DS_NotLastInSet, DiskNo);
		throw EZipBuilder((First) ? ((DiskNo == 1) ? DS_FirstInSet : DS_FirstFileOnHD) : DS_NoValidZip);
	}
	return false;
}
// TZiPBuidler::OpenEOC

// TZipBuilder::_List-----------------------------------------------------------
// 1.73.3.2 Oct 11 2003 RP convert saved comment
// 1.73 (26 July 2003) RA - added test for empty ZipFileName
// 1.73 (15 July 2003) RP / RA ReadJoin
void __fastcall TZipBuilder::_List(void) // All work is local - no DLL calls.
{
	struct ZipEndOfCentral  EOC;
	struct ZipCentralHeader CEH;
	ZipDirEntry *pzd = NULL;
	unsigned long	OffsetDiff = 0;
	char Name[ MAX_PATH ]; //, *fc = NULL;
	bool LiE = false;
	// Can't do LIST at design time.
	if(ComponentState.Contains(csDesigning)) return;

	// Zero out any previous entries.
	FreeZipDirEntryRecords();


	FRealFileSize = 0;
	FZipSOC	= 0;
	FSFXOffset = 0;  //must be before the following "if"
//	FZipComment = "";  //done in openEOC
	FIsSpanned = false;
	FDirOnlyCount = 0;
  ErrCode = 0;  // reset previous error code
  char MadeOS = 0;   	// 1.73.3.2
	char MadeVer = 20;   // 1.73.3.2

  if(FZipFileName =="")
  {
    if(FOnDirUpdate) FOnDirUpdate(this);
    return;
  }
#ifndef NO_SPAN
  // Locate last of multi volume or last disk of spanned
  int Result = GetLastVolume(FZipFileName,EOC,true);
  if(Result == -1) return; // error exception should been thrown when detected;
  if(Result == 1) // Don't complain - this may intentionally be a new zip file.
#else
	if(!FileExists(FZipFileName))
#endif
  {
    if(FOnDirUpdate) FOnDirUpdate(this);
    return;
  }
	try
	{
  	StartWaitCursor();
  	try
  	{
#ifdef NO_SPAN
      FInFileName = FZipFileName; // to open EOC
      if(!OpenEOC(EOC, false))   // if no EOC then not valid zip
           throw EZipBuilder(DS_NoValidZip, true);
#endif
  		FTotalDisks = EOC.ThisDiskNo;	// Needed if GetNewDisk() is called.

  		// This could also be set to True if it's the first and only disk.
  		if(EOC.ThisDiskNo > 0) FIsSpanned = true;

  		// Do we have to request for a previous disk first?
  		if(EOC.ThisDiskNo != EOC.CentralDiskNo)
  		{
#ifndef NO_SPAN
  			GetNewDisk(EOC.CentralDiskNo);
  			FFileSize = FileSeek(FInFileHandle, 0, 2);	//v1.52j
  			OffsetDiff = EOC.CentralOffset;	//v1.52j
#else
        throw EZipBuilder(DS_NoDiskSpan, true);
#endif
  		}
  		else	//v1.52j
  			// Due to the fact that v1.3, v1.4 and v1.45 programs do not change the archives
  			// EOC and CEH records in case of a SFX conversion (and back) we have to
  			// make this extra check.
  			OffsetDiff = FFileSize - EOC.CentralSize - sizeof(EOC) - EOC.ZipCommentLen;
  		FWrongZipStruct = false;
  		if(EOC.CentralOffset != OffsetDiff)
  		{	// Issue a warning only.
  			FWrongZipStruct = true;		// We need this in the ConvertXxx functions.
  			ShowZipMessage( LI_WrongZipStruct );
  		}
  		// Now we can go to the start of the Central directory.
  		if(FileSeek(FInFileHandle, (SeekInt)OffsetDiff, 0 ) == -1 )
  			throw EZipBuilder(LI_ReadZipError);

  		FZipSOC  = OffsetDiff;
  		FSFXOffset = FFileSize;
  		if(FFileSize == 22) FSFXOffset = 0; //v1.52L

  		// Read every entry: The central header and save the information.
  		FZipContents->Capacity = EOC.TotalEntries;
  		for(int i = 0; i < EOC.TotalEntries; i++)
      {
  			// Read a central header.
  			while(FileRead(FInFileHandle, &CEH, sizeof(CEH)) != sizeof(CEH))
        {	//v1.52j
  				// It's possible that we have the central header split up.
  				if(FDiskNr >= EOC.ThisDiskNo)	throw EZipBuilder(DS_CEHBadRead);
  				// We need the next disk with central header info.
#ifndef NO_SPAN
  				GetNewDisk(FDiskNr + 1);
#else
          throw EZipBuilder(DS_NoDiskSpan, true);
#endif
  			}
  			if(CEH.HeaderSig != CentralFileHeaderSig) throw EZipBuilder(DS_CEHWrongSig);

  			// Now the filename.
        ReadJoin( Name, CEH.FileNameLen,DS_CENameLen);
        // Save version info globally for use by codepage translation routine
  			FHostNum = CEH.VersionMadeBy1;
  			FHostVer = CEH.VersionMadeBy0;
        if(FHostNum > 0)	// not msdos

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -