pdf-parser.js 4.8.6 → 4.8.7

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.
@@ -5,7 +5,6 @@ const SHA256_ROUNDS = 64;
5
5
  const SHA512_BLOCK_BYTES = 128;
6
6
  const SHA512_ROUNDS = 80;
7
7
  const WORDS_PER_BLOCK = 16;
8
- const MASK64 = 18446744073709551615n;
9
8
  const K512 = [
10
9
  4794697086780616226n,
11
10
  8158064640168781261n,
@@ -110,6 +109,9 @@ const H384 = [
110
109
  ];
111
110
  const K256 = Uint32Array.from(K512.slice(0, SHA256_ROUNDS), (k) => Number(k >> 32n));
112
111
  const H256 = Uint32Array.from(H512, (h) => Number(h >> 32n));
112
+ const K512_HIGH = Uint32Array.from(K512, (k) => Number(k >> 32n));
113
+ const K512_LOW = Uint32Array.from(K512, (k) => Number(BigInt.asUintN(32, k)));
114
+ const TWO_POW_32 = 4294967296;
113
115
  function padBigEndian(bytes, blockBytes, lengthBytes) {
114
116
  const paddedLength = (Math.floor((bytes.length + lengthBytes) / blockBytes) + 1) * blockBytes;
115
117
  const padded = new Uint8Array(paddedLength);
@@ -185,69 +187,115 @@ function sha256(bytes) {
185
187
  }
186
188
  return digest;
187
189
  }
188
- function rotr64(value, bits) {
189
- return (value >> bits | value << 64n - bits) & MASK64;
190
+ function readWord32(bytes, offset) {
191
+ return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
190
192
  }
191
193
  function sha512Core(bytes, initialState, outputWords) {
192
194
  const padded = padBigEndian(bytes, SHA512_BLOCK_BYTES, 16);
193
- const state = Array.from(initialState);
194
- const w = new Array(SHA512_ROUNDS).fill(0n);
195
+ const stateHigh = Uint32Array.from(initialState, (word) => Number(word >> 32n));
196
+ const stateLow = Uint32Array.from(initialState, (word) => Number(BigInt.asUintN(32, word)));
197
+ const wHigh = new Uint32Array(SHA512_ROUNDS);
198
+ const wLow = new Uint32Array(SHA512_ROUNDS);
195
199
  for (let offset = 0; offset < padded.length; offset += SHA512_BLOCK_BYTES) {
196
- for (let t = 0; t < WORDS_PER_BLOCK; t++) {
197
- let word = 0n;
198
- for (let i = 0; i < 8; i++) word = word << 8n | BigInt(padded[offset + t * 8 + i]);
199
- w[t] = word;
200
- }
201
- for (let t = WORDS_PER_BLOCK; t < SHA512_ROUNDS; t++) {
202
- const x = w[t - 15];
203
- const y = w[t - 2];
204
- const s0 = rotr64(x, 1n) ^ rotr64(x, 8n) ^ x >> 7n;
205
- const s1 = rotr64(y, 19n) ^ rotr64(y, 61n) ^ y >> 6n;
206
- w[t] = w[t - 16] + s0 + w[t - 7] + s1 & MASK64;
207
- }
208
- let a = state[0];
209
- let b = state[1];
210
- let c = state[2];
211
- let d = state[3];
212
- let e = state[4];
213
- let f = state[5];
214
- let g = state[6];
215
- let h = state[7];
200
+ wHigh.forEach((_word, t) => {
201
+ if (t < WORDS_PER_BLOCK) {
202
+ const at = offset + t * 8;
203
+ wHigh[t] = readWord32(padded, at);
204
+ wLow[t] = readWord32(padded, at + 4);
205
+ return;
206
+ }
207
+ const xh = wHigh[t - 15];
208
+ const xl = wLow[t - 15];
209
+ const yh = wHigh[t - 2];
210
+ const yl = wLow[t - 2];
211
+ const s0h = (xh >>> 1 | xl << 31) ^ (xh >>> 8 | xl << 24) ^ xh >>> 7;
212
+ const s0l = (xl >>> 1 | xh << 31) ^ (xl >>> 8 | xh << 24) ^ (xl >>> 7 | xh << 25);
213
+ const s1h = (yh >>> 19 | yl << 13) ^ (yl >>> 29 | yh << 3) ^ yh >>> 6;
214
+ const s1l = (yl >>> 19 | yh << 13) ^ (yh >>> 29 | yl << 3) ^ (yl >>> 6 | yh << 26);
215
+ const low = wLow[t - 16] + (s0l >>> 0) + wLow[t - 7] + (s1l >>> 0);
216
+ const carry = Math.floor(low / TWO_POW_32);
217
+ wLow[t] = low;
218
+ wHigh[t] = wHigh[t - 16] + (s0h >>> 0) + wHigh[t - 7] + (s1h >>> 0) + carry;
219
+ });
220
+ let ah = stateHigh[0];
221
+ let al = stateLow[0];
222
+ let bh = stateHigh[1];
223
+ let bl = stateLow[1];
224
+ let ch = stateHigh[2];
225
+ let cl = stateLow[2];
226
+ let dh = stateHigh[3];
227
+ let dl = stateLow[3];
228
+ let eh = stateHigh[4];
229
+ let el = stateLow[4];
230
+ let fh = stateHigh[5];
231
+ let fl = stateLow[5];
232
+ let gh = stateHigh[6];
233
+ let gl = stateLow[6];
234
+ let hh = stateHigh[7];
235
+ let hl = stateLow[7];
216
236
  for (let t = 0; t < SHA512_ROUNDS; t++) {
217
- const bigS1 = rotr64(e, 14n) ^ rotr64(e, 18n) ^ rotr64(e, 41n);
218
- const ch = e & f ^ ~e & MASK64 & g;
219
- const t1 = h + bigS1 + ch + K512[t] + w[t] & MASK64;
220
- const t2 = (rotr64(a, 28n) ^ rotr64(a, 34n) ^ rotr64(a, 39n)) + (a & b ^ a & c ^ b & c) & MASK64;
221
- h = g;
222
- g = f;
223
- f = e;
224
- e = d + t1 & MASK64;
225
- d = c;
226
- c = b;
227
- b = a;
228
- a = t1 + t2 & MASK64;
237
+ const bigS1h = (eh >>> 14 | el << 18) ^ (eh >>> 18 | el << 14) ^ (el >>> 9 | eh << 23);
238
+ const bigS1l = (el >>> 14 | eh << 18) ^ (el >>> 18 | eh << 14) ^ (eh >>> 9 | el << 23);
239
+ const chh = eh & fh ^ ~eh & gh;
240
+ const chl = el & fl ^ ~el & gl;
241
+ const t1Sum = hl + (bigS1l >>> 0) + (chl >>> 0) + K512_LOW[t] + wLow[t];
242
+ const t1l = t1Sum >>> 0;
243
+ const t1h = hh + (bigS1h >>> 0) + (chh >>> 0) + K512_HIGH[t] + wHigh[t] + Math.floor(t1Sum / TWO_POW_32) >>> 0;
244
+ const bigS0h = (ah >>> 28 | al << 4) ^ (al >>> 2 | ah << 30) ^ (al >>> 7 | ah << 25);
245
+ const bigS0l = (al >>> 28 | ah << 4) ^ (ah >>> 2 | al << 30) ^ (ah >>> 7 | al << 25);
246
+ const majh = ah & bh ^ ah & ch ^ bh & ch;
247
+ const majl = al & bl ^ al & cl ^ bl & cl;
248
+ const t2Sum = (bigS0l >>> 0) + (majl >>> 0);
249
+ const t2l = t2Sum >>> 0;
250
+ const t2h = (bigS0h >>> 0) + (majh >>> 0) + Math.floor(t2Sum / TWO_POW_32) >>> 0;
251
+ hh = gh;
252
+ hl = gl;
253
+ gh = fh;
254
+ gl = fl;
255
+ fh = eh;
256
+ fl = el;
257
+ const eSum = dl + t1l;
258
+ eh = dh + t1h + Math.floor(eSum / TWO_POW_32) >>> 0;
259
+ el = eSum >>> 0;
260
+ dh = ch;
261
+ dl = cl;
262
+ ch = bh;
263
+ cl = bl;
264
+ bh = ah;
265
+ bl = al;
266
+ const aSum = t1l + t2l;
267
+ ah = t1h + t2h + Math.floor(aSum / TWO_POW_32) >>> 0;
268
+ al = aSum >>> 0;
229
269
  }
230
- const next = [
231
- a,
232
- b,
233
- c,
234
- d,
235
- e,
236
- f,
237
- g,
238
- h
270
+ const nextHigh = [
271
+ ah,
272
+ bh,
273
+ ch,
274
+ dh,
275
+ eh,
276
+ fh,
277
+ gh,
278
+ hh
239
279
  ];
240
- for (let i = 0; i < state.length; i++) state[i] = state[i] + next[i] & MASK64;
241
- }
242
- const digest = new Uint8Array(outputWords * 8);
243
- for (let i = 0; i < outputWords; i++) {
244
- let word = state[i];
245
- for (let j = 7; j >= 0; j--) {
246
- digest[i * 8 + j] = Number(word & 255n);
247
- word >>= 8n;
248
- }
280
+ const nextLow = [
281
+ al,
282
+ bl,
283
+ cl,
284
+ dl,
285
+ el,
286
+ fl,
287
+ gl,
288
+ hl
289
+ ];
290
+ stateHigh.forEach((word, i) => {
291
+ const sum = stateLow[i] + nextLow[i];
292
+ stateHigh[i] = word + nextHigh[i] + Math.floor(sum / TWO_POW_32);
293
+ stateLow[i] = sum;
294
+ });
249
295
  }
250
- return digest;
296
+ return Uint8Array.from({ length: outputWords * 8 }, (_unused, index) => {
297
+ return (index % 8 < 4 ? stateHigh : stateLow)[Math.floor(index / 8)] >>> 24 - 8 * (index % 4) & 255;
298
+ });
251
299
  }
252
300
  function sha512(bytes) {
253
301
  return sha512Core(bytes, H512, 8);
@@ -4,7 +4,6 @@ const SHA256_ROUNDS = 64;
4
4
  const SHA512_BLOCK_BYTES = 128;
5
5
  const SHA512_ROUNDS = 80;
6
6
  const WORDS_PER_BLOCK = 16;
7
- const MASK64 = 18446744073709551615n;
8
7
  const K512 = [
9
8
  4794697086780616226n,
10
9
  8158064640168781261n,
@@ -109,6 +108,9 @@ const H384 = [
109
108
  ];
110
109
  const K256 = Uint32Array.from(K512.slice(0, SHA256_ROUNDS), (k) => Number(k >> 32n));
111
110
  const H256 = Uint32Array.from(H512, (h) => Number(h >> 32n));
111
+ const K512_HIGH = Uint32Array.from(K512, (k) => Number(k >> 32n));
112
+ const K512_LOW = Uint32Array.from(K512, (k) => Number(BigInt.asUintN(32, k)));
113
+ const TWO_POW_32 = 4294967296;
112
114
  function padBigEndian(bytes, blockBytes, lengthBytes) {
113
115
  const paddedLength = (Math.floor((bytes.length + lengthBytes) / blockBytes) + 1) * blockBytes;
114
116
  const padded = new Uint8Array(paddedLength);
@@ -184,69 +186,115 @@ function sha256(bytes) {
184
186
  }
185
187
  return digest;
186
188
  }
187
- function rotr64(value, bits) {
188
- return (value >> bits | value << 64n - bits) & MASK64;
189
+ function readWord32(bytes, offset) {
190
+ return (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
189
191
  }
190
192
  function sha512Core(bytes, initialState, outputWords) {
191
193
  const padded = padBigEndian(bytes, SHA512_BLOCK_BYTES, 16);
192
- const state = Array.from(initialState);
193
- const w = new Array(SHA512_ROUNDS).fill(0n);
194
+ const stateHigh = Uint32Array.from(initialState, (word) => Number(word >> 32n));
195
+ const stateLow = Uint32Array.from(initialState, (word) => Number(BigInt.asUintN(32, word)));
196
+ const wHigh = new Uint32Array(SHA512_ROUNDS);
197
+ const wLow = new Uint32Array(SHA512_ROUNDS);
194
198
  for (let offset = 0; offset < padded.length; offset += SHA512_BLOCK_BYTES) {
195
- for (let t = 0; t < WORDS_PER_BLOCK; t++) {
196
- let word = 0n;
197
- for (let i = 0; i < 8; i++) word = word << 8n | BigInt(padded[offset + t * 8 + i]);
198
- w[t] = word;
199
- }
200
- for (let t = WORDS_PER_BLOCK; t < SHA512_ROUNDS; t++) {
201
- const x = w[t - 15];
202
- const y = w[t - 2];
203
- const s0 = rotr64(x, 1n) ^ rotr64(x, 8n) ^ x >> 7n;
204
- const s1 = rotr64(y, 19n) ^ rotr64(y, 61n) ^ y >> 6n;
205
- w[t] = w[t - 16] + s0 + w[t - 7] + s1 & MASK64;
206
- }
207
- let a = state[0];
208
- let b = state[1];
209
- let c = state[2];
210
- let d = state[3];
211
- let e = state[4];
212
- let f = state[5];
213
- let g = state[6];
214
- let h = state[7];
199
+ wHigh.forEach((_word, t) => {
200
+ if (t < WORDS_PER_BLOCK) {
201
+ const at = offset + t * 8;
202
+ wHigh[t] = readWord32(padded, at);
203
+ wLow[t] = readWord32(padded, at + 4);
204
+ return;
205
+ }
206
+ const xh = wHigh[t - 15];
207
+ const xl = wLow[t - 15];
208
+ const yh = wHigh[t - 2];
209
+ const yl = wLow[t - 2];
210
+ const s0h = (xh >>> 1 | xl << 31) ^ (xh >>> 8 | xl << 24) ^ xh >>> 7;
211
+ const s0l = (xl >>> 1 | xh << 31) ^ (xl >>> 8 | xh << 24) ^ (xl >>> 7 | xh << 25);
212
+ const s1h = (yh >>> 19 | yl << 13) ^ (yl >>> 29 | yh << 3) ^ yh >>> 6;
213
+ const s1l = (yl >>> 19 | yh << 13) ^ (yh >>> 29 | yl << 3) ^ (yl >>> 6 | yh << 26);
214
+ const low = wLow[t - 16] + (s0l >>> 0) + wLow[t - 7] + (s1l >>> 0);
215
+ const carry = Math.floor(low / TWO_POW_32);
216
+ wLow[t] = low;
217
+ wHigh[t] = wHigh[t - 16] + (s0h >>> 0) + wHigh[t - 7] + (s1h >>> 0) + carry;
218
+ });
219
+ let ah = stateHigh[0];
220
+ let al = stateLow[0];
221
+ let bh = stateHigh[1];
222
+ let bl = stateLow[1];
223
+ let ch = stateHigh[2];
224
+ let cl = stateLow[2];
225
+ let dh = stateHigh[3];
226
+ let dl = stateLow[3];
227
+ let eh = stateHigh[4];
228
+ let el = stateLow[4];
229
+ let fh = stateHigh[5];
230
+ let fl = stateLow[5];
231
+ let gh = stateHigh[6];
232
+ let gl = stateLow[6];
233
+ let hh = stateHigh[7];
234
+ let hl = stateLow[7];
215
235
  for (let t = 0; t < SHA512_ROUNDS; t++) {
216
- const bigS1 = rotr64(e, 14n) ^ rotr64(e, 18n) ^ rotr64(e, 41n);
217
- const ch = e & f ^ ~e & MASK64 & g;
218
- const t1 = h + bigS1 + ch + K512[t] + w[t] & MASK64;
219
- const t2 = (rotr64(a, 28n) ^ rotr64(a, 34n) ^ rotr64(a, 39n)) + (a & b ^ a & c ^ b & c) & MASK64;
220
- h = g;
221
- g = f;
222
- f = e;
223
- e = d + t1 & MASK64;
224
- d = c;
225
- c = b;
226
- b = a;
227
- a = t1 + t2 & MASK64;
236
+ const bigS1h = (eh >>> 14 | el << 18) ^ (eh >>> 18 | el << 14) ^ (el >>> 9 | eh << 23);
237
+ const bigS1l = (el >>> 14 | eh << 18) ^ (el >>> 18 | eh << 14) ^ (eh >>> 9 | el << 23);
238
+ const chh = eh & fh ^ ~eh & gh;
239
+ const chl = el & fl ^ ~el & gl;
240
+ const t1Sum = hl + (bigS1l >>> 0) + (chl >>> 0) + K512_LOW[t] + wLow[t];
241
+ const t1l = t1Sum >>> 0;
242
+ const t1h = hh + (bigS1h >>> 0) + (chh >>> 0) + K512_HIGH[t] + wHigh[t] + Math.floor(t1Sum / TWO_POW_32) >>> 0;
243
+ const bigS0h = (ah >>> 28 | al << 4) ^ (al >>> 2 | ah << 30) ^ (al >>> 7 | ah << 25);
244
+ const bigS0l = (al >>> 28 | ah << 4) ^ (ah >>> 2 | al << 30) ^ (ah >>> 7 | al << 25);
245
+ const majh = ah & bh ^ ah & ch ^ bh & ch;
246
+ const majl = al & bl ^ al & cl ^ bl & cl;
247
+ const t2Sum = (bigS0l >>> 0) + (majl >>> 0);
248
+ const t2l = t2Sum >>> 0;
249
+ const t2h = (bigS0h >>> 0) + (majh >>> 0) + Math.floor(t2Sum / TWO_POW_32) >>> 0;
250
+ hh = gh;
251
+ hl = gl;
252
+ gh = fh;
253
+ gl = fl;
254
+ fh = eh;
255
+ fl = el;
256
+ const eSum = dl + t1l;
257
+ eh = dh + t1h + Math.floor(eSum / TWO_POW_32) >>> 0;
258
+ el = eSum >>> 0;
259
+ dh = ch;
260
+ dl = cl;
261
+ ch = bh;
262
+ cl = bl;
263
+ bh = ah;
264
+ bl = al;
265
+ const aSum = t1l + t2l;
266
+ ah = t1h + t2h + Math.floor(aSum / TWO_POW_32) >>> 0;
267
+ al = aSum >>> 0;
228
268
  }
229
- const next = [
230
- a,
231
- b,
232
- c,
233
- d,
234
- e,
235
- f,
236
- g,
237
- h
269
+ const nextHigh = [
270
+ ah,
271
+ bh,
272
+ ch,
273
+ dh,
274
+ eh,
275
+ fh,
276
+ gh,
277
+ hh
238
278
  ];
239
- for (let i = 0; i < state.length; i++) state[i] = state[i] + next[i] & MASK64;
240
- }
241
- const digest = new Uint8Array(outputWords * 8);
242
- for (let i = 0; i < outputWords; i++) {
243
- let word = state[i];
244
- for (let j = 7; j >= 0; j--) {
245
- digest[i * 8 + j] = Number(word & 255n);
246
- word >>= 8n;
247
- }
279
+ const nextLow = [
280
+ al,
281
+ bl,
282
+ cl,
283
+ dl,
284
+ el,
285
+ fl,
286
+ gl,
287
+ hl
288
+ ];
289
+ stateHigh.forEach((word, i) => {
290
+ const sum = stateLow[i] + nextLow[i];
291
+ stateHigh[i] = word + nextHigh[i] + Math.floor(sum / TWO_POW_32);
292
+ stateLow[i] = sum;
293
+ });
248
294
  }
249
- return digest;
295
+ return Uint8Array.from({ length: outputWords * 8 }, (_unused, index) => {
296
+ return (index % 8 < 4 ? stateHigh : stateLow)[Math.floor(index / 8)] >>> 24 - 8 * (index % 4) & 255;
297
+ });
250
298
  }
251
299
  function sha512(bytes) {
252
300
  return sha512Core(bytes, H512, 8);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-parser.js",
3
- "version": "4.8.6",
3
+ "version": "4.8.7",
4
4
  "description": "Hand-written, dependency-minimal PDF codec: parses arbitrary real-world PDFs and generates new ones, built on its own codec-owned LayoutDocument item model and Zod 4 codecs.",
5
5
  "type": "module",
6
6
  "repository": {