forked from dabbertorres/bzMapQuery
/
main.cpp
334 lines (259 loc) · 7.06 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
// stl
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
// sfml
#include <SFML/Network/Http.hpp>
// libzip
#include <zip.h>
// os
#ifdef __linux__
#include <unistd.h>
#include <sys/stat.h>
#else
#include <windows.h>
#endif
// servers
#include "BattlezoneOneCom.hpp"
using bbyte = char;
/* constants */
#ifdef __linux__
constexpr unsigned int PATH_MAX = 1024;
constexpr std::string BZ_REG_KEY_STR = "";
#else
const unsigned int PATH_MAX = 1024; // friggin VS not having friggin constexpr is friggin dumb
const std::string BZ_REG_KEY_STR = "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{B3B61934-313A-44A2-B589-700FDAA6C758}_is1";
#endif
// attempts to extract map files from downloaded zip
bool extractMap(const std::string&);
// adds a map to BZ's netmis file
bool addMapToNetmis(const std::string&);
// create a folder given a path
bool makeFolder(const std::string&);
// strip out web characters from string ex: '%20'
void stripWebChars(std::string&);
// get path of our program
std::string getExePath();
// get install location of Battlezone
std::string getBZinstallDir();
int main(int argc, char** argv)
{
mq::MapSite::StrVec args(argv + 1, argv + argc); // "+ 1" to skip first arg. It's the name of the program
if(args.size() < 1)
{
std::cout << "[ERROR]: Not enough arguments. Type at least something to search for after the exe name.\n";
return 3;
}
std::string searchStr = args[0];
for(auto i = 1u; i < args.size(); i++)
searchStr.append(" " + args[i]);
mq::BattlezoneOneCom bz1server;
if(!bz1server.isServerGood())
{
std::cout << "[ERROR]: Cannot contact server. Exiting.\n";
return 1;
}
mq::MapSite::StrMap results = bz1server.getMaps(searchStr);
if(results.empty())
{
std::cout << "No results found for \"" << searchStr << "\"!\n";
return 0;
}
for(auto it = results.begin(); it != results.end(); it++)
{
std::cout << std::distance(results.begin(), it) << ") " << it->first << " : " << it->second << '\n';
}
bool badInput = true;
std::string input;
std::vector<unsigned int> choices(1);
while(badInput)
{
std::cout << "\nEnter the number(s) of the map to download (\"-1\" to cancel): ";
std::getline(std::cin, input);
if(input == "-1")
return 0;
std::stringstream ss(input);
badInput = false;
try
{
while(ss >> choices.back())
choices.emplace_back();
choices.erase(--choices.end()); // get rid of extra item
for(auto& c : choices)
if(c >= results.size())
throw 0;
}
catch(...)
{
badInput = true;
choices.resize(1);
std::cout << "[ERROR]: Bad input. Try again!\n";
}
}
std::string installLocation = getBZinstallDir();
if(installLocation.empty())
installLocation = getExePath();
installLocation += "addon/";
for(auto& c : choices)
{
auto choiceIter = std::next(results.begin(), c);
std::string resFileName = bz1server.downloadMap(choiceIter->second, installLocation);
if(resFileName.empty())
{
std::cout << "[ERROR]: Download failed for \"" << choiceIter->first << "\". Exiting.\n";
return 2;
}
extractMap(resFileName);
}
return 0;
}
bool extractMap(const std::string& file)
{
int err = 0;
zip* zipFile = zip_open(file.c_str(), 0, &err);
if(!zipFile)
{
std::cout << "[ERROR]: Failed to open archive file: " << file << ".\n";
return false;
}
auto fileNumber = zip_get_num_entries(zipFile, 0);
std::string folderName = file.substr(0, file.find_last_of('.')) + "/"; // cut off file extension, add dir char
stripWebChars(folderName);
if(!makeFolder(folderName))
return false;
for(auto i = 0u; i < fileNumber; i++)
{
zip_file* zipped = zip_fopen_index(zipFile, i, 0);
struct zip_stat fileInfo;
zip_stat_init(&fileInfo);
zip_stat_index(zipFile, i, 0, &fileInfo);
if(fileInfo.valid & ZIP_STAT_NAME && fileInfo.valid & ZIP_STAT_SIZE && fileInfo.valid & ZIP_STAT_COMP_SIZE)
{
std::string fileStr = fileInfo.name;
if(fileStr.find('.') == std::string::npos) // if we don't have a dot, this is a folder
{
continue; // skip this folder
}
if(fileStr.find('/') != std::string::npos) // if we have any dir chars in the string, strip out dirs
{
fileStr = fileStr.substr(fileStr.find_last_of('/') + 1);
}
#ifndef __linux__
#pragma warning(push)
#pragma warning(disable: 4244)
#endif
std::vector<bbyte> bytes(fileInfo.size); // just gotta deal with this conversion
#ifndef __linux__
#pragma warning(pop)
#endif
zip_fread(zipped, bytes.data(), fileInfo.size);
std::ofstream fout;
fout.open(folderName + fileStr, std::ofstream::binary);
if(fout.bad())
{
std::cout << "[ERROR]: Unable to extract file: " << fileInfo.name << '\n';
return false;
}
fout.write(bytes.data(), bytes.size());
fout.close();
}
else
{
std::cout << "[ERROR]: Bad file data for file in archive: " << file << '\n';
return false;
}
zip_fclose(zipped);
}
zip_close(zipFile);
// delete the zip file, it's no longer needed
#ifdef __linux__
// TBD
#else
DeleteFile(file.c_str());
#endif
return true;
}
bool addMapToNetmis(const std::string& map)
{
return true;
}
bool makeFolder(const std::string& name)
{
#ifdef __linux__
struct stat st;
int status = 0;
if(stat(name.c_str(), &st) != 0) // check if folder already exists
{
if(mkdir(name.c_str(), 0700) != 0) // check for failure
{
std::cout << "[ERROR]: Failure creating folder: " << name << '\n';
return false;
}
}
#else
if(CreateDirectory(name.c_str(), NULL) != 0) // success check
{
// do nothing.
}
#endif
else
{
std::cout << "[ERROR]: Folder already exists: " << name << '\n';
return false;
}
return true;
}
void stripWebChars(std::string& str)
{
auto pos = str.find("%20"); // look for annoying stuff in string
while(pos != std::string::npos)
{
str.replace(pos, 3, " "); // replace it with a space
pos = str.find("%20");
}
}
std::string getExePath()
{
std::string path;
char buffer[PATH_MAX];
#ifdef __linux__
readlink("/proc/self/exe", buffer, PATH_MAX);
#else
GetModuleFileName(NULL, buffer, PATH_MAX);
#endif
path = buffer;
path = path.substr(0, path.find_last_of('/') + 1);
return std::move(path);
}
std::string getBZinstallDir()
{
std::string path;
#ifdef __linux__
// TBD
#else
HKEY bzRegKey;
unsigned char buffer[MAX_PATH] = {0};
unsigned long int bufferSize = MAX_PATH;
long int err = 0;
err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, BZ_REG_KEY_STR.c_str(), 0, KEY_READ, &bzRegKey);
if(err != ERROR_SUCCESS)
{
std::cout << "[WARNING]: Failed to open BZ registry key. Installing map to my location.\n";
return "";
}
err = RegQueryValueEx(bzRegKey, "InstallLocation", NULL, NULL, buffer, &bufferSize);
if(err != ERROR_SUCCESS)
{
std::cout << "[WARNING]: Could not get InstallLocation of BZ registry key. Installing map to my location.\n";
return "";
}
path = std::string(reinterpret_cast<char*>(buffer), bufferSize);
path.pop_back(); // extra space at the end of the string?
while(path.find('\\') != std::string::npos)
{
path.replace(path.find('\\'), 1, 1, '/');
}
#endif
return std::move(path);
}