72 lines
3.9 KiB
PHP
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);
|
|
}
|
|
}
|