|
Has anyone modified this code to support maintaining path information such that a person could extract files to a directory and it's subdirectories?
|
|
|
|
|
I haven't done this myself but it would be pretty easy. You could add two new items to the table of contents which are the directory path and length of the directory path. You would write these to the sfx in the same way as the filename. Then when you are extracting, use the Windows API MakeSureDirectoryPathExists() (if you are using Windows 2000 or later) to create the new directory structure. If you need to support older windows versions, there is some code on *the other site* to do the same thing.
Cheers
James
|
|
|
|
|
I have made some changes to accomplish this very thing. If you select Add Directory, all subdirectories will be traversed and relative path information is saved and stored in the TOC, then used in the extraction.
The changes that I made to your original files are as follows. As I don't know how similar my current codebase is to yours, I can't think of a better way of showing my changes.
Also, this currently only works when adding a directory from the SelfExtractor.exe, not when adding individual files.
The following changes to SEFileInfo ensure that we remember the relative path of each file.
SEFileInfo.h changes
==============================
BOOL SetData(CString File, CString szAbsolutePathSegment="");
public:
void SetRelatviePath(CString szRelativePath){m_strRelativePath = szRelativePath;};
CString GetRelativePath(){return m_strRelativePath;};
protected:
CString m_strRelativePath;
SEFileInfo.cpp changes
===============================
BOOL CSEFileInfo::SetData(CString Filename, CString szAbsolutePathSegment)
{
...original code...
// ensure trailing backslash
if ('\\' != szAbsolutePathSegment.Right(1))
szAbsolutePathSegment += "\\";
m_strRelativePath = m_strPathname;
m_strRelativePath.Replace(m_strFilename, "");
m_strRelativePath.Replace(szAbsolutePathSegment, "");
return TRUE;
}
SelfExtractor.h
===============================
public:
BOOL AddDirectory(LPCTSTR szDirectory);
void PutAbsolutePath(LPCTSTR lpszAbsolutePath){m_strAbsolutePath = lpszAbsolutePath;}
protected:
BOOL MakeSurePathExists(CString &Path)
{
int Pos=0;
while((Pos=Path.Find('\\',Pos+1))!=-1)
CreateDirectory(Path.Left(Pos),NULL);
CreateDirectory(Path,NULL);
// ensure we can access it
CFileFind finder;
return finder.FindFile(Path);
}
CString m_strAbsolutePath;
SelfExtractor.cpp
===============================
IN CSelfExtractor::ESelfExtractorError CSelfExtractor::CreateArchive(CFile* pFile, funcPtr pFn, void* userData)
I added to the TOC loop.
//Now Write the TOC
for(int j = 0; j < m_nFiles; j++)
{
....Original Code....
//Write the relative path
len = m_InfoArray[j].GetRelativePath().GetLength();
strncpy(buffer, m_InfoArray[j].GetRelativePath(), len);
pFile->Write(buffer, len);
//Write the length of the relative path
pFile->Write(&len, sizeof(int));
}
IN CSelfExtractor::ESelfExtractorError CSelfExtractor::ExtractOne(CFile* file, int index, CString Dir)
I added at the top of the method.
CString szRelativePath = m_InfoArray[index].GetRelativePath();
CString szAbsolutePath = Dir + szRelativePath;
MakeSurePathExists(szAbsolutePath);
I changed...
CString szFileName = Dir + m_InfoArray[index].GetFilename();
to be...
CString szFileName = szAbsolutePath + m_InfoArray[index].GetFilename();
IN CSelfExtractor::ESelfExtractorError CSelfExtractor::ReadTOC(CString Filename)
I added to the beginning of the read TOC loop.
int lenRelPath = 0;
// Get Length of Relative Path
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&lenRelPath, sizeof(int));
LastOffset += lenRelPath;
// Get Relative Path
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(buffer, lenRelPath);
LastOffset += sizeof(int);
CString szRelativePath(buffer);
I added to the end of the read TOC loop.
m_InfoArray[i].SetRelatviePath(szRelativePath.Left(lenRelPath));
IN BOOL CSelfExtractor::AddFile(CString File)
I changed...
if(m_InfoArray[m_nFiles].SetData(File))
to...
if(m_InfoArray[m_nFiles].SetData(File, m_strAbsolutePath))
I added the method
/*******************************************************************************
*
* Function: CSelfExtractor::AddDirectory
*
* Author: Lee W. Spencer, 24/7 Systems, Inc.
* Date: 11/20/2003
* E-mail: spencer_tf7@hotmail.com
*
* Description:
* Add a subdirectory to traverse
*
* Parameters:
* szDirectory: Path to traverse
*
* Return:
* BOOL: Success or Failure
*******************************************************************************/
BOOL CSelfExtractor::AddDirectory(LPCTSTR lpszDirectory)
{
CString szDirectoryPath = lpszDirectory;
// ignore these special cases
if("." == szDirectoryPath.Mid(szDirectoryPath.ReverseFind('\\') + 1))
return FALSE;
if(".." == szDirectoryPath.Mid(szDirectoryPath.ReverseFind('\\') + 1))
return FALSE;
// find all files within this directory
CString szPath = szDirectoryPath + "\\*.*";
CFileFind finder;
BOOL bContinue = finder.FindFile(szPath);
while(bContinue)
{
bContinue = finder.FindNextFile();
CString szFoundFilePath = finder.GetFilePath();
if(!AddFile(szFoundFilePath))
{
// recurse
if(finder.IsDirectory())
AddDirectory(szFoundFilePath);
}
}
return TRUE;
}
Self ExtractorDlg.cpp changes
==============================
IN void CSelfExtractorDlg::OnAddDir()
I changed...
CString Path = dlg.GetPathname();
Path += "\\*.*";
to...
CString Path = dlg.GetPathname();
m_Extractor.PutAbsolutePath(Path);
Path += "\\*.*";
AND...
m_Extractor.AddFile(finder.GetFilePath());
to...
if(!m_Extractor.AddFile(finder.GetFilePath()))
{
if(finder.IsDirectory())
m_Extractor.AddDirectory(finder.GetFilePath());
}
|
|
|
|
|
fix: must make ascii-z c-string:
modify: SelfExtracter.cpp
CSelfExtractor::CreateArchive() and CSelfExtractor::ReadTOC():
fixed project source (self_extractor120220_2.7z) uploaded to :
https://skydrive.live.com/redir.aspx?cid=c17d9b5257172422&resid=C17D9B5257172422!2159&parid=C17D9B5257172422!819&authkey=!AFysZDoThtTrK3k[^]
int CSelfExtractor::CreateArchive(CFile& File, funcPtr pFn, void* userData)
{
char buffer[1000]; // Buffer for data
CFile data; // Input file
try
{
//Copy all the inout files into the archive
for(int i = 0; i < m_nFiles; i++)
{
// Open the input file
if(data.Open(m_InfoArray[i].GetPathname() , CFile::modeRead | CFile::shareDenyNone))
{
// Call the user defined CallBack
if(pFn != NULL)
pFn(SFX_FILE_START, static_cast<void*>(&m_InfoArray[i]), userData);
// Record Start Offset
m_InfoArray[i].SetOffset(File.GetPosition());
// Zlib Stuff
int err = Z_OK;
avail_in = 0;
avail_out = ZLibOutputLength;
next_out = m_ZLibOutputBuffer;
m_ZLibFileLength = data.GetLength();
int level = 6;
deflateInit(this, level);
for ( ; ; )
{
// Load input data
if(!ZLibLoadInput(data))
break;
err = deflate(this, Z_NO_FLUSH);
ZLibFlushOutput(File);
if(err != Z_OK)
break;
// Call the user defined CallBack
if(pFn != NULL)
{
int nPercent = Percent();
pFn(SFX_ZIP_INFO, &nPercent, userData);
}
}
// Close this input file
data.Close();
for ( ; ; )
{
err = deflate(this, Z_FINISH);
// Write the output
if (!ZLibFlushOutput(File))
break;
if(err != Z_OK)
break;
}
deflateEnd(this);
// Update the info array with the new compressed size
m_InfoArray[i].SetCompressedSize(total_out);
// Call the user defined CallBack
if(pFn != NULL)
pFn(SFX_FILE_END, static_cast<void*>(&m_InfoArray[i]), userData);
}
else
return INPUT_FILE_ERROR;
}
//Now Write the TOC //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
for(int j = 0; j < m_nFiles; j++)
{
//Write the File Offset
int Offset = m_InfoArray[j].GetFileOffset();
File.Write(&Offset, sizeof(int));
//Write the File Size
int len = m_InfoArray[j].GetFileSize();
File.Write(&len, sizeof(int));
//Write the Compressed File Size
len = m_InfoArray[j].GetCompressedSize();
File.Write(&len, sizeof(int));
//Write the filename
len = m_InfoArray[j].GetFilename().GetLength();
strncpy(buffer, m_InfoArray[j].GetFilename(), len);
File.Write(buffer, len);
//Write the length of the filename
File.Write(&len, sizeof(int));
//Write the relative path //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
len = m_InfoArray[j].GetRelativePath().GetLength();
strncpy(buffer, m_InfoArray[j].GetRelativePath(), len);
if (len) buffer[len]=0;
if (!len)
{
strcpy(buffer,".\\");
len=2;
}
CString tmp;
tmp.Format("[%s][%d]",buffer,len);
//AfxMessageBox(tmp);
if (len) /*pFile->*/File.Write(buffer, len);
else
{
strcpy(buffer,".\\");
len=2;
}
//Write the length of the relative path
/*pFile->*/File.Write(&len, sizeof(int));
}
//Write the total number of files
File.Write((void*)&m_nFiles, sizeof(int));
//Write the vesion
strcpy(buffer, SFX_VERSION);
File.Write(buffer, strlen(SFX_VERSION));
//Write the SIG
strcpy(buffer, SIGNATURE);
File.Write(buffer, strlen(SIGNATURE));
}
catch(CFileException* e)
{
//Got sick of seeing 'unreferenced local variable'
e->m_cause;
return OUTPUT_FILE_ERROR;
}
return UNKNOWN_ERROR;
}
int CSelfExtractor::ReadTOC(CString Filename)
{
CFile Thisfile; //Archive file
char buffer[1000]; //Buffer to read and write with
//Clear the CSEFileInfo class array
Reset();
//Open the archive
if(!Thisfile.Open(Filename, CFile::modeRead | CFile::shareDenyNone))
return NO_SOURCE;
else
{
//Read in the signature
Thisfile.Seek(- static_cast<int>(strlen(SIGNATURE)), CFile::end);
Thisfile.Read(buffer, strlen(SIGNATURE));
// Check that it matches
buffer[strlen(SIGNATURE)]=0;
CString tmp;
tmp.Format("[%s][%s]",buffer, SIGNATURE);
//AfxMessageBox(tmp);
if(strncmp(buffer, SIGNATURE, strlen(SIGNATURE)) != 0)
{
return INVALID_SIG;
}//else AfxMessageBox("SIGNATURE ok");
// Read in the version
int LastOffset = strlen(SIGNATURE) + strlen(SFX_VERSION);
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(buffer, strlen(SFX_VERSION));
// Check that the version matches
buffer[strlen(SFX_VERSION)]=0;
CString tmp2;
tmp2.Format("[%s][%s]",buffer, SFX_VERSION);
//AfxMessageBox(tmp2);
if(strncmp(buffer, SFX_VERSION, strlen(SFX_VERSION)) != 0)
{
return INVALID_SIG;
}//else AfxMessageBox("SFX_VERSION ok");
// Read Number of files
LastOffset += sizeof(int);
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&m_nFiles, sizeof(int));
//If there are no files in the archive, there is nothing to extract
if(m_nFiles == 0)
{
AfxMessageBox("m_nFiles == 0");
return NOTHING_TO_DO;
}else
{
CString tmp5;
tmp5.Format("m_nFiles=%d,",m_nFiles);
// AfxMessageBox(tmp5);
}
//Read the TOC in. The array is filled in reverse to ensure that it
//corresponds to the data segment
for(int i = (m_nFiles - 1); i >= 0 ; i--)
{
int lenRelPath = 0;
// Get Length of Relative Path
LastOffset += sizeof(int); //<<
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&lenRelPath, sizeof(int));
CString tmp6;
tmp6.Format("lenRelPath=%d,",lenRelPath);
//AfxMessageBox(tmp6);
LastOffset += lenRelPath;
// Get Relative Path
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(buffer, lenRelPath);
//LastOffset += sizeof(int);
buffer[lenRelPath]=0;
CString tmp4;
tmp4.Format("[%s]",buffer);
//AfxMessageBox(tmp4);
CString szRelativePath(buffer); //<<<<<<<<<<<<<<<<<<<<<<<<<<<
int nSize = 0;
int nCompSize = 0;
int nOffset = 0;
int len = 0;
LastOffset += sizeof(int);
// Get Length of Pathname
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&len, sizeof(int));
LastOffset += len;
// Get Path Name
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(buffer, len);
LastOffset += sizeof(int);
buffer[len]=0;
CString tmp3;
tmp3.Format("[%s]",buffer);
// AfxMessageBox(tmp3);
// Get Compressed File Size
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&nCompSize, sizeof(int));
LastOffset += sizeof(int);
// Get File Size
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&nSize, sizeof(int));
LastOffset += sizeof(int);
// Get File Offset
Thisfile.Seek(-LastOffset, CFile::end);
Thisfile.Read(&nOffset, sizeof(int));
//Set the data in the array
m_InfoArray[i].SetSize(nSize);
m_InfoArray[i].SetCompressedSize(nCompSize);
CString Temp(buffer);
m_InfoArray[i].SetFilename(Temp.Left(len));
m_InfoArray[i].SetOffset(nOffset);
m_InfoArray[i].SetRelatviePath(szRelativePath.Left(lenRelPath));//<<<<<<<<<<<<<<<<
}
//Record the total size of the TOC for use
//when extracting the data segment
m_nTOCSize = LastOffset;
}
//Close the archive
Thisfile.Close();
return SUCCESS;
}
|
|
|
|
|