| Server IP : 139.59.63.204 / Your IP : 216.73.217.62 Web Server : Apache/2.4.58 (Ubuntu) System : Linux ubuntu-s-1vcpu-1gb-blr1-01 6.8.0-110-generic #110-Ubuntu SMP PREEMPT_DYNAMIC Thu Mar 19 15:09:20 UTC 2026 x86_64 User : root ( 0) PHP Version : 8.3.6 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/abyogasms.com/vendor/tecnickcom/tc-lib-pdf-parser/test/ |
Upload File : |
<?php
/**
* ParserProcessingTest.php
*
* @since 2011-05-23
* @category Library
* @package Pdfparser
* @author Nicola Asuni <info@tecnick.com>
* @copyright 2011-2026 Nicola Asuni - Tecnick.com LTD
* @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
* @link https://github.com/tecnickcom/tc-lib-pdf-parser
*
* This file is part of tc-lib-pdf-parser software library.
*/
namespace Test;
use Com\Tecnick\Pdf\Parser\Exception as PPException;
/**
* @phpstan-import-type RawObjectArray from \Com\Tecnick\Pdf\Parser\Process\RawObject
*/
class ParserProcessingTest extends TestCase
{
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParseRejectsEmptyAndInvalidData(): void
{
$parser = new ParserHarness();
$this->expectException(PPException::class);
$this->expectExceptionMessageContains('Empty PDF data.');
$parser->parse('');
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParseRejectsDataWithoutPdfHeader(): void
{
$parser = new ParserHarness();
$this->expectException(PPException::class);
$this->expectExceptionMessageContains('Invalid PDF data: missing %PDF header.');
$parser->parse('not a pdf');
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParseLoadsPositiveOffsetsOnlyAndClearsPdfData(): void
{
$parser = new ParserHarness();
$parser->setStubXrefData([
'trailer' => [
'id' => [],
'info' => '',
'root' => '1_0',
'size' => 3,
],
'xref' => [
'1_0' => 10,
'2_0' => 0,
'3_0' => -1,
],
]);
$parser->setStubIndirectReturn([['numeric', '42', 0]]);
$parsed = $parser->parse("junk%PDF-1.7\n");
$calls = $parser->getIndirectCalls();
$firstCall = $calls[0] ?? null;
$this->assertCount(1, $calls);
$this->assertSame(['1_0', 10, true], $firstCall);
$this->assertSame('', $parser->getPdfDataPublic());
$this->assertArrayHasKey('1_0', $parsed[1]);
$this->assertArrayNotHasKey('2_0', $parsed[1]);
$this->assertArrayNotHasKey('3_0', $parsed[1]);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParseUsesDecodeStreamsConfigForDirectObjects(): void
{
$parser = new ParserHarness();
$parser->setStubXrefData([
'trailer' => [
'id' => [],
'info' => '',
'root' => '1_0',
'size' => 2,
],
'xref' => [
'1_0' => 10,
],
]);
$parser->setStubIndirectReturn([['numeric', '42', 0]]);
$parser->parse("%PDF-1.7\n");
$calls = $parser->getIndirectCalls();
$this->assertSame(['1_0', 10, true], $calls[0] ?? null);
$lazy = new ParserHarness(['decode_streams' => false]);
$lazy->setStubXrefData([
'trailer' => [
'id' => [],
'info' => '',
'root' => '1_0',
'size' => 2,
],
'xref' => [
'1_0' => 10,
],
]);
$lazy->setStubIndirectReturn([['numeric', '42', 0]]);
$lazy->parse("%PDF-1.7\n");
$lazyCalls = $lazy->getIndirectCalls();
$this->assertSame(['1_0', 10, false], $lazyCalls[0] ?? null);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParentIndirectObjectRejectsInvalidReference(): void
{
$parser = new ParserHarness();
$parser->setPdfDataPublic("%PDF-1.7\n1 0 obj\nendobj\n");
$this->expectException(PPException::class);
$this->expectExceptionMessageContains('Invalid object reference:');
$parser->callParentGetIndirectObject('invalid', 0, true);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParentIndirectObjectReturnsEmptyResultWhenTargetIsMissing(): void
{
$parser = new ParserHarness();
$parser->setPdfDataPublic("%PDF-1.7\n");
$obj = $parser->callParentGetIndirectObject('1_0', 0, true);
$this->assertSame([], $obj);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testRawIndirectObjectDecodesStreamWhenDictionaryIsPresent(): void
{
$parser = new ParserHarness();
$parser->setRawObjectQueue([
['<<', [['/', 'Length', 0], ['numeric', '3', 0]], 5],
['stream', 'abcdef', 12],
['endobj', 'endobj', 18],
]);
$objdata = $parser->getRawIndirectObjectPublic(0, true);
$this->assertCount(2, $objdata);
$entry = $objdata[1] ?? null;
if (!\is_array($entry)) {
$this->fail('Missing decoded stream entry at index 1.');
}
$this->assertSame('stream', $entry[0]);
$this->assertSame('abcdef', $entry[1]);
$decoded = $entry[3] ?? null;
if (!\is_array($decoded)) {
$this->fail('Decoded stream payload not available.');
}
$this->assertSame('abc', $decoded[0]);
$this->assertSame([], $decoded[1]);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetFiltersParsesSingleAndArraySyntax(): void
{
$parser = new ParserHarness();
$single = [
['/', 'Filter', 0],
['/', 'FlateDecode', 0],
];
$filters = $parser->getFiltersPublic([], $single, 0);
$this->assertSame(['FlateDecode'], $filters);
$list = [
['/', 'Filter', 0],
[
'[',
[
['/', 'FlateDecode', 0],
['numeric', '1', 0],
['/', 'ASCIIHexDecode', 0],
],
0,
],
];
$filters = $parser->getFiltersPublic([], $list, 0);
$this->assertSame(['FlateDecode', 'ASCIIHexDecode'], $filters);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetObjectValResolvesCachedAndMappedObjectReferences(): void
{
$parser = new ParserHarness();
$parser->setObjectsPublic([
'3_0' => [['string', 'cached', 0]],
]);
$cached = $parser->getObjectValPublic(['objref', '3_0', 0]);
$this->assertSame(['string', 'cached', 0], $cached);
$parser = new ParserHarness();
$parser->setXrefMapPublic(['4_0' => 99]);
$parser->setStubIndirectReturn([['string', 'loaded', 0]]);
$loaded = $parser->getObjectValPublic(['objref', '4_0', 0]);
$this->assertSame(['string', 'loaded', 0], $loaded);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetDecodedStreamTracksErrorsWhenConfiguredToIgnore(): void
{
$parser = new ParserHarness(['ignore_filter_errors' => true]);
$result = $parser->getDecodedStreamPublic(['UnknownFilter'], 'sample-data');
$this->assertSame('sample-data', $result[0]);
$this->assertSame(['UnknownFilter'], $result[1]);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetDecodedStreamThrowsWhenFilterErrorsAreNotIgnored(): void
{
$parser = new ParserHarness();
$this->expectException(PPException::class);
$parser->getDecodedStreamPublic(['UnknownFilter'], 'sample-data');
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParentIndirectObjectFindsObjectAfterOffsetShift(): void
{
$parser = new ParserHarness();
$parser->setPdfDataPublic("%PDF-1.7\nX1 0 obj\nendobj\n");
$parser->setRawObjectQueue([
['numeric', '7', 16],
['endobj', 'endobj', 22],
]);
$obj = $parser->callParentGetIndirectObject('1_0', 9, true);
$this->assertSame([['numeric', '7', 16]], $obj);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetFiltersHandlesMissingAndInvalidArrayPayload(): void
{
$parser = new ParserHarness();
$filters = ['FlateDecode'];
$this->assertSame($filters, $parser->getFiltersPublic($filters, [['/', 'Filter', 0]], 0));
$invalid = [
['/', 'Filter', 0],
['[', 'invalid', 0],
];
$this->assertSame([], $parser->getFiltersPublic([], $invalid, 0));
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetDecodeParmsHandlesDictionaryArrayAndMissingValues(): void
{
$parser = new ParserHarness();
$this->assertSame([], $parser->getDecodeParmsPublic([['/', 'DecodeParms', 0]], 0));
$dict = [
['/', 'DecodeParms', 0],
[
'<<',
[
['/', 'Columns', 0],
['numeric', '5', 0],
['/', 'EarlyChange', 0],
['true', 'true', 0],
['/', 'FilterName', 0],
['/', 'FlateDecode', 0],
['/', 'Text', 0],
['string', 'abc', 0],
['/', 'Ignored', 0],
['[', [], 0],
],
0,
],
];
$this->assertSame(
[
'Columns' => 5,
'EarlyChange' => true,
'FilterName' => 'FlateDecode',
'Text' => 'abc',
],
$parser->getDecodeParmsPublic($dict, 0),
);
$array = [
['/', 'DecodeParms', 0],
[
'[',
[
['null', 'null', 0],
[
'<<',
[
['/', 'Rows', 0],
['numeric', '2', 0],
['/', 'Enabled', 0],
['false', 'false', 0],
],
0,
],
],
0,
],
];
$this->assertSame(
[
'Rows' => 2,
'Enabled' => false,
],
$parser->getDecodeParmsPublic($array, 0),
);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testDecodeStreamHandlesEmptyStreamAndDecodeParmsExtraction(): void
{
$parser = new ParserHarness(['ignore_filter_errors' => true]);
$this->assertSame(['', []], $parser->decodeStreamPublic([], ''));
$sdic = [
['/', 'Filter', 0],
['/', 'UnknownFilter', 0],
['/', 'DecodeParms', 0],
[
'<<',
[
['/', 'Columns', 0],
['numeric', '3', 0],
['/', 'Predictor', 0],
['numeric', '12', 0],
],
0,
],
];
$result = $parser->decodeStreamPublic($sdic, 'abc');
$this->assertSame('abc', $result[0]);
$this->assertSame(['UnknownFilter'], $result[1]);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParentIndirectObjectReturnsNullObjectWhenSearchMissesTwice(): void
{
$parser = new ParserHarness();
$parser->setPdfDataPublic("%PDF-1.7\nno objects\n");
$obj = $parser->callParentGetIndirectObject('1_0', 2, true);
$this->assertSame([['null', 'null', 3]], $obj);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetFiltersSkipsSlashEntriesWithNonStringNames(): void
{
$parser = new ParserHarness();
$sdic = [
['/', 'Filter', 0],
[
'[',
[
['/', [['numeric', '1', 0]], 0],
['/', 'FlateDecode', 0],
],
0,
],
];
$filters = $parser->getFiltersPublic([], $sdic, 0);
$this->assertSame(['FlateDecode'], $filters);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetDecodeParmsSkipsInvalidPairsAcrossLoopChecks(): void
{
$parser = new ParserHarness();
$sdic = [
['/', 'DecodeParms', 0],
[
'<<',
[
['numeric', '0', 0],
['numeric', '1', 0],
['/', 'MissingValue', 0],
['null', 'null', 0],
['/', 'Valid', 0],
['numeric', '7', 0],
['/', 'DanglingKey', 0],
],
0,
],
];
$params = $parser->getDecodeParmsPublic($sdic, 0);
$this->assertSame(['Valid' => 7], $params);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParseResolvesCompressedObjectFromObjectStream(): void
{
$parser = new ParserHarness();
$parser->setStubXrefData([
'trailer' => [
'id' => [],
'info' => '',
'root' => '1_0',
'size' => 3,
],
'xref' => [
'1_0' => 10,
'2_0' => '1_0_0',
],
]);
$parser->setStubIndirectReturn($this->buildObjectStreamObject(1, 4, '2 0 (A)'));
$parsed = $parser->parse("%PDF-1.7\n");
$this->assertArrayHasKey('2_0', $parsed[1]);
$obj = $parsed[1]['2_0'] ?? null;
$this->assertIsArray($obj);
$this->assertNotEmpty($obj);
$this->assertCount(1, $parser->getIndirectCalls());
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParseWithLazyStreamsReparsesObjectStreamForDecodedPayload(): void
{
$parser = new class(['decode_streams' => false]) extends ParserHarness {
/** @var array<int, array{0:string,1:int,2:bool}> */
private array $calls = [];
/**
* @return array<int, RawObjectArray>
*/
protected function getIndirectObject(string $obj_ref, int $offset = 0, bool $decoding = true): array
{
$this->calls[] = [$obj_ref, $offset, $decoding];
if ($obj_ref !== '1_0') {
return [['null', 'null', 0]];
}
if ($decoding) {
return [
[
'<<',
[
['/', 'Type', 0],
['/', 'ObjStm', 0],
['/', 'N', 0],
['numeric', '1', 0],
['/', 'First', 0],
['numeric', '4', 0],
],
0,
],
['stream', 'raw', 0, ['2 0 (A)', []]],
];
}
return [
[
'<<',
[
['/', 'Type', 0],
['/', 'ObjStm', 0],
['/', 'N', 0],
['numeric', '1', 0],
['/', 'First', 0],
['numeric', '4', 0],
],
0,
],
['stream', 'raw', 0],
];
}
/** @return array<int, array{0:string,1:int,2:bool}> */
public function getCalls(): array
{
return $this->calls;
}
};
$parser->setStubXrefData([
'trailer' => [
'id' => [],
'info' => '',
'root' => '1_0',
'size' => 3,
],
'xref' => [
'1_0' => 10,
'2_0' => '1_0_0',
],
]);
$parsed = $parser->parse("%PDF-1.7\n");
$this->assertArrayHasKey('2_0', $parsed[1]);
$calls = $parser->getCalls();
$this->assertSame(['1_0', 10, false], $calls[0] ?? null);
$this->assertSame(['1_0', 10, true], $calls[1] ?? null);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParseSkipsObjectAlreadyInjectedDuringIteration(): void
{
$parser = new class() extends ParserHarness {
protected function getIndirectObject(string $obj_ref, int $offset = 0, bool $decoding = true): array
{
$obj = parent::getIndirectObject($obj_ref, $offset, $decoding);
if ($obj_ref === '1_0') {
$this->objects['2_0'] = [['string', 'prefilled', 0]];
}
return $obj;
}
};
$parser->setStubXrefData([
'trailer' => [
'id' => [],
'info' => '',
'root' => '1_0',
'size' => 3,
],
'xref' => [
'1_0' => 10,
'2_0' => 20,
],
]);
$parser->setStubIndirectReturn([['numeric', '9', 0]]);
$parsed = $parser->parse("%PDF-1.7\n");
$calls = $parser->getIndirectCalls();
$this->assertCount(1, $calls);
$first = $calls[0] ?? null;
$this->assertIsArray($first);
$this->assertSame('1_0', $first[0]);
$this->assertSame('prefilled', $parsed[1]['2_0'][0][1] ?? '');
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParseSkipsCompressedObjectWhenStreamEnvelopeIsInvalid(): void
{
$parser = new ParserHarness();
$parser->setStubXrefData([
'trailer' => [
'id' => [],
'info' => '',
'root' => '1_0',
'size' => 3,
],
'xref' => [
'1_0' => 10,
'2_0' => '1_0_0',
],
]);
$parser->setStubIndirectReturn([
['<<', [['/', 'N', 0], ['numeric', '1', 0], ['/', 'First', 0], ['numeric', '4', 0]], 0],
['stream', 'raw', 0],
]);
$parsed = $parser->parse("%PDF-1.7\n");
$this->assertArrayNotHasKey('2_0', $parsed[1]);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetObjectValReturnsOriginalWhenCompressedLookupFails(): void
{
$parser = new ParserHarness();
$parser->setXrefMapPublic([
'2_0' => '1_0_0',
'1_0' => 0,
]);
$obj = ['objref', '2_0', 0];
$result = $parser->getObjectValPublic($obj);
$this->assertSame($obj, $result);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetObjectValReturnsOriginalForNonPositiveOffsetAndInvalidLocator(): void
{
$parser = new ParserHarness();
$parser->setXrefMapPublic(['2_0' => 0]);
$obj = ['objref', '2_0', 0];
$this->assertSame($obj, $parser->getObjectValPublic($obj));
$parser = new ParserHarness();
$parser->setXrefMapPublic(['2_0' => 'bad_locator']);
$this->assertSame($obj, $parser->getObjectValPublic($obj));
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetObjectValReturnsOriginalWhenCachedObjectStreamNeedsMissingReparseOffset(): void
{
$parser = new ParserHarness();
$parser->setObjectsPublic([
'1_0' => [
[
'<<',
[
['/', 'Type', 0],
['/', 'ObjStm', 0],
['/', 'N', 0],
['numeric', '1', 0],
['/', 'First', 0],
['numeric', '4', 0],
],
0,
],
['stream', 'raw', 0],
],
]);
$parser->setXrefMapPublic([
'2_0' => '1_0_0',
]);
$obj = ['objref', '2_0', 0];
$this->assertSame($obj, $parser->getObjectValPublic($obj));
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetObjectValReturnsOriginalWhenIndirectObjectParsesEmpty(): void
{
$parser = new ParserHarness();
$parser->setXrefMapPublic(['2_0' => 10]);
$parser->setStubIndirectReturn([]);
$obj = ['objref', '2_0', 0];
$this->assertSame($obj, $parser->getObjectValPublic($obj));
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetObjectValReturnsFirstElementForResolvedCompressedObject(): void
{
$parser = new ParserHarness();
$parser->setXrefMapPublic([
'2_0' => '1_0_0',
'1_0' => 12,
]);
$parser->setStubIndirectReturn($this->buildObjectStreamObject(1, 4, '2 0 (A)'));
$resolved = $parser->getObjectValPublic(['objref', '2_0', 0]);
$this->assertNotSame('objref', $resolved[0]);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetObjectValHandlesObjectStreamIndexAndBodyValidation(): void
{
$parser = new ParserHarness();
$parser->setXrefMapPublic([
'2_0' => '1_0_0',
'1_0' => 12,
]);
$parser->setStubIndirectReturn($this->buildObjectStreamObject(1, 4, 'x y (A)'));
$obj = ['objref', '2_0', 0];
$this->assertSame($obj, $parser->getObjectValPublic($obj));
$parser = new ParserHarness();
$parser->setXrefMapPublic([
'2_0' => '1_0_0',
'1_0' => 12,
]);
$parser->setStubIndirectReturn($this->buildObjectStreamObject(1, 4, '0 0 ()'));
$this->assertSame($obj, $parser->getObjectValPublic($obj));
$parser = new ParserHarness();
$parser->setXrefMapPublic([
'2_0' => '1_0_0',
'1_0' => 12,
]);
$parser->setStubIndirectReturn($this->buildObjectStreamObject(0, 4, '2 0 (A)'));
$this->assertSame($obj, $parser->getObjectValPublic($obj));
$parser = new ParserHarness();
$parser->setXrefMapPublic([
'2_0' => '1_0_0',
'1_0' => 12,
]);
$parser->setStubIndirectReturn($this->buildObjectStreamObject(1, 0, ''));
$this->assertSame($obj, $parser->getObjectValPublic($obj));
$parser = new ParserHarness();
$parser->setXrefMapPublic([
'2_0' => '1_0_0',
'1_0' => 12,
]);
$parser->setStubIndirectReturn($this->buildObjectStreamObject(1, 6, '2 -10 '));
$this->assertSame($obj, $parser->getObjectValPublic($obj));
$parser = new ParserHarness();
$parser->setXrefMapPublic([
'2_0' => '1_0_0',
'1_0' => 12,
]);
$parser->setStubIndirectReturn($this->buildObjectStreamObject(1, 4, '2 0 '));
$this->assertSame($obj, $parser->getObjectValPublic($obj));
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testGetDecodeParmsHandlesSparseDictionaryIndexes(): void
{
$parser = new ParserHarness();
$sdic = [
['/', 'DecodeParms', 0],
[
'<<',
[
2 => ['/', 'Columns', 0],
3 => ['numeric', '5', 0],
],
0,
],
];
$this->assertSame([], $parser->getDecodeParmsPublic($sdic, 0));
}
/**
* @return array<int, RawObjectArray>
*/
private function buildObjectStreamObject(int $n, int $first, string $decodedData): array
{
return [
[
'<<',
[
['/', 'Type', 0],
['/', 'ObjStm', 0],
['/', 'N', 0],
['numeric', (string) $n, 0],
['/', 'First', 0],
['numeric', (string) $first, 0],
],
0,
],
['stream', 'raw', 0, [$decodedData, []]],
];
}
/**
* Regression: processAngular() must bail out when getRawObject() fails
* to advance $offset, rather than spinning forever and exhausting PHP
* memory. Without the guard, the inner do-while loop accumulates
* identical zero-length tokens at the same offset until OOM.
*
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testProcessAngularBailsOnNonAdvancingByte(): void
{
// `<<` then `~` — a byte that processDefault() cannot consume — and
// no `>>` terminator. Before the fix this hangs / OOMs in
// RawObject::processAngular() at the inner do-while loop.
$parser = new ParserHarness();
$parser->setPdfDataPublic('<<~');
$element = $parser->callParentGetRawObject(0);
$this->assertIsArray($element);
$this->assertSame('<<', $element[0]);
$this->assertIsArray($element[1]);
// The non-advancing guard must short-circuit within a single
// iteration; the trailing array_pop then leaves $objval empty.
$this->assertLessThan(5, \count($element[1]));
}
/**
* Regression: processBracket() must bail out on a non-advancing parse,
* for the same reasons as the dictionary loop above.
*
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testProcessBracketBailsOnNonAdvancingByte(): void
{
$parser = new ParserHarness();
$parser->setPdfDataPublic('[~');
$element = $parser->callParentGetRawObject(0);
$this->assertIsArray($element);
$this->assertSame('[', $element[0]);
$this->assertIsArray($element[1]);
$this->assertLessThan(5, \count($element[1]));
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParentRawObjectParsesBooleanKeywords(): void
{
$parser = new ParserHarness();
$parser->setPdfDataPublic('true false');
$first = $parser->callParentGetRawObject(0);
$second = $parser->callParentGetRawObject(5);
$this->assertSame('boolean', $first[0]);
$this->assertSame('true', $first[1]);
$this->assertSame('boolean', $second[0]);
$this->assertSame('false', $second[1]);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParentRawObjectParsesNestedParentheses(): void
{
$parser = new ParserHarness();
$parser->setPdfDataPublic('((ab))');
$element = $parser->callParentGetRawObject(0);
$this->assertSame('(', $element[0]);
$this->assertSame('(ab)', $element[1]);
}
/**
* @throws \Com\Tecnick\Pdf\Parser\Exception
*/
public function testParentRawObjectParsesHexStringAndMalformedHexFallback(): void
{
$parser = new ParserHarness();
$parser->setPdfDataPublic('< 4A 4B >');
$hex = $parser->callParentGetRawObject(0);
$this->assertSame('<', $hex[0]);
$this->assertSame(' 4A 4B ', $hex[1]);
$parser = new ParserHarness();
$parser->setPdfDataPublic('<GG>');
$fallback = $parser->callParentGetRawObject(0);
$this->assertSame('<', $fallback[0]);
$this->assertSame('', $fallback[1]);
$this->assertSame(4, $fallback[2]);
}
}