Skip to content

Commit 87a657b

Browse files
committed
Init
0 parents  commit 87a657b

File tree

2 files changed

+232
-0
lines changed

2 files changed

+232
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.vscode
2+
*.exe
3+
*.bank
4+
run.bat

main.cpp

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
#define NDEBUG
2+
#include <fstream>
3+
#include <cassert>
4+
#include <tuple>
5+
#include <iomanip>
6+
#include <iostream>
7+
#include <cstdlib>
8+
#include <cstring>
9+
#include <string>
10+
#include <sstream>
11+
#include <vector>
12+
13+
using namespace std;
14+
15+
uint8_t hexSubStringToByte(const string& hexString, int start, int length) {
16+
auto subStr = hexString.substr(start, length);
17+
return strtol(subStr.c_str(), NULL, 16);
18+
}
19+
20+
vector<uint8_t> GUIDStringToByteArray(const string& GUID) {
21+
vector<uint8_t> out(16);
22+
out[3] = hexSubStringToByte(GUID, 1, 2);
23+
out[2] = hexSubStringToByte(GUID, 3, 2);
24+
out[1] = hexSubStringToByte(GUID, 5, 2);
25+
out[0] = hexSubStringToByte(GUID, 7, 2);
26+
out[5] = hexSubStringToByte(GUID, 10, 2);
27+
out[4] = hexSubStringToByte(GUID, 12, 2);
28+
out[7] = hexSubStringToByte(GUID, 15, 2);
29+
out[6] = hexSubStringToByte(GUID, 17, 2);
30+
out[8] = hexSubStringToByte(GUID, 20, 2);
31+
out[9] = hexSubStringToByte(GUID, 22, 2);
32+
out[10] = hexSubStringToByte(GUID, 25, 2);
33+
out[11] = hexSubStringToByte(GUID, 27, 2);
34+
out[12] = hexSubStringToByte(GUID, 29, 2);
35+
out[13] = hexSubStringToByte(GUID, 31, 2);
36+
out[14] = hexSubStringToByte(GUID, 33, 2);
37+
out[15] = hexSubStringToByte(GUID, 35, 2);
38+
return out;
39+
}
40+
41+
string toHexString(int val, int width) {
42+
string valueHexString;
43+
stringstream ss;
44+
ss << setfill('0') << setw(width) << hex << val;
45+
return ss.str();
46+
}
47+
48+
// Input: { 0xFF, 0xAA, 0xCC }
49+
// Ouput: FFAACC
50+
string ByteArrayToString(vector<uint8_t> bytes) {
51+
stringstream ss;
52+
for(int i = 0; i < 16; i++) {
53+
ss << toHexString(bytes[i], 2);
54+
}
55+
return ss.str();
56+
}
57+
58+
// Input is a GUID how it appears in binary format in the file,
59+
// output is a human readable string how that GUID would appear in the GUIDs.txt
60+
// string ByteArrayToGUIDString(char* start) {
61+
string ByteArrayToGUIDString(vector<uint8_t> bytes) {
62+
stringstream ss;
63+
ss << "{";
64+
ss << toHexString(bytes[3] & 0xFF, 2);
65+
ss << toHexString(bytes[2] & 0xFF, 2);
66+
ss << toHexString(bytes[1] & 0xFF, 2);
67+
ss << toHexString(bytes[0] & 0xFF, 2);
68+
ss << '-';
69+
ss << toHexString(bytes[5] & 0xFF, 2);
70+
ss << toHexString(bytes[4] & 0xFF, 2);
71+
ss << '-';
72+
ss << toHexString(bytes[7] & 0xFF, 2);
73+
ss << toHexString(bytes[6] & 0xFF, 2);
74+
ss << '-';
75+
ss << toHexString(bytes[8] & 0xFF, 2);
76+
ss << toHexString(bytes[9] & 0xFF, 2);
77+
ss << '-';
78+
ss << toHexString(bytes[10] & 0xFF, 2);
79+
ss << toHexString(bytes[11] & 0xFF, 2);
80+
ss << toHexString(bytes[12] & 0xFF, 2);
81+
ss << toHexString(bytes[13] & 0xFF, 2);
82+
ss << toHexString(bytes[14] & 0xFF, 2);
83+
ss << toHexString(bytes[15] & 0xFF, 2);
84+
ss << '}';
85+
return ss.str();
86+
}
87+
88+
bool isHexString(const string& s) {
89+
return s.find_first_not_of("0123456789abcdefABCDEF", 2) == string::npos;
90+
}
91+
92+
bool isValidGUIDString(const string &s) {
93+
if(s[0] != '{' || s[37] != '}') {
94+
return false;
95+
} else if(!isHexString(s.substr(1, 8))) {
96+
return false;
97+
} else if(s[9] != '-') {
98+
return false;
99+
} else if(!isHexString(s.substr(9, 4))) {
100+
return false;
101+
} else if(s[14] != '-') {
102+
return false;
103+
} else if(!isHexString(s.substr(14, 4))) {
104+
return false;
105+
} else if(s[19] != '-') {
106+
return false;
107+
} else if(!isHexString(s.substr(19, 4))) {
108+
return false;
109+
} else if(s[24] != '-') {
110+
return false;
111+
} else if(!isHexString(s.substr(24, 12))) {
112+
return false;
113+
}
114+
return true;
115+
}
116+
117+
void test_isValidGUIDString() {
118+
assert(isValidGUIDString("{c7d655d8-ec85-4d25-bc91-cf2cca64fbb7}") == true);
119+
assert(isValidGUIDString("{RRRRRRRR-ec85-4d25-bc91-cf2cca64fbb7}") == false);
120+
assert(isValidGUIDString("{c7d655d8-ec85-4d25-bc91-cf2cca64fbb7") == false);
121+
assert(isValidGUIDString("c7d655d8-ec85-4d25-bc91-cf2cca64fbb7") == false);
122+
}
123+
124+
void test_toHextString() {
125+
assert(toHexString(0, 2).compare(0, 2, "00") == 0);
126+
assert(toHexString(0, 1).compare(0, 2, "0") == 0);
127+
assert(toHexString(15, 2).compare(0, 2, "0f") == 0);
128+
assert(toHexString(15, 1).compare(0, 2, "f") == 0);
129+
}
130+
131+
void test_hexSubStringToByte() {
132+
assert(hexSubStringToByte("FFAA", 1, 1) == 15);
133+
assert(hexSubStringToByte("FFAA", 1, 2) == 250);
134+
assert(hexSubStringToByte("FFAA", 0, 1) == 15);
135+
assert(hexSubStringToByte("FFAA", 0, 2) == 255);
136+
assert(hexSubStringToByte("FFAA", 2, 2) == 170);
137+
}
138+
139+
void test_GUIDStringToByteArray() {
140+
const string testGUID = "{c7d655d8-ec85-4d25-bc91-cf2cca64fbb7}";
141+
const vector<uint8_t> correctOutput = { 216, 85, 214, 199, 133, 236, 37, 77, 188, 145, 207, 44, 202, 100, 251, 183 };
142+
auto bytes = GUIDStringToByteArray(testGUID);
143+
for(int i = 0; i < 16; i++) {
144+
assert(correctOutput[i] == bytes[i]);
145+
}
146+
}
147+
148+
void test_ConversionBackAndForth() {
149+
const string testGUID = "{c7d655d8-ec85-4d25-bc91-cf2cca64fbb7}";
150+
assert(ByteArrayToGUIDString(GUIDStringToByteArray(testGUID)) == testGUID);
151+
}
152+
153+
void run_tests() {
154+
test_toHextString();
155+
test_hexSubStringToByte();
156+
test_GUIDStringToByteArray();
157+
test_ConversionBackAndForth();
158+
test_isValidGUIDString();
159+
}
160+
161+
int wrongUsage() {
162+
cerr << "Usage: guid_replacer.exe your_audio.bank [GUID to replace] [what to replace it with]" << endl;
163+
cerr << "Example: guid_replacer.exe your_audio.bank {bc5e80f9-a380-47c9-8799-3e02eea94feb} {aabbccdd-eeff-00ff-aabb-feffefbbaacc}" << endl;
164+
cerr << "Multiple replacements can be chained like this:" << endl;
165+
cerr << "guid_replacer.exe your_audio.bank GUID_A1 GUID_A2 GUID_B1 GUID_B2" << endl;
166+
return -1;
167+
}
168+
169+
int main(int argc, char** argv) {
170+
run_tests();
171+
vector<tuple<string, string>> guidReplacePairs;
172+
if(argc % 2 == 1) {
173+
return wrongUsage();
174+
}
175+
const string filename = argv[1];
176+
if(filename.find_first_of(".bank") == string::npos) {
177+
return wrongUsage();
178+
}
179+
for(int i = 2; i < argc; i += 2) {
180+
if(!isValidGUIDString(argv[i]) || !isValidGUIDString(argv[i+1])) {
181+
return wrongUsage();
182+
}
183+
guidReplacePairs.push_back(make_tuple(argv[i], argv[i+1]));
184+
}
185+
fstream new_file(filename, ios::in | ios:: out | ios::binary);
186+
const char* EVNTEVTB = "EVNTEVTB";
187+
if(!new_file) {
188+
cout << "Could not open file '" << filename << "': " << strerror(errno) << endl;
189+
} else {
190+
// First find the offset where the string EVNTEVTB ends
191+
int currentMatchingPosition = 0;
192+
while(!new_file.eof()) {
193+
const size_t BUFFER_SIZE = 1024;
194+
string buffer(BUFFER_SIZE, '\0');
195+
int pos = new_file.tellg();
196+
new_file.read(&buffer[0], BUFFER_SIZE);
197+
for(int i = 0; i < BUFFER_SIZE; i++) {
198+
if(buffer[i] == EVNTEVTB[currentMatchingPosition]) {
199+
currentMatchingPosition++;
200+
if(currentMatchingPosition == 8) {
201+
currentMatchingPosition = 0;
202+
// End of EVNTEVTB string found at pos + i + 1, GUID starts 4 bytes later
203+
int GUIDstartPos = pos + i + 1 + 4;
204+
// Read out the GUID
205+
vector<uint8_t> GUID(17);
206+
GUID[16] = 0;
207+
buffer.copy((char*)&GUID[0], 16, i + 1 + 4);
208+
// cout << "Found a GUID at offset " << GUIDstartPos << " - " << ByteArrayToGUIDString(GUID) << " - " << ByteArrayToString(GUID) << endl;
209+
for(auto it = guidReplacePairs.begin(); it != guidReplacePairs.end(); it++) {
210+
const string lookFor = get<0>(*it);
211+
const string replaceWith = get<1>(*it);
212+
if(lookFor.compare(ByteArrayToGUIDString(GUID)) == 0) {
213+
cout << "Replacing " << lookFor << " at offset " << GUIDstartPos << " with " << replaceWith << endl;
214+
new_file.seekp(GUIDstartPos);
215+
auto boop = GUIDStringToByteArray(replaceWith);
216+
new_file.write((char*)&boop[0], 16);
217+
}
218+
}
219+
}
220+
} else {
221+
currentMatchingPosition = 0;
222+
}
223+
}
224+
}
225+
new_file.close();
226+
}
227+
return 0;
228+
}

0 commit comments

Comments
 (0)