Преглед изворни кода

Merge pull request #8950 from overleaf/bg-use-qpdf-xref-table

[clsi] parse xref table from qpdf output

GitOrigin-RevId: cc400c65082c7c8c28c21037b97b4fde66a85835
Jakob Ackermann пре 4 година
родитељ
комит
18768d3f1b
38 измењених фајлова са 880 додато и 262 уклоњено
  1. 0 16
      package-lock.json
  2. 10 2
      services/clsi/app/js/ContentCacheManager.js
  3. 2 0
      services/clsi/app/js/Errors.js
  4. 8 1
      services/clsi/app/js/OutputCacheManager.js
  5. 68 0
      services/clsi/app/js/XrefParser.js
  6. 0 43
      services/clsi/app/lib/pdfjs/FSPdfManager.js
  7. 0 148
      services/clsi/app/lib/pdfjs/FSStream.js
  8. 0 29
      services/clsi/app/lib/pdfjs/parseXrefTable.js
  9. 0 1
      services/clsi/package.json
  10. 81 0
      services/clsi/test/acceptance/fixtures/examples/asymptote/output.pdfxref
  11. 31 0
      services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.pdfxref
  12. 39 0
      services/clsi/test/acceptance/fixtures/examples/draft_legacy/output.pdfxref
  13. 50 0
      services/clsi/test/acceptance/fixtures/examples/draft_mode/output.pdfxref
  14. 30 0
      services/clsi/test/acceptance/fixtures/examples/epstopdf/output.pdfxref
  15. 28 0
      services/clsi/test/acceptance/fixtures/examples/feynmf/output.pdfxref
  16. 20 0
      services/clsi/test/acceptance/fixtures/examples/feynmp/output.pdfxref
  17. 23 0
      services/clsi/test/acceptance/fixtures/examples/fontawesome/output.pdfxref
  18. 26 0
      services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/output.pdfxref
  19. 23 0
      services/clsi/test/acceptance/fixtures/examples/glossaries/output.pdfxref
  20. 22 0
      services/clsi/test/acceptance/fixtures/examples/gnuplot/output.pdfxref
  21. 20 0
      services/clsi/test/acceptance/fixtures/examples/hebrew/output.pdfxref
  22. 31 0
      services/clsi/test/acceptance/fixtures/examples/knitr/output.pdfxref
  23. 39 0
      services/clsi/test/acceptance/fixtures/examples/knitr_utf8/output.pdfxref
  24. 26 0
      services/clsi/test/acceptance/fixtures/examples/latex_compiler/output.pdfxref
  25. 18 0
      services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/output.pdfxref
  26. 26 0
      services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/output.pdfxref
  27. 22 0
      services/clsi/test/acceptance/fixtures/examples/makeindex/output.pdfxref
  28. 19 0
      services/clsi/test/acceptance/fixtures/examples/minted/output.pdfxref
  29. 32 0
      services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/output.pdfxref
  30. 23 0
      services/clsi/test/acceptance/fixtures/examples/nomenclature/output.pdfxref
  31. 22 0
      services/clsi/test/acceptance/fixtures/examples/references_in_include/output.pdfxref
  32. 23 0
      services/clsi/test/acceptance/fixtures/examples/simple_bibliography/output.pdfxref
  33. 26 0
      services/clsi/test/acceptance/fixtures/examples/subdirectories/output.pdfxref
  34. 35 0
      services/clsi/test/acceptance/fixtures/examples/tikz_feynman/output.pdfxref
  35. 19 0
      services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/output.pdfxref
  36. 15 0
      services/clsi/test/acceptance/fixtures/minimal.pdfxref
  37. 9 5
      services/clsi/test/unit/js/ContentCacheManagerTests.js
  38. 14 17
      services/clsi/test/unit/js/pdfjsTests.js

+ 0 - 16
package-lock.json

@@ -23390,14 +23390,6 @@
       "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
       "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
     },
-    "node_modules/pdfjs-dist": {
-      "version": "2.7.570",
-      "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.7.570.tgz",
-      "integrity": "sha512-/ZkA1FwkEOyDaq11JhMLazdwQAA0F9uwrP7h/1L9Akt9KWh1G5/tkzS+bPuUELq2s2GDFnaT+kooN/aSjT7DXQ==",
-      "peerDependencies": {
-        "worker-loader": "^3.0.7"
-      }
-    },
     "node_modules/pdfjs-dist210": {
       "name": "pdfjs-dist",
       "version": "2.10.377",
@@ -31849,7 +31841,6 @@
         "lockfile": "^1.0.4",
         "lodash": "^4.17.21",
         "p-limit": "^3.1.0",
-        "pdfjs-dist": "~2.7.570",
         "request": "^2.88.2",
         "send": "^0.17.1",
         "workerpool": "^6.1.5"
@@ -39703,7 +39694,6 @@
         "mocha": "^8.4.0",
         "mock-fs": "^5.1.2",
         "p-limit": "^3.1.0",
-        "pdfjs-dist": "~2.7.570",
         "request": "^2.88.2",
         "sandboxed-module": "^2.0.4",
         "send": "^0.17.1",
@@ -59303,12 +59293,6 @@
       "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
       "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
     },
-    "pdfjs-dist": {
-      "version": "2.7.570",
-      "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.7.570.tgz",
-      "integrity": "sha512-/ZkA1FwkEOyDaq11JhMLazdwQAA0F9uwrP7h/1L9Akt9KWh1G5/tkzS+bPuUELq2s2GDFnaT+kooN/aSjT7DXQ==",
-      "requires": {}
-    },
     "pdfjs-dist210": {
       "version": "npm:pdfjs-dist@2.10.377",
       "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.10.377.tgz",

+ 10 - 2
services/clsi/app/js/ContentCacheManager.js

@@ -9,8 +9,12 @@ const Path = require('path')
 const Settings = require('@overleaf/settings')
 const OError = require('@overleaf/o-error')
 const pLimit = require('p-limit')
-const { parseXrefTable } = require('../lib/pdfjs/parseXrefTable')
-const { QueueLimitReachedError, TimedOutError } = require('./Errors')
+const { parseXrefTable } = require('./XrefParser')
+const {
+  QueueLimitReachedError,
+  TimedOutError,
+  NoXrefTableError,
+} = require('./Errors')
 const workerpool = require('workerpool')
 const Metrics = require('@overleaf/metrics')
 
@@ -89,6 +93,9 @@ async function updateOtherEventLoop(contentDir, filePath, size, compileTime) {
     if (e.message?.includes?.('Max queue size of ')) {
       throw new QueueLimitReachedError()
     }
+    if (e.message?.includes?.('xref')) {
+      throw new NoXrefTableError(e.message)
+    }
     throw e
   }
 }
@@ -115,6 +122,7 @@ async function updateSameEventLoop(contentDir, filePath, size, compileTime) {
     size,
     checkDeadline
   )
+
   xRefEntries.sort((a, b) => {
     return a.offset - b.offset
   })

+ 2 - 0
services/clsi/app/js/Errors.js

@@ -33,6 +33,7 @@ AlreadyCompilingError.prototype.__proto__ = Error.prototype
 
 class QueueLimitReachedError extends OError {}
 class TimedOutError extends OError {}
