const fs = require('fs'); const align = (t, b) => t % b == 0 ? t : t + b - t % b; const getSerial = (buffer: Buffer, offset: number, base1: number, base2: number) => { if( offset >= base2 ){ let n = Math.floor( (offset-base2) / 8 ); let c = (base1-8) / 3; for(let i=0; i < c; ++i ){ let a = buffer.readUInt16LE(base1 + i*2); let b = buffer.readUInt16LE(base1 + i*2 + 2); if( a <= n && n < b ){ let start = 8 + i * 3; let str = String.fromCharCode( buffer[start], buffer[start+1], buffer[start+2] ); return [str, i]; } } return ["????", -1]; } else if( offset >= base1 && offset < base2 - 2 ) { let n = offset - base1; n = Math.floor( n/2 ); let start = 8 + n * 3; let str = String.fromCharCode( buffer[start], buffer[start+1], buffer[start+2] ); return [str, n]; } else return ["????", -1]; } const describe = (buffer: Buffer, offset: number) => { console.info(`error at ${offset}`); let n = buffer.readUInt16LE(4); let serialbase = 8; let offsetbase = serialbase + 3*n; let cheatbase = offsetbase + 2 * (n+1); let cheatcnt = buffer.readUInt16LE(cheatbase-2); let expandbase = align( cheatbase + 8 * cheatcnt, 32 ); let serial = "????", entry = -1; if( offset >= offsetbase ) [serial, entry] = getSerial(buffer, offset, offsetbase, cheatbase); console.debug("is it right? %d - %d - %d - %d", serialbase, offsetbase, cheatbase, align(expandbase, 32)); if( offset < serialbase ){ // 属于HEAD数据 if( offset < 4){ console.log("INSIDE MAGIC NUMBER"); console.log("ACL?"); console.log(new Array(offset).fill(" ").join("")+"^"); } else if( offset < 6 ){ console.log("INSIDE SERIAL LENGTH"); console.log(n.toString(16).padStart(4, '0')); console.log(new Array(5 - offset).fill(" ").join("")+" ^"); } else { console.log("INSIDE MAX CHEAT PARAGRAPH"); n = buffer.readUInt16LE(6); console.log(n.toString(16).padStart(4, '0')); console.log(new Array(7 - offset).fill(" ").join("")+" ^"); } } else if( offset < offsetbase ){ let start = serialbase + Math.floor( (offset-serialbase)/3 ) * 3; console.log("INSITDE SERIAL COLLECTIONS", "index =", Math.floor( (offset-serialbase)/3 )); console.log( String.fromCharCode( buffer[start], buffer[start+1], buffer[start+2] ) ); console.log( new Array(offset-start).fill(" ").join("")+"^" ); } else if( offset < cheatbase ){ let start = offsetbase + Math.floor( (offset-offsetbase)/2 ) * 2; console.log("INSITDE SERIAL EXTENSIONS", "index =", Math.floor( (offset-offsetbase)/2 ), "serial(3) =", serial); if( offset > offsetbase+1 ){ n = buffer.readUInt16LE(start-2); console.log(n.toString(16).padStart(4, "0"), " <<< ", getSerial(buffer, offset-2, offsetbase, cheatbase)[0]); } n = buffer.readUInt16LE(start); console.log(n.toString(16).padStart(4, '0') ); console.log(new Array(offset - start).fill(" ").join("")+" ^"); } else if( offset < expandbase ){ if( offset < cheatbase + cheatcnt * 8 ){ let start = cheatbase + Math.floor( (offset-cheatbase) / 8 ) * 8; let entstart = buffer.readUInt16LE( offsetbase + entry*2 ), h, l; entstart = cheatbase + entstart * 8; console.log("INSITDE CHEAT SEGMENTS", "index =", Math.floor( (offset-cheatbase)/8 ), "serial(3) =", serial); while( entstart < start ){ h = buffer.readUInt32LE(entstart); l = buffer.readUInt32LE(entstart+4); console.log(h.toString(16).padStart(8, '0') + " " + l.toString(16).padStart(8, '0')); entstart += 8; } h = buffer.readUInt32LE(start); l = buffer.readUInt32LE(start+4); console.log(h.toString(16).padStart(8, '0') + " " + l.toString(16).padStart(8, '0')); if( offset - start < 4 ){ console.log(new Array(3 - (offset - start)).fill(" ").join("")+" ^"); } else console.log(new Array(12 - (offset - start)).fill(" ").join("")+" ^"); } else { console.log("INSITDE CHEAT SEGMENTS PADDING" ); } } else if( offset < buffer.length ){ console.log("INSIDE CHEAT BINARY"); // 1 index from cheatbase // 2 index from offsetbase // 3 get offset for cheat bin // 4 show for entry size/entry record/string table/index table/code table } else { console.error("INVALID POSITION AT %d", offset); } } const main = (argv: string[]) => { if( argv.length < 2 ) { console.info("Usage: explain "); return; } const first: Buffer = fs.readFileSync(argv[0]); const second: Buffer = fs.readFileSync(argv[1]); let diff = 0; for(; first[diff] === second[diff]; diff++); describe(first,diff); console.log("------------------"); describe(second,diff); } main( process.argv.slice(2) );