https://git.reactos.org/?p=reactos.git;a=commitdiff;h=70193adc891cd59b0379b…
commit 70193adc891cd59b0379bef9dd5627ac222ba954
Author: Mark Jansen <mark.jansen(a)reactos.org>
AuthorDate: Sat Sep 12 16:21:34 2020 +0200
Commit: Mark Jansen <mark.jansen(a)reactos.org>
CommitDate: Sun Sep 20 17:28:02 2020 +0200
[CABMAN] Add commandline support for creating a cab with folders
CORE-17230
---
sdk/tools/cabman/cabinet.cxx | 77 ++++++++++++++++++++++++++------------------
sdk/tools/cabman/cabinet.h | 14 +++++---
sdk/tools/cabman/cabman.cxx | 25 +++++++++++---
sdk/tools/cabman/dfp.cxx | 8 ++---
4 files changed, 78 insertions(+), 46 deletions(-)
diff --git a/sdk/tools/cabman/cabinet.cxx b/sdk/tools/cabman/cabinet.cxx
index 175efef918a..29f9975b6fe 100644
--- a/sdk/tools/cabman/cabinet.cxx
+++ b/sdk/tools/cabman/cabinet.cxx
@@ -155,7 +155,7 @@ void CCabinet::ConvertPath(std::string& Path)
}
-const char* CCabinet::GetFileName(const char* Path)
+std::string CCabinet::GetFileName(const std::string& Path)
/*
* FUNCTION: Returns a pointer to file name
* ARGUMENTS:
@@ -172,7 +172,7 @@ const char* CCabinet::GetFileName(const char* Path)
if (IsSeparator(Path [i - 1]))
j = i;
- return Path + j;
+ return Path.c_str() + j;
}
@@ -225,7 +225,7 @@ void CCabinet::SetDestinationPath(const char* DestinationPath)
NormalizePath(DestPath);
}
-ULONG CCabinet::AddSearchCriteria(const char* SearchCriteria)
+ULONG CCabinet::AddSearchCriteria(const std::string& SearchCriteria, const
std::string& TargetFolder)
/*
* FUNCTION: Adds a criteria to the search criteria list
* ARGUMENTS:
@@ -248,6 +248,7 @@ ULONG CCabinet::AddSearchCriteria(const char* SearchCriteria)
// Set the actual criteria string
Criteria->Search = SearchCriteria;
+ Criteria->TargetFolder = TargetFolder;
return CAB_STATUS_SUCCESS;
}
@@ -274,6 +275,16 @@ bool CCabinet::HasSearchCriteria()
return !CriteriaList.empty();
}
+std::string CCabinet::CreateCabFilename(PCFFILE_NODE Node)
+{
+ std::string fname = GetFileName(Node->FileName);
+ if (!Node->TargetFolder.empty())
+ {
+ fname = Node->TargetFolder + fname;
+ }
+ return fname;
+}
+
bool CCabinet::SetCompressionCodec(const char* CodecName)
/*
* FUNCTION: Selects the codec to use for compression
@@ -591,6 +602,7 @@ ULONG CCabinet::FindNext(PCAB_SEARCH Search)
for (PSEARCH_CRITERIA Criteria : CriteriaList)
{
+ // FIXME: We could handle path\filename here
if (MatchFileNamePattern((*Search->Next)->FileName.c_str(),
Criteria->Search.c_str()))
{
bFound = true;
@@ -1202,7 +1214,7 @@ ULONG CCabinet::WriteFileToScratchStorage(PCFFILE_NODE FileNode)
SourceFile = fopen(FileNode->FileName.c_str(), "rb");
if (SourceFile == NULL)
{
- DPRINT(MID_TRACE, ("File not found (%s).\n",
FileNode->FileName.c_str()));
+ DPRINT(MID_TRACE, ("File not found (%s).\n",
FileNode->FileNameOnDisk.c_str()));
return CAB_STATUS_NOFILE;
}
@@ -1227,7 +1239,7 @@ ULONG CCabinet::WriteFileToScratchStorage(PCFFILE_NODE FileNode)
CurrentFolderNode->Commit = true;
PrevCabinetNumber = CurrentDiskNumber;
- Size = sizeof(CFFILE) + (ULONG)strlen(GetFileName(FileNode->FileName.c_str()))
+ 1;
+ Size = sizeof(CFFILE) + (ULONG)CreateCabFilename(FileNode).length() + 1;
CABHeader.FileTableOffset += Size;
TotalFileSize += Size;
DiskSize += Size;
@@ -1500,7 +1512,7 @@ ULONG CCabinet::CloseCabinet()
}
-ULONG CCabinet::AddFile(char* FileName)
+ULONG CCabinet::AddFile(const std::string& FileName, const std::string&
TargetFolder)
/*
* FUNCTION: Adds a file to the current disk
* ARGUMENTS:
@@ -1534,6 +1546,9 @@ ULONG CCabinet::AddFile(char* FileName)
FileNode->FolderNode = CurrentFolderNode;
FileNode->FileName = NewFileName;
+ FileNode->TargetFolder = TargetFolder;
+ if (FileNode->TargetFolder.length() > 0 &&
FileNode->TargetFolder[FileNode->TargetFolder.length() - 1] != '\\')
+ FileNode->TargetFolder += '\\';
/* FIXME: Check for and handle large files (>= 2GB) */
FileNode->File.FileSize = GetSizeOfFile(SrcFile);
@@ -1569,9 +1584,6 @@ bool CCabinet::CreateSimpleCabinet()
*/
{
bool bRet = false;
- const char* pszFile;
- char szFilePath[PATH_MAX];
- char szFile[PATH_MAX];
ULONG Status;
#if defined(_WIN32)
@@ -1595,26 +1607,25 @@ bool CCabinet::CreateSimpleCabinet()
for (PSEARCH_CRITERIA Criteria : CriteriaList)
{
// Store the file path with a trailing slash in szFilePath
- ConvertPath(Criteria->Search);
- pszFile = strrchr(Criteria->Search.c_str(), DIR_SEPARATOR_CHAR);
+ std::string szSearchPath = Criteria->Search;
+ ConvertPath(szSearchPath);
+ auto sep = szSearchPath.find_last_of(DIR_SEPARATOR_CHAR);
+ std::string szFilePath;
+ std::string pszFile;
- if(pszFile)
+ if (sep != std::string::npos)
{
- // Set the pointer to the start of the file name, not the slash
- pszFile++;
+ pszFile = szSearchPath.substr(sep + 1); // We want the filename, not the dir
separator!
- strncpy(szFilePath, Criteria->Search.c_str(), pszFile -
Criteria->Search.c_str());
- szFilePath[pszFile - Criteria->Search.c_str()] = 0;
+ szFilePath = szSearchPath.substr(0, sep + 1);
}
else
{
- pszFile = Criteria->Search.c_str();
+ pszFile = Criteria->Search;
-#if defined(_WIN32)
- szFilePath[0] = 0;
-#else
+#if !defined(_WIN32)
// needed for opendir()
- strcpy(szFilePath, "./");
+ szFilePath = "./";
#endif
}
@@ -1633,10 +1644,10 @@ bool CCabinet::CreateSimpleCabinet()
{
if(!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
- strcpy(szFile, szFilePath);
- strcat(szFile, FindFileData.cFileName);
+ std::string szFile = szFilePath;
+ szFile += FindFileData.cFileName;
- Status = AddFile(szFile);
+ Status = AddFile(szFile, Criteria->TargetFolder);
if(Status != CAB_STATUS_SUCCESS)
{
@@ -1651,22 +1662,22 @@ bool CCabinet::CreateSimpleCabinet()
FindClose(hFind);
#else
// Unix: Use opendir/readdir to loop through all entries, stat to check if
it's a file and MatchFileNamePattern to match the file against the pattern
- dirp = opendir(szFilePath);
+ dirp = opendir(szFilePath.c_str());
if(dirp)
{
while( (dp = readdir(dirp)) )
{
- strcpy(szFile, szFilePath);
- strcat(szFile, dp->d_name);
+ std::string szFile = szFilePath;
+ szFile += dp->d_name;
- if(stat(szFile, &stbuf) == 0)
+ if(stat(szFile.c_str(), &stbuf) == 0)
{
if(stbuf.st_mode != S_IFDIR)
{
- if(MatchFileNamePattern(dp->d_name, pszFile))
+ if(MatchFileNamePattern(dp->d_name, pszFile.c_str()))
{
- Status = AddFile(szFile);
+ Status = AddFile(szFile, Criteria->TargetFolder);
if(Status != CAB_STATUS_SUCCESS)
{
@@ -1890,6 +1901,7 @@ ULONG CCabinet::LocateFile(const char* FileName,
for (PCFFILE_NODE Node : FileList)
{
+ // FIXME: We could handle path\filename here
if (strcasecmp(FileName, Node->FileName.c_str()) == 0)
{
CurrentFolderNode = LocateFolderNode(Node->File.FileControlID);
@@ -2011,6 +2023,7 @@ ULONG CCabinet::ReadFileTable()
Status = ReadString(Buf, PATH_MAX);
if (Status != CAB_STATUS_SUCCESS)
return Status;
+ // FIXME: We could split up folder\file.txt here
File->FileName = Buf;
DPRINT(MAX_TRACE, ("Found file '%s' at uncompressed offset (0x%X).
Size (%u bytes) ControlId (0x%X).\n",
@@ -2195,7 +2208,7 @@ void CCabinet::DestroyDeletedFileNodes()
DPRINT(MAX_TRACE, ("Deleting file node: '%s'\n",
CurNode->FileName.c_str()));
- TotalFileSize -= (sizeof(CFFILE) +
(ULONG)strlen(GetFileName(CurNode->FileName.c_str())) + 1);
+ TotalFileSize -= (sizeof(CFFILE) + (ULONG)CreateCabFilename(CurNode).length()
+ 1);
delete CurNode;
}
@@ -2669,7 +2682,7 @@ ULONG CCabinet::WriteFileEntries()
return CAB_STATUS_CANNOT_WRITE;
}
- std::string fname = GetFileName(File->FileName.c_str());
+ std::string fname = CreateCabFilename(File);
if (fwrite(fname.c_str(), fname.length() + 1, 1, FileHandle) < 1)
{
DPRINT(MIN_TRACE, ("Cannot write to file.\n"));
diff --git a/sdk/tools/cabman/cabinet.h b/sdk/tools/cabman/cabinet.h
index 0940436d975..1697588bbfc 100644
--- a/sdk/tools/cabman/cabinet.h
+++ b/sdk/tools/cabman/cabinet.h
@@ -227,6 +227,7 @@ typedef struct _CFFILE_NODE
{
CFFILE File = { 0 };
std::string FileName;
+ std::string TargetFolder;
PCFDATA_NODE DataBlock = nullptr; // First data block of file. NULL if not
known
bool Commit = false; // true if the file data should be
committed
bool Delete = false; // true if marked for deletion
@@ -235,7 +236,8 @@ typedef struct _CFFILE_NODE
typedef struct _SEARCH_CRITERIA
{
- std::string Search; // The actual search criteria
+ std::string Search; // The actual search criteria
+ std::string TargetFolder; // The filename will be
TargetFolder\file
} SEARCH_CRITERIA, *PSEARCH_CRITERIA;
typedef struct _CAB_SEARCH
@@ -311,8 +313,8 @@ public:
bool IsSeparator(char Char);
/* Replaces \ or / with the one used be the host environment */
void ConvertPath(std::string& Path);
- /* Returns a pointer to the filename part of a fully qualified filename */
- const char* GetFileName(const char* Path);
+ /* Returns the filename part of a fully qualified filename */
+ std::string GetFileName(const std::string& Path);
/* Normalizes a path */
void NormalizePath(std::string& Path);
/* Returns name of cabinet file */
@@ -342,12 +344,14 @@ public:
/* Returns whether a codec engine is selected */
bool IsCodecSelected();
/* Adds a search criteria for adding files to a simple cabinet, displaying files in a
cabinet or extracting them */
- ULONG AddSearchCriteria(const char* SearchCriteria);
+ ULONG AddSearchCriteria(const std::string& SearchCriteria, const std::string&
TargetFolder);
/* Destroys the search criteria list */
void DestroySearchCriteria();
/* Returns whether we have search criteria */
bool HasSearchCriteria();
+ std::string CreateCabFilename(PCFFILE_NODE Node);
+
#ifndef CAB_READ_ONLY
/* Creates a simple cabinet based on the search criteria data */
bool CreateSimpleCabinet();
@@ -370,7 +374,7 @@ public:
/* Closes the current cabinet */
ULONG CloseCabinet();
/* Adds a file to the current disk */
- ULONG AddFile(char* FileName);
+ ULONG AddFile(const std::string& FileName, const std::string& TargetFolder);
/* Sets the maximum size of the current disk */
void SetMaxDiskSize(ULONG Size);
#endif /* CAB_READ_ONLY */
diff --git a/sdk/tools/cabman/cabman.cxx b/sdk/tools/cabman/cabman.cxx
index 0dd0ceaab1d..d258b534e79 100644
--- a/sdk/tools/cabman/cabman.cxx
+++ b/sdk/tools/cabman/cabman.cxx
@@ -193,7 +193,7 @@ void CCABManager::Usage()
printf("ReactOS Cabinet Manager\n\n");
printf("CABMAN [-D | -E] [-A] [-L dir] cabinet [filename ...]\n");
printf("CABMAN [-M mode] -C dirfile [-I] [-RC file] [-P dir]\n");
- printf("CABMAN [-M mode] -S cabinet filename [...]\n");
+ printf("CABMAN [-M mode] -S cabinet filename [-F folder] [filename]
[...]\n");
printf(" cabinet Cabinet file.\n");
printf(" filename Name of the file to add to or extract from the
cabinet.\n");
printf(" Wild cards and multiple filenames\n");
@@ -206,6 +206,7 @@ void CCABManager::Usage()
printf(" -C Create cabinet.\n");
printf(" -D Display cabinet directory.\n");
printf(" -E Extract files from cabinet.\n");
+ printf(" -F Put the files from the next 'filename' filter in the
cab in folder\filename.\n");
printf(" -I Don't create the cabinet, only the .inf file.\n");
printf(" -L dir Location to place extracted or generated files\n");
printf(" (default is current directory).\n");
@@ -233,7 +234,7 @@ bool CCABManager::ParseCmdline(int argc, char* argv[])
int i;
bool ShowUsage;
bool FoundCabinet = false;
-
+ std::string NextFolder;
ShowUsage = (argc < 2);
for (i = 1; i < argc; i++)
@@ -262,6 +263,19 @@ bool CCABManager::ParseCmdline(int argc, char* argv[])
Mode = CM_MODE_EXTRACT;
break;
+ case 'f':
+ case 'F':
+ if (argv[i][2] == 0)
+ {
+ i++;
+ NextFolder = argv[i];
+ }
+ else
+ {
+ NextFolder = argv[i] + 2;
+ }
+ break;
+
case 'i':
case 'I':
InfFileOnly = true;
@@ -374,7 +388,8 @@ bool CCABManager::ParseCmdline(int argc, char* argv[])
else if(FoundCabinet)
{
// For creating simple cabinets, displaying or extracting them, add the
argument as a search criteria
- AddSearchCriteria(argv[i]);
+ AddSearchCriteria(argv[i], NextFolder);
+ NextFolder.clear();
}
else
{
@@ -618,7 +633,7 @@ void CCABManager::OnExtract(PCFFILE File,
{
if (Verbose)
{
- printf("Extracting %s\n", GetFileName(FileName));
+ printf("Extracting %s\n", GetFileName(FileName).c_str());
}
}
@@ -651,7 +666,7 @@ void CCABManager::OnAdd(PCFFILE File,
{
if (Verbose)
{
- printf("Adding %s\n", GetFileName(FileName));
+ printf("Adding %s\n", GetFileName(FileName).c_str());
}
}
diff --git a/sdk/tools/cabman/dfp.cxx b/sdk/tools/cabman/dfp.cxx
index b6b4335e59a..575b48f0816 100644
--- a/sdk/tools/cabman/dfp.cxx
+++ b/sdk/tools/cabman/dfp.cxx
@@ -6,7 +6,7 @@
* PROGRAMMERS: Casper S. Hornstrup (chorns(a)users.sourceforge.net)
* Colin Finck <mail(a)colinfinck.de>
* NOTES: The directive file format is similar to the
- * directive file format used by Microsoft's MAKECAB
+ * directive file format used by Microsoft's MAKECAB (But not entirely
compatible!)
* REVISIONS:
* CSH 21/03-2001 Created
* CSH 15/08-2003 Made it portable
@@ -1123,17 +1123,17 @@ ULONG CDFParser::PerformFileCopy()
DPRINT(MID_TRACE, ("Adding file: '%s' destination:
'%s'.\n", SrcName, DstName));
- Status = AddFile(SrcName);
+ Status = AddFile(SrcName, std::string());
if (Status == CAB_STATUS_CANNOT_OPEN)
{
strcpy(SrcName, FileRelativePath.c_str());
strcat(SrcName, BaseFilename);
- Status = AddFile(SrcName);
+ Status = AddFile(SrcName, std::string());
}
switch (Status)
{
case CAB_STATUS_SUCCESS:
- sprintf(InfLine, "%s=%s", GetFileName(SrcName), DstName);
+ sprintf(InfLine, "%s=%s", GetFileName(SrcName).c_str(), DstName);
WriteInfLine(InfLine);
break;