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

📄 zipbuilder.cpp

📁 zip算法的源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
			// Do we still have enough free space on this disk.
			if(FFreeOnDisk < MinFreeVolumeSize)
			{	// No, too bad...
				FileClose(FOutFileHandle);
				DeleteFile(DiskFile);
				FOutFileHandle = -1;
				if(Unattended) throw EZipBuilder(DS_NoUnattSpan);
				if(FOnStatusDisk)
				{						// v1.60L
          int DiskSeq;
          if(FSpanOptions.Contains(spNoVolumeName)) DiskSeq = FDiskNr + 1;
					else DiskSeq = StrToIntDef(FVolumeName.SubString(9, 3), 1);
					FZipDiskAction = zdaOk;					// The default action
					FZipDiskStatus = TZipDiskStatus() << zdsNotEnoughSpace;
					OnStatusDisk(this, DiskSeq, DiskFile, FZipDiskStatus, FZipDiskAction);
					switch(FZipDiskAction)
					{
						case zdaCancel: Res = IDCANCEL;	break;
						case zdaOk:
						case zdaErase:
						case zdaReject: Res = IDRETRY;
					}
				}
				else
				{
					MsgQ = LoadZipStr(DS_NoDiskSpace, "This disk has not enough free space available");
					Res = Application->MessageBox(MsgQ.c_str(), Application->Title.c_str(),
					                     MB_RETRYCANCEL | MB_ICONERROR );
				}
				if(!Res) throw EZipBuilder(DS_NoMem);
				if(Res != IDRETRY ) throw EZipAbort();
				FDiskWritten = 0;
				FNewDisk = true;
				continue;
			}
			// Set the volume label of this disk if it is not a fixed one.
			if(!FDriveFixed && !FSpanOptions.Contains(spNoVolumeName))
			{
				FVolumeName = "PKBACK# " + IntToStr(1001 + FDiskNr).SubString(2, 3);

				if(!::SetVolumeLabel(FDrive.c_str(), FVolumeName.c_str()))
					throw EZipBuilder(DS_NoVolume);
			}
		}
		// Check if we have at least MinSize available on this disk,
		// headers are not allowed to cross disk boundaries. ( if zero than don't care.)
		if(MinSize && MinSize > FFreeOnDisk)
		{
			FileSetDate(FOutFileHandle, FDateStamp);
			FileClose(FOutFileHandle);
			FOutFileHandle = -1;
			FDiskWritten = 0;
			FDiskNr++;
			FNewDisk = true;
			continue;
		}
		// Don't try to write more bytes than allowed on this disk.
		MaxLen = min(Len, FFreeOnDisk);
		Res = FileWrite(FOutFileHandle, Buf, MaxLen);
		// Give some progress info while writing.
		// While processing the central header we don't want messages.
		if(FShowProgress) CallBack(zacProgress, 0,"",MaxLen);
		if(Res == -1) throw EZipBuilder(DS_NoWrite);	// A write error (disk removed?).
    FDiskWritten += Res;
		FFreeOnDisk  -= MaxLen;
		if(MaxLen == Len) break;

		// We still have some data left, we need a new disk.
		FileSetDate(FOutFileHandle, FDateStamp);
		FileClose(FOutFileHandle);
		FOutFileHandle = -1;
		FFreeOnDisk = FDiskWritten = 0;
		FDiskNr++;
		FNewDisk = true;
		Buf += MaxLen;
		Len -= MaxLen;
	}
}
// TZipBuilder::WriteSplit
#endif

