-
Notifications
You must be signed in to change notification settings - Fork 1
/
chromium.cpp
97 lines (80 loc) · 2.85 KB
/
chromium.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
/*******************************************************************************
* Chromium resource package unpacker
*
* © 2023—2024, Sauron <[email protected]>
******************************************************************************/
#include <iostream>
#include <sys/stat.h>
#include <vector>
#include "REUtils.hpp"
#include "StringUtils.hpp"
#include "TypeRegistration.hpp"
using std::cout;
using std::endl;
using std::string;
using std::vector;
static const uint16_t GZIP_MAGIC=0x8B1F;
static const uint16_t BROTLI_MAGIC=0x9B1E;
struct Resource {
uint16_t resourceId;
uint32_t fileOffset;
};
static void extract(const string &filename, const ByteArray &ba) {
upp::File file(filename.c_str(), O_CREAT|O_WRONLY|O_TRUNC);
file.write(ba.data(),ba.size());
}
static bool detect(BinaryReader &is, const string &filename) {
return endsWith(filename, ".pak");
}
static void extract(BinaryReader &is, const string &outDir) {
uint32_t version=is.readIntLE();
uint8_t encoding=0;
uint16_t nResources=0, nAliases=0;
// Read the header
if (version==4) {
nResources=is.readIntLE();
encoding=is.readByte();
}
else if (version==5) {
encoding=is.readByte();
is.skip(3);
nResources=is.readShortLE();
nAliases=is.readShortLE();
}
else
throw "unknown file format version";
// Read the resource table
vector<Resource> resources(nResources);
for (uint16_t i=0; i<nResources; i++) {
uint16_t resourceId=is.readShortLE();
uint32_t fileOffset=is.readIntLE();
cout << "Entry #" << i << ": resource " << resourceId << endl;
resources[i].resourceId=resourceId;
resources[i].fileOffset=fileOffset;
}
// Read the alias table
for (uint16_t i=0; i<nAliases; i++) {
uint16_t resourceId=is.readShortLE();
uint16_t entryIndex=is.readShortLE();
cout << "Alias #" << i << ": resource " << resourceId << endl;
}
// Finally, unpack the resources
mkdir(outDir.c_str(), 0700);
for (size_t i=0; i<resources.size(); i++) {
uint16_t resourceId=resources[i].resourceId;
uint32_t thisOffset=resources[i].fileOffset;
uint32_t nextOffset=i==resources.size()-1?is.getSize():resources[i+1].fileOffset;
uint32_t fileSize=nextOffset-thisOffset;
ByteArray ba=BinaryReader(is, thisOffset, fileSize).readAll();
uint16_t compressionMagic=ba.size()<2?0:ba[0]|(ba[1]<<8);
const char * extension="";
if (compressionMagic==GZIP_MAGIC)
extension=".gz";
string outFilename=outDir+'/'+std::to_string(resourceId)+extension;
cout << "Extracting " << outFilename << endl;
extract(outFilename, ba);
}
// Create symbolic links for aliases
// TODO
}
TR(chromium);