コード例 #1
0
 public function parseHeader()
 {
     $fp = 0;
     $headerParsed = false;
     $headerOffset = 0;
     while (!$headerParsed) {
         $magic = unpack("c4", self::readBytes($this->fileData, $fp, 4));
         // MPQ 1Bh or 1Ah
         if ($magic[1] != 0x4d || $magic[2] != 0x50 || $magic[3] != 0x51) {
             $this->init = false;
             return false;
         }
         if ($magic[4] == 27) {
             // user data block (1Bh)
             if ($this->debug) {
                 $this->debug(sprintf("Found user data block at %08X", $fp));
             }
             $uDataMaxSize = self::readUInt32($this->fileData, $fp);
             $headerOffset = self::readUInt32($this->fileData, $fp);
             $this->headerOffset = $headerOffset;
             $uDataSize = self::readUInt32($this->fileData, $fp);
             $uDataStart = $fp;
             $userDataArray = MPQFile::parseSerializedData($this->fileData, $fp);
             $this->verMajor = $userDataArray[1][1];
             $this->build = $userDataArray[1][4];
             $this->gameLen = ceil($userDataArray[3] / 16);
             $this->versionString = sprintf("%d.%d.%d.%d", $this->verMajor, $userDataArray[1][2], $userDataArray[1][3], $this->build);
             $fp = $headerOffset;
         } elseif ($magic[4] == 26) {
             // header (1Ah)
             if ($this->debug) {
                 $this->debug(sprintf("Found header at %08X", $fp));
             }
             $headerSize = self::readUInt32($this->fileData, $fp);
             $archiveSize = self::readUInt32($this->fileData, $fp);
             $this->archiveSize = $archiveSize;
             $formatVersion = self::readUInt16($this->fileData, $fp);
             $sectorSizeShift = self::readByte($this->fileData, $fp);
             $sectorSize = 512 * pow(2, $sectorSizeShift);
             $this->sectorSize = $sectorSize;
             $fp++;
             $hashTableOffset = self::readUInt32($this->fileData, $fp) + $headerOffset;
             $this->hashTableOffset = $hashTableOffset;
             $blockTableOffset = self::readUInt32($this->fileData, $fp) + $headerOffset;
             $this->blockTableOffset = $blockTableOffset;
             if ($this->debug) {
                 $this->debug(sprintf("Hash table offset: %08X, Block table offset: %08X", $hashTableOffset, $blockTableOffset));
             }
             $hashTableEntries = self::readUInt32($this->fileData, $fp);
             $this->hashTableSize = $hashTableEntries;
             $blockTableEntries = self::readUInt32($this->fileData, $fp);
             $this->blockTableSize = $blockTableEntries;
             $headerParsed = true;
         } else {
             if ($this->debug) {
                 $this->debug("Could not find MPQ header");
             }
             return false;
         }
     }
     // read and decode the hash table
     $fp = $hashTableOffset;
     $hashSize = $hashTableEntries * 4;
     // hash table size in 4-byte chunks
     $tmp = array();
     for ($i = 0; $i < $hashSize; $i++) {
         $tmp[$i] = self::readUInt32($this->fileData, $fp);
     }
     if ($this->debug) {
         $this->debug("Encrypted hash table:");
         $this->printTable($tmp);
     }
     $hashTable = self::decryptStuff($tmp, self::hashStuff("(hash table)", self::$MPQ_HASH_FILE_KEY));
     if ($this->debug) {
         $this->debug("DEBUG: Hash table");
         $this->debug("HashA, HashB, Language+platform, Fileblockindex");
         $tmpnewline = $this->debugNewline;
         $this->debugNewline = "";
         for ($i = 0; $i < $hashTableEntries; $i++) {
             $filehashA = $hashTable[$i * 4];
             $filehashB = $hashTable[$i * 4 + 1];
             $lanplat = $hashTable[$i * 4 + 2];
             $blockindex = $hashTable[$i * 4 + 3];
             $this->debug(sprintf("<pre>%08X %08X %08X %08X</pre>", $filehashA, $filehashB, $lanplat, $blockindex));
         }
         $this->debugNewline = $tmpnewline;
     }
     // read and decode the block table
     $fp = $blockTableOffset;
     $blockSize = $blockTableEntries * 4;
     // block table size in 4-byte chunks
     $tmp = array();
     for ($i = 0; $i < $blockSize; $i++) {
         $tmp[$i] = self::readUInt32($this->fileData, $fp);
     }
     if ($this->debug) {
         $this->debug("Encrypted block table:");
         $this->printTable($tmp);
     }
     $blockTable = self::decryptStuff($tmp, self::hashStuff("(block table)", self::$MPQ_HASH_FILE_KEY));
     $this->hashtable = $hashTable;
     $this->blocktable = $blockTable;
     if ($this->debug) {
         $this->debug("DEBUG: Block table");
         $this->debug("Offset, Blocksize, Filesize, flags");
         $tmpnewline = $this->debugNewline;
         $this->debugNewline = "";
         for ($i = 0; $i < $blockTableEntries; $i++) {
             $blockIndex = $i * 4;
             $blockOffset = $this->blocktable[$blockIndex] + $this->headerOffset;
             $blockSize = $this->blocktable[$blockIndex + 1];
             $fileSize = $this->blocktable[$blockIndex + 2];
             $flags = $this->blocktable[$blockIndex + 3];
             $this->debug(sprintf("<pre>%08X %8d %8d %08X</pre>", $blockOffset, $blockSize, $fileSize, $flags));
         }
         $this->debugNewline = $tmpnewline;
     }
     $this->init = true;
     if ($this->getFileSize("replay.details") > 0 && $this->getFileSize("replay.initData") > 0) {
         $this->fileType = "SC2replay";
     } elseif ($this->getFileSize("DocumentHeader") > 0 && $this->getFileSize("Minimap.tga") > 0) {
         $this->fileType = "SC2map";
     } else {
         $this->fileType = "Unknown";
     }
     return true;
 }
コード例 #2
0
ファイル: sc2replay.php プロジェクト: ajbdev/phpsc2replay
 function parseDetailsFile($string)
 {
     $numByte = 0;
     $array = MPQFile::parseSerializedData($string, $numByte);
     $playerArray = $array[0];
     foreach ($playerArray as $index => $player) {
         if ($this->debug) {
             echo "<pre>";
             print_r($player);
             echo "</pre>";
         }
         $p = array();
         $p["name"] = $player[0];
         $p["uid"] = $player[1][4];
         $p["uidIndex"] = $player[1][2];
         $p["color"] = sprintf("%02X%02X%02X", $player[3][1], $player[3][2], $player[3][3]);
         $p["apmtotal"] = 0;
         $p["apm"] = array();
         $p["firstevents"] = array();
         $p["numevents"] = array();
         $p["ptype"] = "";
         $p["handicap"] = 0;
         $p["team"] = 0;
         $p["lrace"] = $player[2];
         // locale-specific player race
         $p["race"] = "";
         // player race in english, populated by checking which workers they build
         $p["id"] = $index + 1;
         if ($p["uid"] == 0) {
             $p["isComp"] = true;
         } else {
             $p["isComp"] = false;
         }
         $p["isObs"] = false;
         $p["difficulty"] = "";
         $p["sColor"] = "";
         if ($player[8] == 1) {
             $p["won"] = $player[8];
             $this->winnerKnown = true;
         }
         $this->players[$index + 1] = $p;
     }
     $this->mapName = $array[1];
     $this->gameFiletime = $array[5];
     $this->gameCtime = floor(($array[5] - 116444735995904000) / 10000000);
 }