From dbfde6e853b3db06ce922e6ab32aae0a8d172bd6 Mon Sep 17 00:00:00 2001 From: Talv Date: Mon, 22 Jul 2019 10:22:39 +0200 Subject: [PATCH] add Windows compatibility --- CMakeLists.txt | 11 +++++-- README.md | 22 +++++++++++--- src/storm-extract.cpp | 71 ++++++++++++++++++++++--------------------- 3 files changed, 62 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4aaa35..632f5d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,10 @@ Did you forgot to execute the following commands? git submodule update") endif() - +if(WIN32) + set(CASC_BUILD_STATIC_LIB ON CACHE BOOL "Force Static library building to link test app") + set(CASC_BUILD_SHARED_LIB OFF CACHE BOOL "Compile dynamically linked library") +endif() add_subdirectory(CascLib) include_directories("${STORMEXTRACT_SOURCE_DIR}/src/" @@ -29,7 +32,11 @@ include_directories("${STORMEXTRACT_SOURCE_DIR}/src/" ) add_executable(stormex src/storm-extract.cpp) -target_link_libraries(stormex casc) +if(WIN32) + target_link_libraries(stormex casc_static) +else() + target_link_libraries(stormex casc) +endif() # Set the RPATH if (APPLE) diff --git a/README.md b/README.md index 7fe8449..1d92bd3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # stormex Command-line application to list and extract files from the [CASC](https://wowdev.wiki/CASC) (Content -Addressable Storage Container) archives used in Blizzard games. +Addressable Storage Container) used in Blizzard games. Tested on: @@ -10,16 +10,28 @@ Tested on: ## Building -Requires [cmake](http://www.cmake.org/) to build. +### Linux ```sh -git submodule init -git submodule update +git submodule update --init cd build && cmake .. make ``` -The executable will be put in `build/bin/stormex` +> Executable will be put in `build/bin/stormex` + +### Windows + +* Requires `Visual Studio 15 2017 Build Tools` + +```sh +git submodule update --init +cd build +cmake -G "Visual Studio 15 2017 Win64" .. +MSBuild STORMEXTRACT.sln /p:Configuration=Release +``` + +> Executable will be put in `build\bin\Release\stormex.exe` ## Usage diff --git a/src/storm-extract.cpp b/src/storm-extract.cpp index 53c2e30..ac4f5ee 100644 --- a/src/storm-extract.cpp +++ b/src/storm-extract.cpp @@ -1,3 +1,4 @@ +#define __CASCLIB_SELF__ #include "../CascLib/src/CascLib.h" #include "../include/SimpleOpt.h" @@ -5,8 +6,21 @@ #include #include #include -#include #include + +#if (defined(_WIN32) || defined(_WIN64)) + #include + #define mkdir(name, chmod) _mkdir(name) +#endif + +#if defined(WIN32) || defined(_WIN32) + #define PATH_SEP_STR "\\" + #define PATH_SEP_CHAR '\\' +#else + #define PATH_SEP_STR "/" + #define PATH_SEP_CHAR '/' +#endif + #include #include #include @@ -17,7 +31,7 @@ using namespace std; // All the global variables -string version = "1.3.0"; +string version = "1.4.0"; struct tSearchResult { string strFileName; @@ -211,40 +225,27 @@ vector searchArchive() { } size_t extractFile(string strFullPath) { - char buffer[0x100000]; // 1MB buffer - string strDestName = strDestination; - - { - strDestName += strFullPath; - - size_t offset = strDestName.find("\\"); - while (offset != string::npos) - { - strDestName = strDestName.substr(0, offset) + "/" + strDestName.substr(offset + 1); - offset = strDestName.find("\\"); - } + char buffer[0x1000]; + string strDestName = strDestination + strFullPath; + size_t pos; - offset = strDestName.find_last_of("/"); - if (offset != string::npos) - { - string dest = strDestName.substr(0, offset + 1); - - size_t start = dest.find("/", 0); - while (start != string::npos) - { - string dirname = dest.substr(0, start); + // normalize slashes in the path + std::replace(strDestName.begin(), strDestName.end(), '\\', '/'); - DIR* d = opendir(dirname.c_str()); - if (!d) - mkdir(dirname.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); - else - closedir(d); + // ensure directory path to the file exists + pos = -1; + while ((pos = strDestName.find('/', pos + 1)) != string::npos) + { + string dirname = strDestName.substr(0, pos); - start = dest.find("/", start + 1); - } - } + DIR* d = opendir(dirname.c_str()); + if (!d) + mkdir(dirname.c_str(), 0755); + else + closedir(d); } + // extract data HANDLE hFile; size_t fileSize = 0; if (CascOpenFile(hStorage, strFullPath.c_str(), CASC_LOCALE_ALL, 0, &hFile)) @@ -254,7 +255,7 @@ size_t extractFile(string strFullPath) { if (dest) { do { - if (CascReadFile(hFile, &buffer, 0x100000, &read)) { + if (CascReadFile(hFile, &buffer, sizeof(buffer), &read)) { fileSize += fwrite(&buffer, read, 1, dest); } } while (read > 0); @@ -264,7 +265,7 @@ size_t extractFile(string strFullPath) { else { cerr << "NOFILE: (" << errno << ") Failed to extract '" << strFullPath << "' to " << strDestName << endl; - return 0; + return 0; } CascCloseFile(hFile); } @@ -380,8 +381,8 @@ int main(int argc, char** argv) { int progress; echo("Extracting files:\n"); - if (strDestination.at(strDestination.size() - 1) != '/') - strDestination += "/"; + if (strDestination.at(strDestination.size() - 1) != PATH_SEP_CHAR) + strDestination += PATH_SEP_STR; vector::iterator iter, iterEnd; for (iter = results.begin(), iterEnd = results.end(); iter != iterEnd; ++iter)