-
Notifications
You must be signed in to change notification settings - Fork 67
[TOOLS] GenBIG - A CLI Tool for BIG Archives #535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
set(GENBIG_SRC | ||
"src/BIGFile.h" | ||
"src/BIGFile.cpp" | ||
"src/main.cpp" | ||
) | ||
|
||
add_executable(z_genbig WIN32) | ||
|
||
target_sources(z_genbig PRIVATE ${GENBIG_SRC}) | ||
|
||
target_include_directories(z_genbig PRIVATE | ||
src | ||
) | ||
|
||
target_link_libraries(z_genbig PRIVATE | ||
benchmark | ||
comctl32 | ||
dbghelplib | ||
imm32 | ||
vfw32 | ||
winmm | ||
z_gameengine | ||
z_gameenginedevice | ||
z_profile | ||
z_wwvegas | ||
zi_libraries_include | ||
) | ||
|
||
if(WIN32 OR "${CMAKE_SYSTEM}" MATCHES "Windows") | ||
target_link_options(z_genbig PRIVATE /subsystem:console) | ||
set_target_properties(z_genbig PROPERTIES OUTPUT_NAME GenBIG) | ||
endif() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
#include "BIGFile.h" | ||
#include <iostream> | ||
#include <fstream> | ||
#include <cstring> | ||
#include <filesystem> | ||
|
||
BIGFile::BIGFile() | ||
{ | ||
init(); | ||
} | ||
|
||
BIGFile::~BIGFile() | ||
{ | ||
if (m_archiveFile != nullptr) { | ||
m_archiveFile->close(); | ||
delete m_archiveFile; | ||
m_archiveFile = nullptr; | ||
} | ||
if (m_paths != nullptr) { | ||
delete[] m_paths; | ||
m_paths = nullptr; | ||
} | ||
if (m_outputDir != nullptr) { | ||
delete[] m_outputDir; | ||
m_outputDir = nullptr; | ||
} | ||
if (m_archiveName != nullptr) { | ||
delete[] m_archiveName; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer to not use new/delete where so possible and use things like STL containers ( When interfacing with Engine, can also use |
||
m_archiveName = nullptr; | ||
} | ||
} | ||
|
||
void BIGFile::init(void) { | ||
DEBUG_ASSERTCRASH(TheLocalFileSystem != NULL, ("TheLocalFileSystem must be initialized before TheArchiveFileSystem.")); | ||
if (TheLocalFileSystem == NULL) { | ||
return; | ||
} | ||
} | ||
|
||
bool BIGFile::addToArchive() { | ||
if (m_archiveName == nullptr || m_outputDir == nullptr || m_paths == nullptr) { | ||
return false; | ||
} | ||
|
||
m_archiveFile = TheArchiveFileSystem->openArchiveFile(m_archiveName); | ||
|
||
// logic to add files to the archive | ||
|
||
m_archiveFile->close(); | ||
printf("Failed to Add file to archive.\n"); | ||
return false; | ||
} | ||
|
||
bool BIGFile::deleteFromArchive(const char *path) { | ||
if (path == nullptr) { | ||
return false; | ||
} | ||
|
||
// logic to delete file from the archive | ||
// function to use: doesFileExist | ||
|
||
printf("File not found in archive.\n"); | ||
return false; | ||
} | ||
|
||
bool BIGFile::listArchive() { | ||
if (m_archiveName == nullptr) { | ||
return false; | ||
} | ||
// todo m_archiveFileSystem = ? | ||
m_archiveFile = m_archiveFileSystem->openArchiveFile(m_archiveName); | ||
FilenameList filenameList; | ||
m_archiveFile->getFileListInDirectory(AsciiString(""), AsciiString(""), AsciiString("*"), filenameList, TRUE); | ||
for (const auto &filename : filenameList) { | ||
std::cout << filename.str() << std::endl; | ||
} | ||
m_archiveFile->close(); | ||
return true; | ||
} | ||
|
||
bool BIGFile::extractArchive(const char *path) { | ||
// logic to extract file from the archive | ||
// function to use: openFile, addFile, | ||
return false; | ||
} | ||
|
||
bool BIGFile::setArchiveFileName(const char *path) { | ||
if (path == nullptr) { | ||
return false; | ||
} | ||
// logic to handle relative paths | ||
// function to use: loadIntoDirectoryTree, | ||
m_archiveName = path; | ||
|
||
return true; | ||
} | ||
|
||
bool BIGFile::setOutputDir(const char *path) { | ||
return false; | ||
} | ||
|
||
bool BIGFile::setPaths(const char *path) { | ||
// logic to handle relative paths of files to be added to/remove from the archive | ||
return false; | ||
} | ||
|
||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// | ||
// Created by User on 27/03/2025. | ||
// | ||
|
||
#ifndef GENZH_BIGFILE_H | ||
#define GENZH_BIGFILE_H | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
|
||
#include "Common/ArchiveFile.h" | ||
#include "Common/ArchiveFileSystem.h" | ||
#include "Common/file.h" | ||
#include "Common/LocalFileSystem.h" | ||
#include "Win32Device/Common/Win32BIGFile.h" | ||
#include "Win32Device/Common/Win32BIGFileSystem.h" | ||
|
||
class BIGFile : Win32BIGFileSystem | ||
{ | ||
public: | ||
BIGFile(); | ||
~BIGFile(); | ||
|
||
// Initialize the archive file system | ||
void init( void ) override; | ||
|
||
// Handle archive operations | ||
bool addToArchive(); | ||
bool addDirectoryToArchive(const char* path); | ||
bool deleteFromArchive(const char* name = NULL); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use |
||
bool listArchive(); | ||
bool extractArchive(const char* path = NULL); | ||
|
||
// getters | ||
ArchiveFile* getArchiveFile() const { return m_archiveFile; } | ||
const char* getArchiveFileName() const { return m_archiveName; } | ||
const char* getOutputDir() const { return m_outputDir; } | ||
const char** getPaths() const { return m_paths; } | ||
int getPathCount() const { return m_pathCount; } | ||
|
||
// setters | ||
bool setArchiveFileName(const char* path); | ||
bool setOutputDir(const char* path); | ||
bool setPaths(const char* path); | ||
|
||
private: | ||
Win32BIGFileSystem * m_archiveFileSystem; // or Win32BIGFileSystem? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks odd that this class derives from Before jumping into big implementations, I suggest to take a moment and think carefully about the design. Upon a first look, we could try to have something like:
You would just need to find an elegant way to make This could allow making a new Read Write version of the archive and its system, while reusing what is already there for opening and reading archives. But perhaps the design of the Win32BIGFile and Win32BIGFileSystem make it hard to fit in the write functionality nicely. In that case a different strategy may be better. Please also be mindful about performance when implementing this. |
||
ArchiveFile* m_archiveFile; | ||
const char *m_archiveName; | ||
const char *m_outputDir; | ||
const char **m_paths; | ||
int m_pathCount; | ||
// list files to archive | ||
std::vector<std::string> m_files; | ||
}; | ||
|
||
#endif //GENZH_BIGFILE_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/** | ||
* @file main.cpp | ||
* | ||
* @author DevGeniusCode | ||
* | ||
* @brief A CLI tool to handle BIG files for Command & Conquer Generals & Zero Hour | ||
* | ||
* @project GenBIG | ||
* | ||
* @date March 2025 | ||
* | ||
* @version 1.0 | ||
* | ||
* @copyright GenBIG is free software: you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public License | ||
* as published by the Free Software Foundation, either version | ||
* 2 of the License, or (at your option) any later version. | ||
* A full copy of the GNU General Public License can be found in | ||
* LICENSE | ||
*/ | ||
|
||
|
||
#include <iostream> | ||
#include "BIGFile.h" | ||
|
||
void printHelp() | ||
{ | ||
printf("Usage: GenBIG [options] <path> <path> ...\n\n"); | ||
|
||
printf("Options:\n" | ||
" -a <path> Add a file or directory to the archive\n" | ||
" -d <name> Delete a file from the archive\n" | ||
" -l List the contents of the archive\n" | ||
" -x Extract the contents of the archive\n" | ||
" -o <path> Output dir\n" | ||
" -h Display this help message\n\n"); | ||
|
||
printf("Examples:" | ||
" Example 1: Add a file to the archive\n" | ||
" GenBIG -a file.txt -o archive.big\n\n" | ||
" Example 2: Add a directory to the archive\n" | ||
" GenBIG -a dir -o archive.big\n\n" | ||
" Example 3: Add multiple files and directories to the archive\n" | ||
" GenBIG -a file1.txt -a file2.txt -a dir1 -a dir2 -o archive.big\n\n" | ||
" Example 4: Extract the contents of the archive\n" | ||
" GenBIG -x archive.big -o dir\n\n" | ||
" Example 5: Extract the contents of the archive from specific directory\n" | ||
" GenBIG -x your/path/archive.big -o .\n\n" | ||
" Example 6: Delete a file from an archive\n" | ||
" GenBIG -d file.txt -o archive.big\n\n"); | ||
} | ||
|
||
// GLOBALS //////////////////////////////////////////////////////////////////// | ||
HINSTANCE ApplicationHInstance = NULL; ///< our application instance | ||
HWND ApplicationHWnd = NULL; ///< our application window handle | ||
|
||
const Char *g_strFile = "data\\Generals.str"; | ||
const Char *g_csfFile = "data\\%s\\Generals.csf"; | ||
const char *gAppPrefix = ""; /// So WB can have a different debug log file name. | ||
|
||
// Main function to handle user input and options | ||
int main(int argc, char *argv[]) { | ||
printf("GenBIG - BIG Archive Tool By TheSuperHackers v1.0\n\n"); | ||
|
||
if (argc < 2) { | ||
printHelp(); | ||
return 1; | ||
} | ||
|
||
BIGFile *bigFile = new BIGFile(); | ||
|
||
int optionError = 0; | ||
|
||
for (int i = 1; i < argc; ++i) { | ||
switch (argv[i][0]) { | ||
case '-': | ||
switch (argv[i][1]) { | ||
case 'a': // Add file or directory to the archive | ||
case 'd': // Delete file from archive | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suggest we use cxxopts for command line, to standardize setups. You can see example how it is used in https://github.com/xezon/unassemblize |
||
if (i + 1 < argc && argv[i + 1][0] != '-') { | ||
bigFile->setPaths(argv[i + 1]); | ||
i++; // Skip the next argument | ||
} else { | ||
printf("Error: Missing path\n"); | ||
optionError = 1; | ||
} | ||
break; | ||
case 'l': // List the contents of the archive | ||
case 'x': // Extract contents from the archive | ||
if (i + 1 < argc && argv[i + 1][0] != '-') { | ||
bigFile->setArchiveFileName(argv[i + 1]); | ||
i++; | ||
} else { | ||
printf("Error: Missing archive name\n"); | ||
optionError = 1; | ||
} | ||
break; | ||
case 'o': // Set output directory or BIG file name to create | ||
if (i + 1 < argc && argv[i + 1][0] != '-') { | ||
bigFile->setOutputDir(argv[i + 1]); | ||
i++; | ||
} else { | ||
printf("Error: Missing output directory after -o\n"); | ||
optionError = 1; | ||
} | ||
break; | ||
case 'h': // Display help message | ||
printHelp(); | ||
return 0; | ||
|
||
default: | ||
printf("Error: Unknown option -%c\n", argv[i][1]); | ||
optionError = 1; | ||
} | ||
break; | ||
|
||
default: | ||
printf("Error: Invalid argument %s\n", argv[i]); | ||
optionError = 1; | ||
} | ||
if (optionError) { | ||
break; | ||
} | ||
} | ||
|
||
if (optionError || bigFile->getArchiveFileName() == NULL) { | ||
return 1; | ||
} | ||
|
||
// Perform the appropriate action based on the options | ||
if (strcmp(argv[1], "-a") == 0) { | ||
bigFile->addToArchive(); | ||
} | ||
else if (strcmp(argv[1], "-d") == 0) { | ||
bigFile->deleteFromArchive(); | ||
} | ||
else if (strcmp(argv[1], "-l") == 0) { | ||
bigFile->listArchive(); | ||
} | ||
else if (strcmp(argv[1], "-x") == 0) { | ||
bigFile->extractArchive(); | ||
} | ||
|
||
delete bigFile; | ||
return 0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest call it
BigArchiver
or similar.