📄 zipbuilder.cpp
字号:
{
MadeOS = FHostNum;
MadeVer = FHostVer;
}
Name[CEH.FileNameLen] = '\0';
// Name = ConvertOEM(Name, cpdOEM2ISO);
// ConvertOem2Iso( Name, cpdOEM2ISO );
// Create a new ZipDirEntry record
pzd = new ZipDirEntry; // These will be deleted in: FreeZipDirEntryRecords().
// Copy the information from the central header.
memcpy(pzd, &CEH.VersionMadeBy0, LocalDirEntrySize );
pzd->FileName = SetSlash(ConvertOEM(Name, cpdOEM2ISO), false);
// pzd->FileName = ReplaceForwardSlash( Name );
pzd->Encrypted = pzd->Flag & 0x01;
// Read the extra data if present new v1.6
pzd->ExtraData = ""; // empty
if(CEH.ExtraLen)
{
pzd->ExtraData.SetLength(CEH.ExtraLen);
ReadJoin(pzd->ExtraData.c_str(), CEH.ExtraLen ,LI_ReadZipError);
}
// Read the FileComment if present and save.
if(CEH.FileComLen)
{
pzd->FileComment.SetLength(CEH.FileComLen);
ReadJoin(pzd->FileComment.c_str(), CEH.FileComLen ,DS_CECommentLen);
// pzd->FileComment = ConvertOEM(pzd->FileComment, cpdOEM2ISO);
}
if(FUseDirOnlyEntries || ExtractFileName( pzd->FileName ) != "" )
{
// Add it to our contents tabel.
FZipContents->Add( pzd );
// Notify user of the next entry in the ZipDir.
if(FOnNewName) FOnNewName(this, i + 1, *pzd);
}
else
{
FDirOnlyCount++;
pzd->ExtraData = "";
delete pzd;
}
// Calculate the earliest Local Header start.
if(FSFXOffset > (int)CEH.RelOffLocal) FSFXOffset = (int)CEH.RelOffLocal;
}
FTotalDisks = EOC.ThisDiskNo; // We need this when we are going to extract.
}
catch (const EZipBuilder &ezl)
{ // Catch all Zip List specific errors.
ShowExceptionError(ezl);
LiE = true;
}
catch (const MEMEXCEPT &me)
{
ShowZipMessage(GE_NoMem);
LiE = true;
}
catch(const Exception &E)
{
ShowZipMessage(LI_ErrorUnknown, "\n" + E.Message);
LiE = true;
}
catch ( ... )
{
ShowZipMessage(LI_ErrorUnknown);
LiE = true;
}
}
__finally
{
StopWaitCursor();
if(FInFileHandle != -1 ) FileClose(FInFileHandle);
if(LiE)
{
FZipFileName = "";
FSFXOffset = 0;
}
else FSFXOffset += (OffsetDiff - EOC.CentralOffset); // Correct the offset for v1.3, 1.4 and 1.45
// Let user's program know we just refreshed the zip dir contents.
FHostNum = MadeOS; // if any not dos assume comment not oem
FHostVer = MadeVer;
FZipComment = ConvertOEM(FEOCComment, cpdOEM2ISO);
if(FOnDirUpdate) FOnDirUpdate(this);
}
}
// TZipBuilder::_List
/* TZipBuilder::Rename----------------------------------------------------------
1.73.3.2 11 October 2003 RP changed comment variable
1.73.3.2 8 Oct 2003 RA if filename has extended chars change HostVer + extfileattrib
1.73 23 september 2003 RA changeing date/time of protected file is not allowed
1.73 7 August 2003 RA init FOutFileHandle
1.73 (16 July 2003) RP use SetSlash + ConvertOEM
1.73 (14 July 2003) RA convertion/re-convertion of filenames with OEM chars
Function to read a Zip archive and change one or more file specifications.
Source and Destination should be of the same type. (path or file)
If NewDateTime is 0 then no change is made in the date/time fields.
Return values:
0 All Ok.
-7 Rename errors. See ZipMsgXX.rc
-8 Memory allocation error.
-9 General unknown Rename error.
-10 Dest should also be a filename.
*/
int __fastcall TZipBuilder::Rename(TList &RenameList, unsigned long DateTime)
{
ZipEndOfCentral EOC;
ZipCentralHeader CEH;
ZipLocalHeader LOH;
String OrigFileName;
String MsgStr;
String OutFilePath;
char *Buffer = NULL;
int TotalBytesToRead = 0;
int TotalBytesWrite;
int Result = 0;
ZipRenameRec *RenRec;
TMZipDataList* MDZD = NULL;
FShowProgress = false;
FInFileName = FZipFileName;
FInFileHandle = -1;
FOutFileHandle = -1;
if(Busy()) return BUSY_ERROR;
FZipBusy = true;
StartWaitCursor();
// If we only have a source path make sure the destination is also a path.
for(int i = 0; i < RenameList.Count; i++)
{
RenRec = (ZipRenameRec *)RenameList.Items[i];
RenRec->Source = SetSlash(RenRec->Source,false);
RenRec->Dest = SetSlash(RenRec->Dest,false);
RemoveDriveSpec(RenRec->Source);
RemoveDriveSpec(RenRec->Dest);
if(RenRec->Source.AnsiPos("*") || RenRec->Source.AnsiPos("?") ||
RenRec->Dest.AnsiPos("*") || RenRec->Dest.AnsiPos("?"))
{
ShowZipMessage(AD_InvalidName); // no wildcards allowed
StopWaitCursor();
FZipBusy = false;
return -7; // Rename error
}
if(!ExtractFileName(RenRec->Source).Length())
{ // Assume it's a path.
// Make sure destination is a path also.
RenRec->Dest = SetSlash(ExtractFilePath(RenRec->Dest),true);
RenRec->Source = SetSlash(RenRec->Source, true);
}
else if(!ExtractFileName(RenRec->Dest).Length())
{
StopWaitCursor();
FZipBusy = false;
return -10; // Dest should also be a filename.
}
}
try
{
Buffer = new char[BufSize];
// Check the input file.
if(!FileExists(FZipFileName)) throw EZipBuilder(GE_NoZipSpecified);
if((OutFilePath = MakeTempFileName()) == "") throw EZipBuilder(DS_NoTempFile );
// Create the output file.
FOutFileHandle = FileCreate(OutFilePath);
if(FOutFileHandle == -1) throw EZipBuilder( DS_NoOutFile );
// The following function will read the EOC and some other stuff:
OpenEOC(EOC, false); // do not throw exceptions yet
// Get the date-time stamp and save for later.
FDateStamp = FileGetDate(FInFileHandle);
// Now we now the number of zipped entries in the zip archive
FTotalDisks = EOC.ThisDiskNo;
if(EOC.ThisDiskNo) throw EZipBuilder(RN_NoRenOnSpan);
// Go to the start of the input file.
if(FileSeek(FInFileHandle, 0, 0) == -1) throw EZipBuilder(DS_FailedSeek);
// Write the SFX header if present.
if(CopyBuffer(FInFileHandle, FOutFileHandle, FSFXOffset))
throw EZipBuilder(RN_ZipSFXData);
// Go to the start of the Central directory.
if(FileSeek(FInFileHandle, (SeekInt)EOC.CentralOffset, 0) == -1)
throw EZipBuilder(DS_FailedSeek);
MDZD = new TMZipDataList(EOC.TotalEntries); // create class
// Read for every entry: The central header and save information for later use.
for(int i = 0; i < EOC.TotalEntries; i++)
{
// Read a central header.
ReadJoin(&CEH, sizeof(CEH), DS_CEHBadRead);
if(CEH.HeaderSig != CentralFileHeaderSig) throw EZipBuilder(DS_CEHWrongSig);
// Now the filename.
ReadJoin( Buffer, CEH.FileNameLen, DS_CENameLen);
// Save the file name info in the MDZD structure.
MDZD->Items[i]->FileNameLen = CEH.FileNameLen;
MDZD->Items[i]->FileName = new char[CEH.FileNameLen + 1];
StrLCopy(MDZD->Items[i]->FileName, Buffer, CEH.FileNameLen);
MDZD->Items[i]->FileName[CEH.FileNameLen] = '\0';
//convert OEM char set in original file else we don't find the file
FHostNum = CEH.VersionMadeBy1;
FHostVer = CEH.VersionMadeBy0;
AnsiString Name = ConvertOEM(MDZD->Items[i]->FileName, cpdOEM2ISO);
StrCopy(MDZD->Items[i]->FileName,Name.c_str());
//DiskStart is not used in this function and we need FHostNum later
MDZD->Items[i]->DiskStart = (FHostNum << 8) + FHostVer;
MDZD->Items[i]->RelOffLocal = CEH.RelOffLocal;
// if encrypted use CRC32 as flag
MDZD->Items[i]->CRC32 = CEH.Flag & 1;
MDZD->Items[i]->DateTime = DateTime;
// We need the total number of bytes we are going to read for the progress event.
TotalBytesToRead += (int)(CEH.ComprSize + CEH.FileNameLen + CEH.ExtraLen);
// Seek past the extra field and the file comment.
if(FileSeek(FInFileHandle, (SeekInt)(CEH.ExtraLen + CEH.FileComLen), 1 ) == -1)
throw EZipBuilder(DS_FailedSeek);
}
FShowProgress = true;
CallBack(zacCount,0, "", EOC.TotalEntries);
CallBack(zacSize,0, "", TotalBytesToRead);
// Read for every zipped entry: The local header, variable data, fixed data
// and if present the Data descriptor area.
for(int i = 0; i < EOC.TotalEntries; i++)
{
// Seek to the first/next entry.
FileSeek(FInFileHandle, (SeekInt)MDZD->Items[i]->RelOffLocal, 0);
// First the local header.
ReadJoin(&LOH, sizeof(LOH), DS_LOHBadRead);
if(LOH.HeaderSig != LocalFileHeaderSig) throw EZipBuilder(DS_LOHWrongSig);
// Now the filename.
ReadJoin( Buffer, LOH.FileNameLen, DS_LONameLen);
// Set message info on the start of this new fileread now we still have the old filename.
MsgStr = LoadZipStr(RN_ProcessFile, "Processing: ") + MDZD->Items[i]->FileName;
// Calculate the bytes we are going to write; we 'forget' the difference
// between the old and new filespecification length.
TotalBytesWrite = LOH.FileNameLen + LOH.ExtraLen + LOH.ComprSize;
// Check if the original path and/or filename needs to be changed.
OrigFileName = SetSlash(MDZD->Items[i]->FileName,false);
for(int m = 0; m < RenameList.Count; m++)
{
RenRec = (ZipRenameRec *)RenameList.Items[m];
int k = UpperCase(OrigFileName).Pos(UpperCase(RenRec->Source));
if(k)
{
OrigFileName.Delete(k, RenRec->Source.Length());
OrigFileName.Insert(RenRec->Dest, k);
LOH.FileNameLen = MDZD->Items[i]->FileNameLen = (unsigned short)OrigFileName.Length();
for(k = 1; k <= OrigFileName.Length(); k++)
if(OrigFileName[k] == '\\') OrigFileName[k] = '/';
MsgStr += LoadZipStr(RN_RenameTo, " renamed to: ") + OrigFileName;
delete[] MDZD->Items[i]->FileName;
MDZD->Items[i]->FileName = new char[OrigFileName.Length() + 1];
StrPLCopy(MDZD->Items[i]->FileName, OrigFileName, LOH.FileNameLen + 1);
//check if new filename has extended chars if it is we need to set FHostVer to NTFS
if(!(HasExtendedChars(OrigFileName) && !(MDZD->Items[i]->DiskStart & 0xFF00)))
{
FHostNum = (MDZD->Items[i]->DiskStart & 0xFF00) >> 8;
FHostVer = MDZD->Items[i]->DiskStart & 0xFF;
OrigFileName = ConvertOEM(OrigFileName, cpdISO2OEM);
}
StrPLCopy(MDZD->Items[i]->FileName, OrigFileName, OrigFileName.Length() + 1);
MDZD->Items[i]->FileNameLen = OrigFileName.Length();
// Change Date and Time if needed.
try
{
if(RenRec->DateTime)
{
// not allowed to change date on protected file
if(MDZD->Items[i]->CRC32)
throw EZipBuilder(RN_InvalidDateTime);
// test if valid date/time will throw error if not
FileDateToDateTime(RenRec->DateTime);
MDZD->Items[i]->DateTime = RenRec->DateTime;
}
}
catch(...)
{
ShowZipMessage(RN_InvalidDateTime, MDZD->Items[i]->FileName);
}
}
}
CallBack(zacMessage,0,MsgStr,0);
// Change Date and/or Time if needed.
if(MDZD->Items[i]->DateTime)
{
LOH.ModifDate = HIWORD(MDZD->Items[i]->DateTime );
LOH.ModifTime = LOWORD(MDZD->Items[i]->DateTime );
}
// Change info for later while writing the central dir.
MDZD->Items[i]->RelOffLocal = FileSeek(FOutFileHandle, 0, 1);
CallBack(zacItem,0,SetSlash(MDZD->Items[i]->FileName,false),TotalBytesWrite);
// Write the local header to the destination.
WriteJoin(&LOH, sizeof(LOH), DS_LOHBadWrite);
// Write the filename.
WriteJoin(MDZD->Items[i]->FileName, LOH.FileNameLen, DS_LOHBadWrite);
// And the extra field
if(CopyBuffer(FInFileHandle, FOutFileHandle, LOH.ExtraLen))
throw EZipBuilder(DS_LOExtraLen);
// Read and write Zipped data
if(CopyBuffer(FInFileHandle, FOutFileHandle, LOH.ComprSize))
throw EZipBuilder(DS_ZipData);
// Read DataDescriptor if present.
if(LOH.Flag & 0x0008)
if(CopyBuffer(FInFileHandle, FOutFileHandle, sizeof(ZipDataDescriptor)))
throw EZipBuilder(DS_DataDesc);
} // Now we have written al entries.
// Now write the central directory with possibly changed offsets and filename(s).
FShowProgress = false;
for(int i = 0; i < EOC.TotalEntries; i++)
{
// Read a central header.
ReadJoin(&CEH, sizeof(CEH), DS_CEHBadRead);
if(CEH.HeaderSig != CentralFileHeaderSig) throw EZipBuilder(DS_CEHWrongSig);
// Change Date and/or Time if needed.
if(MDZD->Items[i]->DateTime)
{
CEH.ModifDate = HIWORD(MDZD->Items[i]->DateTime);
CEH.ModifTime = LOWORD(MDZD->Items[i]->DateTime);
}
// Now the filename.
ReadJoin( Buffer, CEH.FileNameLen, DS_CENameLen);
// Save the first Central directory offset for use in EOC record.
if(!i) EOC.CentralOffset = FileSeek(FOutFileHandle, 0, 1);
// Change the central header info with our saved information.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -