dictionary)) { return $this->dictionary; } $startDictionaryPos = $document->stream->firstPos(DelimiterCharacter::LESS_THAN_SIGN, $this->startOffset, $this->endOffset); if ($startDictionaryPos === null) { return $this->dictionary = new Dictionary(); } $endDictionaryPos = $document->stream->firstPos(Marker::STREAM, $startDictionaryPos, $this->endOffset) ?? $document->stream->lastPos(Marker::END_OBJ, $document->stream->getSizeInBytes() - $this->endOffset) ?? throw new ParseFailureException('Unable to locate start of stream or end of current object'); return $this->dictionary = DictionaryParser::parse($document->stream, $startDictionaryPos, $endDictionaryPos - $startDictionaryPos); } public function getCompressedObject(int $objectNumber, Document $document): CompressedObject { $byteOffsets = $this->getByteOffsets($document); $startByteOffset = $byteOffsets->getRelativeByteOffsetForObject($objectNumber) ?? throw new InvalidArgumentException('Compressed object does not exist in this uncompressed object'); return new CompressedObject( $objectNumber, $this, $startByteOffset, $byteOffsets->getNextRelativeByteOffset($startByteOffset), ); } public function getByteOffsets(Document $document): CompressedObjectByteOffsets { if (isset($this->byteOffsets)) { return $this->byteOffsets; } $dictionary = $this->getDictionary($document); if ($dictionary->getType() !== TypeNameValue::OBJ_STM) { throw new ParseFailureException('Unable to get stream data from item that is not a stream'); } return $this->byteOffsets = CompressedObjectByteOffsetParser::parse( $document->stream, $this->startOffset, $this->endOffset, $dictionary ); } #[Override] public function getContent(Document $document): Stream { if (($startStreamPos = $document->stream->getStartNextLineAfter(Marker::STREAM, $this->startOffset, $this->endOffset)) !== null && ($endStreamPos = $document->stream->lastPos(Marker::END_STREAM, $document->stream->getSizeInBytes() - $this->endOffset)) !== null) { return CompressedObjectContentParser::parseBinary( $document, $startStreamPos, ($document->stream->getEndOfCurrentLine($endStreamPos - 1, $this->endOffset) ?? throw new ParseFailureException(sprintf('Unable to locate marker %s', WhitespaceCharacter::LINE_FEED->value))) - $startStreamPos, $this->getDictionary($document), ); } $nextLineAfterStartObj = $document->stream->getStartNextLineAfter(Marker::OBJ, $this->startOffset, $this->endOffset) ?? throw new ParseFailureException(sprintf('Unable to locate newline after marker %s', Marker::OBJ->value)); $endObjPos = $document->stream->lastPos(Marker::END_OBJ, $document->stream->getSizeInBytes() - $this->endOffset) ?? throw new ParseFailureException(sprintf('Unable to locate marker %s', Marker::END_OBJ->value)); $eolObjContent = $document->stream->getEndOfCurrentLine($endObjPos - 2, $this->endOffset) ?? throw new ParseFailureException(sprintf('Unable to locate newline after marker %s', Marker::END_OBJ->value)); return FileStream::fromString( $document->stream->read( $nextLineAfterStartObj, $eolObjContent - $nextLineAfterStartObj, ) ); } }