diff --git a/CharEditor.php b/CharEditor.php index a7b5868..56e46d5 100644 --- a/CharEditor.php +++ b/CharEditor.php @@ -12,6 +12,7 @@ require_once './_pdo.php'; require_once './src/D2Functions.php'; require_once './src/D2BitReader.php'; +require_once './src/D2ByteReader.php'; //require_once './src/D2Item.php'; @@ -39,35 +40,41 @@ $filePath = "D:\Diablo II\MODS\ironman-dev\save\Sorc.d2s"; $fp = fopen($filePath, 'r+b'); $data = file_get_contents($filePath); +$i_TotalOffset = strpos($data, "JM"); +fseek($fp, $i_TotalOffset + 2); +$i_Total = unpack('S*', (fread($fp, 2)))[1]; - -$i_offset = strpos($data, "JM"); - -fseek($fp, $i_offset + 2); -$i_total = unpack('S*', (fread($fp, 2)))[1]; - -$items = null; - -$offset = $i_offset + 4; // JM00 - -$first_item_offset = strposX($data, "JM", 2); -$second_item_offset = strposX($data, "JM", 3); - -$item_size = $second_item_offset - $first_item_offset; - -for ($i = 2; $i <= $i_total; $i++) { - fseek($fp, strposX($data, 'JM', $i)); - $_items[] = unpack('C*', fread($fp, 21)); +$i_Offsets = []; +for($i=0; $i <= $i_Total; $i++){ + $i_Offsets[] = strposX($data, "JM", $i+2); } - -foreach ($_items as $_item) { - $item = null; - foreach ($_item as $i_bytes) { - $item .= strrev(str_pad(decbin($i_bytes), 8, 0, STR_PAD_LEFT)); - // $item .= (str_pad(dechex($i_bytes), 2, 0, STR_PAD_LEFT)); - } - $items[] = $item; +foreach($i_Offsets as $k=>$v){ + $itemOffsets[$v] = $i_Offsets[$k+1] - $i_Offsets[$k]; } +array_pop($itemOffsets); + + +//$items = null; +// +//$offset = $i_offset + 4; // JM00 +// +//$first_item_offset = strposX($data, "JM", 2); +//$second_item_offset = strposX($data, "JM", 3); +// +//$item_size = $second_item_offset - $first_item_offset; +// +//for ($i = 2; $i <= $i_total; $i++) { +// fseek($fp, strposX($data, 'JM', $i)); +// $_items[] = unpack('C*', fread($fp, 21)); +//} +// +//foreach ($_items as $_item) { +// $item = null; +// foreach ($_item as $i_bytes) { +// $item .= strrev(str_pad(decbin($i_bytes), 8, 0, STR_PAD_LEFT)); +// } +// $items[] = $item; +//} // ddump($items); diff --git a/genDocs.php b/genDocs.php index 12b77ad..b0c24b8 100755 --- a/genDocs.php +++ b/genDocs.php @@ -789,8 +789,8 @@ if ($cmd == "genDocGems") { $htmlFinal = ''; $htmlFinal .= $htmltop; - echo $htmltop; - ob_flush(); + //echo $htmltop; + //ob_flush(); $table = ' @@ -804,9 +804,9 @@ if ($cmd == "genDocGems") { '; - echo $table; + //echo $table; $htmlFinal .= $table; - ob_flush(); + //ob_flush(); // $gems are all the gems, processed, now display them foreach ($gems as $g) { @@ -858,17 +858,17 @@ if ($cmd == "genDocGems") { $htmlRow .= ""; $htmlFinal .= $htmlRow; - echo $htmlRow; - ob_flush(); + //echo $htmlRow; + // ob_flush(); } $htmlFinal .= $tableBottom . $htmlbottom; - echo $tableBottom . $htmlbottom; - ob_flush(); + //echo $tableBottom . $htmlbottom; + //ob_flush(); - ob_start(); + //ob_start(); file_put_contents("$dir/gems.html", $htmlFinal); - header("Location: /docs/{$_SESSION['modname']}/gems.html"); + header("Location: /docs/{$_SESSION['modname']}/gems.html",TRUE,301); } diff --git a/src/D2ByteReader.php b/src/D2ByteReader.php new file mode 100644 index 0000000..26afbd9 --- /dev/null +++ b/src/D2ByteReader.php @@ -0,0 +1,154 @@ +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); + } + +} \ No newline at end of file diff --git a/src/D2Char.php b/src/D2Char.php index 9ec34f6..16ee5cc 100644 --- a/src/D2Char.php +++ b/src/D2Char.php @@ -5,6 +5,7 @@ require_once 'D2Files.php'; require_once 'D2BitReader.php'; require_once 'D2Strings.php'; require_once 'D2Item.php'; +require_once 'D2ByteReader.php'; class D2Char { @@ -31,32 +32,25 @@ class D2Char { } public function parseItems() { - $_data = file_get_contents($this->filePath); - // get offset of first JM and skip it - $_offset = strpos($_data, "JM") + 2; - // seek to items_total offset - fseek($this->fp, $_offset); - // item total is a SHORT 16 bits, 2 bytes - $_total = unpack('S*', (fread($this->fp, 2)))[1]; + $data = file_get_contents($this->filePath); + $ByteReader = new D2ByteReader($data); + + $i_TotalOffset = strpos($data, "JM"); + fseek($this->fp, $i_TotalOffset + 2); + $i_Total = unpack('S*', (fread($this->fp, 2)))[1]; - // Items start from 2nd JM - for ($i = 2; $i <= $_total; $i++) { - // seek to Each JM (every item begins with JM - fseek($this->fp, strposX($_data, 'JM', $i)); - // read and unpack 21 bytes as array of byte/char (8 bit each) - $_items[] = unpack('C*', fread($this->fp, 21)); + $i_Offsets = []; + for ($i = 0; $i <= $i_Total; $i++) { + $i_Offsets[] = strposX($data, "JM", $i + 2); } - // Convert item bytes to 21x8 bitfield - // each byte is reversed with strrev() for correct bit position - // to convert back to ascii, read bits from any position, reverse, bindec(chr()) - foreach ($_items as $_item) { - $item = null; - foreach ($_item as $i_bytes) { - $item .= strrev(str_pad(decbin($i_bytes), 8, 0, STR_PAD_LEFT)); - // $item .= (str_pad(dechex($i_bytes), 2, 0, STR_PAD_LEFT)); - } - $this->items[] = new D2Item($item); // return an array of item details + foreach ($i_Offsets as $k => $v) { + $itemOffsets[$v] = $i_Offsets[$k + 1] - $i_Offsets[$k]; } + array_pop($itemOffsets); + $_items=[]; + foreach ($itemOffsets as $offset => $bytes) { + $this->items[] = new D2Item($ByteReader->toBits($ByteReader->readh($offset, $bytes))); + } } public function parseChar() { diff --git a/src/tabs/Chars.php b/src/tabs/Chars.php index 721ea53..4e097b4 100644 --- a/src/tabs/Chars.php +++ b/src/tabs/Chars.php @@ -42,7 +42,7 @@ $form = new Formr\Formr(); SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - //ddump($charData); + ddump($charData); ?>