The chunk checksum is just a CRC32. It seems to be inverted though. Right now it does nothing except check the signatures of each chunk.
It is easy to add json serialization/unserialization later.
{ | |
"name": "patchnode-19232", | |
"version": "1.0.0", | |
"description": "", | |
"main": "patch.js", | |
"dependencies": { | |
"crc-32": "^1.0.1" | |
}, | |
"devDependencies": {}, | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"author": "Tim Peters", | |
"license": "ISC" | |
} |
const CRC32 = require('crc-32'); | |
const fs = require('fs'); | |
const buffer = fs.readFileSync('./patch_v3.lvl.3'); | |
const header = buffer.slice(0,8); | |
const maps = buffer.readUInt32LE(4); | |
console.log(maps); | |
for(let index = 0; index < maps; index++) { | |
let chunk = buffer.slice(8+185344*index,8+185344*(index+1)); | |
let checksum = chunk.readUInt32LE(4); | |
chunk[4] = 0; | |
chunk[5] = 0; | |
chunk[6] = 0; | |
chunk[7] = 0; | |
// checksum seems to be inverted. | |
// So invert & treat as unsigned. | |
let crc = ~CRC32.buf(chunk) >>> 0; | |
console.log(checksum.toString(16), crc.toString(16)); | |
} |
meta: | |
id: patch_v3 | |
file-extension: lvl | |
endian: le | |
instances: | |
header: | |
type: header | |
pos: 0 | |
maps: | |
type: map | |
pos: 8 | |
repeat: expr | |
repeat-expr: header.map_count | |
size: 185344 | |
types: | |
max_teams: | |
seq: | |
- id: none | |
type: u1 | |
- id: ctf | |
type: u1 | |
- id: slayer | |
type: u1 | |
- id: oddball | |
type: u1 | |
- id: koth | |
type: u1 | |
- id: race | |
type: u1 | |
- id: headhunter | |
type: u1 | |
- id: juggernaught | |
type: u1 | |
- id: territories | |
type: u1 | |
- id: assault | |
type: u1 | |
- id: stub_10 | |
type: u1 | |
- id: stub_11 | |
type: u1 | |
- id: stub_12 | |
type: u1 | |
- id: stub_13 | |
type: u1 | |
- id: stub_14 | |
type: u1 | |
- id: stub_15 | |
type: u1 | |
header: | |
seq: | |
- id: version | |
type: u4 | |
- id: map_count | |
type: u4 | |
map: | |
seq: | |
- id: version | |
type: u4 | |
- id: patch_checksum | |
type: u4 | |
doc: > | |
Inverted CRC32 of the chunk, patch_checksum field should be zero. | |
A chunk is 185344 bytes long. | |
It does not include the 8 byte file header. | |
- id: unknown2 | |
type: u4 | |
doc: always seems to be '1' | |
- id: scenario | |
type: str | |
encoding: UTF-8 | |
size: 256 | |
- id: map_checksum | |
type: u4 | |
- id: map_end | |
type: u4 | |
doc: offering_id? | |
- id: unknown5 | |
type: u4 | |
doc: always seems to be '0xFFFFFFFF' | |
- id: name_en | |
type: str | |
encoding: UTF-16 | |
size: 64 | |
- id: name2 | |
type: str | |
encoding: UTF-16 | |
size: 64 | |
- id: name_de | |
type: str | |
encoding: UTF-16 | |
size: 64 | |
- id: name_fr | |
type: str | |
encoding: UTF-16 | |
size: 64 | |
- id: name5 | |
type: str | |
encoding: UTF-16 | |
size: 64 | |
- id: name6 | |
type: str | |
encoding: UTF-16 | |
size: 64 | |
- id: name_ch | |
type: str | |
encoding: UTF-16 | |
size: 64 | |
- id: name8 | |
type: str | |
encoding: UTF-16 | |
size: 64 | |
- id: name9 | |
type: str | |
encoding: UTF-16 | |
size: 64 | |
- id: description_en | |
type: str | |
encoding: UTF-16 | |
size: 256 | |
- id: description2 | |
type: str | |
encoding: UTF-16 | |
size: 256 | |
- id: description_de | |
type: str | |
encoding: UTF-16 | |
size: 256 | |
- id: description_fr | |
type: str | |
encoding: UTF-16 | |
size: 256 | |
- id: description5 | |
type: str | |
encoding: UTF-16 | |
size: 256 | |
- id: description6 | |
type: str | |
encoding: UTF-16 | |
size: 256 | |
- id: description_ch | |
type: str | |
encoding: UTF-16 | |
size: 256 | |
- id: description8 | |
type: str | |
encoding: UTF-16 | |
size: 256 | |
- id: description9 | |
type: str | |
encoding: UTF-16 | |
size: 256 | |
- id: map_start | |
type: u4 | |
- id: unknown6 | |
type: u4 | |
doc: > | |
always seems be '0'. | |
Possibly flags or sort order? | |
- id: max_teams | |
type: max_teams | |
- id: raw_dxt1 | |
size: 0x2C790 | |
doc: > | |
This is DDS file with DXT1. | |
Width is 220. | |
Height is 207. | |
Size is 0x2C790. | |
This is the raw dxt1 bitmap, it just needs a header. |