Skip to content

Commit dbfde6e

Browse files
committed
add Windows compatibility
1 parent 49021fa commit dbfde6e

File tree

3 files changed

+62
-42
lines changed

3 files changed

+62
-42
lines changed

CMakeLists.txt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ Did you forgot to execute the following commands?
2020
git submodule update")
2121
endif()
2222

23-
23+
if(WIN32)
24+
set(CASC_BUILD_STATIC_LIB ON CACHE BOOL "Force Static library building to link test app")
25+
set(CASC_BUILD_SHARED_LIB OFF CACHE BOOL "Compile dynamically linked library")
26+
endif()
2427
add_subdirectory(CascLib)
2528

2629
include_directories("${STORMEXTRACT_SOURCE_DIR}/src/"
@@ -29,7 +32,11 @@ include_directories("${STORMEXTRACT_SOURCE_DIR}/src/"
2932
)
3033

3134
add_executable(stormex src/storm-extract.cpp)
32-
target_link_libraries(stormex casc)
35+
if(WIN32)
36+
target_link_libraries(stormex casc_static)
37+
else()
38+
target_link_libraries(stormex casc)
39+
endif()
3340

3441
# Set the RPATH
3542
if (APPLE)

README.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# stormex
22

33
Command-line application to list and extract files from the [CASC](https://wowdev.wiki/CASC) (Content
4-
Addressable Storage Container) archives used in Blizzard games.
4+
Addressable Storage Container) used in Blizzard games.
55

66
Tested on:
77

@@ -10,16 +10,28 @@ Tested on:
1010

1111
## Building
1212

13-
Requires [cmake](http://www.cmake.org/) to build.
13+
### Linux
1414

1515
```sh
16-
git submodule init
17-
git submodule update
16+
git submodule update --init
1817
cd build && cmake ..
1918
make
2019
```
2120

22-
The executable will be put in `build/bin/stormex`
21+
> Executable will be put in `build/bin/stormex`
22+
23+
### Windows
24+
25+
* Requires `Visual Studio 15 2017 Build Tools`
26+
27+
```sh
28+
git submodule update --init
29+
cd build
30+
cmake -G "Visual Studio 15 2017 Win64" ..
31+
MSBuild STORMEXTRACT.sln /p:Configuration=Release
32+
```
33+
34+
> Executable will be put in `build\bin\Release\stormex.exe`
2335
2436
## Usage
2537

src/storm-extract.cpp

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1+
#define __CASCLIB_SELF__
12
#include "../CascLib/src/CascLib.h"
23
#include "../include/SimpleOpt.h"
34

45
#include <iostream>
56
#include <string>
67
#include <vector>
78
#include <algorithm>
8-
#include <unistd.h>
99
#include <dirent.h>
10+
11+
#if (defined(_WIN32) || defined(_WIN64))
12+
#include <direct.h>
13+
#define mkdir(name, chmod) _mkdir(name)
14+
#endif
15+
16+
#if defined(WIN32) || defined(_WIN32)
17+
#define PATH_SEP_STR "\\"
18+
#define PATH_SEP_CHAR '\\'
19+
#else
20+
#define PATH_SEP_STR "/"
21+
#define PATH_SEP_CHAR '/'
22+
#endif
23+
1024
#include <stdlib.h>
1125
#include <stdio.h>
1226
#include <sys/stat.h>
@@ -17,7 +31,7 @@ using namespace std;
1731

1832

1933
// All the global variables
20-
string version = "1.3.0";
34+
string version = "1.4.0";
2135

2236
struct tSearchResult {
2337
string strFileName;
@@ -211,40 +225,27 @@ vector<string> searchArchive() {
211225
}
212226

213227
size_t extractFile(string strFullPath) {
214-
char buffer[0x100000]; // 1MB buffer
215-
string strDestName = strDestination;
216-
217-
{
218-
strDestName += strFullPath;
219-
220-
size_t offset = strDestName.find("\\");
221-
while (offset != string::npos)
222-
{
223-
strDestName = strDestName.substr(0, offset) + "/" + strDestName.substr(offset + 1);
224-
offset = strDestName.find("\\");
225-
}
228+
char buffer[0x1000];
229+
string strDestName = strDestination + strFullPath;
230+
size_t pos;
226231

227-
offset = strDestName.find_last_of("/");
228-
if (offset != string::npos)
229-
{
230-
string dest = strDestName.substr(0, offset + 1);
231-
232-
size_t start = dest.find("/", 0);
233-
while (start != string::npos)
234-
{
235-
string dirname = dest.substr(0, start);
232+
// normalize slashes in the path
233+
std::replace(strDestName.begin(), strDestName.end(), '\\', '/');
236234

237-
DIR* d = opendir(dirname.c_str());
238-
if (!d)
239-
mkdir(dirname.c_str(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
240-
else
241-
closedir(d);
235+
// ensure directory path to the file exists
236+
pos = -1;
237+
while ((pos = strDestName.find('/', pos + 1)) != string::npos)
238+
{
239+
string dirname = strDestName.substr(0, pos);
242240

243-
start = dest.find("/", start + 1);
244-
}
245-
}
241+
DIR* d = opendir(dirname.c_str());
242+
if (!d)
243+
mkdir(dirname.c_str(), 0755);
244+
else
245+
closedir(d);
246246
}
247247

248+
// extract data
248249
HANDLE hFile;
249250
size_t fileSize = 0;
250251
if (CascOpenFile(hStorage, strFullPath.c_str(), CASC_LOCALE_ALL, 0, &hFile))
@@ -254,7 +255,7 @@ size_t extractFile(string strFullPath) {
254255
if (dest)
255256
{
256257
do {
257-
if (CascReadFile(hFile, &buffer, 0x100000, &read)) {
258+
if (CascReadFile(hFile, &buffer, sizeof(buffer), &read)) {
258259
fileSize += fwrite(&buffer, read, 1, dest);
259260
}
260261
} while (read > 0);
@@ -264,7 +265,7 @@ size_t extractFile(string strFullPath) {
264265
else
265266
{
266267
cerr << "NOFILE: (" << errno << ") Failed to extract '" << strFullPath << "' to " << strDestName << endl;
267-
return 0;
268+
return 0;
268269
}
269270
CascCloseFile(hFile);
270271
}
@@ -380,8 +381,8 @@ int main(int argc, char** argv) {
380381
int progress;
381382
echo("Extracting files:\n");
382383

383-
if (strDestination.at(strDestination.size() - 1) != '/')
384-
strDestination += "/";
384+
if (strDestination.at(strDestination.size() - 1) != PATH_SEP_CHAR)
385+
strDestination += PATH_SEP_STR;
385386

386387
vector<string>::iterator iter, iterEnd;
387388
for (iter = results.begin(), iterEnd = results.end(); iter != iterEnd; ++iter)

0 commit comments

Comments
 (0)