* @copyright 2002-2026 Nicola Asuni - Tecnick.com LTD * @license https://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE) * @link https://github.com/tecnickcom/tc-lib-pdf * * This file is part of tc-lib-pdf software library. */ namespace Test; /** * @phpstan-import-type TAnnot from \Com\Tecnick\Pdf\Output * @phpstan-import-type TObjID from \Com\Tecnick\Pdf\Output * @phpstan-import-type TOutline from \Com\Tecnick\Pdf\Output * @phpstan-import-type TSignDocPrepared from \Com\Tecnick\Pdf\Output * @phpstan-import-type TSVGMaskObject from \Com\Tecnick\Pdf\Base */ class TestableOutput extends \Com\Tecnick\Pdf\Tcpdf { protected string $mockTsaResp = ''; protected bool $mockTsaThrows = false; protected string $tsaReq = ''; protected string $mockOcspResp = ''; protected bool $mockOcspThrows = false; protected string $ocspReq = ''; protected string $ocspUrl = ''; protected string $mockCrlResp = ''; protected bool $mockCrlThrows = false; protected string $crlUrl = ''; /** * @phpstan-param array $annotData * @phpstan-return TAnnot */ private function toAnnot(array $annotData): array { $base = [ 'n' => 1, 'x' => 0.0, 'y' => 0.0, 'w' => 0.0, 'h' => 0.0, 'txt' => '', 'opt' => ['subtype' => 'text'], ]; /** @var TAnnot */ return \array_replace_recursive($base, $annotData); } /** @phpstan-return array */ public function exposeGetPDFObjectOffsets(string $data): array { return $this->getPDFObjectOffsets($data); } /** @phpstan-param array $offset */ public function exposeGetOutPDFXref(array $offset): string { return $this->getOutPDFXref($offset); } public function exposeGetOutPDFTrailer(): string { return $this->getOutPDFTrailer(); } /** @phpstan-param array $color */ public function exposeGetColorStringFromPercArray(array $color): string { return self::getColorStringFromPercArray($color); } /** @phpstan-param array $annot */ public function exposeGetAnnotationBorder(array $annot): string { return $this->getAnnotationBorder($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationFlags(array $annot): string { return $this->getOutAnnotationFlags($this->toAnnot($annot)); } /** @phpstan-param array|int $flags */ public function exposeGetAnnotationFlagsCode(int|array $flags): int { return $this->getAnnotationFlagsCode($flags); } public function exposeGetOnOff(mixed $val): string { return $this->getOnOff($val); } /** * @param array $transpNames */ public function exposeStreamUsesTransparency(string $stream, array $transpNames): bool { return $this->streamUsesTransparency($stream, $transpNames); } /** @return array */ public function exposeGetTransparencyResourceNames(): array { return $this->getTransparencyResourceNames(); } /** @throws \Throwable */ public function exposeGetOutDestinations(): string { return $this->getOutDestinations(); } public function exposeSortBookmarks(): void { $this->sortBookmarks(); } public function exposeProcessPrevNextBookmarks(): int { return $this->processPrevNextBookmarks(); } /** @throws \Throwable */ public function exposeGetOutBookmarks(): string { return $this->getOutBookmarks(); } /** @throws \Throwable */ public function exposeGetOutJavascript(): string { return $this->getOutJavascript(); } public function exposeGetXObjectDict(): string { return $this->getXObjectDict(); } public function exposeGetLayerDict(): string { return $this->getLayerDict(); } public function exposeGetOutResourcesDict(): string { return $this->getOutResourcesDict(); } public function exposeGetPatternStreamResourceDict(string $stream): string { return $this->getPatternStreamResourceDict($stream); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeLine(array $annot): string { return $this->getOutAnnotationOptSubtypeLine($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeSquare(array $annot): string { return $this->getOutAnnotationOptSubtypeSquare($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeCircle(array $annot): string { return $this->getOutAnnotationOptSubtypeCircle($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypePolygon(array $annot): string { return $this->getOutAnnotationOptSubtypePolygon($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypePolyline(array $annot): string { return $this->getOutAnnotationOptSubtypePolyline($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeHighlight(array $annot): string { return $this->getOutAnnotationOptSubtypeHighlight($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeUnderline(array $annot): string { return $this->getOutAnnotationOptSubtypeUnderline($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeSquiggly(array $annot): string { return $this->getOutAnnotationOptSubtypeSquiggly($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeStrikeout(array $annot): string { return $this->getOutAnnotationOptSubtypeStrikeout($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeStamp(array $annot): string { return $this->getOutAnnotationOptSubtypeStamp($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeCaret(array $annot): string { return $this->getOutAnnotationOptSubtypeCaret($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeInk(array $annot): string { return $this->getOutAnnotationOptSubtypeInk($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypePopup(array $annot): string { return $this->getOutAnnotationOptSubtypePopup($this->toAnnot($annot)); } /** * @phpstan-param array $annot * @throws \Throwable */ public function exposeGetOutAnnotationOptSubtypeMovie(array $annot): string { return $this->getOutAnnotationOptSubtypeMovie($this->toAnnot($annot)); } /** * @phpstan-param array $annot * @throws \Throwable */ public function exposeGetOutAnnotationOptSubtypeScreen(array $annot): string { return $this->getOutAnnotationOptSubtypeScreen($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypePrintermark(array $annot): string { return $this->getOutAnnotationOptSubtypePrintermark($this->toAnnot($annot)); } /** * @phpstan-param array $annot * @throws \Throwable */ public function exposeGetOutAnnotationOptSubtypeRedact(array $annot): string { return $this->getOutAnnotationOptSubtypeRedact($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeTrapnet(array $annot): string { return $this->getOutAnnotationOptSubtypeTrapnet($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeWatermark(array $annot): string { return $this->getOutAnnotationOptSubtypeWatermark($this->toAnnot($annot)); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtype3D(array $annot): string { return $this->getOutAnnotationOptSubtype3D($this->toAnnot($annot)); } /** * @phpstan-param array $annot * @throws \Throwable */ public function exposeGetAnnotationRadioButtons(array $annot): string { return $this->getAnnotationRadioButtons($this->toAnnot($annot)); } /** * @phpstan-param array $annot * @return array{string, string} * @throws \Throwable */ public function exposeGetAnnotationAppearanceStream(array $annot, float $width = 0, float $height = 0): array { $method = new \ReflectionMethod($this, 'getAnnotationAppearanceStream'); /** @var array{string, string} */ return $method->invokeArgs($this, [$this->toAnnot($annot), $width, $height]); } /** * @phpstan-param array $annot * @throws \Throwable */ public function exposeGetOutAnnotationMarkups(array $annot, int $oid): string { return $this->getOutAnnotationMarkups($this->toAnnot($annot), $oid); } /** * @phpstan-param array $annot * @throws \Throwable */ public function exposeGetOutAnnotationOptSubtype(array $annot, int $pagenum, int $oid, int $key): string { return $this->getOutAnnotationOptSubtype($this->toAnnot($annot), $pagenum, $oid, $key); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeText(array $annot): string { return $this->getOutAnnotationOptSubtypeText($this->toAnnot($annot)); } /** * @phpstan-param array $annot * @throws \Throwable */ public function exposeGetOutAnnotationOptSubtypeLink(array $annot, int $pagenum, int $oid): string { return $this->getOutAnnotationOptSubtypeLink($this->toAnnot($annot), $pagenum, $oid); } /** * @phpstan-param array $annot * @throws \Throwable */ public function exposeGetOutAnnotationOptSubtypeFreetext(array $annot, int $oid): string { return $this->getOutAnnotationOptSubtypeFreetext($this->toAnnot($annot), $oid); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeFileattachment(array $annot, int $key): string { return $this->getOutAnnotationOptSubtypeFileattachment($this->toAnnot($annot), $key); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationOptSubtypeSound(array $annot): string { return $this->getOutAnnotationOptSubtypeSound($this->toAnnot($annot)); } /** * @phpstan-param array $annot * @throws \Throwable */ public function exposeGetOutAnnotationOptSubtypeWidget(array $annot, int $oid): string { return $this->getOutAnnotationOptSubtypeWidget($this->toAnnot($annot), $oid); } public function exposeGetOutPDFHeader(): string { return $this->getOutPDFHeader(); } /** @throws \Throwable */ public function exposeGetOutPDFBody(): string { return $this->getOutPDFBody(); } /** @throws \Throwable */ public function exposeGetOutCatalog(): string { return $this->getOutCatalog(); } /** @throws \Throwable */ public function exposeAppendDssRevision(string $pdf): string { return $this->appendDssRevision($pdf); } /** @throws \Throwable */ public function exposeAppendDocTimeStampRevision(string $pdf): string { return $this->appendDocTimeStampRevision($pdf); } public function exposeExtractSignatureContents(string $pdf): string { return $this->extractSignatureContents($pdf); } /** @throws \Throwable */ public function exposeGetOutICC(): string { return $this->getOutICC(); } /** @throws \Throwable */ public function exposeGetOutputIntentsSrgb(): string { return $this->getOutputIntentsSrgb(); } /** @throws \Throwable */ public function exposeGetOutputIntentsPdfX(): string { return $this->getOutputIntentsPdfX(); } /** @throws \Throwable */ public function exposeGetOutputIntents(): string { return $this->getOutputIntents(); } /** @throws \Throwable */ public function exposeGetPDFLayers(): string { return $this->getPDFLayers(); } /** @throws \Throwable */ public function exposeGetOutOCG(): string { return $this->getOutOCG(); } /** @throws \Throwable */ public function exposeGetOutAPXObjects(float $width = 0, float $height = 0, string $stream = ''): string { return $this->getOutAPXObjects($width, $height, $stream); } /** @throws \Throwable */ public function exposeGetOutXObjects(): string { return $this->getOutXObjects(); } /** @throws \Throwable */ public function exposeGetOutPatterns(): string { return $this->getOutPatterns(); } /** @throws \Throwable */ public function exposeGetOutEmbeddedFiles(): string { return $this->getOutEmbeddedFiles(); } /** @throws \Throwable */ public function exposeGetOutAnnotations(): string { return $this->getOutAnnotations(); } /** @throws \Throwable */ public function exposeGetOutSignatureFields(): string { return $this->getOutSignatureFields(); } /** * @phpstan-return TSignDocPrepared */ public function exposePrepareDocumentForSignature(string $pdfdoc): array { return $this->prepareDocumentForSignature($pdfdoc); } /** @throws \Throwable */ public function exposeConvertBinarySignatureToHex(string $signature): string { return $this->convertBinarySignatureToHex($signature); } /** * @return array{certs: list, ocsp: list, crls: list} * @throws \Throwable */ public function exposeCollectDssMaterial(): array { return $this->collectDssMaterial(); } public function setMockTimestampResponse(string $response): void { $this->mockTsaResp = $response; } public function setMockTimestampThrows(bool $throws): void { $this->mockTsaThrows = $throws; } public function getCapturedTimestampRequest(): string { return $this->tsaReq; } public function setMockOcspResponse(string $response): void { $this->mockOcspResp = $response; } public function setMockOcspThrows(bool $throws): void { $this->mockOcspThrows = $throws; } public function getCapturedOcspRequest(): string { return $this->ocspReq; } public function getCapturedOcspUrl(): string { return $this->ocspUrl; } public function setMockCrlResponse(string $response): void { $this->mockCrlResp = $response; } public function setMockCrlThrows(bool $throws): void { $this->mockCrlThrows = $throws; } public function getCapturedCrlUrl(): string { return $this->crlUrl; } protected function postTimestampRequest(string $request): string { $this->tsaReq = $request; if ($this->mockTsaThrows) { throw new \Com\Tecnick\Pdf\Exception('mock tsa transport error'); } if ($this->mockTsaResp !== '') { return $this->mockTsaResp; } return parent::postTimestampRequest($request); } protected function postOcspRequest(string $url, string $request): string { $this->ocspUrl = $url; $this->ocspReq = $request; if ($this->mockOcspThrows) { throw new \Com\Tecnick\Pdf\Exception('mock ocsp transport error'); } if ($this->mockOcspResp !== '') { return $this->mockOcspResp; } return parent::postOcspRequest($url, $request); } protected function getCrlData(string $url): string { $this->crlUrl = $url; if ($this->mockCrlThrows) { throw new \Com\Tecnick\Pdf\Exception('mock crl transport error'); } if ($this->mockCrlResp !== '') { return $this->mockCrlResp; } return parent::getCrlData($url); } /** @throws \Throwable */ public function exposeSignDocument(string $pdfdoc): string { return $this->signDocument($pdfdoc); } /** @throws \Throwable */ public function exposeBuildSignatureCms(string $content): string { return $this->buildSignatureCms($content); } public function exposeSignatureSubFilter(): string { return $this->signatureSubFilter(); } public function exposeSignatureDigestAlgorithm(): string { return $this->signatureDigestAlgorithm(); } public function exposeSignatureContentsLength(): int { return $this->signatureContentsLength(); } /** * @param array $objects * @throws \Throwable */ public function exposeAppendIncrementalRevision(string $pdf, array $objects): string { return $this->appendIncrementalRevision($pdf, $objects); } /** * @return list * @throws \Throwable */ public function exposeLoadExtraCertificates(string $extracerts): array { return $this->loadExtraCertificates($extracerts); } /** @throws \Throwable */ public function exposeGetOutSignature(): string { return $this->getOutSignature(); } public function exposeGetOutSignatureDocMDP(): string { return $this->getOutSignatureDocMDP(); } public function exposeGetOutSignatureUserRights(): string { return $this->getOutSignatureUserRights(); } /** @phpstan-param array> $objid */ public function setOutputState(int $pon, array $objid, string $fileid = 'ABC123', int $encryptObjId = 0): void { $this->pon = $pon; $form = $objid['form'] ?? null; if (\is_array($form)) { $typedForm = \array_map(static fn($objId): int => (int) $objId, $form); $this->objid['form'] = $typedForm; } $intKeys = ['catalog', 'dests', 'dss', 'info', 'pages', 'resdic', 'signature', 'srgbicc', 'xmp']; foreach ($intKeys as $key) { $value = $objid[$key] ?? null; if (!\is_int($value)) { continue; } switch ($key) { case 'catalog': $this->objid['catalog'] = $value; break; case 'dests': $this->objid['dests'] = $value; break; case 'dss': $this->objid['dss'] = $value; break; case 'info': $this->objid['info'] = $value; break; case 'pages': $this->objid['pages'] = $value; break; case 'resdic': $this->objid['resdic'] = $value; break; case 'signature': $this->objid['signature'] = $value; break; case 'srgbicc': $this->objid['srgbicc'] = $value; break; case 'xmp': $this->objid['xmp'] = $value; break; } } $this->fileid = $fileid; $ref = new \ReflectionObject($this->encrypt); $prop = $ref->getProperty('encryptdata'); /** @var array $data */ $data = $prop->getValue($this->encrypt); $data['objid'] = $encryptObjId; $prop->setValue($this->encrypt, $data); } public function setPdfaMode(int $pdfa): void { $this->pdfa = $pdfa; } /** @phpstan-return array */ public function getOutlinesState(): array { return $this->outlines; } public function getJavascriptTree(): string { return $this->jstree; } /** @throws \Throwable */ public function exposeGetOutSVGMasks(): string { return $this->getOutSVGMasks(); } public function exposeGetSVGMaskExtGStateEntries(): string { return $this->getSVGMaskExtGStateEntries(); } /** @phpstan-param array> $masks */ public function setSvgMasks(array $masks): void { /** @var array $typedMasks */ $typedMasks = []; foreach ($masks as $key => $mask) { if (!isset($mask['bbox']) || !\is_array($mask['bbox'])) { continue; } $bbox = $mask['bbox']; $bbox0 = isset($bbox[0]) && \is_numeric($bbox[0]) ? (float) $bbox[0] : 0.0; $bbox1 = isset($bbox[1]) && \is_numeric($bbox[1]) ? (float) $bbox[1] : 0.0; $bbox2 = isset($bbox[2]) && \is_numeric($bbox[2]) ? (float) $bbox[2] : 0.0; $bbox3 = isset($bbox[3]) && \is_numeric($bbox[3]) ? (float) $bbox[3] : 0.0; $typedMasks[$key] = [ 'id' => isset($mask['id']) ? (string) $mask['id'] : $key, 'stream' => isset($mask['stream']) ? (string) $mask['stream'] : '', 'bbox' => [ $bbox0, $bbox1, $bbox2, $bbox3, ], 'gs_n' => (int) ($mask['gs_n'] ?? 0), ]; } $this->svgmasks = $typedMasks; } /** @return array */ public function getSvgMasks(): array { return $this->svgmasks; } /** * @param array $names */ public function exposeExtractNamedResourceRefs(string $dict, array $names): string { return $this->extractNamedResourceRefs($dict, $names); } /** @throws \Throwable */ public function exposeGetOutStructTreeRoot(): string { return $this->getOutStructTreeRoot(); } /** @phpstan-param array $annot */ public function exposeGetOutAnnotationRD(array $annot): string { return $this->getOutAnnotationRectDifferences($annot); } public function exposeSetPageStructParents(string $pdfpages): string { return $this->setPageStructParents($pdfpages); } /** @throws \Throwable */ public function exposePostTimestampRequest(string $request): string { return $this->postTimestampRequest($request); } /** @throws \Throwable */ public function exposeParentPostTimestampRequest(string $request): string { return parent::postTimestampRequest($request); } /** @throws \Throwable */ public function exposeGetCertificateSourceContent(string $source): string { return $this->getCertificateSourceContent($source); } /** * @return array * @throws \Throwable */ public function exposeExtractPemCertificates(string $content): array { return $this->extractPemCertificates($content); } public function exposeGetPatternDict(): string { return $this->getPatternDict(); } /** @throws \Throwable */ public function exposeWriteRawPdfOutput(string $rawpdf): void { $this->writeRawPdfOutput($rawpdf); } }