FSStream.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. const { Stream } = require('pdfjs-dist/lib/core/stream')
  2. const { MissingDataException } = require('pdfjs-dist/lib/core/core_utils')
  3. const BUF_SIZE = 1024 // read from the file in 1024 byte pages
  4. class FSStream extends Stream {
  5. constructor(fh, start, length, dict, cachedBytes) {
  6. const nonEmptyDummyBuffer = Buffer.alloc(1, 0)
  7. super(nonEmptyDummyBuffer, start, length, dict)
  8. delete this.bytes
  9. this.fh = fh
  10. this.cachedBytes = cachedBytes || []
  11. }
  12. get length() {
  13. return this.end - this.start
  14. }
  15. get isEmpty() {
  16. return this.length === 0
  17. }
  18. // Manage cached reads from the file
  19. requestRange(begin, end) {
  20. // expand small ranges to read a larger amount
  21. if (end - begin < BUF_SIZE) {
  22. end = begin + BUF_SIZE
  23. }
  24. end = Math.min(end, this.length)
  25. // keep a cache of previous reads with {begin,end,buffer} values
  26. const result = {
  27. begin: begin,
  28. end: end,
  29. buffer: Buffer.alloc(end - begin, 0)
  30. }
  31. this.cachedBytes.push(result)
  32. return this.fh.read(result.buffer, 0, end - begin, begin)
  33. }
  34. _ensureGetPos(pos) {
  35. const found = this.cachedBytes.find((x) => {
  36. return x.begin <= pos && pos < x.end
  37. })
  38. if (!found) {
  39. throw new MissingDataException(pos, pos + 1)
  40. }
  41. return found
  42. }
  43. _ensureGetRange(begin, end) {
  44. end = Math.min(end, this.length) // BG: handle overflow case
  45. const found = this.cachedBytes.find((x) => {
  46. return x.begin <= begin && end <= x.end
  47. })
  48. if (!found) {
  49. throw new MissingDataException(begin, end)
  50. }
  51. return found
  52. }
  53. _readByte(found, pos) {
  54. return found.buffer[pos - found.begin]
  55. }
  56. _readBytes(found, pos, end) {
  57. return found.buffer.subarray(pos - found.begin, end - found.begin)
  58. }
  59. // handle accesses to the bytes
  60. ensureByte(pos) {
  61. this._ensureGetPos(pos) // may throw a MissingDataException
  62. }
  63. getByte() {
  64. const pos = this.pos
  65. if (this.pos >= this.end) {
  66. return -1
  67. }
  68. const found = this._ensureGetPos(pos)
  69. return this._readByte(found, this.pos++)
  70. }
  71. // BG: for a range, end is not included (see Buffer.subarray for example)
  72. ensureBytes(length, forceClamped = false) {
  73. const pos = this.pos
  74. this._ensureGetRange(pos, pos + length)
  75. }
  76. getBytes(length, forceClamped = false) {
  77. const pos = this.pos
  78. const strEnd = this.end
  79. const found = this._ensureGetRange(pos, pos + length)
  80. if (!length) {
  81. const subarray = this._readBytes(found, pos, strEnd)
  82. // `this.bytes` is always a `Uint8Array` here.
  83. return forceClamped ? new Uint8ClampedArray(subarray) : subarray
  84. }
  85. let end = pos + length
  86. if (end > strEnd) {
  87. end = strEnd
  88. }
  89. this.pos = end
  90. const subarray = this._readBytes(found, pos, end)
  91. // `this.bytes` is always a `Uint8Array` here.
  92. return forceClamped ? new Uint8ClampedArray(subarray) : subarray
  93. }
  94. getByteRange() {
  95. // BG: this isn't needed as far as I can tell
  96. throw new Error('not implemented')
  97. }
  98. reset() {
  99. this.pos = this.start
  100. }
  101. moveStart() {
  102. this.start = this.pos
  103. }
  104. makeSubStream(start, length, dict = null) {
  105. // BG: had to add this check for null length, it is being called with only
  106. // the start value at one point in the xref decoding. The intent is clear
  107. // enough
  108. // - a null length means "to the end of the file" -- not sure how it is
  109. // working in the existing pdfjs code without this.
  110. if (!length) {
  111. length = this.end - start
  112. }
  113. return new FSStream(this.fh, start, length, dict, this.cachedBytes)
  114. }
  115. }
  116. module.exports = { FSStream }