WoW Model Viewer
Your premiere tool for viewing, equipping and animating World of Warcraft models.
Loading...
Searching...
No Matches
CASCFolder.cpp
Go to the documentation of this file.
1#include "CASCFolder.h"
2
3#ifndef __CASCLIB_SELF__
4#define __CASCLIB_SELF__
5#endif
6#include "CascLib.h"
7
8#include <locale>
9#include <map>
10#include <utility>
11#include <filesystem>
12#include <fstream>
13#include <regex>
14#include <string>
15
16#include "CASCFile.h"
17#include "string_utils.h"
18#include "Logger.h"
19
21 : m_currentCascLocale(CASC_LOCALE_NONE), m_folder(""), m_openError(ERROR_SUCCESS), hStorage(nullptr)
22{
23}
24
25void CASCFolder::init(const std::string& path)
26{
27 m_folder = path;
28
29 if (!m_folder.empty() && m_folder.back() == '\\')
30 m_folder.pop_back();
31
33}
34
36{
37 m_currentConfig = config;
38
39 // init map based on CASCLib
40 std::map<std::string, int> locales;
41 locales["frFR"] = CASC_LOCALE_FRFR;
42 locales["deDE"] = CASC_LOCALE_DEDE;
43 locales["esES"] = CASC_LOCALE_ESES;
44 locales["esMX"] = CASC_LOCALE_ESMX;
45 locales["ptBR"] = CASC_LOCALE_PTBR;
46 locales["itIT"] = CASC_LOCALE_ITIT;
47 locales["ptPT"] = CASC_LOCALE_PTPT;
48 locales["enGB"] = CASC_LOCALE_ENGB;
49 locales["ruRU"] = CASC_LOCALE_RURU;
50 locales["enUS"] = CASC_LOCALE_ENUS;
51 locales["enCN"] = CASC_LOCALE_ENCN;
52 locales["enTW"] = CASC_LOCALE_ENTW;
53 locales["koKR"] = CASC_LOCALE_KOKR;
54 locales["zhCN"] = CASC_LOCALE_ZHCN;
55 locales["zhTW"] = CASC_LOCALE_ZHTW;
56
57 // set locale
58 if (!m_currentConfig.locale.empty())
59 {
60 const auto& it = locales.find(m_currentConfig.locale);
61
62 if (it != locales.end())
63 {
64 const std::string cascParams = m_folder + "*" + m_currentConfig.product;
65 LOG_INFO << "Loading Game Folder:" << cascParams;
66 // locale found => try to open it
67 if (!CascOpenStorage(std::filesystem::path(cascParams).wstring().c_str(), it->second, &hStorage))
68 {
69 m_openError = GetLastError();
70 LOG_ERROR << "CASCFolder: Opening" << cascParams << "failed." << "Error" << m_openError;
71 return false;
72 }
73
75
76 m_currentCascLocale = it->second;
77 }
78 }
79
80 return true;
81}
82
84{
85 const std::string buildinfofile = m_folder + "\\..\\.build.info";
86 LOG_INFO << "buildinfofile : " << buildinfofile;
87
88 std::ifstream file(buildinfofile);
89 if (!file.is_open())
90 {
91 LOG_ERROR << "Fail to open .build.info to grab game config info";
92 return;
93 }
94
95 std::string stdline;
96
97 // read first line and grab VERSION index
98 if (!std::getline(file, stdline))
99 return;
100
101 auto headers = core::split(stdline, '|');
102 int activeIndex = 0;
103 int versionIndex = 0;
104 int tagIndex = 0;
105 int productIndex = 0;
106 for (int index = 0; index < static_cast<int>(headers.size()); index++)
107 {
108 if (core::containsIgnoreCase(headers[index], "Active"))
109 activeIndex = index;
110 else if (core::containsIgnoreCase(headers[index], "Version"))
111 versionIndex = index;
112 else if (core::containsIgnoreCase(headers[index], "Tags"))
113 tagIndex = index;
114 else if (core::containsIgnoreCase(headers[index], "Product"))
115 productIndex = index;
116 }
117
118 // now loop across file lines with actual values
119 const std::regex re(R"(^(\d+).(\d+).(\d+).(\d+)$)");
120 while (std::getline(file, stdline))
121 {
122 std::string version;
123 auto values = core::split(stdline, '|');
124
125 // if inactive config, skip it
126 if (values[activeIndex] == "0")
127 continue;
128
129 // grab version for this line
130 std::smatch result;
131 if (std::regex_match(values[versionIndex], result, re))
132 version = result[1].str() + "." + result[2].str() + "." + result[3].str() + "." + result[4].str();
133
134 // grab product name for this line
135 const std::string product = values[productIndex];
136
137 // grab locale(s) for this line
138 auto tagValues = core::split(values[tagIndex], ':');
139 for (const auto& value : tagValues)
140 {
141 if (value.find("text?") != std::string::npos)
142 {
143 auto tags = core::split(value, ' ');
144 core::GameConfig config;
145 config.locale = tags[tags.size() - 2];
146 config.version = version;
147 config.product = product;
148 m_configs.push_back(config);
149 }
150 }
151 }
152
153 for (auto& it : m_configs)
154 LOG_INFO << "config" << it.locale << it.version;
155}
156
158{
159 //LOG_INFO << __FUNCTION__ << " " << file.c_str();
160 if (!hStorage)
161 return false;
162
163 HANDLE dummy;
164
165 if (CascOpenFile(hStorage, CASC_FILE_DATA_ID(id), m_currentCascLocale, CASC_OPEN_BY_FILEID, &dummy))
166 {
167 // LOG_INFO << "OK";
168 CascCloseFile(dummy);
169 return true;
170 }
171 // LOG_ERROR << "File" << id << "doesn't exist." << "Error" << GetLastError();
172 return false;
173}
174
175bool CASCFolder::openFile(int id, HANDLE* result)
176{
177 return CascOpenFile(hStorage, CASC_FILE_DATA_ID(id), m_currentCascLocale, CASC_OPEN_BY_FILEID, result);
178}
179
180bool CASCFolder::closeFile(HANDLE file)
181{
182 return CascCloseFile(file);
183}
184
186{
187 std::ifstream tactKeys("extraEncryptionKeys.csv");
188
189 if (tactKeys.is_open())
190 {
191 std::string stdline;
192 while (std::getline(tactKeys, stdline))
193 {
194 if (stdline.starts_with("##") || stdline.starts_with("\"##"))
195 // ignore lines beginning with ##, useful for adding comments.
196 continue;
197
198 auto lineData = core::split(stdline, ';');
199 if (lineData.size() != 2)
200 continue;
201 const std::string& keyName = lineData[0];
202 const std::string& keyValue = lineData[1];
203 if (keyName.empty() || keyValue.empty())
204 continue;
205
206 const unsigned long long keyNameVal = std::stoull(keyName, nullptr, 16);
207 const bool ok2 = CascAddStringEncryptionKey(hStorage, keyNameVal, keyValue.c_str());
208 if (!ok2)
209 LOG_ERROR << "Failed to add TACT key from file, Name:" << keyName << ", Value:" << keyValue;
210 }
211 }
212}
213
214/*
215int CASCFolder::fileDataId(std::string & filename)
216{
217 return CascGetFileId(hStorage, filename.c_str());
218}
219*/
#define LOG_ERROR
Definition Logger.h:11
#define LOG_INFO
Definition Logger.h:10
bool setConfig(core::GameConfig config)
void init(const std::string &path)
bool closeFile(HANDLE file)
void initBuildInfo()
bool openFile(int id, HANDLE *result)
HANDLE hStorage
Definition CASCFolder.h:59
void addExtraEncryptionKeys()
bool fileExists(int id)
std::string version()
Definition CASCFolder.h:31
int m_currentCascLocale
Definition CASCFolder.h:54
int m_openError
Definition CASCFolder.h:58
core::GameConfig m_currentConfig
Definition CASCFolder.h:55
std::vector< core::GameConfig > m_configs
Definition CASCFolder.h:61
std::string m_folder
Definition CASCFolder.h:57
Describes a detected game installation (locale, version, product).
Definition GameFolder.h:16
std::string product
e.g. "wow" or "wow_classic".
Definition GameFolder.h:20
std::string version
e.g. "11.0.7.58238".
Definition GameFolder.h:19
std::string locale
e.g. "enUS".
Definition GameFolder.h:18
std::vector< std::string > split(const std::string &s, char delimiter)
Split a string by a single-character delimiter.
bool containsIgnoreCase(const std::string &s, const std::string &substr)