-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLibRipper.cpp
208 lines (194 loc) · 7.6 KB
/
LibRipper.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
/*/////////////////////////////////////////////////////////////////
LibRipper
Copyright 2024 (C) - SolatoroboHacking
This program is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program.
If not, see <https://www.gnu.org/licenses/>.
*//////////////////////////////////////////////////////////////////
// Importing essential libraries
#include <iostream>
#include <fstream>
#include <cstring>
#include <filesystem>
using namespace std;
// Function to convert the raw text from the library files into a more readable layout.
// This essentially just adds lines of ------- to break up sections
void convertReadable(unsigned char* inputText, FILE* outputFile, uint32_t sectionSize) {
// For every byte in the current section,
for (uint32_t i = 0; i < sectionSize; i++) {
// If there is a null byte,
if (inputText[i] == 0x00) {
// Skip over all the null bytes
while (inputText[i+1] == 0x00 && i < sectionSize - 1) {
i++;
}
// If we are not at the end of the section,
if (i < sectionSize - 1) {
// Add a line under the title
fputs("\n---------------------\n\n", outputFile);
}
// If the file contains 0xEFBBBF section breaks,
} else if (inputText[i] == 0xEF && inputText[i+1] == 0xBB && inputText[i+2] == 0xBF) {
// Skip over them
i = i + 2;
// The only real terminator that the game recognizes is 0x00, a null byte, to terminate the current section/string.
// 0xEFBBBF are not printed, as they are zero-width spaces in Unicode.
// They are not written to the output.
// If the current character is just a regular character,
} else {
// Write it to the output
fputc(inputText[i], outputFile);
}
}
// Return when done with the current section
return;
}
// Function to convert the raw text from the library files into markdown for modification and re-insertion
void convertMarkdown(unsigned char* inputText, FILE* outputFile, uint32_t sectionSize) {
// Insert section start flag
fputs("<sec>", outputFile);
// For every byte in the current section,
for (uint32_t i = 0; i < sectionSize; i++) {
// If there is a null byte,
if (inputText[i] == 0x00) {
//Skip over all the null bytes
while (inputText[i+1] == 0x00 && i < sectionSize - 1) {
i++;
}
// Insert a section end flag
fputs("<end>\n\n", outputFile);
// If we are not at the end of the section,
if (i < sectionSize - 1) {
// This must be a title, so add another section start flag for the content
fputs("\n<sec>", outputFile);
}
// If the file contains 0xEFBBBF section breaks,
} else if (inputText[i] == 0xEF && inputText[i+1] == 0xBB && inputText[i+2] == 0xBF) {
// Skip over them
i = i + 2;
// If the current character is just a regular character,
} else {
// Write it to the output
fputc(inputText[i], outputFile);
}
}
// Return when done wiith the current section
return;
}
// Main function
int main(int argc, char** argv) {
// If no input file was provided,
if (argc < 2) {
// Error out
cout << "Error: Provide input file" << endl;
return 1;
} else {
// If the input file does not exist,
if (!filesystem::exists(argv[1])) {
// Error out
cout << "Error: input file does not exist" << endl;
return 1;
}
}
bool GENERATE_MARKDOWN;
// If the -m parameter was passed, set the flag to generate markdown instead of readable text
if (argc >= 3 && strcmp(argv[2], "-m") == 0) {
GENERATE_MARKDOWN = true;
}
// Open source file
FILE* inputFile = fopen(argv[1], "rb");
// Define a pointer for output file to be written
FILE* outputFile;
// If the input file is a .cclhd file, or a "CyberConnect Library Header" file,
if (string(argv[1]).find(".cclhd") != -1) {
// Open an output file called "[SOURCE_NAME].cclhd.txt"
FILE* outputFile = fopen(string(argv[1]).append(".txt").c_str(), "wb");
// Go to offset 0x10, decimal 16, as this is where the content starts.
// The header data for these files, despite being 16 bytes long, is not very useful
fseek(inputFile, 16, SEEK_SET);
// Run the following code twice; once for the section title, once for the hint
for (int i = 0; i < 2; i++) {
// If generating markdown, insert a section start flag
if (GENERATE_MARKDOWN) {
fputs("<sec>", outputFile);
}
// Define an unsigned char to hold current byte (we do not know or need to know the size of the section)
unsigned char currentByte = fgetc(inputFile);
// While the current byte is not 0x00, the null terminator,
while (currentByte != 0x00) {
// Check if there is a 0xEFBBBF separator. If there is not, backtrack and continue
if (currentByte == 0xEF) {
currentByte = fgetc(inputFile);
if (currentByte == 0xBB) {
currentByte = fgetc(inputFile);
if (currentByte == 0xBF) {
currentByte = fgetc(inputFile);
} else {
fseek(inputFile, -3, SEEK_CUR);
currentByte = fgetc(inputFile);
}
} else {
fseek(inputFile, -2, SEEK_CUR);
currentByte = fgetc(inputFile);
}
}
// Write the current byte to the output file
fputc(currentByte, outputFile);
// Read the next input byte
currentByte = fgetc(inputFile);
}
// If generating markdown, insert a sectio end flag
if (GENERATE_MARKDOWN) {
fputs("<end>", outputFile);
}
// Write line breaks after each section
fputs("\n\n", outputFile);
}
// Close the output file when done
fclose(outputFile);
} else {
// Define a new array pointer to hold buffer
unsigned char* readBytes = new unsigned char[4];
// Open output file to be written
outputFile = fopen(string(argv[1]).substr(0, string(argv[1]).find(".cclbm")).append(".txt").c_str(), "wb");
// Skip over the first 4-bytes of the file (file type identifier, not useful)
fseek(inputFile, 4, SEEK_SET);
// For each of the three sections (title + content) in the file,
for (int i = 0; i < 3; i++) {
// Read 4-byte size value of current section from source file
fread(readBytes, 1, 4, inputFile);
// Convert these 4 bytes into an unsigned 32-bit integer
uint32_t sectionSize = ((uint32_t)(readBytes[3] << 24) + (uint32_t)(readBytes[2] << 16) + (uint32_t)(readBytes[1] << 8) + (uint32_t)readBytes[0]);
// This size value, for some reason, includes the 4-bytes of the size value, so subtract them.
sectionSize = sectionSize - 4;
// Read the current section into the buffer
readBytes = new unsigned char[sectionSize];
fread(readBytes, 1, sectionSize, inputFile);
// If generating markdown, use the markdown function
if (GENERATE_MARKDOWN) {
convertMarkdown(readBytes, outputFile, sectionSize);
// Otherwise,
} else {
// Send the current section off to be converted into a readable layout
convertReadable(readBytes, outputFile, sectionSize);
// If we are not at the last section, write a section break when done with the current section
if (i != 2) {
fputs("\n---------------------\n\n\n", outputFile);
}
}
}
// Close the output file
fclose(outputFile);
}
// Close the input file
fclose(inputFile);
return 0;
}