2026-01-09 07:13:59 +00:00

72 lines
3.9 KiB
PHP

<?php
declare(strict_types=1);
namespace PrinsFrank\PdfParser\Document\Object\Item\CompressedObject\CompressedObjectContent;
use PrinsFrank\PdfParser\Document\Dictionary\Dictionary;
use PrinsFrank\PdfParser\Document\Dictionary\DictionaryKey\DictionaryKey;
use PrinsFrank\PdfParser\Document\Dictionary\DictionaryValue\Array\ArrayValue;
use PrinsFrank\PdfParser\Document\Dictionary\DictionaryValue\Name\FilterNameValue;
use PrinsFrank\PdfParser\Document\Dictionary\DictionaryValue\Reference\ReferenceValue;
use PrinsFrank\PdfParser\Document\Document;
use PrinsFrank\PdfParser\Document\Encryption\RC4;
use PrinsFrank\PdfParser\Exception\ParseFailureException;
use PrinsFrank\PdfParser\Exception\PdfParserException;
use PrinsFrank\PdfParser\Exception\RuntimeException;
use PrinsFrank\PdfParser\Stream\FileStream;
use PrinsFrank\PdfParser\Stream\Stream;
/** @internal */
class CompressedObjectContentParser {
/**
* @param Stream|Document $context the document (or stream during parsing) that is currently being parsed
* @throws PdfParserException
* @return Stream with content in binary format
*/
public static function parseBinary(Stream|Document $context, int $startPos, int $nrOfBytes, Dictionary $dictionary): Stream {
$binaryStreamContent = ($context instanceof Document ? $context->stream : $context)->read($startPos, $nrOfBytes);
if ($context instanceof Document && $context->security !== null && ($encryptDictionary = $context->getEncryptDictionary()) !== null) {
$binaryStreamContent = RC4::crypt(
$context->security->getUserFileEncryptionKey($encryptDictionary, $context->crossReferenceSource->getFirstId()),
$binaryStreamContent
);
}
if (($filterType = $dictionary->getTypeForKey(DictionaryKey::FILTER)) === FilterNameValue::class) {
$binaryStreamContent = ($dictionary->getValueForKey(DictionaryKey::FILTER, FilterNameValue::class) ?? throw new ParseFailureException())
->decodeBinary($binaryStreamContent, $dictionary, ($context instanceof Document ? $context : null));
} elseif ($filterType === ArrayValue::class) {
foreach ($dictionary->getValueForKey(DictionaryKey::FILTER, ArrayValue::class)->value ?? throw new ParseFailureException() as $filterValue) {
if (is_string($filterValue) === false || ($filter = FilterNameValue::tryFrom(ltrim($filterValue, '/'))) === null) {
throw new ParseFailureException();
}
$binaryStreamContent = $filter
->decodeBinary($binaryStreamContent, $dictionary, ($context instanceof Document ? $context : null));
}
} elseif ($filterType === ReferenceValue::class) {
if (!$context instanceof Document) {
throw new ParseFailureException('Filter reference is only supported in a Document');
}
$filter = $dictionary->getObjectForReference($context, DictionaryKey::FILTER) ?? throw new ParseFailureException('Unable to retrieve filter object');
if (($filterArray = ArrayValue::fromValue($filter->getStream()->toString())) instanceof ArrayValue === false) {
throw new ParseFailureException('Filter object is not an array');
}
foreach ($filterArray->value as $filterValue) {
if (is_string($filterValue) === false || ($filter = FilterNameValue::tryFrom(ltrim($filterValue, '/'))) === null) {
throw new ParseFailureException();
}
$binaryStreamContent = $filter
->decodeBinary($binaryStreamContent, $dictionary, $context);
}
} elseif ($filterType !== null) {
throw new RuntimeException(sprintf('Expected filter to be a FilterNameValue or ArrayValue, got %s', $filterType));
}
return FileStream::fromString($binaryStreamContent);
}
}