// TZipBuilder::CopyZippedFiles-------------------------------------------------
// 1.73 1 Oct 2003 RA corrected slashes in central dir
// 1.73 8 August 2003 RA close InFileHandle after error, set to -1 in non-error case
// 1.73 (31 July 2003) RA close InFileHandle for Spanerror
// 1.73 (24 July 2003) RA init OutFileHandle
// 1.73 (12 July 2003) RP string extra data
// 1.73 (2 June 2003) RA Use of ConvertOEM
// Function to copy one or more zipped files from the zip archive to another zip archive
// FSpecArgs in source is used to hold the filename(s) to be copied.
// When this function is ready FSpecArgs contains the file(s) that where not copied.
// Return values:
// 0            All Ok.
// -6           CopyZippedFiles Busy
// -7           CopyZippedFiles errors. See ZipMsgXX.rc
// -8           Memory allocation error.
// -9           General unknown CopyZippedFiles error.
int __fastcall TZipBuilder::CopyZippedFiles(TZipBuilder *DestZipBuilder, bool DeleteFromSource,
                                            OvrOpts OverwriteDest)
{
	ZipEndOfCentral    EOC;
	ZipCentralHeader   CEH;
	ZipDirEntry			*zde, *pzd;
	String             OutFilePath;
	char				   *Buffer = NULL;
	int				    Result = 0;
	int					 In2FileHandle = -1; //to avoid external exception in case of error RAEL
	TStringList			*NotCopiedFiles = NULL;
	bool					 Found;
	int					 DestMemCount;
  TMZipDataList* MDZD = NULL;
  if(Busy()) return BUSY_ERROR;
	StartWaitCursor();
  FZipBusy = true;
	FShowProgress = false;
  FOutFileHandle = -1;
	try
	{
		// Are source and destination different?
		if(DestZipBuilder == this || !AnsiStrIComp(ZipFileName.c_str(),
		                                           DestZipBuilder->ZipFileName.c_str()))
			throw EZipBuilder(CF_SourceIsDest);
    //testing for diskspan  added RAEL
    // The following function a.o. opens the input file no. 1.
    OpenEOC(EOC, false);
    if(DestZipBuilder->IsSpanned || FIsSpanned)
      throw EZipBuilder(CF_NoCopyOnSpan, true);
		Buffer = new char[BufSize];

		// Now check for every source file if it is in the destination archive and determine what to do.
		// we use the three most significant bits from the Flag field from ZipDirEntry to specify the action
		// None           = 000xxxxx, Destination no change. Action: Copy old Dest to New Dest
		// Add            = 001xxxxx (New).                  Action: Copy Source to New Dest
		// Overwrite      = 010xxxxx (OvrAlways)             Action: Copy Source to New Dest
		// AskToOverwrite = 011xxxxx (OvrConfirm)	Action to perform: Overwrite or NeverOverwrite
		// NeverOverwrite = 100xxxxx (OvrNever)				  Action: Copy old Dest to New Dest
		for(int s = 0; s < FSpecArgs->Count; s++)
		{
    //added R.Aelbrecht to allow drive name in FSpecArg
      AnsiString FSpec = FSpecArgs->Strings[s];
      RemoveDriveSpec(FSpec);
			Found = false;
			for(int d = 0; d < DestZipBuilder->Count; d++)
			{
				zde = (ZipDirEntry *)DestZipBuilder->ZipContents->Items[d];
				if(!AnsiStrIComp(FSpec.c_str(), zde->FileName.c_str()))
				{
					Found = true;
					zde->Flag &= 0x1FFF;	// Clear the three upper bits.
					zde->Flag |= (OverwriteDest == OvrAlways) ? 0x4000ui16 : (OverwriteDest == OvrNever) ? 0x8000ui16 : 0x6000ui16;
					break;
				}
			}
			if(!Found)
			{	// Add the Filename to the list and set flag
				zde = new ZipDirEntry;
				DestZipBuilder->FZipContents->Add(zde);
				zde->FileName       = FSpec;
				zde->FileName.Unique();
				zde->FileNameLength = (Word)FSpecArgs->Strings[s].Length();
				zde->Flag |= 0x2000;		// (a new entry)
				zde->ExtraData = NULL;	//Needed when deleting zde
			}
		}
		// Make a temporary filename like: C:\...\zipxxxx.zip for the new destination
		if((OutFilePath = MakeTempFileName()) == "")	throw EZipBuilder(DS_NoTempFile);

		// Create the output file.
		FOutFileHandle = FileCreate(OutFilePath);
		if(FOutFileHandle == -1)	throw EZipBuilder(DS_NoOutFile);

		// Open the second input archive, i.e. the original destination.
		if((In2FileHandle = FileOpen(DestZipBuilder->ZipFileName, fmShareDenyWrite | fmOpenRead )) == -1)
			throw EZipBuilder(CF_DestFileNoOpen);

		// Get the date-time stamp and save for later.
		FDateStamp = FileGetDate(In2FileHandle);

		// Write the SFX header if present.
		if(CopyBuffer(In2FileHandle, FOutFileHandle, DestZipBuilder->SFXOffset))
			throw EZipBuilder(CF_SFXCopyError);

		NotCopiedFiles = new TStringList();
		// Now walk trough the destination, copying and replacing
		DestMemCount = DestZipBuilder->FZipContents->Count;
		MDZD = new TMZipDataList(DestMemCount);  // create class

		// Copy the local data and save central header info for later use.
		for(int d = 0; d < DestMemCount; d++)
		{
			zde = (ZipDirEntry *)DestZipBuilder->ZipContents->Items[d];
			if((zde->Flag & 0xE000) == 0x6000)
			{	// Ask first if we may overwrite.
				bool Overwrite = false;
				// Do we have a event assigned for this then don't ask.
				if(FOnCopyZipOverwrite)	FOnCopyZipOverwrite(DestZipBuilder, zde->FileName, Overwrite);
				else Overwrite = (Application->MessageBox( Format(LoadZipStr(CF_OverwriteYN, "Overwrite %s in %s ?"),
											ARRAYOFCONST((zde->FileName, DestZipBuilder->ZipFileName))).c_str(),
											Application->Title.c_str(),
											MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2 )== IDYES) ? true : false;
				zde->Flag &= 0x1FFF;	// Clear the three upper bits.
				zde->Flag |= (Overwrite) ? 0x4000ui16 : 0x8000ui16;
			}
			// Change info for later while writing the central dir in new Dest.
			MDZD->Items[d]->RelOffLocal = FileSeek(FOutFileHandle, 0, 1);

			if((zde->Flag & 0x6000) == 0x0000)
			{	// Copy from original dest to new dest.
				// Set the file pointer to the start of the local header.
				FileSeek(In2FileHandle, (SeekInt)zde->RelOffLocalHdr, 0);
				if(CopyBuffer(In2FileHandle, FOutFileHandle, sizeof(ZipLocalHeader) +
				                                                    zde->FileNameLength +
				                                                    zde->ExtraFieldLength +
				                                                    zde->CompressedSize))
					throw EZipBuilder(CF_CopyFailed, DestZipBuilder->ZipFileName, DestZipBuilder->ZipFileName);
				if(zde->Flag & 0x8000)
				{
					NotCopiedFiles->Add(zde->FileName);
					// Delete also from FSpecArgs, should not be deleted from source later.
					FSpecArgs->Delete(FSpecArgs->IndexOf(zde->FileName));
				}
			}
			else
			{	// Copy from source to new dest.
				// Find the filename in the source archive and position the file pointer.
				for(int s = 0; s < Count; s++)
				{
					pzd = (ZipDirEntry *)ZipContents->Items[s];
					if(!AnsiStrIComp(pzd->FileName.c_str(), zde->FileName.c_str()))
					{
						FileSeek(FInFileHandle, (SeekInt)pzd->RelOffLocalHdr, 0);
						if(CopyBuffer(FInFileHandle, FOutFileHandle, sizeof(ZipLocalHeader) +
						                                                    pzd->FileNameLength +
						                                                    pzd->ExtraFieldLength +
						                                                    pzd->CompressedSize))
							throw EZipBuilder(CF_CopyFailed, ZipFileName, DestZipBuilder->ZipFileName);
						break;
					}
				}
			}
			// Save the file name info in the MDZD structure.
			MDZD->Items[d]->FileNameLen = zde->FileNameLength;
      MDZD->Items[d]->FileName    = new char[zde->FileNameLength + 1];
			StrCopy(MDZD->Items[d]->FileName, zde->FileName.c_str());
		}	// Now we have written al entries.

		// Now write the central directory with possibly changed offsets.
		// Remember the EOC we are going to use is from the wrong input file!
		EOC.CentralSize = 0;
		for(int d = 0; d < DestMemCount; d++)
		{
			zde = (ZipDirEntry *)DestZipBuilder->ZipContents->Items[d];
			Found = false;
			// Rebuild the CEH structure.
			if((zde->Flag & 0x6000) == 0x0000)
			{	// Copy from original dest to new dest.
				pzd = (ZipDirEntry *)DestZipBuilder->ZipContents->Items[d];
				Found = true;
			}
			else
			{	// Copy from source to new dest.
				// Find the filename in the source archive and position the file pointer.
				for(int s = 0; s < Count; s++)
				{
					pzd = (ZipDirEntry *)ZipContents->Items[s];
					if(!AnsiStrIComp(pzd->FileName.c_str(), zde->FileName.c_str()))
					{
						Found = true;
						break;
					}
				}
			}
			if(!Found)
      	throw EZipBuilder(CF_SourceNotFound, zde->FileName, ZipFileName);
			memcpy(&CEH.VersionMadeBy0, pzd, sizeof(ZipCentralHeader )- 4);
			CEH.HeaderSig = CentralFileHeaderSig;
			CEH.Flag &= 0x1FFF;
			CEH.RelOffLocal = MDZD->Items[d]->RelOffLocal;
			// Save the first Central directory offset for use in EOC record.
			if(!d) EOC.CentralOffset = FileSeek(FOutFileHandle, 0, 1);
			EOC.CentralSize += (sizeof(CEH) + CEH.FileNameLen + CEH.ExtraLen + CEH.FileComLen);

			// Write this changed central header to disk
			WriteJoin(&CEH, sizeof(CEH), DS_CEHBadWrite);
      //if filename was converted OEM2ISO then we have to reconvert before copying
      FHostNum = CEH.VersionMadeBy1;
      FHostVer = CEH.VersionMadeBy0;
//      StrCopy(MDZD->Items[d]->FileName,(ConvertOEM(MDZD->Items[d]->FileName, cpdISO2OEM)).c_str());
      StrCopy(MDZD->Items[d]->FileName,SetSlash(ConvertOEM(MDZD->Items[d]->FileName, cpdISO2OEM), true).c_str());
			// Write to destination the central filename.
			WriteJoin(MDZD->Items[d]->FileName, CEH.FileNameLen, DS_CEHBadWrite);

			// And the extra field from zde or pzd.
			if(CEH.ExtraLen) WriteJoin(pzd->ExtraData.c_str(), CEH.ExtraLen, DS_CEExtraLen);

			// And the file comment.
      if(CEH.FileComLen) WriteJoin(pzd->FileComment.c_str(), CEH.FileComLen, DS_CECommentLen);
		}
		EOC.TotalEntries = EOC.CentralEntries = (unsigned short)DestMemCount;
		EOC.ZipCommentLen = (unsigned short)DestZipBuilder->ZipComment.Length();

		// Write the changed EndOfCentral directory record.
		WriteJoin(&EOC, sizeof(EOC), DS_EOCBadWrite);

		// And finally the archive comment
		FileSeek(In2FileHandle, (SeekInt)DestZipBuilder->ZipEOC + sizeof(EOC), 0);
		if(CopyBuffer(In2FileHandle, FOutFileHandle, DestZipBuilder->ZipComment.Length()))
			throw EZipBuilder(DS_EOArchComLen);

		if(FInFileHandle != -1 ) FileClose(FInFileHandle);
    FInFileHandle = -1;
		// Now delete all copied files from the source when deletion is wanted.
		if(DeleteFromSource && FSpecArgs->Count > 0)
    {
      FZipBusy = false;
      Delete();	// Delete files specified in FSpecArgs and update the contents.
      FInFileHandle = -1; // closed by _Delete and _List
    }
		FSpecArgs->Assign(NotCopiedFiles);	// Info for the caller.
	}
	catch(const EZipBuilder &ers)
	{	// All CopyZippedFiles specific errors..
		ShowExceptionError(ers);
		Result = -7;
	}
	catch(const MEMEXCEPT &me)
	{		// All memory allocation errors.
		ShowZipMessage(GE_NoMem);
		Result = -8;
	}
	catch(const Exception &E)
	{
		ShowZipMessage(DS_ErrorUnknown, "\n" + E.Message);
		Result = -9;
	}
	catch( ... )
	{								// The remaining errors, should not occur.
		ShowZipMessage(DS_ErrorUnknown);
		Result = -9;
	}
	if(MDZD) delete MDZD;
	delete NotCopiedFiles;

⌨️ 快捷键说明

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