+class NoXrefTableError extends OError {}
 
 module.exports = Errors = {
   QueueLimitReachedError,
@@ -40,4 +41,5 @@ module.exports = Errors = {
   NotFoundError,
   FilesOutOfSyncError,
   AlreadyCompilingError,
+  NoXrefTableError,
 }

+ 8 - 1
services/clsi/app/js/OutputCacheManager.js

@@ -24,7 +24,11 @@ const Metrics = require('./Metrics')
 
 const OutputFileOptimiser = require('./OutputFileOptimiser')
 const ContentCacheManager = require('./ContentCacheManager')
-const { QueueLimitReachedError, TimedOutError } = require('./Errors')
+const {
+  QueueLimitReachedError,
+  TimedOutError,
+  NoXrefTableError,
+} = require('./Errors')
 
 const OLDEST_BUILD_DIR = new Map()
 const PENDING_PROJECT_ACTIONS = new Map()
@@ -397,6 +401,9 @@ module.exports = OutputCacheManager = {
           pdfSize,
           timings.compile,
           function (err, result) {
+            if (err && err instanceof NoXrefTableError) {
+              return callback(null, err.message)
+            }
             if (err && err instanceof QueueLimitReachedError) {
               logger.warn({ err, outputDir }, 'pdf caching queue limit reached')
               stats['pdf-caching-queue-limit-reached'] = 1

+ 68 - 0
services/clsi/app/js/XrefParser.js

@@ -0,0 +1,68 @@
+const { NoXrefTableError } = require('./Errors')
+const fs = require('fs')
+const { O_RDONLY, O_NOFOLLOW } = fs.constants
+const MAX_XREF_FILE_SIZE = 1024 * 1024
+
+/**  Parse qpdf --show-xref output to get a table of xref entries
+ *
+ * @param {string} filePath
+ * @param {integer} pdfFileSize
+ * @returns
+ */
+async function parseXrefTable(filePath, pdfFileSize) {
+  try {
+    // the xref table will be written to output.pdfxref when available
+    const xRefFilePath = filePath + 'xref'
+    // check the size of the file (as it is untrusted)
+    const stats = await fs.promises.stat(xRefFilePath)
+    if (!stats.isFile()) {
+      throw new NoXrefTableError('xref file invalid type')
+    }
+    if (stats.size === 0) {
+      throw new NoXrefTableError('xref file empty')
+    }
+    if (stats.size > MAX_XREF_FILE_SIZE) {
+      throw new NoXrefTableError('xref file too large')
+    }
+    const content = await fs.promises.readFile(xRefFilePath, {
+      encoding: 'ascii',
+      flag: O_RDONLY | O_NOFOLLOW,
+    })
+    // the qpdf xref table output looks like this:
+    //
+    //    3/0: uncompressed; offset = 194159
+    //
+    // we only need the uncompressed objects
+    const matches = content.matchAll(
+      // put an upper limit of 10^10 on all the matched numbers for safety
+      // ignore the generation id in "id/gen"
+      // in a linearized pdf all objects must have generation number 0
+      /^(\d{1,9})\/\d{1,9}: uncompressed; offset = (\d{1,9})$/gm
+    )
+    // include a zero-index object for backwards compatibility with
+    // our existing xref table parsing code
+    const xRefEntries = [{ offset: 0 }]
+    // extract all the xref table entries
+    for (const match of matches) {
+      const id = parseInt(match[1], 10) // must convert from strings to integers
+      const offset = parseInt(match[2], 10)
+      xRefEntries[id] = { offset, uncompressed: true }
+    }
+    if (xRefEntries.length === 1) {
+      throw new NoXrefTableError('xref file has no objects')
+    }
+    return { xRefEntries }
+  } catch (err) {
+    if (err instanceof NoXrefTableError) {
+      throw err
+    } else if (err.code) {
+      throw new NoXrefTableError(`xref file error ${err.code}`)
+    } else {
+      throw new NoXrefTableError('xref file parse error')
+    }
+  }
+}
+
+module.exports = {
+  parseXrefTable,
+}

+ 0 - 43
services/clsi/app/lib/pdfjs/FSPdfManager.js

@@ -1,43 +0,0 @@
-const { PDFDocument } = require('pdfjs-dist/lib/core/document')
-const { LocalPdfManager } = require('pdfjs-dist/lib/core/pdf_manager')
-const { MissingDataException } = require('pdfjs-dist/lib/core/core_utils')
-const { FSStream } = require('./FSStream')
-
-class FSPdfManager extends LocalPdfManager {
-  constructor(docId, { fh, size, checkDeadline }) {
-    const nonEmptyDummyBuffer = Buffer.alloc(1, 0)
-    super(docId, nonEmptyDummyBuffer)
-    this.stream = new FSStream(fh, 0, size, null, null, checkDeadline)
-    this.pdfDocument = new PDFDocument(this, this.stream)
-  }
-
-  async ensure(obj, prop, args) {
-    try {
-      const value = obj[prop]
-      if (typeof value === 'function') {
-        return value.apply(obj, args)
-      }
-      return value
-    } catch (ex) {
-      if (!(ex instanceof MissingDataException)) {
-        throw ex
-      }
-      await this.requestRange(ex.begin, ex.end)
-      return this.ensure(obj, prop, args)
-    }
-  }
-
-  requestRange(begin, end) {
-    return this.stream.requestRange(begin, end)
-  }
-
-  requestLoadedStream() {}
-
-  onLoadedStream() {}
-
-  terminate(reason) {}
-}
-
-module.exports = {
-  FSPdfManager,
-}

+ 0 - 148
services/clsi/app/lib/pdfjs/FSStream.js

@@ -1,148 +0,0 @@
-const { Stream } = require('pdfjs-dist/lib/core/stream')
-const { MissingDataException } = require('pdfjs-dist/lib/core/core_utils')
-
-const BUF_SIZE = 1024 // read from the file in 1024 byte pages
-
-class FSStream extends Stream {
-  constructor(fh, start, length, dict, cachedBytes, checkDeadline) {
-    const nonEmptyDummyBuffer = Buffer.alloc(1, 0)
-    super(nonEmptyDummyBuffer, start, length, dict)
-    delete this.bytes
-    this.fh = fh
-    this.checkDeadline = checkDeadline
-    this.cachedBytes = cachedBytes || []
-  }
-
-  get length() {
-    return this.end - this.start
-  }
-
-  get isEmpty() {
-    return this.length === 0
-  }
-
-  // Manage cached reads from the file
-
-  requestRange(begin, end) {
-    this.checkDeadline(`request range ${begin} - ${end}`)
-    // expand small ranges to read a larger amount
-    if (end - begin < BUF_SIZE) {
-      end = begin + BUF_SIZE
-    }
-    end = Math.min(end, this.length)
-    // keep a cache of previous reads with {begin,end,buffer} values
-    const result = {
-      begin,
-      end,
-      buffer: Buffer.alloc(end - begin, 0),
-    }
-    this.cachedBytes.push(result)
-    return this.fh.read(result.buffer, 0, end - begin, begin)
-  }
-
-  _ensureGetPos(pos) {
-    const found = this.cachedBytes.find(x => {
-      return x.begin <= pos && pos < x.end
-    })
-    if (!found) {
-      throw new MissingDataException(pos, pos + 1)
-    }
-    return found
-  }
-
-  _ensureGetRange(begin, end) {
-    end = Math.min(end, this.length) // BG: handle overflow case
-    const found = this.cachedBytes.find(x => {
-      return x.begin <= begin && end <= x.end
-    })
-    if (!found) {
-      throw new MissingDataException(begin, end)
-    }
-    return found
-  }
-
-  _readByte(found, pos) {
-    return found.buffer[pos - found.begin]
-  }
-
-  _readBytes(found, pos, end) {
-    return found.buffer.subarray(pos - found.begin, end - found.begin)
-  }
-
-  // handle accesses to the bytes
-
-  ensureByte(pos) {
-    this._ensureGetPos(pos) // may throw a MissingDataException
-  }
-
-  getByte() {
-    const pos = this.pos
-    if (this.pos >= this.end) {
-      return -1
-    }
-    const found = this._ensureGetPos(pos)
-    return this._readByte(found, this.pos++)
-  }
-
-  // BG: for a range, end is not included (see Buffer.subarray for example)
-
-  ensureBytes(length, forceClamped = false) {
-    const pos = this.pos
-    this._ensureGetRange(pos, pos + length)
-  }
-
-  getBytes(length, forceClamped = false) {
-    const pos = this.pos
-    const strEnd = this.end
-
-    const found = this._ensureGetRange(pos, pos + length)
-    if (!length) {
-      const subarray = this._readBytes(found, pos, strEnd)
-      // `this.bytes` is always a `Uint8Array` here.
-      return forceClamped ? new Uint8ClampedArray(subarray) : subarray
-    }
-    let end = pos + length
-    if (end > strEnd) {
-      end = strEnd
-    }
-    this.pos = end
-    const subarray = this._readBytes(found, pos, end)
-    // `this.bytes` is always a `Uint8Array` here.
-    return forceClamped ? new Uint8ClampedArray(subarray) : subarray
-  }
-
-  getByteRange() {
-    // BG: this isn't needed as far as I can tell
-    throw new Error('not implemented')
-  }
-
-  reset() {
-    this.pos = this.start
-  }
-
-  moveStart() {
-    this.start = this.pos
-  }
-
-  makeSubStream(start, length, dict = null) {
-    this.checkDeadline(`make sub stream start=${start}/length=${length}`)
-    // BG: had to add this check for null length, it is being called with only
-    // the start value at one point in the xref decoding. The intent is clear
-    // enough
-    // - a null length means "to the end of the file" -- not sure how it is
-    //   working in the existing pdfjs code without this.
-    if (!length) {
-      length = this.end - start
-    }
-    return new FSStream(
-      this.fh,
-      start,
-      length,
-      dict,
-      this.cachedBytes,
-      this.checkDeadline
-    )
-  }
-}
-
-module.exports = { FSStream }

+ 0 - 29
services/clsi/app/lib/pdfjs/parseXrefTable.js

@@ -1,29 +0,0 @@
-const fs = require('fs')
-const { FSPdfManager } = require('./FSPdfManager')
-
-async function parseXrefTable(path, size, checkDeadline) {
-  if (size === 0) {
-    return []
-  }
-
-  const file = await fs.promises.open(path)
-  try {
-    const manager = new FSPdfManager(0, { fh: file, size, checkDeadline })
-
-    await manager.ensureDoc('checkHeader')
-    checkDeadline('pdfjs: after checkHeader')
-    await manager.ensureDoc('parseStartXRef')
-    checkDeadline('pdfjs: after parseStartXRef')
-    await manager.ensureDoc('parse')
-    checkDeadline('pdfjs: after parse')
-    const xRefEntries = manager.pdfDocument.xref.entries || []
-    const startXRefTable = manager.pdfDocument.xref.topDict?.get('Prev')
-    return { xRefEntries, startXRefTable }
-  } finally {
-    file.close()
-  }
-}
-
-module.exports = {
-  parseXrefTable,
-}

+ 0 - 1
services/clsi/package.json

@@ -30,7 +30,6 @@
     "lockfile": "^1.0.4",
     "lodash": "^4.17.21",
     "p-limit": "^3.1.0",
-    "pdfjs-dist": "~2.7.570",
     "request": "^2.88.2",
     "send": "^0.17.1",
     "workerpool": "^6.1.5"

+ 81 - 0
services/clsi/test/acceptance/fixtures/examples/asymptote/output.pdfxref

@@ -0,0 +1,81 @@
+1/0: uncompressed; offset = 123103
+2/0: uncompressed; offset = 123422
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 1084
+6/0: uncompressed; offset = 1244
+7/0: uncompressed; offset = 4001
+8/0: uncompressed; offset = 4155
+9/0: uncompressed; offset = 4297
+10/0: uncompressed; offset = 4933
+11/0: uncompressed; offset = 5309
+12/0: uncompressed; offset = 5498
+13/0: uncompressed; offset = 30250
+14/0: uncompressed; offset = 31471
+15/0: uncompressed; offset = 38404
+16/0: uncompressed; offset = 39046
+17/0: uncompressed; offset = 40166
+18/0: uncompressed; offset = 40906
+19/0: uncompressed; offset = 65560
+20/0: uncompressed; offset = 74702
+21/0: uncompressed; offset = 81705
+22/0: uncompressed; offset = 97182
+23/0: uncompressed; offset = 104117
+24/0: uncompressed; offset = 111195
+25/0: uncompressed; offset = 118571
+26/0: compressed; stream = 6, index = 0
+27/0: compressed; stream = 6, index = 1
+28/0: compressed; stream = 6, index = 2
+29/0: compressed; stream = 6, index = 3
+30/0: compressed; stream = 6, index = 4
+31/0: compressed; stream = 6, index = 5
+32/0: compressed; stream = 6, index = 6
+33/0: compressed; stream = 6, index = 7
+34/0: compressed; stream = 6, index = 8
+35/0: compressed; stream = 6, index = 9
+36/0: compressed; stream = 6, index = 10
+37/0: compressed; stream = 6, index = 11
+38/0: compressed; stream = 6, index = 12
+39/0: compressed; stream = 6, index = 13
+40/0: compressed; stream = 6, index = 14
+41/0: compressed; stream = 6, index = 15
+42/0: compressed; stream = 6, index = 16
+43/0: compressed; stream = 6, index = 17
+44/0: compressed; stream = 6, index = 18
+45/0: compressed; stream = 6, index = 19
+46/0: compressed; stream = 6, index = 20
+47/0: compressed; stream = 6, index = 21
+48/0: compressed; stream = 6, index = 22
+49/0: compressed; stream = 6, index = 23
+50/0: compressed; stream = 6, index = 24
+51/0: compressed; stream = 6, index = 25
+52/0: compressed; stream = 6, index = 26
+53/0: compressed; stream = 6, index = 27
+54/0: compressed; stream = 6, index = 28
+55/0: compressed; stream = 6, index = 29
+56/0: compressed; stream = 6, index = 30
+57/0: compressed; stream = 6, index = 31
+58/0: compressed; stream = 6, index = 32
+59/0: compressed; stream = 6, index = 33
+60/0: compressed; stream = 6, index = 34
+61/0: compressed; stream = 6, index = 35
+62/0: compressed; stream = 6, index = 36
+63/0: compressed; stream = 6, index = 37
+64/0: compressed; stream = 6, index = 38
+65/0: compressed; stream = 6, index = 39
+66/0: compressed; stream = 6, index = 40
+67/0: compressed; stream = 6, index = 41
+68/0: compressed; stream = 6, index = 42
+69/0: compressed; stream = 6, index = 43
+70/0: compressed; stream = 6, index = 44
+71/0: compressed; stream = 6, index = 45
+72/0: compressed; stream = 6, index = 46
+73/0: compressed; stream = 6, index = 47
+74/0: compressed; stream = 6, index = 48
+75/0: compressed; stream = 6, index = 49
+76/0: compressed; stream = 6, index = 50
+77/0: compressed; stream = 6, index = 51
+78/0: compressed; stream = 6, index = 52
+79/0: compressed; stream = 6, index = 53
+80/0: compressed; stream = 6, index = 54
+81/0: compressed; stream = 6, index = 55

+ 31 - 0
services/clsi/test/acceptance/fixtures/examples/biber_bibliography/output.pdfxref

@@ -0,0 +1,31 @@
+1/0: uncompressed; offset = 59313
+2/0: uncompressed; offset = 59561
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 734
+6/0: uncompressed; offset = 784
+7/0: uncompressed; offset = 913
+8/0: uncompressed; offset = 1028
+9/0: uncompressed; offset = 1528
+10/0: uncompressed; offset = 9787
+11/0: uncompressed; offset = 18282
+12/0: uncompressed; offset = 33607
+13/0: uncompressed; offset = 45579
+14/0: uncompressed; offset = 58005
+15/0: compressed; stream = 14, index = 0
+16/0: compressed; stream = 14, index = 1
+17/0: compressed; stream = 14, index = 2
+18/0: compressed; stream = 14, index = 3
+19/0: compressed; stream = 14, index = 4
+20/0: compressed; stream = 14, index = 5
+21/0: compressed; stream = 14, index = 6
+22/0: compressed; stream = 14, index = 7
+23/0: compressed; stream = 14, index = 8
+24/0: compressed; stream = 14, index = 9
+25/0: compressed; stream = 14, index = 10
+26/0: compressed; stream = 14, index = 11
+27/0: compressed; stream = 14, index = 12
+28/0: compressed; stream = 14, index = 13
+29/0: compressed; stream = 14, index = 14
+30/0: compressed; stream = 14, index = 15
+31/0: compressed; stream = 14, index = 16

+ 39 - 0
services/clsi/test/acceptance/fixtures/examples/draft_legacy/output.pdfxref

@@ -0,0 +1,39 @@
+1/0: uncompressed; offset = 67338
+2/0: uncompressed; offset = 67606
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 790
+6/0: uncompressed; offset = 840
+7/0: uncompressed; offset = 975
+8/0: uncompressed; offset = 1083
+9/0: uncompressed; offset = 1578
+10/0: uncompressed; offset = 9881
+11/0: uncompressed; offset = 17868
+12/0: uncompressed; offset = 29906
+13/0: uncompressed; offset = 38400
+14/0: uncompressed; offset = 46656
+15/0: uncompressed; offset = 56198
+16/0: uncompressed; offset = 65682
+17/0: compressed; stream = 16, index = 0
+18/0: compressed; stream = 16, index = 1
+19/0: compressed; stream = 16, index = 2
+20/0: compressed; stream = 16, index = 3
+21/0: compressed; stream = 16, index = 4
+22/0: compressed; stream = 16, index = 5
+23/0: compressed; stream = 16, index = 6
+24/0: compressed; stream = 16, index = 7
+25/0: compressed; stream = 16, index = 8
+26/0: compressed; stream = 16, index = 9
+27/0: compressed; stream = 16, index = 10
+28/0: compressed; stream = 16, index = 11
+29/0: compressed; stream = 16, index = 12
+30/0: compressed; stream = 16, index = 13
+31/0: compressed; stream = 16, index = 14
+32/0: compressed; stream = 16, index = 15
+33/0: compressed; stream = 16, index = 16
+34/0: compressed; stream = 16, index = 17
+35/0: compressed; stream = 16, index = 18
+36/0: compressed; stream = 16, index = 19
+37/0: compressed; stream = 16, index = 20
+38/0: compressed; stream = 16, index = 21
+39/0: compressed; stream = 16, index = 22

+ 50 - 0
services/clsi/test/acceptance/fixtures/examples/draft_mode/output.pdfxref

@@ -0,0 +1,50 @@
+1/0: uncompressed; offset = 69708
+2/0: uncompressed; offset = 70038
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 867
+6/0: uncompressed; offset = 990
+7/0: uncompressed; offset = 1143
+8/0: uncompressed; offset = 1251
+9/0: uncompressed; offset = 1834
+10/0: uncompressed; offset = 10137
+11/0: uncompressed; offset = 18124
+12/0: uncompressed; offset = 31939
+13/0: uncompressed; offset = 40433
+14/0: uncompressed; offset = 48689
+15/0: uncompressed; offset = 58231
+16/0: uncompressed; offset = 67715
+17/0: compressed; stream = 16, index = 0
+18/0: compressed; stream = 16, index = 1
+19/0: compressed; stream = 16, index = 2
+20/0: compressed; stream = 16, index = 3
+21/0: compressed; stream = 16, index = 4
+22/0: compressed; stream = 16, index = 5
+23/0: compressed; stream = 16, index = 6
+24/0: compressed; stream = 16, index = 7
+25/0: compressed; stream = 16, index = 8
+26/0: compressed; stream = 16, index = 9
+27/0: compressed; stream = 16, index = 10
+28/0: compressed; stream = 16, index = 11
+29/0: compressed; stream = 16, index = 12
+30/0: compressed; stream = 16, index = 13
+31/0: compressed; stream = 16, index = 14
+32/0: compressed; stream = 16, index = 15
+33/0: compressed; stream = 16, index = 16
+34/0: compressed; stream = 16, index = 17
+35/0: compressed; stream = 16, index = 18
+36/0: compressed; stream = 16, index = 19
+37/0: compressed; stream = 16, index = 20
+38/0: compressed; stream = 16, index = 21
+39/0: compressed; stream = 16, index = 22
+40/0: compressed; stream = 16, index = 23
+41/0: compressed; stream = 16, index = 24
+42/0: compressed; stream = 16, index = 25
+43/0: compressed; stream = 16, index = 26
+44/0: compressed; stream = 16, index = 27
+45/0: compressed; stream = 16, index = 28
+46/0: compressed; stream = 16, index = 29
+47/0: compressed; stream = 16, index = 30
+48/0: compressed; stream = 16, index = 31
+49/0: compressed; stream = 16, index = 32
+50/0: compressed; stream = 16, index = 33

+ 30 - 0
services/clsi/test/acceptance/fixtures/examples/epstopdf/output.pdfxref

@@ -0,0 +1,30 @@
+1/0: uncompressed; offset = 31354
+2/0: uncompressed; offset = 31614
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 727
+6/0: uncompressed; offset = 777
+7/0: uncompressed; offset = 909
+8/0: uncompressed; offset = 1017
+9/0: uncompressed; offset = 19127
+10/0: uncompressed; offset = 19313
+11/0: uncompressed; offset = 19557
+12/0: uncompressed; offset = 19948
+13/0: uncompressed; offset = 20677
+14/0: uncompressed; offset = 23321
+15/0: uncompressed; offset = 30318
+16/0: compressed; stream = 15, index = 0
+17/0: compressed; stream = 15, index = 1
+18/0: compressed; stream = 15, index = 2
+19/0: compressed; stream = 15, index = 3
+20/0: compressed; stream = 15, index = 4
+21/0: compressed; stream = 15, index = 5
+22/0: compressed; stream = 15, index = 6
+23/0: compressed; stream = 15, index = 7
+24/0: compressed; stream = 15, index = 8
+25/0: compressed; stream = 15, index = 9
+26/0: compressed; stream = 15, index = 10
+27/0: compressed; stream = 15, index = 11
+28/0: compressed; stream = 15, index = 12
+29/0: compressed; stream = 15, index = 13
+30/0: compressed; stream = 15, index = 14

+ 28 - 0
services/clsi/test/acceptance/fixtures/examples/feynmf/output.pdfxref

@@ -0,0 +1,28 @@
+1/0: uncompressed; offset = 27064
+2/0: uncompressed; offset = 27312
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 713
+6/0: uncompressed; offset = 763
+7/0: uncompressed; offset = 892
+8/0: uncompressed; offset = 1007
+9/0: uncompressed; offset = 1235
+10/0: uncompressed; offset = 4832
+11/0: uncompressed; offset = 12199
+12/0: uncompressed; offset = 19196
+13/0: uncompressed; offset = 26341
+14/0: compressed; stream = 13, index = 0
+15/0: compressed; stream = 13, index = 1
+16/0: compressed; stream = 13, index = 2
+17/0: compressed; stream = 13, index = 3
+18/0: compressed; stream = 13, index = 4
+19/0: compressed; stream = 13, index = 5
+20/0: compressed; stream = 13, index = 6
+21/0: compressed; stream = 13, index = 7
+22/0: compressed; stream = 13, index = 8
+23/0: compressed; stream = 13, index = 9
+24/0: compressed; stream = 13, index = 10
+25/0: compressed; stream = 13, index = 11
+26/0: compressed; stream = 13, index = 12
+27/0: compressed; stream = 13, index = 13
+28/0: compressed; stream = 13, index = 14

+ 20 - 0
services/clsi/test/acceptance/fixtures/examples/feynmp/output.pdfxref

@@ -0,0 +1,20 @@
+1/0: uncompressed; offset = 4964
+2/0: uncompressed; offset = 5023
+3/0: uncompressed; offset = 5234
+4/0: uncompressed; offset = 15
+5/0: uncompressed; offset = 734
+6/0: uncompressed; offset = 799
+7/0: uncompressed; offset = 933
+8/0: uncompressed; offset = 1104
+9/0: uncompressed; offset = 1947
+10/0: uncompressed; offset = 1992
+11/0: uncompressed; offset = 2182
+12/0: uncompressed; offset = 2427
+13/0: uncompressed; offset = 2597
+14/0: uncompressed; offset = 2822
+15/0: uncompressed; offset = 2989
+16/0: uncompressed; offset = 3239
+17/0: uncompressed; offset = 3271
+18/0: uncompressed; offset = 3328
+19/0: uncompressed; offset = 3740
+20/0: uncompressed; offset = 4270

+ 23 - 0
services/clsi/test/acceptance/fixtures/examples/fontawesome/output.pdfxref

@@ -0,0 +1,23 @@
+1/0: uncompressed; offset = 31058
+2/0: uncompressed; offset = 31307
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 678
+6/0: uncompressed; offset = 728
+7/0: uncompressed; offset = 855
+8/0: uncompressed; offset = 970
+9/0: uncompressed; offset = 1203
+10/0: uncompressed; offset = 18852
+11/0: uncompressed; offset = 30165
+12/0: compressed; stream = 11, index = 0
+13/0: compressed; stream = 11, index = 1
+14/0: compressed; stream = 11, index = 2
+15/0: compressed; stream = 11, index = 3
+16/0: compressed; stream = 11, index = 4
+17/0: compressed; stream = 11, index = 5
+18/0: compressed; stream = 11, index = 6
+19/0: compressed; stream = 11, index = 7
+20/0: compressed; stream = 11, index = 8
+21/0: compressed; stream = 11, index = 9
+22/0: compressed; stream = 11, index = 10
+23/0: compressed; stream = 11, index = 11

+ 26 - 0
services/clsi/test/acceptance/fixtures/examples/fontawesome_xelatex/output.pdfxref

@@ -0,0 +1,26 @@
+1/0: uncompressed; offset = 6344
+2/0: uncompressed; offset = 15
+3/0: uncompressed; offset = 216
+4/0: uncompressed; offset = 707
+5/0: uncompressed; offset = 757
+6/0: uncompressed; offset = 887
+7/0: uncompressed; offset = 990
+8/0: uncompressed; offset = 1257
+9/0: uncompressed; offset = 1679
+10/0: uncompressed; offset = 2052
+11/0: uncompressed; offset = 4249
+12/0: uncompressed; offset = 4343
+13/0: uncompressed; offset = 5387
+14/0: uncompressed; offset = 5481
+15/0: uncompressed; offset = 5519
+16/0: compressed; stream = 15, index = 0
+17/0: compressed; stream = 15, index = 1
+18/0: compressed; stream = 15, index = 2
+19/0: compressed; stream = 15, index = 3
+20/0: compressed; stream = 15, index = 4
+21/0: compressed; stream = 15, index = 5
+22/0: compressed; stream = 15, index = 6
+23/0: compressed; stream = 15, index = 7
+24/0: compressed; stream = 15, index = 8
+25/0: compressed; stream = 15, index = 9
+26/0: compressed; stream = 15, index = 10

+ 23 - 0
services/clsi/test/acceptance/fixtures/examples/glossaries/output.pdfxref

@@ -0,0 +1,23 @@
+1/0: uncompressed; offset = 34767
+2/0: uncompressed; offset = 35015
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 678
+6/0: uncompressed; offset = 728
+7/0: uncompressed; offset = 856
+8/0: uncompressed; offset = 971
+9/0: uncompressed; offset = 1394
+10/0: uncompressed; offset = 10990
+11/0: uncompressed; offset = 19087
+12/0: uncompressed; offset = 33769
+13/0: compressed; stream = 12, index = 0
+14/0: compressed; stream = 12, index = 1
+15/0: compressed; stream = 12, index = 2
+16/0: compressed; stream = 12, index = 3
+17/0: compressed; stream = 12, index = 4
+18/0: compressed; stream = 12, index = 5
+19/0: compressed; stream = 12, index = 6
+20/0: compressed; stream = 12, index = 7
+21/0: compressed; stream = 12, index = 8
+22/0: compressed; stream = 12, index = 9
+23/0: compressed; stream = 12, index = 10

+ 22 - 0
services/clsi/test/acceptance/fixtures/examples/gnuplot/output.pdfxref

@@ -0,0 +1,22 @@
+1/0: uncompressed; offset = 23295
+2/0: uncompressed; offset = 23543
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 671
+6/0: uncompressed; offset = 721
+7/0: uncompressed; offset = 847
+8/0: uncompressed; offset = 955
+9/0: uncompressed; offset = 7385
+10/0: uncompressed; offset = 15752
+11/0: uncompressed; offset = 22721
+12/0: compressed; stream = 11, index = 0
+13/0: compressed; stream = 11, index = 1
+14/0: compressed; stream = 11, index = 2
+15/0: compressed; stream = 11, index = 3
+16/0: compressed; stream = 11, index = 4
+17/0: compressed; stream = 11, index = 5
+18/0: compressed; stream = 11, index = 6
+19/0: compressed; stream = 11, index = 7
+20/0: compressed; stream = 11, index = 8
+21/0: compressed; stream = 11, index = 9
+22/0: compressed; stream = 11, index = 10

+ 20 - 0
services/clsi/test/acceptance/fixtures/examples/hebrew/output.pdfxref

@@ -0,0 +1,20 @@
+1/0: uncompressed; offset = 24490
+2/0: uncompressed; offset = 24739
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 657
+6/0: uncompressed; offset = 707
+7/0: uncompressed; offset = 833
+8/0: uncompressed; offset = 948
+9/0: uncompressed; offset = 1290
+10/0: uncompressed; offset = 13083
+11/0: uncompressed; offset = 23411
+12/0: compressed; stream = 11, index = 0
+13/0: compressed; stream = 11, index = 1
+14/0: compressed; stream = 11, index = 2
+15/0: compressed; stream = 11, index = 3
+16/0: compressed; stream = 11, index = 4
+17/0: compressed; stream = 11, index = 5
+18/0: compressed; stream = 11, index = 6
+19/0: compressed; stream = 11, index = 7
+20/0: compressed; stream = 11, index = 8

+ 31 - 0
services/clsi/test/acceptance/fixtures/examples/knitr/output.pdfxref

@@ -0,0 +1,31 @@
+1/0: uncompressed; offset = 43550
+2/0: uncompressed; offset = 43799
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 734
+6/0: uncompressed; offset = 784
+7/0: uncompressed; offset = 913
+8/0: uncompressed; offset = 1021
+9/0: uncompressed; offset = 1546
+10/0: uncompressed; offset = 5794
+11/0: uncompressed; offset = 12915
+12/0: uncompressed; offset = 23660
+13/0: uncompressed; offset = 30657
+14/0: uncompressed; offset = 42604
+15/0: compressed; stream = 14, index = 0
+16/0: compressed; stream = 14, index = 1
+17/0: compressed; stream = 14, index = 2
+18/0: compressed; stream = 14, index = 3
+19/0: compressed; stream = 14, index = 4
+20/0: compressed; stream = 14, index = 5
+21/0: compressed; stream = 14, index = 6
+22/0: compressed; stream = 14, index = 7
+23/0: compressed; stream = 14, index = 8
+24/0: compressed; stream = 14, index = 9
+25/0: compressed; stream = 14, index = 10
+26/0: compressed; stream = 14, index = 11
+27/0: compressed; stream = 14, index = 12
+28/0: compressed; stream = 14, index = 13
+29/0: compressed; stream = 14, index = 14
+30/0: compressed; stream = 14, index = 15
+31/0: compressed; stream = 14, index = 16

+ 39 - 0
services/clsi/test/acceptance/fixtures/examples/knitr_utf8/output.pdfxref

@@ -0,0 +1,39 @@
+1/0: uncompressed; offset = 75299
+2/0: uncompressed; offset = 75548
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 790
+6/0: uncompressed; offset = 840
+7/0: uncompressed; offset = 975
+8/0: uncompressed; offset = 1083
+9/0: uncompressed; offset = 2128
+10/0: uncompressed; offset = 13799
+11/0: uncompressed; offset = 23682
+12/0: uncompressed; offset = 31867
+13/0: uncompressed; offset = 36116
+14/0: uncompressed; offset = 50352
+15/0: uncompressed; offset = 61569
+16/0: uncompressed; offset = 73516
+17/0: compressed; stream = 16, index = 0
+18/0: compressed; stream = 16, index = 1
+19/0: compressed; stream = 16, index = 2
+20/0: compressed; stream = 16, index = 3
+21/0: compressed; stream = 16, index = 4
+22/0: compressed; stream = 16, index = 5
+23/0: compressed; stream = 16, index = 6
+24/0: compressed; stream = 16, index = 7
+25/0: compressed; stream = 16, index = 8
+26/0: compressed; stream = 16, index = 9
+27/0: compressed; stream = 16, index = 10
+28/0: compressed; stream = 16, index = 11
+29/0: compressed; stream = 16, index = 12
+30/0: compressed; stream = 16, index = 13
+31/0: compressed; stream = 16, index = 14
+32/0: compressed; stream = 16, index = 15
+33/0: compressed; stream = 16, index = 16
+34/0: compressed; stream = 16, index = 17
+35/0: compressed; stream = 16, index = 18
+36/0: compressed; stream = 16, index = 19
+37/0: compressed; stream = 16, index = 20
+38/0: compressed; stream = 16, index = 21
+39/0: compressed; stream = 16, index = 22

+ 26 - 0
services/clsi/test/acceptance/fixtures/examples/latex_compiler/output.pdfxref

@@ -0,0 +1,26 @@
+1/0: uncompressed; offset = 25097
+2/0: uncompressed; offset = 25156
+3/0: uncompressed; offset = 25367
+4/0: uncompressed; offset = 15
+5/0: uncompressed; offset = 854
+6/0: uncompressed; offset = 919
+7/0: uncompressed; offset = 1074
+8/0: uncompressed; offset = 1245
+9/0: uncompressed; offset = 18343
+10/0: uncompressed; offset = 18388
+11/0: uncompressed; offset = 18752
+12/0: uncompressed; offset = 19071
+13/0: uncompressed; offset = 19360
+14/0: uncompressed; offset = 19604
+15/0: uncompressed; offset = 19770
+16/0: uncompressed; offset = 20007
+17/0: uncompressed; offset = 20174
+18/0: uncompressed; offset = 20424
+19/0: uncompressed; offset = 20456
+20/0: uncompressed; offset = 20525
+21/0: uncompressed; offset = 23109
+22/0: uncompressed; offset = 23500
+23/0: uncompressed; offset = 24229
+24/0: uncompressed; offset = 24641
+25/0: uncompressed; offset = 24741
+26/0: uncompressed; offset = 24985

+ 18 - 0
services/clsi/test/acceptance/fixtures/examples/lualatex_compiler/output.pdfxref

@@ -0,0 +1,18 @@
+1/0: uncompressed; offset = 3568
+2/0: uncompressed; offset = 3777
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 643
+6/0: uncompressed; offset = 693
+7/0: uncompressed; offset = 819
+8/0: uncompressed; offset = 934
+9/0: uncompressed; offset = 1118
+10/0: uncompressed; offset = 1210
+11/0: uncompressed; offset = 2555
+12/0: uncompressed; offset = 3030
+13/0: compressed; stream = 12, index = 0
+14/0: compressed; stream = 12, index = 1
+15/0: compressed; stream = 12, index = 2
+16/0: compressed; stream = 12, index = 3
+17/0: compressed; stream = 12, index = 4
+18/0: compressed; stream = 12, index = 5

+ 26 - 0
services/clsi/test/acceptance/fixtures/examples/makeindex-custom-style/output.pdfxref

@@ -0,0 +1,26 @@
+1/0: uncompressed; offset = 16762
+2/0: uncompressed; offset = 16877
+3/0: uncompressed; offset = 17142
+4/0: uncompressed; offset = 24335
+5/0: uncompressed; offset = 32164
+6/0: uncompressed; offset = 32412
+7/0: uncompressed; offset = 15
+8/0: uncompressed; offset = 216
+9/0: uncompressed; offset = 671
+10/0: uncompressed; offset = 721
+11/0: uncompressed; offset = 856
+12/0: uncompressed; offset = 973
+13/0: uncompressed; offset = 1318
+14/0: uncompressed; offset = 2218
+15/0: compressed; stream = 13, index = 0
+16/0: compressed; stream = 13, index = 1
+17/0: compressed; stream = 13, index = 2
+18/0: compressed; stream = 13, index = 3
+19/0: compressed; stream = 13, index = 4
+20/0: compressed; stream = 13, index = 5
+21/0: compressed; stream = 13, index = 6
+22/0: compressed; stream = 13, index = 7
+23/0: compressed; stream = 13, index = 8
+24/0: compressed; stream = 13, index = 9
+25/0: compressed; stream = 13, index = 10
+26/0: compressed; stream = 13, index = 11

+ 22 - 0
services/clsi/test/acceptance/fixtures/examples/makeindex/output.pdfxref

@@ -0,0 +1,22 @@
+1/0: uncompressed; offset = 16778
+2/0: uncompressed; offset = 16893
+3/0: uncompressed; offset = 17109
+4/0: uncompressed; offset = 24938
+5/0: uncompressed; offset = 25186
+6/0: uncompressed; offset = 15
+7/0: uncompressed; offset = 216
+8/0: uncompressed; offset = 650
+9/0: uncompressed; offset = 700
+10/0: uncompressed; offset = 836
+11/0: uncompressed; offset = 953
+12/0: uncompressed; offset = 1298
+13/0: uncompressed; offset = 2103
+14/0: compressed; stream = 12, index = 0
+15/0: compressed; stream = 12, index = 1
+16/0: compressed; stream = 12, index = 2
+17/0: compressed; stream = 12, index = 3
+18/0: compressed; stream = 12, index = 4
+19/0: compressed; stream = 12, index = 5
+20/0: compressed; stream = 12, index = 6
+21/0: compressed; stream = 12, index = 7
+22/0: compressed; stream = 12, index = 8

+ 19 - 0
services/clsi/test/acceptance/fixtures/examples/minted/output.pdfxref

@@ -0,0 +1,19 @@
+1/0: uncompressed; offset = 20679
+2/0: uncompressed; offset = 20927
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 650
+6/0: uncompressed; offset = 700
+7/0: uncompressed; offset = 826
+8/0: uncompressed; offset = 934
+9/0: uncompressed; offset = 1252
+10/0: uncompressed; offset = 8248
+11/0: uncompressed; offset = 20115
+12/0: compressed; stream = 11, index = 0
+13/0: compressed; stream = 11, index = 1
+14/0: compressed; stream = 11, index = 2
+15/0: compressed; stream = 11, index = 3
+16/0: compressed; stream = 11, index = 4
+17/0: compressed; stream = 11, index = 5
+18/0: compressed; stream = 11, index = 6
+19/0: compressed; stream = 11, index = 7

+ 32 - 0
services/clsi/test/acceptance/fixtures/examples/multibib_bibliography/output.pdfxref

@@ -0,0 +1,32 @@
+1/0: uncompressed; offset = 29506
+2/0: uncompressed; offset = 29621
+3/0: uncompressed; offset = 29918
+4/0: uncompressed; offset = 30033
+5/0: uncompressed; offset = 30274
+6/0: uncompressed; offset = 30389
+7/0: uncompressed; offset = 30644
+8/0: uncompressed; offset = 42802
+9/0: uncompressed; offset = 43050
+10/0: uncompressed; offset = 15
+11/0: uncompressed; offset = 216
+12/0: uncompressed; offset = 695
+13/0: uncompressed; offset = 746
+14/0: uncompressed; offset = 900
+15/0: uncompressed; offset = 1017
+16/0: uncompressed; offset = 1286
+17/0: uncompressed; offset = 2443
+18/0: uncompressed; offset = 13147
+19/0: compressed; stream = 16, index = 0
+20/0: compressed; stream = 16, index = 1
+21/0: compressed; stream = 16, index = 2
+22/0: compressed; stream = 16, index = 3
+23/0: compressed; stream = 16, index = 4
+24/0: compressed; stream = 16, index = 5
+25/0: compressed; stream = 16, index = 6
+26/0: compressed; stream = 16, index = 7
+27/0: compressed; stream = 16, index = 8
+28/0: compressed; stream = 16, index = 9
+29/0: compressed; stream = 16, index = 10
+30/0: compressed; stream = 16, index = 11
+31/0: compressed; stream = 16, index = 12
+32/0: compressed; stream = 16, index = 13

+ 23 - 0
services/clsi/test/acceptance/fixtures/examples/nomenclature/output.pdfxref

@@ -0,0 +1,23 @@
+1/0: uncompressed; offset = 34102
+2/0: uncompressed; offset = 34350
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 678
+6/0: uncompressed; offset = 728
+7/0: uncompressed; offset = 856
+8/0: uncompressed; offset = 971
+9/0: uncompressed; offset = 1514
+10/0: uncompressed; offset = 10973
+11/0: uncompressed; offset = 19139
+12/0: uncompressed; offset = 33047
+13/0: compressed; stream = 12, index = 0
+14/0: compressed; stream = 12, index = 1
+15/0: compressed; stream = 12, index = 2
+16/0: compressed; stream = 12, index = 3
+17/0: compressed; stream = 12, index = 4
+18/0: compressed; stream = 12, index = 5
+19/0: compressed; stream = 12, index = 6
+20/0: compressed; stream = 12, index = 7
+21/0: compressed; stream = 12, index = 8
+22/0: compressed; stream = 12, index = 9
+23/0: compressed; stream = 12, index = 10

+ 22 - 0
services/clsi/test/acceptance/fixtures/examples/references_in_include/output.pdfxref

@@ -0,0 +1,22 @@
+1/0: uncompressed; offset = 9449
+2/0: uncompressed; offset = 9564
+3/0: uncompressed; offset = 9730
+4/0: uncompressed; offset = 17293
+5/0: uncompressed; offset = 17541
+6/0: uncompressed; offset = 15
+7/0: uncompressed; offset = 216
+8/0: uncompressed; offset = 650
+9/0: uncompressed; offset = 700
+10/0: uncompressed; offset = 835
+11/0: uncompressed; offset = 952
+12/0: uncompressed; offset = 1097
+13/0: uncompressed; offset = 1758
+14/0: compressed; stream = 12, index = 0
+15/0: compressed; stream = 12, index = 1
+16/0: compressed; stream = 12, index = 2
+17/0: compressed; stream = 12, index = 3
+18/0: compressed; stream = 12, index = 4
+19/0: compressed; stream = 12, index = 5
+20/0: compressed; stream = 12, index = 6
+21/0: compressed; stream = 12, index = 7
+22/0: compressed; stream = 12, index = 8

+ 23 - 0
services/clsi/test/acceptance/fixtures/examples/simple_bibliography/output.pdfxref

@@ -0,0 +1,23 @@
+1/0: uncompressed; offset = 37282
+2/0: uncompressed; offset = 37530
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 678
+6/0: uncompressed; offset = 728
+7/0: uncompressed; offset = 856
+8/0: uncompressed; offset = 971
+9/0: uncompressed; offset = 1322
+10/0: uncompressed; offset = 9581
+11/0: uncompressed; offset = 24286
+12/0: uncompressed; offset = 36258
+13/0: compressed; stream = 12, index = 0
+14/0: compressed; stream = 12, index = 1
+15/0: compressed; stream = 12, index = 2
+16/0: compressed; stream = 12, index = 3
+17/0: compressed; stream = 12, index = 4
+18/0: compressed; stream = 12, index = 5
+19/0: compressed; stream = 12, index = 6
+20/0: compressed; stream = 12, index = 7
+21/0: compressed; stream = 12, index = 8
+22/0: compressed; stream = 12, index = 9
+23/0: compressed; stream = 12, index = 10

+ 26 - 0
services/clsi/test/acceptance/fixtures/examples/subdirectories/output.pdfxref

@@ -0,0 +1,26 @@
+1/0: uncompressed; offset = 48194
+2/0: uncompressed; offset = 48442
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 699
+6/0: uncompressed; offset = 749
+7/0: uncompressed; offset = 878
+8/0: uncompressed; offset = 1000
+9/0: uncompressed; offset = 8546
+10/0: uncompressed; offset = 9072
+11/0: uncompressed; offset = 10659
+12/0: uncompressed; offset = 18919
+13/0: uncompressed; offset = 35129
+14/0: uncompressed; offset = 47101
+15/0: compressed; stream = 14, index = 0
+16/0: compressed; stream = 14, index = 1
+17/0: compressed; stream = 14, index = 2
+18/0: compressed; stream = 14, index = 3
+19/0: compressed; stream = 14, index = 4
+20/0: compressed; stream = 14, index = 5
+21/0: compressed; stream = 14, index = 6
+22/0: compressed; stream = 14, index = 7
+23/0: compressed; stream = 14, index = 8
+24/0: compressed; stream = 14, index = 9
+25/0: compressed; stream = 14, index = 10
+26/0: compressed; stream = 14, index = 11

+ 35 - 0
services/clsi/test/acceptance/fixtures/examples/tikz_feynman/output.pdfxref

@@ -0,0 +1,35 @@
+1/0: uncompressed; offset = 2924
+2/0: uncompressed; offset = 3039
+3/0: uncompressed; offset = 4606
+4/0: uncompressed; offset = 4721
+5/0: uncompressed; offset = 7754
+6/0: uncompressed; offset = 7870
+7/0: uncompressed; offset = 11668
+8/0: uncompressed; offset = 21077
+9/0: uncompressed; offset = 28498
+10/0: uncompressed; offset = 35464
+11/0: uncompressed; offset = 35699
+12/0: uncompressed; offset = 15
+13/0: uncompressed; offset = 216
+14/0: uncompressed; offset = 703
+15/0: uncompressed; offset = 754
+16/0: uncompressed; offset = 909
+17/0: uncompressed; offset = 1026
+18/0: uncompressed; offset = 2161
+19/0: compressed; stream = 18, index = 0
+20/0: compressed; stream = 18, index = 1
+21/0: compressed; stream = 18, index = 2
+22/0: compressed; stream = 18, index = 3
+23/0: compressed; stream = 18, index = 4
+24/0: compressed; stream = 18, index = 5
+25/0: compressed; stream = 18, index = 6
+26/0: compressed; stream = 18, index = 7
+27/0: compressed; stream = 18, index = 8
+28/0: compressed; stream = 18, index = 9
+29/0: compressed; stream = 18, index = 10
+30/0: compressed; stream = 18, index = 11
+31/0: compressed; stream = 18, index = 12
+32/0: compressed; stream = 18, index = 13
+33/0: compressed; stream = 18, index = 14
+34/0: compressed; stream = 18, index = 15
+35/0: compressed; stream = 18, index = 16

+ 19 - 0
services/clsi/test/acceptance/fixtures/examples/xelatex_compiler/output.pdfxref

@@ -0,0 +1,19 @@
+1/0: uncompressed; offset = 8578
+2/0: uncompressed; offset = 15
+3/0: uncompressed; offset = 216
+4/0: uncompressed; offset = 658
+5/0: uncompressed; offset = 708
+6/0: uncompressed; offset = 837
+7/0: uncompressed; offset = 940
+8/0: uncompressed; offset = 1191
+9/0: uncompressed; offset = 1627
+10/0: uncompressed; offset = 7676
+11/0: uncompressed; offset = 7784
+12/0: uncompressed; offset = 7822
+13/0: compressed; stream = 12, index = 0
+14/0: compressed; stream = 12, index = 1
+15/0: compressed; stream = 12, index = 2
+16/0: compressed; stream = 12, index = 3
+17/0: compressed; stream = 12, index = 4
+18/0: compressed; stream = 12, index = 5
+19/0: compressed; stream = 12, index = 6

+ 15 - 0
services/clsi/test/acceptance/fixtures/minimal.pdfxref

@@ -0,0 +1,15 @@
+1/0: uncompressed; offset = 11784
+2/0: uncompressed; offset = 12033
+3/0: uncompressed; offset = 15
+4/0: uncompressed; offset = 216
+5/0: uncompressed; offset = 621
+6/0: uncompressed; offset = 671
+7/0: uncompressed; offset = 791
+8/0: uncompressed; offset = 906
+9/0: uncompressed; offset = 1070
+10/0: uncompressed; offset = 11235
+11/0: compressed; stream = 10, index = 0
+12/0: compressed; stream = 10, index = 1
+13/0: compressed; stream = 10, index = 2
+14/0: compressed; stream = 10, index = 3
+15/0: compressed; stream = 10, index = 4

+ 9 - 5
services/clsi/test/unit/js/ContentCacheManagerTests.js

@@ -5,7 +5,7 @@ const { expect } = require('chai')
 const MODULE_PATH = '../../../app/js/ContentCacheManager'
 
 describe('ContentCacheManager', function () {
-  let contentDir, pdfPath
+  let contentDir, pdfPath, xrefPath
   let ContentCacheManager, files, Settings
   before(function () {
     Settings = require('@overleaf/settings')
@@ -38,6 +38,8 @@ describe('ContentCacheManager', function () {
       '/overleaf/services/clsi/output/602cee6f6460fca0ba7921e6/content/1797a7f48f9-5abc1998509dea1f'
     pdfPath =
       '/overleaf/services/clsi/output/602cee6f6460fca0ba7921e6/generated-files/1797a7f48ea-8ac6805139f43351/output.pdf'
+    xrefPath =
+      '/overleaf/services/clsi/output/602cee6f6460fca0ba7921e6/generated-files/1797a7f48ea-8ac6805139f43351/output.pdfxref'
 
     reclaimed = 0
     Settings.pdfCachingMinChunkSize = 1024
@@ -50,7 +52,8 @@ describe('ContentCacheManager', function () {
   })
 
   describe('minimal', function () {
-    const PATH_MINIMAL = 'test/acceptance/fixtures/minimal.pdf'
+    const PATH_MINIMAL_PDF = 'test/acceptance/fixtures/minimal.pdf'
+    const PATH_MINIMAL_XREF = 'test/acceptance/fixtures/minimal.pdfxref'
     const OBJECT_ID_1 = '9 0 '
     const HASH_LARGE =
       'd7cfc73ad2fba4578a437517923e3714927bbf35e63ea88bd93c7a8076cf1fcd'
@@ -62,9 +65,10 @@ describe('ContentCacheManager', function () {
     }
     let MINIMAL_SIZE, RANGE_1, RANGE_2, h1, h2, START_1, START_2, END_1, END_2
     before(async function () {
-      await fs.promises.copyFile(PATH_MINIMAL, pdfPath)
-      const MINIMAL = await fs.promises.readFile(PATH_MINIMAL)
-      MINIMAL_SIZE = (await fs.promises.stat(PATH_MINIMAL)).size
+      await fs.promises.copyFile(PATH_MINIMAL_PDF, pdfPath)
+      await fs.promises.copyFile(PATH_MINIMAL_XREF, xrefPath)
+      const MINIMAL = await fs.promises.readFile(PATH_MINIMAL_PDF)
+      MINIMAL_SIZE = (await fs.promises.stat(PATH_MINIMAL_PDF)).size
       RANGE_1 = await fs.promises.readFile(getChunkPath(HASH_LARGE))
       RANGE_2 = await fs.promises.readFile(getChunkPath(HASH_SMALL))
       h1 = HASH_LARGE

+ 14 - 17
services/clsi/test/unit/js/pdfjsTests.js

@@ -1,7 +1,8 @@
 const fs = require('fs')
 const Path = require('path')
 const { expect } = require('chai')
-const { parseXrefTable } = require('../../../app/lib/pdfjs/parseXrefTable')
+const { parseXrefTable } = require('../../../app/js/XrefParser')
+const { NoXrefTableError } = require('../../../app/js/Errors')
 const PATH_EXAMPLES = 'test/acceptance/fixtures/examples/'
 const PATH_SNAPSHOTS = 'test/unit/js/snapshots/pdfjs/'
 const EXAMPLES = fs.readdirSync(PATH_EXAMPLES)
@@ -48,24 +49,11 @@ describe('pdfjs', function () {
   describe('when the pdf is an empty file', function () {
     it('should yield no entries', async function () {
       const path = 'does/not/matter.pdf'
-      const table = await parseXrefTable(path, 0)
-      expect(table).to.deep.equal([])
-    })
-  })
-
-  describe('when the operation times out', function () {
-    it('should bail out', async function () {
-      const path = pdfPath(EXAMPLES[0])
-      const { size } = await loadContext(EXAMPLES[0])
-      const err = new Error()
       let table
       try {
-        table = await parseXrefTable(path, size, () => {
-          throw err
-        })
+        table = await parseXrefTable(path, 0)
       } catch (e) {
-        expect(e).to.equal(err)
-        return
+        expect(e).to.be.an.instanceof(NoXrefTableError)
       }
       expect(table).to.not.exist
     })
@@ -89,7 +77,16 @@ describe('pdfjs', function () {
 
       it('should produce the expected xRef table', async function () {
         const table = await parseXrefTable(pdfPath(example), size, () => {})
-        expect(table).to.deep.equal(snapshot)
+        // compare the essential parts of the xref table only
+        expect(table.xRefEntries[0]).to.include({ offset: 0 })
+        expect(table.xRefEntries.slice(1)).to.deep.equal(
+          snapshot.xRefEntries
+            .slice(1)
+            .filter(xref => xref.uncompressed) // we only use the uncompressed fields
+            .map(xref => {
+              return { offset: xref.offset, uncompressed: xref.uncompressed } // ignore unused gen field
+            })
+        )
       })
     })
   }