Checksum code fixed. Added DocBlocks to D2Classes. TODO: Fill in docblocks, refactor, code cleanup

This commit is contained in:
Hash Borgir
2022-07-06 17:41:24 -06:00
parent f3b24de2a8
commit eb28039f88
28 changed files with 1285 additions and 340 deletions

219
test.php
View File

@@ -1,195 +1,42 @@
<?php
// from unpack('H*', file_get_contents("Char.d2s")) for 3v4l.org to read d2s file here
//$data = hex2bin('55aa55aa60000000f1060000b5bc59b300000000536f72630000000000000000000000002400000001103863000000003cc7ae62ffffffffffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff0000ffff000000000000570300000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8000005e3e9b11000000008888d5f80100000035b70300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000576f6f21060000002a0101000190fd9ffe9ffd9ffe9ffd9f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057530100000050000201ffffffff7f00000000000000000000000000000000000201ffffffff7f00000000000000000000000000000000000201ffffffff7f0000000000000000000000000000000000017734002e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000067660028083082000a06644000b10252067094c1018082800020292400480a0a0030c202008cc060dcc0f0ca3afa160a0000e03f696600000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000004a4d32004a4d100082006500069226160382af144fb080e03f4a4d1000820065000a9226260302791c00c480e03f4a4d10008000654415c076c606821c7ffff58080010a06fe034a4d1000800065008013268303827e82896086dccb000066c5bcfeffff014a4d1000820065000022f6860782b067b7ec80e03f4a4d1000820065001a922636038249b154da80a025040000c07f4a4d1000a0006500a442665363034a4d1000a0006500fe13367703024a4d1000a0006500de13362703024a4d1000a0006500be13361703024a4d1000a00065009e13360703024a4d1000a00065007e1336a707024a4d1000a00065005e13369707024a4d1000a00065003e1336f706024a4d1000a0006500c013e65606024a4d1000a00065006012d68607024a4d1000a00065000e12d60603024a4d1000a00065006412564306024a4d1000800065001e83179303029920441686e03f4a4d1000a0006500fe12d69606024a4d1000a0006500de12d68606024a4d1000a0006500be12d67606024a4d1000a00065009e12e67606024a4d1000a00065007e12e69606024a4d1000a0006500fc13e6a606024a4d1000a0006500dc13c68603024a4d1000a0006500bc13e6b606024a4d1000800065009c83272303826f9aed3186e03f4a4d1000800065007c8317730302acd0c26e86e03f4a4d1000a00065005c13560603024a4d1000a00065003c13569607024a4d1000a00065001c13464603024a4d1000a00065001212d66607024a4d1000a00865001412d66607024a4d1000a0006500fc1226f606024a4d1000a0006500dc12265607024a4d1000a0086500bc12265607024a4d1000a00865009c12265607024a4d1000a00865007c12265607024a4d1000a0086500fa13265607024a4d1000a0006500da43665363034a4d1000a0086500ba43665363034a4d1000a00065009a53468333064a4d10008000650016421616038245fc36c6822cff014a4d100080006500a032166707028c6e88690101000408052c30c0c00054e03f4a4d10008000650411c026c60602385900c78080010a08fe034a4d1000800065004632166707822c1b5e930001000498042c30c0c00054e03f4a4d1000800065007a8337130382a07c2a5786e03f4a4d1008800065000ec326c60602915c92ea8280010a07e23f4a4d100880046500b23237470612e9b107ed80104b83c140fc3776ece0f80f4a4d1000a00065180010365603024a4d00006a664a4d00006b6600');
/*
Diablo 2 D2S Save File Checksum Calculator
By Hash Borgir (https://www.psychedelicsdaily.com)
@date 6/4/2022
require_once './src/D2Functions.php';
require_once './src/D2BitReader.php';
class D2ByteReader {
private string $data;
private int $offset = 0;
public function __construct(string $data) {
if (!$data)
return false;
$this->data = $data;
}
public function skip(int $numBytes): bool {
if ($numBytes < 0 || $numBytes > strlen($this->data))
return false;
$this->offset += $numBytes;
return $true;
}
public function seek(int $pos): bool {
if ($pos < 0 || $pos > strlen($this->data))
return false;
$this->offset = $pos;
return true;
}
public function readh(int $offset, int $numBytes, bool $str = true): string {
$this->seek($offset);
$bytes = null;
for ($i = $this->offset; $i < $this->offset + $numBytes; $i++) {
$str ? $bytes .= $this->data[$i] : $bytes[] = $this->data[$i];
}
return unpack('H*', $bytes)[1];
}
public function readc(int $offset, int $numBytes, bool $str = true): array {
$this->seek($offset);
$bytes = null;
for ($i = $this->offset; $i < $this->offset + $numBytes; $i++) {
$str ? $bytes .= $this->data[$i] : $bytes[] = $this->data[$i];
}
return unpack('C*', $bytes);
}
public function rewind(): bool {
$this->offset = 0;
return true;
}
public function writeByte(int $offset, int $byte) {
$this->data[$offset] = pack('C', $byte);
}
public function writeBytes(int $offset, string $bytes) {
if ($offset < 0 || $offset > strlen($this->data) || $bytes == '')
return false;
$_bytes = str_split($bytes, 2);
foreach ($_bytes as $k => $byte) {
$pos = $offset + $k;
$this->data[$pos] = pack('H*', $byte);
}
}
public function getData() {
return $this->data ? $this->data : false;
}
public function getOffset(): int {
return $this->offset;
}
public function isHexString(string $str): bool {
if (strlen($str) % 2 == 0 && (ctype_xdigit($str))) {
return true;
}
return false;
}
public function toBits($input): string {
$output = '';
if ($this->isHexString($input)) {
foreach (str_split($input, 2) as $byte) {
$output .= (strrev(str_pad(decbin(hexdec($byte)), 8, 0, STR_PAD_LEFT)));
}
return $output;
} else if (is_string($input)) {
foreach (str_split($input) as $i) {
$output .= strrev(str_pad(decbin(ord($i)), 8, 0, STR_PAD_LEFT));
}
return $output;
} else if (is_int($input)) {
return strrev(str_pad(decbin($input), 8, 0, STR_PAD_LEFT));
} else if (is_array($input)) {
foreach ($input as $i) {
$output .= $this->tobits($i);
}
return $output;
}
}
public function toBytes(string $bits) {
foreach (str_split($bits, 8) as $byteString) {
$bytes[] = (bindec(strrev($byteString)));
}
foreach ($bytes as $byte) {
dump($byte);
}
}
public function bitsToHexString(string $bits): string {
$bytes = '';
foreach (str_split($bits, 8) as $byte) {
$bytes .= (str_pad(dechex((bindec(strrev($byte)))), 2, 0, STR_PAD_LEFT));
}
return $bytes;
}
public function bitsToHexArray(string $bits): array {
$bytes = [];
foreach (str_split($bits, 8) as $byte) {
$bytes[] = (str_pad(dechex((bindec(strrev($byte)))), 2, 0, STR_PAD_LEFT));
}
return $bytes;
}
public function bitsToIntArray(string $bits): array {
$bytes = [];
foreach (str_split($bits, 8) as $byte) {
$bytes[] = (int) (str_pad(dechex((bindec(strrev($byte)))), 2, 0, STR_PAD_LEFT));
}
return $bytes;
}
/*
@return Byte with Nth bit set to X
*/
public function setBit(int $byte, int $pos, bool $bit) {
return ($bit ? ($byte | (1 << $pos)) : ($byte & ~(1 << $pos)) );
}
/*
@return Bit at Nth position in Byte
*/
public function getBit(int $byte, int $pos): int {
return intval(($byte & (1 << $pos)) != 0);
}
Checksum field is at byte 12.
Bytes 12/13/14/15 as a uint32.
Set this to 0.
After clearing the checksum field add up the values of all the bytes in the file and rotate the running total one bit to the left before adding the next byte.
*/
function swapEndianness(string $hex) {
return implode('', array_reverse(str_split($hex, 2)));
}
$filename = "D:\Diablo II\MODS\ironman-dev\save\Barb.d2s";
function checksum($fileData) {
$nSignature = 0;
foreach ($fileData as $k => $byte) {
if ($k == 12 || $k == 13 || $k == 14 || $k == 15) {
$byte = 0;
}
$nSignature = ((($nSignature << 1) | ($nSignature >> 31)) + $byte & 0xFFFFFFFF);
}
return swapEndianness(str_pad(dechex($nSignature), 8, 0, STR_PAD_LEFT));
}
$filename = "D:\Diablo II\MODS\ironman-dev\save\Necro.d2s";
$fp = fopen($filename, "r+b");
fseek($fp, 12); // go to byte 12
fwrite($fp, pack('I', 0)); // clear the checksum field uInt32
$fileData = unpack('C*', file_get_contents($filename)); // open file and unpack
var_dump(checksum($fileData));
//$file = "D:\Diablo II\MODS\ironman-dev\save\Barb.d2s";
//$data = file_get_contents($file);
//
//$c = new D2ByteReader($data);
//
//$checksum = checksum(unpack('C*', $c->getData()));
//
//ddump($checksum);
//$bytes = $c->readh(643, 5);
//$bits = $c->toBits($bytes);
//
//$bits[4] = 0;
//$bits[5] = 0;
//$bits[8] = 0;
//$newBytes = $c->bitsToHexString($bits);
//$c->writeBytes(643, $newBytes);
//
//$c->writeBytes(12, "00000000"); // zero old checksum
//
//dump($c->readh(12, 4));
//
//$newChecksum = checksum(unpack('C*', $c->getData())); // get new checksum
//$c->writeBytes(12, $newChecksum); // write new checksum
//
//dump($c->readh(12, 4));
//
//file_put_contents($file, $c->getData()); // write bytestream to file
fseek($fp, 12); // go to byte 12
fwrite($fp, pack('H8', checksum($fileData))); // write new checksum
fclose($fp);