diff --git a/src/Document/Dictionary/DictionaryValue/Name/FilterNameValue.php b/src/Document/Dictionary/DictionaryValue/Name/FilterNameValue.php index ede13c9..f81a6f3 100644 --- a/src/Document/Dictionary/DictionaryValue/Name/FilterNameValue.php +++ b/src/Document/Dictionary/DictionaryValue/Name/FilterNameValue.php @@ -7,6 +7,7 @@ use PrinsFrank\PdfParser\Document\Dictionary\DictionaryKey\DictionaryKey; use PrinsFrank\PdfParser\Document\Dictionary\DictionaryValue\Integer\IntegerValue; use PrinsFrank\PdfParser\Document\Document; +use PrinsFrank\PdfParser\Document\Filter\Decode\ASCII85Decode; use PrinsFrank\PdfParser\Document\Filter\Decode\CCITTFaxDecode; use PrinsFrank\PdfParser\Document\Filter\Decode\FlateDecode; use PrinsFrank\PdfParser\Document\Filter\Decode\LZWFlatePredictorValue; @@ -54,6 +55,7 @@ public function decodeBinary(string $content, ?Dictionary $dictionary, ?Document $decodeParams->getValueForKey(DictionaryKey::K, IntegerValue::class)->value ?? throw new ParseFailureException('Missing K'), ), + self::ASCII_85_DECODE => ASCII85Decode::decodeBinary($content), default => throw new ParseFailureException(sprintf('Content "%.100s..." cannot be decoded for filter "%s"', $content, $this->name)) }; } diff --git a/src/Document/Document.php b/src/Document/Document.php index b511c18..3b2fddf 100644 --- a/src/Document/Document.php +++ b/src/Document/Document.php @@ -20,6 +20,7 @@ use PrinsFrank\PdfParser\Document\Object\Item\UncompressedObject\UncompressedObjectParser; use PrinsFrank\PdfParser\Document\Security\StandardSecurity; use PrinsFrank\PdfParser\Document\Version\Version; +use PrinsFrank\PdfParser\Exception\AuthenticationFailedException; use PrinsFrank\PdfParser\Exception\NotImplementedException; use PrinsFrank\PdfParser\Exception\ParseFailureException; use PrinsFrank\PdfParser\Exception\PdfParserException; @@ -40,8 +41,16 @@ public function __construct( public readonly CrossReferenceSource $crossReferenceSource, public ?StandardSecurity $security, ) { - if ($this->getEncryptDictionary() !== null) { - throw new NotImplementedException('Encrypted documents are not supported yet'); + if (($encryptDictionary = $this->getEncryptDictionary()) !== null) { + if ($encryptDictionary->getSecurityHandler() === null) { + throw new NotImplementedException('Empty security handler is not supported'); + } + + $this->security ??= new StandardSecurity(); + if ($this->security->isUserPasswordValid($encryptDictionary, $crossReferenceSource->getFirstId()) === false + && $this->security->isOwnerPasswordValid($encryptDictionary, $crossReferenceSource->getFirstId()) === false) { + throw new AuthenticationFailedException($security === null ? 'Document could not be decrypted using default credentials, please supply an owner or user password' : 'User and owner password are invalid, please supply valid credentials'); + } } } diff --git a/src/Document/Filter/Decode/ASCII85Decode.php b/src/Document/Filter/Decode/ASCII85Decode.php new file mode 100644 index 0000000..6290044 --- /dev/null +++ b/src/Document/Filter/Decode/ASCII85Decode.php @@ -0,0 +1,53 @@ +')) { + $string = substr($string, 2, -2); + } + + $string = preg_replace('/\s+/', '', $string) + ?? throw new RuntimeException('An unexpected error occurred while sanitizing ASCII85 string'); + $length = strlen($string); + $decoded = $block = ''; + for ($i = 0; $i < $length; ++$i) { + $char = $string[$i]; + if ($char === 'z') { + $decoded .= "\0\0\0\0"; + continue; + } + + $block .= $char; + if (strlen($block) === 5) { + $value = 0; + for ($j = 0; $j < 5; ++$j) { + $value = $value * 85 + (ord($block[$j]) - 33); + } + + $decoded .= pack('N', $value); + $block = ''; + } + } + + if ($block !== '') { + $padding = 5 - strlen($block); + $block = str_pad($block, 5, 'u'); + $value = 0; + for ($i = 0; $i < 5; ++$i) { + $value = $value * 85 + (ord($block[$i]) - 33); + } + + $binaryData = pack('N', $value); + $decoded .= substr($binaryData, 0, 4 - $padding); + } + + return $decoded; + } +} diff --git a/tests/Samples/Info/FileInfo.php b/tests/Samples/Info/FileInfo.php index 0938686..4f4dd86 100644 --- a/tests/Samples/Info/FileInfo.php +++ b/tests/Samples/Info/FileInfo.php @@ -9,7 +9,8 @@ class FileInfo { public function __construct( public readonly string $pdfPath, public readonly int $version, - public readonly ?string $password, + public readonly ?string $userPassword, + public readonly ?string $ownerPassword, public readonly ?string $title, public readonly ?string $producer, public readonly ?string $author, diff --git a/tests/Samples/Info/SampleProvider.php b/tests/Samples/Info/SampleProvider.php index 7b93e0f..78e5514 100644 --- a/tests/Samples/Info/SampleProvider.php +++ b/tests/Samples/Info/SampleProvider.php @@ -23,17 +23,14 @@ public static function samples(): iterable { throw new RuntimeException(); } - /** @var object{version: float, password: ?string, title: ?string, producer: ?string, author: ?string, creator: ?string, creationDate: ?\DateTimeImmutable, modificationDate: ?\DateTimeImmutable, pages: list} $content */ + /** @var object{version: float, userPassword: ?string, ownerPassword: ?string, title: ?string, producer: ?string, author: ?string, creator: ?string, creationDate: ?\DateTimeImmutable, modificationDate: ?\DateTimeImmutable, pages: list} $content */ $content = Yaml::parseFile($contentsPath, Yaml::PARSE_OBJECT_FOR_MAP | Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE | Yaml::PARSE_DATETIME); - if ($content->password !== null) { - continue; - } - yield $sampleName => [ new FileInfo( $pdfPath, (int) ($content->version * 10), - $content->password, + $content->userPassword, + $content->ownerPassword, $content->title, $content->producer, $content->author, diff --git a/tests/Samples/SamplesTest.php b/tests/Samples/SamplesTest.php index 625b24b..e4b6976 100644 --- a/tests/Samples/SamplesTest.php +++ b/tests/Samples/SamplesTest.php @@ -6,6 +6,7 @@ use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\DataProviderExternal; use PHPUnit\Framework\TestCase; +use PrinsFrank\PdfParser\Document\Security\StandardSecurity; use PrinsFrank\PdfParser\Document\Version\Version; use PrinsFrank\PdfParser\PdfParser; use PrinsFrank\PdfParser\Tests\Samples\Info\FileInfo; @@ -18,8 +19,10 @@ class SamplesTest extends TestCase { /** @throws TypeError|ValueError|RuntimeException */ #[DataProviderExternal(SampleProvider::class, 'samples')] - public function testExternalSourcePDFs(FileInfo $fileInfo): void { - $document = (new PdfParser())->parseFile($fileInfo->pdfPath); + public function testSamples(FileInfo $fileInfo): void { + $document = (new PdfParser()) + ->parseFile($fileInfo->pdfPath, security: new StandardSecurity($fileInfo->userPassword, $fileInfo->ownerPassword)); + static::assertSame(Version::from(number_format($fileInfo->version / 10, 1)), $document->version); static::assertSame($fileInfo->title, $document->getInformationDictionary()?->getTitle()); static::assertSame($fileInfo->producer, $document->getInformationDictionary()?->getProducer()); diff --git a/tests/Samples/files/gdocs-hello-world-simple/contents.yml b/tests/Samples/files/gdocs-hello-world-simple/contents.yml index ddf13c3..9262f9a 100644 --- a/tests/Samples/files/gdocs-hello-world-simple/contents.yml +++ b/tests/Samples/files/gdocs-hello-world-simple/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.4' -password: null +userPassword: null +ownerPassword: null title: 'Untitled document' producer: 'Skia/PDF m133 Google Docs Renderer' author: null diff --git a/tests/Samples/files/gdocs-image-simple/contents.yml b/tests/Samples/files/gdocs-image-simple/contents.yml index b173803..4f3e312 100644 --- a/tests/Samples/files/gdocs-image-simple/contents.yml +++ b/tests/Samples/files/gdocs-image-simple/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.4' -password: null +userPassword: null +ownerPassword: null title: 'File with image' producer: 'Skia/PDF m138 Google Docs Renderer' author: null diff --git a/tests/Samples/files/gdocs-lorem-ipsum-with-titles-and-formatting/contents.yml b/tests/Samples/files/gdocs-lorem-ipsum-with-titles-and-formatting/contents.yml index 2f0c1c6..049df87 100644 --- a/tests/Samples/files/gdocs-lorem-ipsum-with-titles-and-formatting/contents.yml +++ b/tests/Samples/files/gdocs-lorem-ipsum-with-titles-and-formatting/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.4' -password: null +userPassword: null +ownerPassword: null title: 'lorem ipsum' producer: 'Skia/PDF m133 Google Docs Renderer' author: null diff --git a/tests/Samples/files/gdocs-scripts/contents.yml b/tests/Samples/files/gdocs-scripts/contents.yml index edd1452..103ee2e 100644 --- a/tests/Samples/files/gdocs-scripts/contents.yml +++ b/tests/Samples/files/gdocs-scripts/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.4' -password: null +userPassword: null +ownerPassword: null title: Scripts producer: 'Skia/PDF m134 Google Docs Renderer' author: null diff --git a/tests/Samples/files/issue-127/contents.yml b/tests/Samples/files/issue-127/contents.yml index b68d962..1663177 100644 --- a/tests/Samples/files/issue-127/contents.yml +++ b/tests/Samples/files/issue-127/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '2.0' -password: null +userPassword: null +ownerPassword: null title: !!binary /v8AMQAuADIAIABUAGEAYgBlAGwAbABlAF8AMQBfAEsAQQBfADEAOQAtADAANwAwADUAOQ== producer: 'Kofax Power PDF' author: 'Rehm, Martin (LSN)' diff --git a/tests/Samples/files/issue-149/contents.yml b/tests/Samples/files/issue-149/contents.yml index 1462baa..8356650 100644 --- a/tests/Samples/files/issue-149/contents.yml +++ b/tests/Samples/files/issue-149/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: '(Dossier représentation Mme BEGOT-3.pdf)' producer: 'GPL Ghostscript 10.03.1' author: mgomes03 diff --git a/tests/Samples/files/issue-150/contents.yml b/tests/Samples/files/issue-150/contents.yml index 9f362e6..e0ab106 100644 --- a/tests/Samples/files/issue-150/contents.yml +++ b/tests/Samples/files/issue-150/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.3' -password: null +userPassword: null +ownerPassword: null title: null producer: 'RICOH M C251FW (6577f3)' author: null diff --git a/tests/Samples/files/issue-153/contents.yml b/tests/Samples/files/issue-153/contents.yml new file mode 100644 index 0000000..8255bc5 --- /dev/null +++ b/tests/Samples/files/issue-153/contents.yml @@ -0,0 +1,81 @@ +# yaml-language-server: $schema=./.yml-schema.json +version: '1.4' +password: null +title: reception0658@reseau-intersport.fr +producer: 'Oracle PDF driver' +author: 'Oracle Reports' +creator: 'Oracle12c AS Reports Services' +creationDate: 2025-07-22T10:00:03+00:00 +modificationDate: 2025-07-22T10:00:03+00:00 +pages: + - + content: |- + CUSTOMER IE802719 + INTERSPORT PAIMPOL + SASU C.E.F SPORTS - 17 T RUE RAYMOND PELLIER + 22500 PAIMPOL France + CHAMPION PRODUCTS EUROPE UNLIMITED COMPANY + Blanchardstown Corporate Park 2 D15 Blanchardstown - Dublin Ireland + Tel. Acc. + +353 (0)1 8864217 +353 (0)1 8864217Fax +353 (0)1 8665927 + Tel. CS + IE802719 + DESTINATION + INTERSPORT PAIMPOL + ZONE DE KERPUNS CARREFOUR ILN Code: 3025810065800 + 22500 PAIMPOL France + DELIVERY NOTE + DC REF. + 5204/165/2025/DN/5204 21/07/2025 + FORWARDER + Label + UPS - United Parcel Service S.r.l 2.0 + VIA G. FANTOLI, 15/2 + REASON + 20138 MILANO Milano + Italy + Subcontractor + TRANSPORTATION COST + Delivery Note N + CHH/2025/70BO/058510DATE 21/07/2025 + COMMENTS + SALES REP VORACE SAS François RAMOND + ARTICLE DESCRIPTION COLOUR SIZE TOTAL + ORD. NUM. + 35/38 39/42 43/46 + 8 19 13 + 4402026619 + 3pk Sneaker Socks + U20100-CHA + WW001 WHT + 40 + 40 + 35/38 39/42 43/46 + 8 17 14 + 4402026619 + 3pk Crew Socks + U24558-CHA + KK001 NBK + 39 + 8 17 14 + 4402026619 + WW001 WHT + 39 + 78 + Tot. qty 118 + Cartons Summary + 250570819669 250570830162 + Picking List-N. + CHH-2025-VE-430761 + Packing list W2025/PL/CHH282537 + Leave from + PACKING Cartons Nr 2 Net Wght 16,790 Gross Wght 18,490 + LABEL NOTES + Label + FORWARDER DESTINATION + CIE + Signature Date Time Signature Date Time Signature Date Time + 1 of + Copy for Customer Page 1 + images: + - page_0_image_0.jpg diff --git a/tests/Samples/files/issue-153/file.pdf b/tests/Samples/files/issue-153/file.pdf new file mode 100644 index 0000000..ba86eb7 Binary files /dev/null and b/tests/Samples/files/issue-153/file.pdf differ diff --git a/tests/Samples/files/issue-153/images/page_0_image_0.jpg b/tests/Samples/files/issue-153/images/page_0_image_0.jpg new file mode 100644 index 0000000..0474c54 Binary files /dev/null and b/tests/Samples/files/issue-153/images/page_0_image_0.jpg differ diff --git a/tests/Samples/files/issue-214/contents.yml b/tests/Samples/files/issue-214/contents.yml index f4008a2..6a13755 100644 --- a/tests/Samples/files/issue-214/contents.yml +++ b/tests/Samples/files/issue-214/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: null producer: 'PStill Engine 1.90' author: null diff --git a/tests/Samples/files/issue-235/contents.yml b/tests/Samples/files/issue-235/contents.yml index 972fe02..96f4f94 100644 --- a/tests/Samples/files/issue-235/contents.yml +++ b/tests/Samples/files/issue-235/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.6' -password: null +userPassword: null +ownerPassword: null title: '' producer: 'Adobe PDF Library 20.1.50' author: null diff --git a/tests/Samples/files/issue-254/contents.yml b/tests/Samples/files/issue-254/contents.yml index 17bd88c..da8e1dd 100644 --- a/tests/Samples/files/issue-254/contents.yml +++ b/tests/Samples/files/issue-254/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: 'Publications Office' producer: 'PDFlib+PDI 9.1.2p4 (C++/Win64)' author: 'Publications Office' diff --git a/tests/Samples/files/issue-255/contents.yml b/tests/Samples/files/issue-255/contents.yml index 0aebd68..9642271 100644 --- a/tests/Samples/files/issue-255/contents.yml +++ b/tests/Samples/files/issue-255/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: null producer: 'PStill Engine 1.90' author: null diff --git a/tests/Samples/files/libreoffice-hello-world-hybrid/contents.yml b/tests/Samples/files/libreoffice-hello-world-hybrid/contents.yml index cbd8f89..cd6a5ae 100644 --- a/tests/Samples/files/libreoffice-hello-world-hybrid/contents.yml +++ b/tests/Samples/files/libreoffice-hello-world-hybrid/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: null producer: 'LibreOffice 24.2' author: null diff --git a/tests/Samples/files/libreoffice-hello-world-open-password-hello/contents.yml b/tests/Samples/files/libreoffice-hello-world-open-password-hello/contents.yml index fc9ebe7..26d97fa 100644 --- a/tests/Samples/files/libreoffice-hello-world-open-password-hello/contents.yml +++ b/tests/Samples/files/libreoffice-hello-world-open-password-hello/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: 1.7 -password: Hello +userPassword: hello +ownerPassword: null title: null producer: LibreOffice 24.2 author: null diff --git a/tests/Samples/files/libreoffice-hello-world-simple/contents.yml b/tests/Samples/files/libreoffice-hello-world-simple/contents.yml index de3afb8..5ac9181 100644 --- a/tests/Samples/files/libreoffice-hello-world-simple/contents.yml +++ b/tests/Samples/files/libreoffice-hello-world-simple/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: null producer: 'LibreOffice 24.2' author: null diff --git a/tests/Samples/files/libreoffice-hello-world-watermarked/contents.yml b/tests/Samples/files/libreoffice-hello-world-watermarked/contents.yml index d7c5c34..8103c63 100644 --- a/tests/Samples/files/libreoffice-hello-world-watermarked/contents.yml +++ b/tests/Samples/files/libreoffice-hello-world-watermarked/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: null producer: 'LibreOffice 24.2' author: null diff --git a/tests/Samples/files/libreofficelorem-ipsum-with-titles-and-formatting/contents.yml b/tests/Samples/files/libreofficelorem-ipsum-with-titles-and-formatting/contents.yml index 991b0d9..2db529c 100644 --- a/tests/Samples/files/libreofficelorem-ipsum-with-titles-and-formatting/contents.yml +++ b/tests/Samples/files/libreofficelorem-ipsum-with-titles-and-formatting/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: null producer: 'LibreOffice 24.2' author: null diff --git a/tests/Samples/files/pdftex-hello-world-simple/contents.yml b/tests/Samples/files/pdftex-hello-world-simple/contents.yml index 081fd50..586f378 100644 --- a/tests/Samples/files/pdftex-hello-world-simple/contents.yml +++ b/tests/Samples/files/pdftex-hello-world-simple/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.5' -password: null +userPassword: null +ownerPassword: null title: null producer: pdfTeX-1.40.25 author: null diff --git a/tests/Samples/files/text-objects-across-multiple-streams/contents.yml b/tests/Samples/files/text-objects-across-multiple-streams/contents.yml index 7341f95..85305c2 100644 --- a/tests/Samples/files/text-objects-across-multiple-streams/contents.yml +++ b/tests/Samples/files/text-objects-across-multiple-streams/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.4' -password: null +userPassword: null +ownerPassword: null title: 'MPK Router Control Interface to 7707DT' producer: 'Acrobat Distiller 5.0.5 (Windows)' author: 'Alex Martin' diff --git a/tests/Samples/files/word365-hello-world-simple/contents.yml b/tests/Samples/files/word365-hello-world-simple/contents.yml index 33ac58d..8d5b5b1 100644 --- a/tests/Samples/files/word365-hello-world-simple/contents.yml +++ b/tests/Samples/files/word365-hello-world-simple/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: null producer: null author: 'Frank Prins' diff --git a/tests/Samples/files/word365-lorem-ipsum-with-titles-and-formatting/contents.yml b/tests/Samples/files/word365-lorem-ipsum-with-titles-and-formatting/contents.yml index 7b2250b..505866d 100644 --- a/tests/Samples/files/word365-lorem-ipsum-with-titles-and-formatting/contents.yml +++ b/tests/Samples/files/word365-lorem-ipsum-with-titles-and-formatting/contents.yml @@ -1,6 +1,7 @@ -# yaml-language-server: $schema=./.yml-schema.json +# yaml-language-server: $schema=../../schema.json version: '1.7' -password: null +userPassword: null +ownerPassword: null title: null producer: null author: 'Frank Prins' diff --git a/tests/Samples/schema.json b/tests/Samples/schema.json index e8a8c1f..0aa7bbe 100644 --- a/tests/Samples/schema.json +++ b/tests/Samples/schema.json @@ -6,10 +6,14 @@ "type": "number", "description": "PDF version" }, - "password": { + "userPassword": { "type": ["string", "null"], "description": "Password to open the file" }, + "ownerPassword": { + "type": ["string", "null"], + "description": "Password to restrict document actions" + }, "title": { "type": ["string", "null"], "description": "Title of the document" diff --git a/tests/Samples/update-content b/tests/Samples/update-content index d21b573..9eacf6d 100755 --- a/tests/Samples/update-content +++ b/tests/Samples/update-content @@ -46,7 +46,8 @@ foreach (array_diff(scandir($filesDir = __DIR__ . '/files'), ['..', '.']) as $sa $yamlContent = Yaml::dump( [ 'version' => $parsedPDF->version->value, - 'password' => null, + 'userPassword' => null, + 'ownerPassword' => null, 'title' => $parsedPDF->getInformationDictionary()?->getTitle(), 'producer' => $parsedPDF->getInformationDictionary()?->getProducer(), 'author' => $parsedPDF->getInformationDictionary()?->getAuthor(), @@ -62,6 +63,6 @@ foreach (array_diff(scandir($filesDir = __DIR__ . '/files'), ['..', '.']) as $sa file_put_contents( $sampleFolder . DIRECTORY_SEPARATOR . 'contents.yml', - '# yaml-language-server: $schema=./.yml-schema.json' . PHP_EOL . trim($yamlContent, PHP_EOL) . PHP_EOL + '# yaml-language-server: $schema=../../schema.json' . PHP_EOL . trim($yamlContent, PHP_EOL) . PHP_EOL ); } diff --git a/tests/Unit/Document/Filter/ASCII85DecodeTest.php b/tests/Unit/Document/Filter/ASCII85DecodeTest.php new file mode 100644 index 0000000..2a29fd9 --- /dev/null +++ b/tests/Unit/Document/Filter/ASCII85DecodeTest.php @@ -0,0 +1,37 @@ +Cj@.4Gp$d7F!,L7@<6@)/0JDEF@3BB/F*&OCAfu2/AKYi( + DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF-FD5W8ARlolDIal( + DIdu + D.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c + ASCII85 + ) + ); + static::assertSame( + 'Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.', + ASCII85Decode::decodeBinary( + <<<'ASCII85' + <~9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKFCj@.4Gp$d7F!,L7@<6@)/0JDEF@3BB/F*&OCAfu2/AKYi( + DIb:@FD,*)+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF-FD5W8ARlolDIal( + DIdu + D.RTpAKYo'+CT/5+Cei#DII?(E,9)oF*2M7/c~> + ASCII85 + ) + ); + } +}