@fin.cx/einvoice 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.decoder.d.ts +40 -0
- package/dist_ts/classes.decoder.js +320 -0
- package/dist_ts/classes.encoder.d.ts +51 -0
- package/dist_ts/classes.encoder.js +293 -0
- package/dist_ts/classes.xinvoice.d.ts +136 -0
- package/dist_ts/classes.xinvoice.js +352 -0
- package/dist_ts/einvoice.d.ts +217 -0
- package/dist_ts/einvoice.js +505 -0
- package/dist_ts/errors.d.ts +121 -0
- package/dist_ts/errors.js +241 -0
- package/dist_ts/formats/base/base.decoder.d.ts +32 -0
- package/dist_ts/formats/base/base.decoder.js +52 -0
- package/dist_ts/formats/base/base.encoder.d.ts +13 -0
- package/dist_ts/formats/base/base.encoder.js +7 -0
- package/dist_ts/formats/base/base.validator.d.ts +44 -0
- package/dist_ts/formats/base/base.validator.js +39 -0
- package/dist_ts/formats/base.decoder.d.ts +19 -0
- package/dist_ts/formats/base.decoder.js +130 -0
- package/dist_ts/formats/base.validator.d.ts +44 -0
- package/dist_ts/formats/base.validator.js +39 -0
- package/dist_ts/formats/cii/cii.decoder.d.ts +61 -0
- package/dist_ts/formats/cii/cii.decoder.js +111 -0
- package/dist_ts/formats/cii/cii.encoder.d.ts +43 -0
- package/dist_ts/formats/cii/cii.encoder.js +48 -0
- package/dist_ts/formats/cii/cii.types.d.ts +31 -0
- package/dist_ts/formats/cii/cii.types.js +40 -0
- package/dist_ts/formats/cii/cii.validator.d.ts +56 -0
- package/dist_ts/formats/cii/cii.validator.js +146 -0
- package/dist_ts/formats/cii/facturx/facturx.decoder.d.ts +43 -0
- package/dist_ts/formats/cii/facturx/facturx.decoder.js +207 -0
- package/dist_ts/formats/cii/facturx/facturx.encoder.d.ts +82 -0
- package/dist_ts/formats/cii/facturx/facturx.encoder.js +400 -0
- package/dist_ts/formats/cii/facturx/facturx.types.d.ts +10 -0
- package/dist_ts/formats/cii/facturx/facturx.types.js +15 -0
- package/dist_ts/formats/cii/facturx/facturx.validator.d.ts +32 -0
- package/dist_ts/formats/cii/facturx/facturx.validator.js +138 -0
- package/dist_ts/formats/cii/zugferd/zugferd.decoder.d.ts +43 -0
- package/dist_ts/formats/cii/zugferd/zugferd.decoder.js +218 -0
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.d.ts +97 -0
- package/dist_ts/formats/cii/zugferd/zugferd.encoder.js +550 -0
- package/dist_ts/formats/cii/zugferd/zugferd.types.d.ts +10 -0
- package/dist_ts/formats/cii/zugferd/zugferd.types.js +15 -0
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.d.ts +49 -0
- package/dist_ts/formats/cii/zugferd/zugferd.v1.decoder.js +229 -0
- package/dist_ts/formats/cii/zugferd/zugferd.validator.d.ts +16 -0
- package/dist_ts/formats/cii/zugferd/zugferd.validator.js +29 -0
- package/dist_ts/formats/decoder.factory.d.ts +15 -0
- package/dist_ts/formats/decoder.factory.js +46 -0
- package/dist_ts/formats/factories/decoder.factory.d.ts +13 -0
- package/dist_ts/formats/factories/decoder.factory.js +56 -0
- package/dist_ts/formats/factories/encoder.factory.d.ts +14 -0
- package/dist_ts/formats/factories/encoder.factory.js +40 -0
- package/dist_ts/formats/factories/validator.factory.d.ts +12 -0
- package/dist_ts/formats/factories/validator.factory.js +110 -0
- package/dist_ts/formats/factorx.decoder.d.ts +18 -0
- package/dist_ts/formats/factorx.decoder.js +178 -0
- package/dist_ts/formats/factorx.encoder.d.ts +51 -0
- package/dist_ts/formats/factorx.encoder.js +293 -0
- package/dist_ts/formats/facturx.decoder.d.ts +18 -0
- package/dist_ts/formats/facturx.decoder.js +210 -0
- package/dist_ts/formats/facturx.encoder.d.ts +51 -0
- package/dist_ts/formats/facturx.encoder.js +293 -0
- package/dist_ts/formats/facturx.validator.d.ts +67 -0
- package/dist_ts/formats/facturx.validator.js +266 -0
- package/dist_ts/formats/pdf/extractors/associated.extractor.d.ts +14 -0
- package/dist_ts/formats/pdf/extractors/associated.extractor.js +68 -0
- package/dist_ts/formats/pdf/extractors/base.extractor.d.ts +92 -0
- package/dist_ts/formats/pdf/extractors/base.extractor.js +319 -0
- package/dist_ts/formats/pdf/extractors/index.d.ts +4 -0
- package/dist_ts/formats/pdf/extractors/index.js +5 -0
- package/dist_ts/formats/pdf/extractors/standard.extractor.d.ts +13 -0
- package/dist_ts/formats/pdf/extractors/standard.extractor.js +74 -0
- package/dist_ts/formats/pdf/extractors/text.extractor.d.ts +45 -0
- package/dist_ts/formats/pdf/extractors/text.extractor.js +151 -0
- package/dist_ts/formats/pdf/pdf.embedder.d.ts +69 -0
- package/dist_ts/formats/pdf/pdf.embedder.js +183 -0
- package/dist_ts/formats/pdf/pdf.extractor.d.ts +49 -0
- package/dist_ts/formats/pdf/pdf.extractor.js +98 -0
- package/dist_ts/formats/pdf/robust-pdf.extractor.d.ts +40 -0
- package/dist_ts/formats/pdf/robust-pdf.extractor.js +324 -0
- package/dist_ts/formats/ubl/en16931.ubl.validator.d.ts +18 -0
- package/dist_ts/formats/ubl/en16931.ubl.validator.js +169 -0
- package/dist_ts/formats/ubl/generic/ubl.encoder.d.ts +151 -0
- package/dist_ts/formats/ubl/generic/ubl.encoder.js +892 -0
- package/dist_ts/formats/ubl/ubl.decoder.d.ts +61 -0
- package/dist_ts/formats/ubl/ubl.decoder.js +95 -0
- package/dist_ts/formats/ubl/ubl.encoder.d.ts +38 -0
- package/dist_ts/formats/ubl/ubl.encoder.js +46 -0
- package/dist_ts/formats/ubl/ubl.types.d.ts +16 -0
- package/dist_ts/formats/ubl/ubl.types.js +21 -0
- package/dist_ts/formats/ubl/ubl.validator.d.ts +50 -0
- package/dist_ts/formats/ubl/ubl.validator.js +112 -0
- package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.d.ts +34 -0
- package/dist_ts/formats/ubl/xrechnung/xrechnung.decoder.js +424 -0
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.d.ts +75 -0
- package/dist_ts/formats/ubl/xrechnung/xrechnung.encoder.js +555 -0
- package/dist_ts/formats/ubl/xrechnung.validator.d.ts +15 -0
- package/dist_ts/formats/ubl/xrechnung.validator.js +107 -0
- package/dist_ts/formats/ubl.validator.d.ts +82 -0
- package/dist_ts/formats/ubl.validator.js +306 -0
- package/dist_ts/formats/utils/format.detector.d.ts +62 -0
- package/dist_ts/formats/utils/format.detector.js +249 -0
- package/dist_ts/formats/validation/en16931.validator.d.ts +23 -0
- package/dist_ts/formats/validation/en16931.validator.js +119 -0
- package/dist_ts/formats/validator.factory.d.ts +18 -0
- package/dist_ts/formats/validator.factory.js +78 -0
- package/dist_ts/formats/xinvoice.decoder.d.ts +28 -0
- package/dist_ts/formats/xinvoice.decoder.js +332 -0
- package/dist_ts/formats/xinvoice.encoder.d.ts +19 -0
- package/dist_ts/formats/xinvoice.encoder.js +282 -0
- package/dist_ts/index.d.ts +51 -0
- package/dist_ts/index.js +90 -0
- package/dist_ts/interfaces/common.d.ts +79 -0
- package/dist_ts/interfaces/common.js +24 -0
- package/dist_ts/interfaces.d.ts +87 -0
- package/dist_ts/interfaces.js +23 -0
- package/dist_ts/plugins.d.ts +14 -0
- package/dist_ts/plugins.js +31 -0
- package/npmextra.json +35 -0
- package/package.json +71 -0
- package/readme.hints.md +1107 -0
- package/readme.howtofixtests.md +38 -0
- package/readme.literature.md +1 -0
- package/readme.md +998 -0
- package/readme.plan.md +481 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/einvoice.ts +603 -0
- package/ts/errors.ts +341 -0
- package/ts/formats/base/base.decoder.ts +68 -0
- package/ts/formats/base/base.encoder.ts +14 -0
- package/ts/formats/base/base.validator.ts +64 -0
- package/ts/formats/cii/cii.decoder.ts +139 -0
- package/ts/formats/cii/cii.encoder.ts +64 -0
- package/ts/formats/cii/cii.types.ts +44 -0
- package/ts/formats/cii/cii.validator.ts +171 -0
- package/ts/formats/cii/facturx/facturx.decoder.ts +243 -0
- package/ts/formats/cii/facturx/facturx.encoder.ts +483 -0
- package/ts/formats/cii/facturx/facturx.types.ts +18 -0
- package/ts/formats/cii/facturx/facturx.validator.ts +180 -0
- package/ts/formats/cii/zugferd/zugferd.decoder.ts +256 -0
- package/ts/formats/cii/zugferd/zugferd.encoder.ts +661 -0
- package/ts/formats/cii/zugferd/zugferd.types.ts +18 -0
- package/ts/formats/cii/zugferd/zugferd.v1.decoder.ts +267 -0
- package/ts/formats/cii/zugferd/zugferd.validator.ts +31 -0
- package/ts/formats/factories/decoder.factory.ts +62 -0
- package/ts/formats/factories/encoder.factory.ts +47 -0
- package/ts/formats/factories/validator.factory.ts +134 -0
- package/ts/formats/pdf/extractors/associated.extractor.ts +78 -0
- package/ts/formats/pdf/extractors/base.extractor.ts +355 -0
- package/ts/formats/pdf/extractors/index.ts +4 -0
- package/ts/formats/pdf/extractors/standard.extractor.ts +86 -0
- package/ts/formats/pdf/extractors/text.extractor.ts +162 -0
- package/ts/formats/pdf/pdf.embedder.ts +242 -0
- package/ts/formats/pdf/pdf.extractor.ts +141 -0
- package/ts/formats/ubl/en16931.ubl.validator.ts +216 -0
- package/ts/formats/ubl/generic/ubl.encoder.ts +1041 -0
- package/ts/formats/ubl/ubl.decoder.ts +121 -0
- package/ts/formats/ubl/ubl.encoder.ts +63 -0
- package/ts/formats/ubl/ubl.types.ts +22 -0
- package/ts/formats/ubl/ubl.validator.ts +133 -0
- package/ts/formats/ubl/xrechnung/xrechnung.decoder.ts +471 -0
- package/ts/formats/ubl/xrechnung/xrechnung.encoder.ts +619 -0
- package/ts/formats/ubl/xrechnung.validator.ts +185 -0
- package/ts/formats/utils/format.detector.ts +306 -0
- package/ts/formats/validation/en16931.validator.ts +135 -0
- package/ts/index.ts +164 -0
- package/ts/interfaces/common.ts +90 -0
- package/ts/interfaces.ts +98 -0
- package/ts/plugins.ts +61 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseXMLExtractor } from './base.extractor.js';
|
|
2
|
+
/**
|
|
3
|
+
* Associated files extractor for PDF/A-3 documents
|
|
4
|
+
* Extracts XML from associated files (AF entry in the catalog)
|
|
5
|
+
* Particularly useful for ZUGFeRD v1 and some Factur-X documents
|
|
6
|
+
*/
|
|
7
|
+
export declare class AssociatedFilesExtractor extends BaseXMLExtractor {
|
|
8
|
+
/**
|
|
9
|
+
* Extract XML from a PDF buffer using associated files
|
|
10
|
+
* @param pdfBuffer PDF buffer
|
|
11
|
+
* @returns XML content or null if not found
|
|
12
|
+
*/
|
|
13
|
+
extractXml(pdfBuffer: Uint8Array | Buffer): Promise<string | null>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { PDFDocument, PDFDict, PDFName, PDFRawStream, PDFArray, PDFString } from '../../../plugins.js';
|
|
2
|
+
import { BaseXMLExtractor } from './base.extractor.js';
|
|
3
|
+
/**
|
|
4
|
+
* Associated files extractor for PDF/A-3 documents
|
|
5
|
+
* Extracts XML from associated files (AF entry in the catalog)
|
|
6
|
+
* Particularly useful for ZUGFeRD v1 and some Factur-X documents
|
|
7
|
+
*/
|
|
8
|
+
export class AssociatedFilesExtractor extends BaseXMLExtractor {
|
|
9
|
+
/**
|
|
10
|
+
* Extract XML from a PDF buffer using associated files
|
|
11
|
+
* @param pdfBuffer PDF buffer
|
|
12
|
+
* @returns XML content or null if not found
|
|
13
|
+
*/
|
|
14
|
+
async extractXml(pdfBuffer) {
|
|
15
|
+
try {
|
|
16
|
+
const pdfDoc = await PDFDocument.load(pdfBuffer);
|
|
17
|
+
// Try to find associated files via the AF entry in the catalog
|
|
18
|
+
const afArray = pdfDoc.catalog.lookup(PDFName.of('AF'));
|
|
19
|
+
if (!(afArray instanceof PDFArray)) {
|
|
20
|
+
console.warn('No AF (Associated Files) entry found in PDF catalog');
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
// Process each associated file
|
|
24
|
+
for (let i = 0; i < afArray.size(); i++) {
|
|
25
|
+
const fileSpec = afArray.lookup(i);
|
|
26
|
+
if (!(fileSpec instanceof PDFDict)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
// Get the file name
|
|
30
|
+
const fileNameObj = fileSpec.lookup(PDFName.of('F')) || fileSpec.lookup(PDFName.of('UF'));
|
|
31
|
+
if (!(fileNameObj instanceof PDFString)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const fileName = fileNameObj.decodeText();
|
|
35
|
+
// Check if it's a known invoice XML file name
|
|
36
|
+
const isKnownFileName = this.knownFileNames.some(knownName => fileName.toLowerCase() === knownName.toLowerCase());
|
|
37
|
+
// Check if it's any XML file or has invoice-related keywords
|
|
38
|
+
const isXmlFile = fileName.toLowerCase().endsWith('.xml') ||
|
|
39
|
+
fileName.toLowerCase().includes('zugferd') ||
|
|
40
|
+
fileName.toLowerCase().includes('factur-x') ||
|
|
41
|
+
fileName.toLowerCase().includes('xrechnung') ||
|
|
42
|
+
fileName.toLowerCase().includes('invoice');
|
|
43
|
+
if (isKnownFileName || isXmlFile) {
|
|
44
|
+
// Get the embedded file dictionary
|
|
45
|
+
const efDict = fileSpec.lookup(PDFName.of('EF'));
|
|
46
|
+
if (!(efDict instanceof PDFDict)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
// Get the file stream
|
|
50
|
+
const fileStream = efDict.lookup(PDFName.of('F'));
|
|
51
|
+
if (fileStream instanceof PDFRawStream) {
|
|
52
|
+
const xmlContent = await this.extractXmlFromStream(fileStream, fileName);
|
|
53
|
+
if (xmlContent) {
|
|
54
|
+
return xmlContent;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
console.warn('No valid XML found in associated files');
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error('Error in associated files extraction:', error);
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzb2NpYXRlZC5leHRyYWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9mb3JtYXRzL3BkZi9leHRyYWN0b3JzL2Fzc29jaWF0ZWQuZXh0cmFjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ3ZHLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRXZEOzs7O0dBSUc7QUFDSCxNQUFNLE9BQU8sd0JBQXlCLFNBQVEsZ0JBQWdCO0lBQzVEOzs7O09BSUc7SUFDSSxLQUFLLENBQUMsVUFBVSxDQUFDLFNBQThCO1FBQ3BELElBQUksQ0FBQztZQUNILE1BQU0sTUFBTSxHQUFHLE1BQU0sV0FBVyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUVqRCwrREFBK0Q7WUFDL0QsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQ3hELElBQUksQ0FBQyxDQUFDLE9BQU8sWUFBWSxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUNuQyxPQUFPLENBQUMsSUFBSSxDQUFDLHFEQUFxRCxDQUFDLENBQUM7Z0JBQ3BFLE9BQU8sSUFBSSxDQUFDO1lBQ2QsQ0FBQztZQUVELCtCQUErQjtZQUMvQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7Z0JBQ3hDLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ25DLElBQUksQ0FBQyxDQUFDLFFBQVEsWUFBWSxPQUFPLENBQUMsRUFBRSxDQUFDO29CQUNuQyxTQUFTO2dCQUNYLENBQUM7Z0JBRUQsb0JBQW9CO2dCQUNwQixNQUFNLFdBQVcsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxRQUFRLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztnQkFDMUYsSUFBSSxDQUFDLENBQUMsV0FBVyxZQUFZLFNBQVMsQ0FBQyxFQUFFLENBQUM7b0JBQ3hDLFNBQVM7Z0JBQ1gsQ0FBQztnQkFFRCxNQUFNLFFBQVEsR0FBRyxXQUFXLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBRTFDLDhDQUE4QztnQkFDOUMsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQzlDLFNBQVMsQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxLQUFLLFNBQVMsQ0FBQyxXQUFXLEVBQUUsQ0FDaEUsQ0FBQztnQkFFRiw2REFBNkQ7Z0JBQzdELE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDO29CQUN2QyxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztvQkFDMUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUM7b0JBQzNDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDO29CQUM1QyxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO2dCQUU3RCxJQUFJLGVBQWUsSUFBSSxTQUFTLEVBQUUsQ0FBQztvQkFDakMsbUNBQW1DO29CQUNuQyxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztvQkFDakQsSUFBSSxDQUFDLENBQUMsTUFBTSxZQUFZLE9BQU8sQ0FBQyxFQUFFLENBQUM7d0JBQ2pDLFNBQVM7b0JBQ1gsQ0FBQztvQkFFRCxzQkFBc0I7b0JBQ3RCLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO29CQUNsRCxJQUFJLFVBQVUsWUFBWSxZQUFZLEVBQUUsQ0FBQzt3QkFDdkMsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUMsVUFBVSxFQUFFLFFBQVEsQ0FBQyxDQUFDO3dCQUN6RSxJQUFJLFVBQVUsRUFBRSxDQUFDOzRCQUNmLE9BQU8sVUFBVSxDQUFDO3dCQUNwQixDQUFDO29CQUNILENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7WUFFRCxPQUFPLENBQUMsSUFBSSxDQUFDLHdDQUF3QyxDQUFDLENBQUM7WUFDdkQsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsdUNBQXVDLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDOUQsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztDQUNGIn0=
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { PDFRawStream } from '../../../plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Base class for PDF XML extractors with common functionality
|
|
4
|
+
*/
|
|
5
|
+
export declare abstract class BaseXMLExtractor {
|
|
6
|
+
/**
|
|
7
|
+
* Known XML file names for different invoice formats
|
|
8
|
+
*/
|
|
9
|
+
protected readonly knownFileNames: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Known XML formats to validate extracted content
|
|
12
|
+
*/
|
|
13
|
+
protected readonly knownFormats: string[];
|
|
14
|
+
/**
|
|
15
|
+
* Known XML end tags for extracting content from strings
|
|
16
|
+
*/
|
|
17
|
+
protected readonly knownEndTags: string[];
|
|
18
|
+
/**
|
|
19
|
+
* Extract XML from a PDF buffer
|
|
20
|
+
* @param pdfBuffer PDF buffer
|
|
21
|
+
* @returns XML content or null if not found
|
|
22
|
+
*/
|
|
23
|
+
abstract extractXml(pdfBuffer: Uint8Array | Buffer): Promise<string | null>;
|
|
24
|
+
/**
|
|
25
|
+
* Check if an XML string is valid
|
|
26
|
+
* @param xmlString XML string to check
|
|
27
|
+
* @returns True if the XML is valid
|
|
28
|
+
*/
|
|
29
|
+
protected isValidXml(xmlString: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Check if the XML string contains a known element
|
|
32
|
+
* @param xmlString XML string to check
|
|
33
|
+
* @returns True if the XML contains a known element
|
|
34
|
+
*/
|
|
35
|
+
protected hasKnownXmlElement(xmlString: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Check if the XML string contains a known format
|
|
38
|
+
* @param xmlString XML string to check
|
|
39
|
+
* @returns True if the XML contains a known format
|
|
40
|
+
*/
|
|
41
|
+
protected hasKnownFormat(xmlString: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Check if the XML string has a proper structure
|
|
44
|
+
* @param xmlString XML string to check
|
|
45
|
+
* @returns True if the XML has a proper structure
|
|
46
|
+
*/
|
|
47
|
+
protected hasProperXmlStructure(xmlString: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Check if the XML string contains binary data
|
|
50
|
+
* @param xmlString XML string to check
|
|
51
|
+
* @returns True if the XML contains binary data
|
|
52
|
+
*/
|
|
53
|
+
protected hasBinaryData(xmlString: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Extract XML from a string
|
|
56
|
+
* @param text Text to extract XML from
|
|
57
|
+
* @param startIndex Index to start extraction from
|
|
58
|
+
* @returns XML content or null if not found
|
|
59
|
+
*/
|
|
60
|
+
protected extractXmlFromString(text: string, startIndex?: number): string | null;
|
|
61
|
+
/**
|
|
62
|
+
* Decompress and decode XML content from a PDF stream
|
|
63
|
+
* @param stream PDF stream containing XML data
|
|
64
|
+
* @param fileName Name of the file (for logging)
|
|
65
|
+
* @returns XML content or null if not valid
|
|
66
|
+
*/
|
|
67
|
+
protected extractXmlFromStream(stream: PDFRawStream, fileName: string): Promise<string | null>;
|
|
68
|
+
/**
|
|
69
|
+
* Try to decompress a buffer using different methods
|
|
70
|
+
* @param buffer Buffer to decompress
|
|
71
|
+
* @returns Decompressed buffer or null if decompression failed
|
|
72
|
+
*/
|
|
73
|
+
protected tryDecompress(buffer: Uint8Array): Uint8Array | null;
|
|
74
|
+
/**
|
|
75
|
+
* Try to decode a buffer to a string using different encodings
|
|
76
|
+
* @param buffer Buffer to decode
|
|
77
|
+
* @returns Decoded string or null if decoding failed
|
|
78
|
+
*/
|
|
79
|
+
protected tryDecodeBuffer(buffer: Uint8Array): string | null;
|
|
80
|
+
/**
|
|
81
|
+
* Decode a buffer using ISO-8859-1 (Latin1) encoding
|
|
82
|
+
* @param buffer Buffer to decode
|
|
83
|
+
* @returns Decoded string
|
|
84
|
+
*/
|
|
85
|
+
protected decodeLatin1(buffer: Uint8Array): string;
|
|
86
|
+
/**
|
|
87
|
+
* Check if a string is plausibly XML (quick check before validation)
|
|
88
|
+
* @param content String to check
|
|
89
|
+
* @returns True if the string is plausibly XML
|
|
90
|
+
*/
|
|
91
|
+
protected isPlausibleXml(content: string): boolean;
|
|
92
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { PDFDocument, PDFDict, PDFName, PDFRawStream, PDFArray, PDFString, pako } from '../../../plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Base class for PDF XML extractors with common functionality
|
|
4
|
+
*/
|
|
5
|
+
export class BaseXMLExtractor {
|
|
6
|
+
constructor() {
|
|
7
|
+
/**
|
|
8
|
+
* Known XML file names for different invoice formats
|
|
9
|
+
*/
|
|
10
|
+
this.knownFileNames = [
|
|
11
|
+
'factur-x.xml',
|
|
12
|
+
'zugferd-invoice.xml',
|
|
13
|
+
'ZUGFeRD-invoice.xml',
|
|
14
|
+
'xrechnung.xml',
|
|
15
|
+
'ubl-invoice.xml',
|
|
16
|
+
'invoice.xml',
|
|
17
|
+
'metadata.xml'
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Known XML formats to validate extracted content
|
|
21
|
+
*/
|
|
22
|
+
this.knownFormats = [
|
|
23
|
+
'CrossIndustryInvoice',
|
|
24
|
+
'CrossIndustryDocument',
|
|
25
|
+
'Invoice',
|
|
26
|
+
'CreditNote',
|
|
27
|
+
'ubl:Invoice',
|
|
28
|
+
'ubl:CreditNote',
|
|
29
|
+
'rsm:CrossIndustryInvoice',
|
|
30
|
+
'rsm:CrossIndustryDocument',
|
|
31
|
+
'ram:CrossIndustryDocument',
|
|
32
|
+
'urn:un:unece:uncefact',
|
|
33
|
+
'urn:ferd:CrossIndustryDocument',
|
|
34
|
+
'urn:zugferd',
|
|
35
|
+
'urn:factur-x',
|
|
36
|
+
'factur-x.eu',
|
|
37
|
+
'ZUGFeRD',
|
|
38
|
+
'FatturaElettronica'
|
|
39
|
+
];
|
|
40
|
+
/**
|
|
41
|
+
* Known XML end tags for extracting content from strings
|
|
42
|
+
*/
|
|
43
|
+
this.knownEndTags = [
|
|
44
|
+
'</CrossIndustryInvoice>',
|
|
45
|
+
'</CrossIndustryDocument>',
|
|
46
|
+
'</Invoice>',
|
|
47
|
+
'</CreditNote>',
|
|
48
|
+
'</rsm:CrossIndustryInvoice>',
|
|
49
|
+
'</rsm:CrossIndustryDocument>',
|
|
50
|
+
'</ram:CrossIndustryDocument>',
|
|
51
|
+
'</ubl:Invoice>',
|
|
52
|
+
'</ubl:CreditNote>',
|
|
53
|
+
'</FatturaElettronica>'
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if an XML string is valid
|
|
58
|
+
* @param xmlString XML string to check
|
|
59
|
+
* @returns True if the XML is valid
|
|
60
|
+
*/
|
|
61
|
+
isValidXml(xmlString) {
|
|
62
|
+
try {
|
|
63
|
+
// Basic checks for XML validity
|
|
64
|
+
if (!xmlString || typeof xmlString !== 'string') {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
// Check if it starts with XML declaration or a valid element
|
|
68
|
+
if (!xmlString.includes('<?xml') && !this.hasKnownXmlElement(xmlString)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
// Check if the XML string contains known invoice formats
|
|
72
|
+
const hasKnownFormat = this.hasKnownFormat(xmlString);
|
|
73
|
+
if (!hasKnownFormat) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
// Check if the XML string contains binary data or invalid characters
|
|
77
|
+
if (this.hasBinaryData(xmlString)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
// Check if the XML string is too short
|
|
81
|
+
if (xmlString.length < 100) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
// Check if XML has a proper structure (contains both opening and closing tags)
|
|
85
|
+
if (!this.hasProperXmlStructure(xmlString)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
console.error('Error validating XML:', error);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Check if the XML string contains a known element
|
|
97
|
+
* @param xmlString XML string to check
|
|
98
|
+
* @returns True if the XML contains a known element
|
|
99
|
+
*/
|
|
100
|
+
hasKnownXmlElement(xmlString) {
|
|
101
|
+
for (const format of this.knownFormats) {
|
|
102
|
+
// Check for opening tag of format
|
|
103
|
+
if (xmlString.includes(`<${format}`)) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if the XML string contains a known format
|
|
111
|
+
* @param xmlString XML string to check
|
|
112
|
+
* @returns True if the XML contains a known format
|
|
113
|
+
*/
|
|
114
|
+
hasKnownFormat(xmlString) {
|
|
115
|
+
for (const format of this.knownFormats) {
|
|
116
|
+
if (xmlString.includes(format)) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Check if the XML string has a proper structure
|
|
124
|
+
* @param xmlString XML string to check
|
|
125
|
+
* @returns True if the XML has a proper structure
|
|
126
|
+
*/
|
|
127
|
+
hasProperXmlStructure(xmlString) {
|
|
128
|
+
// Check for at least one matching opening and closing tag
|
|
129
|
+
for (const endTag of this.knownEndTags) {
|
|
130
|
+
const startTag = endTag.replace('/', '');
|
|
131
|
+
if (xmlString.includes(startTag) && xmlString.includes(endTag)) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// If no specific tag is found but it has a basic XML structure
|
|
136
|
+
return ((xmlString.includes('<?xml') && xmlString.includes('?>')) ||
|
|
137
|
+
(xmlString.match(/<[^>]+>/) !== null && xmlString.match(/<\/[^>]+>/) !== null));
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Check if the XML string contains binary data
|
|
141
|
+
* @param xmlString XML string to check
|
|
142
|
+
* @returns True if the XML contains binary data
|
|
143
|
+
*/
|
|
144
|
+
hasBinaryData(xmlString) {
|
|
145
|
+
// Check for common binary data indicators
|
|
146
|
+
const binaryChars = ['\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005'];
|
|
147
|
+
const consecutiveNulls = '\u0000\u0000\u0000';
|
|
148
|
+
// Check for control characters that shouldn't be in XML
|
|
149
|
+
if (binaryChars.some(char => xmlString.includes(char))) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
// Check for consecutive null bytes which indicate binary data
|
|
153
|
+
if (xmlString.includes(consecutiveNulls)) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
// Check for high concentration of non-printable characters
|
|
157
|
+
const nonPrintableCount = (xmlString.match(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g) || []).length;
|
|
158
|
+
if (nonPrintableCount > xmlString.length * 0.05) { // More than 5% non-printable
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Extract XML from a string
|
|
165
|
+
* @param text Text to extract XML from
|
|
166
|
+
* @param startIndex Index to start extraction from
|
|
167
|
+
* @returns XML content or null if not found
|
|
168
|
+
*/
|
|
169
|
+
extractXmlFromString(text, startIndex = 0) {
|
|
170
|
+
try {
|
|
171
|
+
// Find the start of the XML document
|
|
172
|
+
let xmlStartIndex = text.indexOf('<?xml', startIndex);
|
|
173
|
+
// If no XML declaration, try to find known elements
|
|
174
|
+
if (xmlStartIndex === -1) {
|
|
175
|
+
for (const format of this.knownFormats) {
|
|
176
|
+
const formatStartIndex = text.indexOf(`<${format.split(':').pop()}`, startIndex);
|
|
177
|
+
if (formatStartIndex !== -1) {
|
|
178
|
+
xmlStartIndex = formatStartIndex;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// Still didn't find any start marker
|
|
183
|
+
if (xmlStartIndex === -1) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Try to find the end of the XML document
|
|
188
|
+
let xmlEndIndex = -1;
|
|
189
|
+
for (const endTag of this.knownEndTags) {
|
|
190
|
+
const endIndex = text.indexOf(endTag, xmlStartIndex);
|
|
191
|
+
if (endIndex !== -1) {
|
|
192
|
+
xmlEndIndex = endIndex + endTag.length;
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// If no known end tag found, try to use a heuristic approach
|
|
197
|
+
if (xmlEndIndex === -1) {
|
|
198
|
+
// Try to find the last closing tag
|
|
199
|
+
const lastClosingTagMatch = text.slice(xmlStartIndex).match(/<\/[^>]+>(?!.*<\/[^>]+>)/);
|
|
200
|
+
if (lastClosingTagMatch && lastClosingTagMatch.index !== undefined) {
|
|
201
|
+
xmlEndIndex = xmlStartIndex + lastClosingTagMatch.index + lastClosingTagMatch[0].length;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Extract the XML content
|
|
208
|
+
const xmlContent = text.substring(xmlStartIndex, xmlEndIndex);
|
|
209
|
+
// Validate the extracted content
|
|
210
|
+
if (this.isValidXml(xmlContent)) {
|
|
211
|
+
return xmlContent;
|
|
212
|
+
}
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
console.error('Error extracting XML from string:', error);
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Decompress and decode XML content from a PDF stream
|
|
222
|
+
* @param stream PDF stream containing XML data
|
|
223
|
+
* @param fileName Name of the file (for logging)
|
|
224
|
+
* @returns XML content or null if not valid
|
|
225
|
+
*/
|
|
226
|
+
async extractXmlFromStream(stream, fileName) {
|
|
227
|
+
try {
|
|
228
|
+
// Get the raw bytes from the stream
|
|
229
|
+
const rawBytes = stream.getContents();
|
|
230
|
+
// First try without decompression (in case the content is not compressed)
|
|
231
|
+
let xmlContent = this.tryDecodeBuffer(rawBytes);
|
|
232
|
+
if (xmlContent && this.isValidXml(xmlContent)) {
|
|
233
|
+
console.log(`Successfully extracted uncompressed XML from PDF file. File name: ${fileName}`);
|
|
234
|
+
return xmlContent;
|
|
235
|
+
}
|
|
236
|
+
// Try with decompression
|
|
237
|
+
try {
|
|
238
|
+
const decompressedBytes = this.tryDecompress(rawBytes);
|
|
239
|
+
if (decompressedBytes) {
|
|
240
|
+
xmlContent = this.tryDecodeBuffer(decompressedBytes);
|
|
241
|
+
if (xmlContent && this.isValidXml(xmlContent)) {
|
|
242
|
+
console.log(`Successfully extracted decompressed XML from PDF file. File name: ${fileName}`);
|
|
243
|
+
return xmlContent;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
catch (decompressError) {
|
|
248
|
+
console.log(`Decompression failed for ${fileName}: ${decompressError}`);
|
|
249
|
+
}
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
console.error('Error extracting XML from stream:', error);
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Try to decompress a buffer using different methods
|
|
259
|
+
* @param buffer Buffer to decompress
|
|
260
|
+
* @returns Decompressed buffer or null if decompression failed
|
|
261
|
+
*/
|
|
262
|
+
tryDecompress(buffer) {
|
|
263
|
+
try {
|
|
264
|
+
// Try pako inflate (for deflate/zlib compression)
|
|
265
|
+
return pako.inflate(buffer);
|
|
266
|
+
}
|
|
267
|
+
catch (error) {
|
|
268
|
+
// If pako fails, try other methods if needed
|
|
269
|
+
console.warn('Pako decompression failed, might be uncompressed or using a different algorithm');
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Try to decode a buffer to a string using different encodings
|
|
275
|
+
* @param buffer Buffer to decode
|
|
276
|
+
* @returns Decoded string or null if decoding failed
|
|
277
|
+
*/
|
|
278
|
+
tryDecodeBuffer(buffer) {
|
|
279
|
+
try {
|
|
280
|
+
// Try UTF-8 first
|
|
281
|
+
let content = new TextDecoder('utf-8').decode(buffer);
|
|
282
|
+
if (this.isPlausibleXml(content)) {
|
|
283
|
+
return content;
|
|
284
|
+
}
|
|
285
|
+
// Try ISO-8859-1 (Latin1)
|
|
286
|
+
content = this.decodeLatin1(buffer);
|
|
287
|
+
if (this.isPlausibleXml(content)) {
|
|
288
|
+
return content;
|
|
289
|
+
}
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
catch (error) {
|
|
293
|
+
console.warn('Error decoding buffer:', error);
|
|
294
|
+
return null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Decode a buffer using ISO-8859-1 (Latin1) encoding
|
|
299
|
+
* @param buffer Buffer to decode
|
|
300
|
+
* @returns Decoded string
|
|
301
|
+
*/
|
|
302
|
+
decodeLatin1(buffer) {
|
|
303
|
+
return Array.from(buffer)
|
|
304
|
+
.map(byte => String.fromCharCode(byte))
|
|
305
|
+
.join('');
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Check if a string is plausibly XML (quick check before validation)
|
|
309
|
+
* @param content String to check
|
|
310
|
+
* @returns True if the string is plausibly XML
|
|
311
|
+
*/
|
|
312
|
+
isPlausibleXml(content) {
|
|
313
|
+
return content.includes('<') &&
|
|
314
|
+
content.includes('>') &&
|
|
315
|
+
(content.includes('<?xml') ||
|
|
316
|
+
this.knownFormats.some(format => content.includes(format)));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS5leHRyYWN0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9mb3JtYXRzL3BkZi9leHRyYWN0b3JzL2Jhc2UuZXh0cmFjdG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxXQUFXLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUU3Rzs7R0FFRztBQUNILE1BQU0sT0FBZ0IsZ0JBQWdCO0lBQXRDO1FBQ0U7O1dBRUc7UUFDZ0IsbUJBQWMsR0FBRztZQUNsQyxjQUFjO1lBQ2QscUJBQXFCO1lBQ3JCLHFCQUFxQjtZQUNyQixlQUFlO1lBQ2YsaUJBQWlCO1lBQ2pCLGFBQWE7WUFDYixjQUFjO1NBQ2YsQ0FBQztRQUVGOztXQUVHO1FBQ2dCLGlCQUFZLEdBQUc7WUFDaEMsc0JBQXNCO1lBQ3RCLHVCQUF1QjtZQUN2QixTQUFTO1lBQ1QsWUFBWTtZQUNaLGFBQWE7WUFDYixnQkFBZ0I7WUFDaEIsMEJBQTBCO1lBQzFCLDJCQUEyQjtZQUMzQiwyQkFBMkI7WUFDM0IsdUJBQXVCO1lBQ3ZCLGdDQUFnQztZQUNoQyxhQUFhO1lBQ2IsY0FBYztZQUNkLGFBQWE7WUFDYixTQUFTO1lBQ1Qsb0JBQW9CO1NBQ3JCLENBQUM7UUFFRjs7V0FFRztRQUNnQixpQkFBWSxHQUFHO1lBQ2hDLHlCQUF5QjtZQUN6QiwwQkFBMEI7WUFDMUIsWUFBWTtZQUNaLGVBQWU7WUFDZiw2QkFBNkI7WUFDN0IsOEJBQThCO1lBQzlCLDhCQUE4QjtZQUM5QixnQkFBZ0I7WUFDaEIsbUJBQW1CO1lBQ25CLHVCQUF1QjtTQUN4QixDQUFDO0lBMlNKLENBQUM7SUFsU0M7Ozs7T0FJRztJQUNPLFVBQVUsQ0FBQyxTQUFpQjtRQUNwQyxJQUFJLENBQUM7WUFDSCxnQ0FBZ0M7WUFDaEMsSUFBSSxDQUFDLFNBQVMsSUFBSSxP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
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './base.extractor.js';
|
|
2
|
+
export * from './standard.extractor.js';
|
|
3
|
+
export * from './associated.extractor.js';
|
|
4
|
+
export * from './text.extractor.js';
|
|
5
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi90cy9mb3JtYXRzL3BkZi9leHRyYWN0b3JzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGNBQWMscUJBQXFCLENBQUM7QUFDcEMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLDJCQUEyQixDQUFDO0FBQzFDLGNBQWMscUJBQXFCLENBQUMifQ==
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BaseXMLExtractor } from './base.extractor.js';
|
|
2
|
+
/**
|
|
3
|
+
* Standard PDF XML extractor that extracts XML from embedded files
|
|
4
|
+
* Works with PDF/A-3 documents that follow the standard for embedding files
|
|
5
|
+
*/
|
|
6
|
+
export declare class StandardXMLExtractor extends BaseXMLExtractor {
|
|
7
|
+
/**
|
|
8
|
+
* Extract XML from a PDF buffer using standard PDF/A-3 embedded files
|
|
9
|
+
* @param pdfBuffer PDF buffer
|
|
10
|
+
* @returns XML content or null if not found
|
|
11
|
+
*/
|
|
12
|
+
extractXml(pdfBuffer: Uint8Array | Buffer): Promise<string | null>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { PDFDocument, PDFDict, PDFName, PDFRawStream, PDFArray, PDFString } from '../../../plugins.js';
|
|
2
|
+
import { BaseXMLExtractor } from './base.extractor.js';
|
|
3
|
+
/**
|
|
4
|
+
* Standard PDF XML extractor that extracts XML from embedded files
|
|
5
|
+
* Works with PDF/A-3 documents that follow the standard for embedding files
|
|
6
|
+
*/
|
|
7
|
+
export class StandardXMLExtractor extends BaseXMLExtractor {
|
|
8
|
+
/**
|
|
9
|
+
* Extract XML from a PDF buffer using standard PDF/A-3 embedded files
|
|
10
|
+
* @param pdfBuffer PDF buffer
|
|
11
|
+
* @returns XML content or null if not found
|
|
12
|
+
*/
|
|
13
|
+
async extractXml(pdfBuffer) {
|
|
14
|
+
try {
|
|
15
|
+
const pdfDoc = await PDFDocument.load(pdfBuffer);
|
|
16
|
+
// Get the document's metadata dictionary
|
|
17
|
+
const namesDictObj = pdfDoc.catalog.lookup(PDFName.of('Names'));
|
|
18
|
+
if (!(namesDictObj instanceof PDFDict)) {
|
|
19
|
+
console.warn('No Names dictionary found in PDF! This PDF does not contain embedded files.');
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
// Get the embedded files dictionary
|
|
23
|
+
const embeddedFilesDictObj = namesDictObj.lookup(PDFName.of('EmbeddedFiles'));
|
|
24
|
+
if (!(embeddedFilesDictObj instanceof PDFDict)) {
|
|
25
|
+
console.warn('No EmbeddedFiles dictionary found! This PDF does not contain embedded files.');
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
// Get the names array
|
|
29
|
+
const filesSpecObj = embeddedFilesDictObj.lookup(PDFName.of('Names'));
|
|
30
|
+
if (!(filesSpecObj instanceof PDFArray)) {
|
|
31
|
+
console.warn('No files specified in EmbeddedFiles dictionary!');
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
// Try to find an XML file in the embedded files
|
|
35
|
+
for (let i = 0; i < filesSpecObj.size(); i += 2) {
|
|
36
|
+
const fileNameObj = filesSpecObj.lookup(i);
|
|
37
|
+
const fileSpecObj = filesSpecObj.lookup(i + 1);
|
|
38
|
+
if (!(fileNameObj instanceof PDFString) || !(fileSpecObj instanceof PDFDict)) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// Get the filename as string
|
|
42
|
+
const fileName = fileNameObj.decodeText();
|
|
43
|
+
// Check if it's a known invoice XML file name
|
|
44
|
+
const isKnownFileName = this.knownFileNames.some(knownName => fileName.toLowerCase() === knownName.toLowerCase());
|
|
45
|
+
// Check if it's any XML file or has invoice-related keywords
|
|
46
|
+
const isXmlFile = fileName.toLowerCase().endsWith('.xml') ||
|
|
47
|
+
fileName.toLowerCase().includes('zugferd') ||
|
|
48
|
+
fileName.toLowerCase().includes('factur-x') ||
|
|
49
|
+
fileName.toLowerCase().includes('xrechnung') ||
|
|
50
|
+
fileName.toLowerCase().includes('invoice');
|
|
51
|
+
if (isKnownFileName || isXmlFile) {
|
|
52
|
+
const efDictObj = fileSpecObj.lookup(PDFName.of('EF'));
|
|
53
|
+
if (!(efDictObj instanceof PDFDict)) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const fileStream = efDictObj.lookup(PDFName.of('F'));
|
|
57
|
+
if (fileStream instanceof PDFRawStream) {
|
|
58
|
+
const xmlContent = await this.extractXmlFromStream(fileStream, fileName);
|
|
59
|
+
if (xmlContent) {
|
|
60
|
+
return xmlContent;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
console.warn('No valid XML found in embedded files');
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
console.error('Error in standard extraction:', error);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhbmRhcmQuZXh0cmFjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vdHMvZm9ybWF0cy9wZGYvZXh0cmFjdG9ycy9zdGFuZGFyZC5leHRyYWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFdBQVcsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDdkcsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFdkQ7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLG9CQUFxQixTQUFRLGdCQUFnQjtJQUN4RDs7OztPQUlHO0lBQ0ksS0FBSyxDQUFDLFVBQVUsQ0FBQyxTQUE4QjtRQUNwRCxJQUFJLENBQUM7WUFDSCxNQUFNLE1BQU0sR0FBRyxNQUFNLFdBQVcsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7WUFFakQseUNBQXlDO1lBQ3pDLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztZQUNoRSxJQUFJLENBQUMsQ0FBQyxZQUFZLFlBQVksT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDdkMsT0FBTyxDQUFDLElBQUksQ0FBQyw2RUFBNkUsQ0FBQyxDQUFDO2dCQUM1RixPQUFPLElBQUksQ0FBQztZQUNkLENBQUM7WUFFRCxvQ0FBb0M7WUFDcEMsTUFBTSxvQkFBb0IsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQztZQUM5RSxJQUFJLENBQUMsQ0FBQyxvQkFBb0IsWUFBWSxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUMvQyxPQUFPLENBQUMsSUFBSSxDQUFDLDhFQUE4RSxDQUFDLENBQUM7Z0JBQzdGLE9BQU8sSUFB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
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BaseXMLExtractor } from './base.extractor.js';
|
|
2
|
+
/**
|
|
3
|
+
* Text-based XML extractor for PDF documents
|
|
4
|
+
* Extracts XML by searching for XML patterns in the PDF text
|
|
5
|
+
* Used as a fallback when other extraction methods fail
|
|
6
|
+
*/
|
|
7
|
+
export declare class TextXMLExtractor extends BaseXMLExtractor {
|
|
8
|
+
private readonly CHUNK_SIZE;
|
|
9
|
+
private readonly MAX_CHUNKS;
|
|
10
|
+
private readonly XML_PATTERNS;
|
|
11
|
+
/**
|
|
12
|
+
* Extract XML from a PDF buffer by searching for XML patterns in the text
|
|
13
|
+
* Uses a chunked approach to handle large files efficiently
|
|
14
|
+
* @param pdfBuffer PDF buffer
|
|
15
|
+
* @returns XML content or null if not found
|
|
16
|
+
*/
|
|
17
|
+
extractXml(pdfBuffer: Uint8Array | Buffer): Promise<string | null>;
|
|
18
|
+
/**
|
|
19
|
+
* Extract XML from buffer using a chunked approach
|
|
20
|
+
* This helps avoid memory issues with large PDFs
|
|
21
|
+
* @param buffer Buffer to search in
|
|
22
|
+
* @returns XML content or null if not found
|
|
23
|
+
*/
|
|
24
|
+
private extractXmlFromBufferChunked;
|
|
25
|
+
/**
|
|
26
|
+
* Process a single chunk of the PDF buffer
|
|
27
|
+
* @param chunk Chunk buffer to process
|
|
28
|
+
* @param chunkOffset Offset position of the chunk in the original buffer
|
|
29
|
+
* @returns XML content or null if not found
|
|
30
|
+
*/
|
|
31
|
+
private processChunk;
|
|
32
|
+
/**
|
|
33
|
+
* Safely decode a buffer to string using the specified encoding
|
|
34
|
+
* @param buffer Buffer to decode
|
|
35
|
+
* @param encoding Encoding to use ('utf-8' or 'latin1')
|
|
36
|
+
* @returns Decoded string
|
|
37
|
+
*/
|
|
38
|
+
private decodeBufferToString;
|
|
39
|
+
/**
|
|
40
|
+
* Search for XML patterns in a string
|
|
41
|
+
* @param content String to search in
|
|
42
|
+
* @returns XML content or null if not found
|
|
43
|
+
*/
|
|
44
|
+
private searchForXmlInString;
|
|
45
|
+
}
|