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. |