/** * Read the file header and lumps. * * @throws \Exception */ private function readHeader() { // size = 4 (header) + 4 (version) + (64 * 32) $this->buffer = new ResourceBuffer($this->stream); $header = $this->buffer->read(4); if ($header != 'VBSP') { throw new BSPException('Invalid header!'); } $this->version = $this->buffer->getInteger(); $this->lumpHeader = []; for ($i = 0; $i < 64; $i++) { $this->lumpHeader[] = ['fileofs' => $this->buffer->getInteger(), 'filelen' => $this->buffer->getInteger(), 'version' => $this->buffer->getInteger(), 'fourCC' => $this->buffer->read(4)]; } }
/** * 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; } } } }