Skip to content

Commit

Permalink
Merge 8e2c35f into 92fad66
Browse files Browse the repository at this point in the history
  • Loading branch information
vbuch committed Apr 4, 2022
2 parents 92fad66 + 8e2c35f commit 335f959
Show file tree
Hide file tree
Showing 10 changed files with 408 additions and 123 deletions.
Binary file added resources/issue-158-test.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion src/helpers/index.test.js
Expand Up @@ -2,6 +2,6 @@ import * as helpers from './index';

describe('Helpers index', () => {
it('Exports expected helpers', () => {
expect(Object.keys(helpers)).toMatchSnapshot();
expect(Object.keys(helpers).sort()).toMatchSnapshot();
});
});
@@ -1,11 +1,19 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`getXref Throws an error when next EOF is not found 1`] = `"Expected EOF after xref and trailer but could not find one."`;

exports[`getXref Throws an error when size has unexpected value 1`] = `"Failed to parse size of xref table."`;

exports[`getXref Throws an error when size is not found 1`] = `"Size not found in xref table."`;

exports[`getXref Throws an error when xref is not at its expected position 1`] = `"Expected xref at 2 but found other content."`;

exports[`getXref Throws an error when xref is not found at position 1`] = `"Could not find xref anywhere at or after 0."`;

