Пример #1
0
 /**
  * Read a specific lump. Currently only supports entities.
  *
  * @param $index
  * @throws \Exception
  */
 private function readLump($index)
 {
     $info = $this->lumpHeader[$index];
     $this->buffer->seek($info['fileofs']);
     if ($index === 0) {
         $hdr = $this->buffer->peek(4);
         if ($hdr == 'LZMA') {
             // Team Fortress 2
             // Decompress
             $buffer = $this->decompressLZMALump($this->buffer);
         } else {
             $buffer = $this->buffer->slice($info['filelen']);
         }
         $parts = explode("}", $buffer->getData());
         $lump = [];
         foreach ($parts as $data) {
             $data = trim($data);
             if (strlen($data) < 1 || $data[0] != '{') {
                 continue;
             }
             $lump[] = KeyValues::decode("\"Entity\"\n" . trim($data) . "\n}")['Entity'];
         }
     } else {
         if ($index === 40) {
             $file = tempnam(sys_get_temp_dir(), 'zip');
             $tmp = fopen($file, 'w');
             $remaining = $info['filelen'];
             while ($remaining > 0) {
                 $chunk = $this->buffer->read($remaining > CHUNK_SIZE ? CHUNK_SIZE : $remaining);
                 fwrite($tmp, $chunk);
                 $remaining -= strlen($chunk);
             }
             $lump = new PakFile($file);
         }
     }
     return $lump;
 }
Пример #2
0
 /**
  * Load the archive.
  *
  * @throws VPKException
  * @throws \Exception
  * @throws \VLib\Buffer\BufferUnderflowException
  */
 private function load()
 {
     $this->multiChunk = strpos($this->path, '_dir') !== false;
     // Load it from our filesystem. This uses Flysystem to support remote files.
     $fh = $this->filesystem->readStream($this->path);
     if (!$fh) {
         throw new VPKException('Unable to open path ' . $this->path);
     }
     /**
      * Use a temporary buffer for the header data.
      */
     $buffer = new ResourceBuffer($fh);
     $sig = $buffer->getInteger();
     if ($sig !== 1437209140) {
         throw new VPKException('Invalid file signature.');
     }
     $this->version = $buffer->getInteger();
     switch ($this->version) {
         case 1:
             $headerSize = 12;
             break;
         case 2:
             $headerSize = 28;
             $buffer->skip(16);
             break;
         default:
             throw new VPKException('Invalid file version.');
     }
     $this->dictSize = $buffer->getInteger();
     $this->pathEntries = [];
     while ($type = $buffer->getString()) {
         while ($dir = $buffer->getString()) {
             while ($name = $buffer->getString()) {
                 $crc32 = $buffer->getInteger();
                 $preloadSize = $buffer->getShort();
                 $chunkIndex = $buffer->getShort();
                 $offset = $buffer->getInteger();
                 $size = $buffer->getInteger();
                 $term = $buffer->getShort();
                 if ($term !== 0xffff) {
                     throw new VPKException('Unexpected termination character.');
                 }
                 $preload = '';
                 if ($preloadSize > 0) {
                     $preload = $buffer->read($preloadSize);
                 }
                 if ($this->multiChunk) {
                     $entryName = sprintf('%s_%03d.vpk', $this->vpkName, $chunkIndex);
                     $entryName = $this->dir . '/' . $entryName;
                 } else {
                     $entryName = $this->file;
                     if ($this->version == 1) {
                         $offset += $headerSize + $this->dictSize;
                     }
                 }
                 $entry = new VPKEntry($this->filesystem, $entryName);
                 $entry->setType($type);
                 $entry->setName($name);
                 $entry->setDir($dir);
                 $entry->setCRC32($crc32);
                 $entry->setOffset($offset);
                 $entry->setSize($size);
                 $entry->setPreload($preload);
                 $this->pathEntries[$entry->getPath()] = $entry;
             }
         }
     }
 }