🚧 Add reader for .solidpkg files
This commit is contained in:
parent
1a37702b24
commit
90a090f6e3
2 changed files with 87 additions and 0 deletions
|
@ -1,6 +1,10 @@
|
|||
import getSolidpkg from './getSolidpkg';
|
||||
import readSolidpkg from './readSolidpkg';
|
||||
|
||||
(async () => {
|
||||
const buffer = await getSolidpkg('assets_swtor_de_de', -1, 0);
|
||||
console.log(buffer.length, buffer);
|
||||
|
||||
const output = readSolidpkg(buffer);
|
||||
console.log(output);
|
||||
})();
|
||||
|
|
83
src/readSolidpkg.ts
Normal file
83
src/readSolidpkg.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
const MAGIC_END_OF_CENTRAL_DIR = 0x06054b50;
|
||||
const MAGIC_CENTRAL_DIR = 0x02014b50;
|
||||
const COMPRESSION_DEFLATE = 8;
|
||||
|
||||
export default function readSolidpkg(buffer: Buffer) {
|
||||
const dv = new DataView(buffer.buffer);
|
||||
|
||||
//--------------- READ END OF CENTRAL DIR ---------------
|
||||
|
||||
//Go to end of file
|
||||
let pos = buffer.length - 22; //end of central dir is at least 22 bytes long
|
||||
|
||||
//Find end of central dir
|
||||
while (pos >= 0 && dv.getUint32(pos, true) !== MAGIC_END_OF_CENTRAL_DIR) {
|
||||
pos -= 1;
|
||||
}
|
||||
if (pos < 0) {
|
||||
throw new Error('Could not find end of central dir.');
|
||||
}
|
||||
|
||||
//skip 6 bytes
|
||||
pos += 6;
|
||||
|
||||
/** Total number of entries in the central directory */
|
||||
const numEntries = dv.getUint16(pos, true); pos += 2;
|
||||
/** Size of the central directory */
|
||||
const centralDirSize = dv.getUint32(pos, true); pos += 4;
|
||||
/** Offset of start of central directory with respect to the starting disk number */
|
||||
const centralDirOffset = dv.getUint32(pos, true); pos += 4;
|
||||
|
||||
if (numEntries !== 1) {
|
||||
throw new Error(`Expected numEntries == 1 in end of central dir but it was "${numEntries}"`);
|
||||
}
|
||||
if (centralDirSize < 46 * numEntries) {
|
||||
throw new Error('centralDirSize was smaller than expected in end of central dir.');
|
||||
}
|
||||
if (pos - centralDirSize < 0) {
|
||||
throw new Error(`Central dir points before file start (0x${(pos - centralDirSize).toString(16)})`);
|
||||
}
|
||||
|
||||
//--------------- READ CENTRAL DIR ---------------
|
||||
|
||||
//Go to start of central dir
|
||||
pos -= -20 - centralDirSize;
|
||||
|
||||
{
|
||||
const magicNum = dv.getUint32(pos, true); pos += 4;
|
||||
if (magicNum !== MAGIC_CENTRAL_DIR) {
|
||||
throw new Error(`Expected central dir signature but found "0x${magicNum.toString(16)}"`);
|
||||
}
|
||||
}
|
||||
|
||||
pos += 4; //skip version
|
||||
|
||||
/** The bitflag stores whether the file is encrypted or not. Most files are encrypted but there are
|
||||
* some exceptions: assets_swtor_test_main_248to249.solidpkg, assets_swtor_test_en_us_270to271.solidpkg, and
|
||||
* retailclient_publictest_246to247.solidpkg are not encrypted.
|
||||
*/
|
||||
const bitFlag = dv.getUint16(pos, true); pos += 2;
|
||||
|
||||
/** Type of compression, 8 = DEFLATE. Files are always compressed. */
|
||||
const compression = dv.getUint16(pos, true); pos += 2;
|
||||
if (compression !== COMPRESSION_DEFLATE) {
|
||||
throw new Error(`File is not using DEFLATE compression but "${compression}"`);
|
||||
}
|
||||
|
||||
const lastMod1 = dv.getUint16(pos, true); pos += 2;
|
||||
const lastMod2 = dv.getUint16(pos, true); pos += 2;
|
||||
const fileCrc = dv.getUint32(pos, true); pos += 4;
|
||||
const comprSize = dv.getUint32(pos, true); pos += 4;
|
||||
const uncomprSize = dv.getUint32(pos, true); pos += 4;
|
||||
const fileNameLength = dv.getUint16(pos, true); pos += 2;
|
||||
const extraFieldLength = dv.getUint16(pos, true); pos += 2;
|
||||
const fileCommentLength = dv.getUint16(pos, true); pos += 2;
|
||||
pos += 8; //skip disk num start and file attributes
|
||||
const relOffset = dv.getUint32(pos, true); pos += 4;
|
||||
pos += fileNameLength; //skip file name
|
||||
//TODO: read password from extra field
|
||||
|
||||
//...
|
||||
|
||||
return { lastMod1, lastMod2, fileCrc, comprSize, uncomprSize, fileNameLength, extraFieldLength, fileCommentLength, relOffset };
|
||||
}
|
Loading…
Reference in a new issue