https://git.reactos.org/?p=reactos.git;a=commitdiff;h=70193adc891cd59b0379bef9dd5627ac222ba954

commit 70193adc891cd59b0379bef9dd5627ac222ba954
Author:     Mark Jansen <[email protected]>
AuthorDate: Sat Sep 12 16:21:34 2020 +0200
Commit:     Mark Jansen <[email protected]>
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 ([email protected])
  *              Colin Finck <[email protected]>
  * 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;
 

Reply via email to