exports[`readRefTable Expects to merge correctly the refTable of resources 1`] = `
Object {
"maxIndex": 19,
"maxOffset": 19012,
"offsets": Map {
0 => 0,
1 => 19012,
2 => 19,
3 => 224,
Expand All @@ -24,7 +32,6 @@ Object {
17 => 13264,
18 => 18742,
19 => 18860,
-1 => 0,
},
"startingIndex": 0,
}
Expand All @@ -33,9 +40,7 @@ Object {
exports[`readRefTable Expects to merge correctly the refTable of resources 2`] = `
Object {
"maxIndex": 21,
"maxOffset": 25091,
"offsets": Map {
0 => 0,
1 => 25091,
2 => 19,
3 => 224,
Expand All @@ -56,18 +61,15 @@ Object {
19 => 25016,
20 => 19431,
21 => 24878,
-1 => 0,
},
"startingIndex": 0,
}
`;

exports[`readRefTable Expects to merge correctly the refTable of resources 3`] = `
Object {
"maxIndex": 25,
"maxOffset": 72070,
"maxIndex": 24,
"offsets": Map {
0 => 0,
1 => 15,
2 => 4075,
3 => 265,
Expand All @@ -92,18 +94,15 @@ Object {
22 => 71288,
23 => 71522,
24 => 71742,
-1 => 0,
},
"startingIndex": 0,
}
`;

exports[`readRefTable Expects to merge correctly the refTable of resources 4`] = `
Object {
"maxIndex": 63,
"maxOffset": 63939,
"maxIndex": 62,
"offsets": Map {
0 => 0,
1 => 53230,
2 => 19,
3 => 1785,
Expand Down Expand Up @@ -166,19 +165,16 @@ Object {
60 => 63251,
61 => 63625,
62 => 63939,
-1 => 0,
},
"startingIndex": 0,
}
`;

exports[`readRefTable Expects to merge correctly the refTable of resources 5`] = `
Object {
"maxIndex": 17,
"maxOffset": 16812,
"maxIndex": 18,
"offsets": Map {
0 => 0,
1 => 11997,
1 => 16964,
2 => 19,
3 => 224,
4 => 12330,
Expand All @@ -191,21 +187,20 @@ Object {
11 => 11943,
12 => 12140,
13 => 12196,
14 => 12429,
14 => 16880,
15 => 12494,
-1 => 0,
NaN => 16812,
16 => 13264,
17 => 16694,
18 => 16812,
},
"startingIndex": 0,
}
`;

exports[`readRefTable Expects to merge correctly the refTable of resources 6`] = `
Object {
"maxIndex": 14,
"maxOffset": 4163,
"maxIndex": 13,
"offsets": Map {
0 => 0,
1 => 4163,
2 => 4098,
3 => 4077,
Expand All @@ -219,18 +214,15 @@ Object {
11 => 3932,
12 => 3957,
13 => 3982,
-1 => 0,
},
"startingIndex": 0,
}
`;

exports[`readRefTable Expects to merge correctly the refTable of resources 7`] = `
Object {
"maxIndex": 16,
"maxOffset": 12494,
"maxIndex": 15,
"offsets": Map {
0 => 0,
1 => 11997,
2 => 19,
3 => 224,
Expand All @@ -246,7 +238,6 @@ Object {
13 => 12196,
14 => 12429,
15 => 12494,
-1 => 0,
},
"startingIndex": 0,
}
Expand Down
@@ -0,0 +1,90 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`xrefToRefMap Predefined xrefs match their snapshots 1`] = `
Map {
1 => 100423,
2 => 100501,
3 => 100361,
4 => 100340,
5 => 61908,
6 => 61783,
7 => 61679,
8 => 99156,
9 => 121651,
10 => 15,
11 => 62401,
12 => 62300,
13 => 62193,
14 => 97854,
15 => 64460,
16 => 64370,
17 => 64263,
18 => 97049,
19 => 96948,
20 => 96824,
21 => 96650,
22 => 96706,
23 => 100195,
24 => 97749,
25 => 97600,
26 => 97625,
27 => 97650,
28 => 97686,
29 => 97718,
30 => 100548,
31 => 97952,
32 => 98210,
33 => 98776,
34 => 113292,
35 => 99303,
36 => 99567,
37 => 99874,
38 => 115410,
}
`;

exports[`xrefToRefMap Predefined xrefs match their snapshots 2`] = `
Map {
6 => 662716,
7 => 662578,
39 => 655893,
40 => 656101,
41 => 656080,
42 => 656127,
43 => 656181,
44 => 656389,
45 => 656368,
46 => 656415,
47 => 656469,
48 => 656794,
49 => 656771,
50 => 672037,
51 => 656877,
52 => 657136,
53 => 657114,
54 => 661923,
55 => 657252,
56 => 659653,
57 => 659629,
58 => 661899,
59 => 662162,
60 => 662140,
61 => 662250,
62 => 662498,
63 => 662476,
64 => 663052,
65 => 662932,
66 => 663030,
67 => 663185,
68 => 663207,
69 => 672013,
70 => 672535,
71 => 672943,
72 => 672920,
73 => 673269,
}
`;

exports[`xrefToRefMap Throws an error when non-integer offset is given 1`] = `"Expected integer offset. Got \\"20a\\"."`;

exports[`xrefToRefMap Throws an error when unknown in-use flag is uses 1`] = `"Unknown in-use flag \\"w\\". Expected \\"n\\" or \\"f\\"."`;
6 changes: 3 additions & 3 deletions src/helpers/plainAddPlaceholder/findObject.js
Expand Up @@ -10,11 +10,11 @@ const findObject = (pdf, refTable, ref) => {

const offset = refTable.offsets.get(index);
let slice = pdf.slice(offset);
slice = slice.slice(0, slice.indexOf('endobj'));
slice = slice.slice(0, slice.indexOf('endobj', 'utf8'));

// FIXME: What if it is a stream?
slice = slice.slice(slice.indexOf('<<') + 2);
slice = slice.slice(0, slice.lastIndexOf('>>'));
slice = slice.slice(slice.indexOf('<<', 'utf8') + 2);
slice = slice.slice(0, slice.lastIndexOf('>>', 'utf8'));
return slice;
};

Expand Down
70 changes: 16 additions & 54 deletions src/helpers/plainAddPlaceholder/readRefTable.js
@@ -1,32 +1,5 @@
import SignPdfError from '../../SignPdfError';

const parseTrailerXref = (prev, curr) => {
const isObjectId = curr.split(' ').length === 2;

if (isObjectId) {
const [id] = curr.split(' ');
return {...prev, [id]: undefined};
}

const [offset] = curr.split(' ');
const prevId = Object.keys(prev).find((id) => prev[id] === undefined);

return {...prev, [prevId]: parseInt(offset)};
};

const parseRootXref = (prev, l, i) => {
const element = l.split(' ')[0];
const isPageObject = parseInt(element) === 0 && element.length > 3;

if (isPageObject) {
return {...prev, 0: 0};
}

let [offset] = l.split(' ');
offset = parseInt(offset);

return {...prev, [i - 1]: offset};
};
import xrefToRefMap from './xrefToRefMap';

export const getLastTrailerPosition = (pdf) => {
const trailerStart = pdf.lastIndexOf(Buffer.from('trailer', 'utf8'));
Expand Down Expand Up @@ -58,18 +31,27 @@ export const getXref = (pdf, position) => {
}
}

const nextEofPosition = refTable.indexOf(Buffer.from('%%EOF', 'utf8'));
if (nextEofPosition === -1) {
throw new SignPdfError(
'Expected EOF after xref and trailer but could not find one.',
SignPdfError.TYPE_PARSE,
);
}
refTable = refTable.slice(0, nextEofPosition);
refTable = refTable.slice(realPosition + 4); // move ahead with the "xref"
refTable = refTable.slice(refTable.indexOf('\n') + 1); // move after the next new line

// extract the size
let size = refTable.toString().split('/Size')[1];

if (!size) {
throw new SignPdfError(
'Size not found in xref table.',
SignPdfError.TYPE_PARSE,
);
}
size = (/\s*(\d+)/).exec(size);
size = (/^\s*(\d+)/).exec(size);
if (size === null) {
throw new SignPdfError(
'Failed to parse size of xref table.',
Expand All @@ -83,23 +65,14 @@ export const getXref = (pdf, position) => {
const isContainingPrev = infos.split('/Prev')[1] != null;

let prev;
let reducer;

if (isContainingPrev) {
const pagesRefRegex = /Prev (\d+)/g;
const match = pagesRefRegex.exec(infos);
const [, prevPosition] = match;
prev = prevPosition;
reducer = parseTrailerXref;
} else {
reducer = parseRootXref;
}

const lines = objects
.split('\n')
.filter((l) => l !== '');

const xRefContent = lines.reduce(reducer, {});
const xRefContent = xrefToRefMap(objects);

return {
size,
Expand All @@ -118,10 +91,10 @@ export const getFullXrefTable = (pdf) => {
const pdfWithoutLastTrailer = pdf.slice(0, lastTrailerPosition);
const partOfXrefTable = getFullXrefTable(pdfWithoutLastTrailer);

const mergedXrefTable = {
const mergedXrefTable = new Map([
...partOfXrefTable,
...lastXrefTable.xRefContent,
};
]);

return mergedXrefTable;
};
Expand All @@ -131,25 +104,14 @@ export const getFullXrefTable = (pdf) => {
* @returns {object}
*/
const readRefTable = (pdf) => {
const offsetsMap = new Map();
const fullXrefTable = getFullXrefTable(pdf);

const startingIndex = 0;

let maxOffset = 0;
const maxIndex = parseInt(Object.keys(fullXrefTable).length) - 1;

Object.keys(fullXrefTable).forEach((id) => {
const offset = parseInt(fullXrefTable[id]);
maxOffset = Math.max(maxOffset, offset);
offsetsMap.set(parseInt(id), offset);
});
const maxIndex = Math.max(...fullXrefTable.keys());

return {
maxOffset,
startingIndex,
maxIndex,
offsets: offsetsMap,
offsets: fullXrefTable,
};
};

Expand Down

0 comments on commit 335f959

Please sign in to comment.