parser.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. /**
  2. * @licstart The following is the entire license notice for the
  3. * Javascript code in this page
  4. *
  5. * Copyright 2017 Mozilla Foundation
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * @licend The above is the entire license notice for the
  20. * Javascript code in this page
  21. */
  22. 'use strict';
  23. Object.defineProperty(exports, "__esModule", {
  24. value: true
  25. });
  26. exports.Parser = exports.Linearization = exports.Lexer = undefined;
  27. var _stream = require('./stream');
  28. var _util = require('../shared/util');
  29. var _primitives = require('./primitives');
  30. var _ccitt_stream = require('./ccitt_stream');
  31. var _jbig2_stream = require('./jbig2_stream');
  32. var _jpeg_stream = require('./jpeg_stream');
  33. var _jpx_stream = require('./jpx_stream');
  34. var MAX_LENGTH_TO_CACHE = 1000;
  35. var MAX_ADLER32_LENGTH = 5552;
  36. function computeAdler32(bytes) {
  37. var bytesLength = bytes.length;
  38. if (bytesLength >= MAX_ADLER32_LENGTH) {
  39. throw new Error('computeAdler32: The input is too large.');
  40. }
  41. var a = 1,
  42. b = 0;
  43. for (var i = 0; i < bytesLength; ++i) {
  44. a += bytes[i] & 0xFF;
  45. b += a;
  46. }
  47. return b % 65521 << 16 | a % 65521;
  48. }
  49. var Parser = function ParserClosure() {
  50. function Parser(lexer, allowStreams, xref, recoveryMode) {
  51. this.lexer = lexer;
  52. this.allowStreams = allowStreams;
  53. this.xref = xref;
  54. this.recoveryMode = recoveryMode || false;
  55. this.imageCache = Object.create(null);
  56. this.refill();
  57. }
  58. Parser.prototype = {
  59. refill: function Parser_refill() {
  60. this.buf1 = this.lexer.getObj();
  61. this.buf2 = this.lexer.getObj();
  62. },
  63. shift: function Parser_shift() {
  64. if ((0, _primitives.isCmd)(this.buf2, 'ID')) {
  65. this.buf1 = this.buf2;
  66. this.buf2 = null;
  67. } else {
  68. this.buf1 = this.buf2;
  69. this.buf2 = this.lexer.getObj();
  70. }
  71. },
  72. tryShift: function Parser_tryShift() {
  73. try {
  74. this.shift();
  75. return true;
  76. } catch (e) {
  77. if (e instanceof _util.MissingDataException) {
  78. throw e;
  79. }
  80. return false;
  81. }
  82. },
  83. getObj: function Parser_getObj(cipherTransform) {
  84. var buf1 = this.buf1;
  85. this.shift();
  86. if (buf1 instanceof _primitives.Cmd) {
  87. switch (buf1.cmd) {
  88. case 'BI':
  89. return this.makeInlineImage(cipherTransform);
  90. case '[':
  91. var array = [];
  92. while (!(0, _primitives.isCmd)(this.buf1, ']') && !(0, _primitives.isEOF)(this.buf1)) {
  93. array.push(this.getObj(cipherTransform));
  94. }
  95. if ((0, _primitives.isEOF)(this.buf1)) {
  96. if (!this.recoveryMode) {
  97. throw new _util.FormatError('End of file inside array');
  98. }
  99. return array;
  100. }
  101. this.shift();
  102. return array;
  103. case '<<':
  104. var dict = new _primitives.Dict(this.xref);
  105. while (!(0, _primitives.isCmd)(this.buf1, '>>') && !(0, _primitives.isEOF)(this.buf1)) {
  106. if (!(0, _primitives.isName)(this.buf1)) {
  107. (0, _util.info)('Malformed dictionary: key must be a name object');
  108. this.shift();
  109. continue;
  110. }
  111. var key = this.buf1.name;
  112. this.shift();
  113. if ((0, _primitives.isEOF)(this.buf1)) {
  114. break;
  115. }
  116. dict.set(key, this.getObj(cipherTransform));
  117. }
  118. if ((0, _primitives.isEOF)(this.buf1)) {
  119. if (!this.recoveryMode) {
  120. throw new _util.FormatError('End of file inside dictionary');
  121. }
  122. return dict;
  123. }
  124. if ((0, _primitives.isCmd)(this.buf2, 'stream')) {
  125. return this.allowStreams ? this.makeStream(dict, cipherTransform) : dict;
  126. }
  127. this.shift();
  128. return dict;
  129. default:
  130. return buf1;
  131. }
  132. }
  133. if (Number.isInteger(buf1)) {
  134. var num = buf1;
  135. if (Number.isInteger(this.buf1) && (0, _primitives.isCmd)(this.buf2, 'R')) {
  136. var ref = new _primitives.Ref(num, this.buf1);
  137. this.shift();
  138. this.shift();
  139. return ref;
  140. }
  141. return num;
  142. }
  143. if ((0, _util.isString)(buf1)) {
  144. var str = buf1;
  145. if (cipherTransform) {
  146. str = cipherTransform.decryptString(str);
  147. }
  148. return str;
  149. }
  150. return buf1;
  151. },
  152. findDefaultInlineStreamEnd: function findDefaultInlineStreamEnd(stream) {
  153. var E = 0x45,
  154. I = 0x49,
  155. SPACE = 0x20,
  156. LF = 0xA,
  157. CR = 0xD;
  158. var n = 10,
  159. NUL = 0x0;
  160. var startPos = stream.pos,
  161. state = 0,
  162. ch = void 0,
  163. maybeEIPos = void 0;
  164. while ((ch = stream.getByte()) !== -1) {
  165. if (state === 0) {
  166. state = ch === E ? 1 : 0;
  167. } else if (state === 1) {
  168. state = ch === I ? 2 : 0;
  169. } else {
  170. (0, _util.assert)(state === 2);
  171. if (ch === SPACE || ch === LF || ch === CR) {
  172. maybeEIPos = stream.pos;
  173. var followingBytes = stream.peekBytes(n);
  174. for (var i = 0, ii = followingBytes.length; i < ii; i++) {
  175. ch = followingBytes[i];
  176. if (ch === NUL && followingBytes[i + 1] !== NUL) {
  177. continue;
  178. }
  179. if (ch !== LF && ch !== CR && (ch < SPACE || ch > 0x7F)) {
  180. state = 0;
  181. break;
  182. }
  183. }
  184. if (state === 2) {
  185. break;
  186. }
  187. } else {
  188. state = 0;
  189. }
  190. }
  191. }
  192. if (ch === -1) {
  193. (0, _util.warn)('findDefaultInlineStreamEnd: ' + 'Reached the end of the stream without finding a valid EI marker');
  194. if (maybeEIPos) {
  195. (0, _util.warn)('... trying to recover by using the last "EI" occurrence.');
  196. stream.skip(-(stream.pos - maybeEIPos));
  197. }
  198. }
  199. return stream.pos - 4 - startPos;
  200. },
  201. findDCTDecodeInlineStreamEnd: function Parser_findDCTDecodeInlineStreamEnd(stream) {
  202. var startPos = stream.pos,
  203. foundEOI = false,
  204. b,
  205. markerLength,
  206. length;
  207. while ((b = stream.getByte()) !== -1) {
  208. if (b !== 0xFF) {
  209. continue;
  210. }
  211. switch (stream.getByte()) {
  212. case 0x00:
  213. break;
  214. case 0xFF:
  215. stream.skip(-1);
  216. break;
  217. case 0xD9:
  218. foundEOI = true;
  219. break;
  220. case 0xC0:
  221. case 0xC1:
  222. case 0xC2:
  223. case 0xC3:
  224. case 0xC5:
  225. case 0xC6:
  226. case 0xC7:
  227. case 0xC9:
  228. case 0xCA:
  229. case 0xCB:
  230. case 0xCD:
  231. case 0xCE:
  232. case 0xCF:
  233. case 0xC4:
  234. case 0xCC:
  235. case 0xDA:
  236. case 0xDB:
  237. case 0xDC:
  238. case 0xDD:
  239. case 0xDE:
  240. case 0xDF:
  241. case 0xE0:
  242. case 0xE1:
  243. case 0xE2:
  244. case 0xE3:
  245. case 0xE4:
  246. case 0xE5:
  247. case 0xE6:
  248. case 0xE7:
  249. case 0xE8:
  250. case 0xE9:
  251. case 0xEA:
  252. case 0xEB:
  253. case 0xEC:
  254. case 0xED:
  255. case 0xEE:
  256. case 0xEF:
  257. case 0xFE:
  258. markerLength = stream.getUint16();
  259. if (markerLength > 2) {
  260. stream.skip(markerLength - 2);
  261. } else {
  262. stream.skip(-2);
  263. }
  264. break;
  265. }
  266. if (foundEOI) {
  267. break;
  268. }
  269. }
  270. length = stream.pos - startPos;
  271. if (b === -1) {
  272. (0, _util.warn)('Inline DCTDecode image stream: ' + 'EOI marker not found, searching for /EI/ instead.');
  273. stream.skip(-length);
  274. return this.findDefaultInlineStreamEnd(stream);
  275. }
  276. this.inlineStreamSkipEI(stream);
  277. return length;
  278. },
  279. findASCII85DecodeInlineStreamEnd: function Parser_findASCII85DecodeInlineStreamEnd(stream) {
  280. var TILDE = 0x7E,
  281. GT = 0x3E;
  282. var startPos = stream.pos,
  283. ch,
  284. length;
  285. while ((ch = stream.getByte()) !== -1) {
  286. if (ch === TILDE && stream.peekByte() === GT) {
  287. stream.skip();
  288. break;
  289. }
  290. }
  291. length = stream.pos - startPos;
  292. if (ch === -1) {
  293. (0, _util.warn)('Inline ASCII85Decode image stream: ' + 'EOD marker not found, searching for /EI/ instead.');
  294. stream.skip(-length);
  295. return this.findDefaultInlineStreamEnd(stream);
  296. }
  297. this.inlineStreamSkipEI(stream);
  298. return length;
  299. },
  300. findASCIIHexDecodeInlineStreamEnd: function Parser_findASCIIHexDecodeInlineStreamEnd(stream) {
  301. var GT = 0x3E;
  302. var startPos = stream.pos,
  303. ch,
  304. length;
  305. while ((ch = stream.getByte()) !== -1) {
  306. if (ch === GT) {
  307. break;
  308. }
  309. }
  310. length = stream.pos - startPos;
  311. if (ch === -1) {
  312. (0, _util.warn)('Inline ASCIIHexDecode image stream: ' + 'EOD marker not found, searching for /EI/ instead.');
  313. stream.skip(-length);
  314. return this.findDefaultInlineStreamEnd(stream);
  315. }
  316. this.inlineStreamSkipEI(stream);
  317. return length;
  318. },
  319. inlineStreamSkipEI: function Parser_inlineStreamSkipEI(stream) {
  320. var E = 0x45,
  321. I = 0x49;
  322. var state = 0,
  323. ch;
  324. while ((ch = stream.getByte()) !== -1) {
  325. if (state === 0) {
  326. state = ch === E ? 1 : 0;
  327. } else if (state === 1) {
  328. state = ch === I ? 2 : 0;
  329. } else if (state === 2) {
  330. break;
  331. }
  332. }
  333. },
  334. makeInlineImage: function Parser_makeInlineImage(cipherTransform) {
  335. var lexer = this.lexer;
  336. var stream = lexer.stream;
  337. var dict = new _primitives.Dict(this.xref),
  338. dictLength = void 0;
  339. while (!(0, _primitives.isCmd)(this.buf1, 'ID') && !(0, _primitives.isEOF)(this.buf1)) {
  340. if (!(0, _primitives.isName)(this.buf1)) {
  341. throw new _util.FormatError('Dictionary key must be a name object');
  342. }
  343. var key = this.buf1.name;
  344. this.shift();
  345. if ((0, _primitives.isEOF)(this.buf1)) {
  346. break;
  347. }
  348. dict.set(key, this.getObj(cipherTransform));
  349. }
  350. if (lexer.beginInlineImagePos !== -1) {
  351. dictLength = stream.pos - lexer.beginInlineImagePos;
  352. }
  353. var filter = dict.get('Filter', 'F'),
  354. filterName;
  355. if ((0, _primitives.isName)(filter)) {
  356. filterName = filter.name;
  357. } else if (Array.isArray(filter)) {
  358. var filterZero = this.xref.fetchIfRef(filter[0]);
  359. if ((0, _primitives.isName)(filterZero)) {
  360. filterName = filterZero.name;
  361. }
  362. }
  363. var startPos = stream.pos,
  364. length = void 0;
  365. if (filterName === 'DCTDecode' || filterName === 'DCT') {
  366. length = this.findDCTDecodeInlineStreamEnd(stream);
  367. } else if (filterName === 'ASCII85Decode' || filterName === 'A85') {
  368. length = this.findASCII85DecodeInlineStreamEnd(stream);
  369. } else if (filterName === 'ASCIIHexDecode' || filterName === 'AHx') {
  370. length = this.findASCIIHexDecodeInlineStreamEnd(stream);
  371. } else {
  372. length = this.findDefaultInlineStreamEnd(stream);
  373. }
  374. var imageStream = stream.makeSubStream(startPos, length, dict);
  375. var cacheKey = void 0;
  376. if (length < MAX_LENGTH_TO_CACHE && dictLength < MAX_ADLER32_LENGTH) {
  377. var imageBytes = imageStream.getBytes();
  378. imageStream.reset();
  379. var initialStreamPos = stream.pos;
  380. stream.pos = lexer.beginInlineImagePos;
  381. var dictBytes = stream.getBytes(dictLength);
  382. stream.pos = initialStreamPos;
  383. cacheKey = computeAdler32(imageBytes) + '_' + computeAdler32(dictBytes);
  384. var cacheEntry = this.imageCache[cacheKey];
  385. if (cacheEntry !== undefined) {
  386. this.buf2 = _primitives.Cmd.get('EI');
  387. this.shift();
  388. cacheEntry.reset();
  389. return cacheEntry;
  390. }
  391. }
  392. if (cipherTransform) {
  393. imageStream = cipherTransform.createStream(imageStream, length);
  394. }
  395. imageStream = this.filter(imageStream, dict, length);
  396. imageStream.dict = dict;
  397. if (cacheKey !== undefined) {
  398. imageStream.cacheKey = 'inline_' + length + '_' + cacheKey;
  399. this.imageCache[cacheKey] = imageStream;
  400. }
  401. this.buf2 = _primitives.Cmd.get('EI');
  402. this.shift();
  403. return imageStream;
  404. },
  405. makeStream: function Parser_makeStream(dict, cipherTransform) {
  406. var lexer = this.lexer;
  407. var stream = lexer.stream;
  408. lexer.skipToNextLine();
  409. var pos = stream.pos - 1;
  410. var length = dict.get('Length');
  411. if (!Number.isInteger(length)) {
  412. (0, _util.info)('Bad ' + length + ' attribute in stream');
  413. length = 0;
  414. }
  415. stream.pos = pos + length;
  416. lexer.nextChar();
  417. if (this.tryShift() && (0, _primitives.isCmd)(this.buf2, 'endstream')) {
  418. this.shift();
  419. } else {
  420. stream.pos = pos;
  421. var SCAN_BLOCK_SIZE = 2048;
  422. var ENDSTREAM_SIGNATURE_LENGTH = 9;
  423. var ENDSTREAM_SIGNATURE = [0x65, 0x6E, 0x64, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6D];
  424. var skipped = 0,
  425. found = false,
  426. i,
  427. j;
  428. while (stream.pos < stream.end) {
  429. var scanBytes = stream.peekBytes(SCAN_BLOCK_SIZE);
  430. var scanLength = scanBytes.length - ENDSTREAM_SIGNATURE_LENGTH;
  431. if (scanLength <= 0) {
  432. break;
  433. }
  434. found = false;
  435. i = 0;
  436. while (i < scanLength) {
  437. j = 0;
  438. while (j < ENDSTREAM_SIGNATURE_LENGTH && scanBytes[i + j] === ENDSTREAM_SIGNATURE[j]) {
  439. j++;
  440. }
  441. if (j >= ENDSTREAM_SIGNATURE_LENGTH) {
  442. found = true;
  443. break;
  444. }
  445. i++;
  446. }
  447. if (found) {
  448. skipped += i;
  449. stream.pos += i;
  450. break;
  451. }
  452. skipped += scanLength;
  453. stream.pos += scanLength;
  454. }
  455. if (!found) {
  456. throw new _util.FormatError('Missing endstream');
  457. }
  458. length = skipped;
  459. lexer.nextChar();
  460. this.shift();
  461. this.shift();
  462. }
  463. this.shift();
  464. stream = stream.makeSubStream(pos, length, dict);
  465. if (cipherTransform) {
  466. stream = cipherTransform.createStream(stream, length);
  467. }
  468. stream = this.filter(stream, dict, length);
  469. stream.dict = dict;
  470. return stream;
  471. },
  472. filter: function Parser_filter(stream, dict, length) {
  473. var filter = dict.get('Filter', 'F');
  474. var params = dict.get('DecodeParms', 'DP');
  475. if ((0, _primitives.isName)(filter)) {
  476. if (Array.isArray(params)) {
  477. (0, _util.warn)('/DecodeParms should not contain an Array, ' + 'when /Filter contains a Name.');
  478. }
  479. return this.makeFilter(stream, filter.name, length, params);
  480. }
  481. var maybeLength = length;
  482. if (Array.isArray(filter)) {
  483. var filterArray = filter;
  484. var paramsArray = params;
  485. for (var i = 0, ii = filterArray.length; i < ii; ++i) {
  486. filter = this.xref.fetchIfRef(filterArray[i]);
  487. if (!(0, _primitives.isName)(filter)) {
  488. throw new _util.FormatError('Bad filter name: ' + filter);
  489. }
  490. params = null;
  491. if (Array.isArray(paramsArray) && i in paramsArray) {
  492. params = this.xref.fetchIfRef(paramsArray[i]);
  493. }
  494. stream = this.makeFilter(stream, filter.name, maybeLength, params);
  495. maybeLength = null;
  496. }
  497. }
  498. return stream;
  499. },
  500. makeFilter: function Parser_makeFilter(stream, name, maybeLength, params) {
  501. if (maybeLength === 0) {
  502. (0, _util.warn)('Empty "' + name + '" stream.');
  503. return new _stream.NullStream();
  504. }
  505. try {
  506. var xrefStreamStats = this.xref.stats.streamTypes;
  507. if (name === 'FlateDecode' || name === 'Fl') {
  508. xrefStreamStats[_util.StreamType.FLATE] = true;
  509. if (params) {
  510. return new _stream.PredictorStream(new _stream.FlateStream(stream, maybeLength), maybeLength, params);
  511. }
  512. return new _stream.FlateStream(stream, maybeLength);
  513. }
  514. if (name === 'LZWDecode' || name === 'LZW') {
  515. xrefStreamStats[_util.StreamType.LZW] = true;
  516. var earlyChange = 1;
  517. if (params) {
  518. if (params.has('EarlyChange')) {
  519. earlyChange = params.get('EarlyChange');
  520. }
  521. return new _stream.PredictorStream(new _stream.LZWStream(stream, maybeLength, earlyChange), maybeLength, params);
  522. }
  523. return new _stream.LZWStream(stream, maybeLength, earlyChange);
  524. }
  525. if (name === 'DCTDecode' || name === 'DCT') {
  526. xrefStreamStats[_util.StreamType.DCT] = true;
  527. return new _jpeg_stream.JpegStream(stream, maybeLength, stream.dict, params);
  528. }
  529. if (name === 'JPXDecode' || name === 'JPX') {
  530. xrefStreamStats[_util.StreamType.JPX] = true;
  531. return new _jpx_stream.JpxStream(stream, maybeLength, stream.dict, params);
  532. }
  533. if (name === 'ASCII85Decode' || name === 'A85') {
  534. xrefStreamStats[_util.StreamType.A85] = true;
  535. return new _stream.Ascii85Stream(stream, maybeLength);
  536. }
  537. if (name === 'ASCIIHexDecode' || name === 'AHx') {
  538. xrefStreamStats[_util.StreamType.AHX] = true;
  539. return new _stream.AsciiHexStream(stream, maybeLength);
  540. }
  541. if (name === 'CCITTFaxDecode' || name === 'CCF') {
  542. xrefStreamStats[_util.StreamType.CCF] = true;
  543. return new _ccitt_stream.CCITTFaxStream(stream, maybeLength, params);
  544. }
  545. if (name === 'RunLengthDecode' || name === 'RL') {
  546. xrefStreamStats[_util.StreamType.RL] = true;
  547. return new _stream.RunLengthStream(stream, maybeLength);
  548. }
  549. if (name === 'JBIG2Decode') {
  550. xrefStreamStats[_util.StreamType.JBIG] = true;
  551. return new _jbig2_stream.Jbig2Stream(stream, maybeLength, stream.dict, params);
  552. }
  553. (0, _util.warn)('filter "' + name + '" not supported yet');
  554. return stream;
  555. } catch (ex) {
  556. if (ex instanceof _util.MissingDataException) {
  557. throw ex;
  558. }
  559. (0, _util.warn)('Invalid stream: \"' + ex + '\"');
  560. return new _stream.NullStream();
  561. }
  562. }
  563. };
  564. return Parser;
  565. }();
  566. var Lexer = function LexerClosure() {
  567. function Lexer(stream, knownCommands) {
  568. this.stream = stream;
  569. this.nextChar();
  570. this.strBuf = [];
  571. this.knownCommands = knownCommands;
  572. this.beginInlineImagePos = -1;
  573. }
  574. var specialChars = [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  575. function toHexDigit(ch) {
  576. if (ch >= 0x30 && ch <= 0x39) {
  577. return ch & 0x0F;
  578. }
  579. if (ch >= 0x41 && ch <= 0x46 || ch >= 0x61 && ch <= 0x66) {
  580. return (ch & 0x0F) + 9;
  581. }
  582. return -1;
  583. }
  584. Lexer.prototype = {
  585. nextChar: function Lexer_nextChar() {
  586. return this.currentChar = this.stream.getByte();
  587. },
  588. peekChar: function Lexer_peekChar() {
  589. return this.stream.peekByte();
  590. },
  591. getNumber: function Lexer_getNumber() {
  592. var ch = this.currentChar;
  593. var eNotation = false;
  594. var divideBy = 0;
  595. var sign = 1;
  596. if (ch === 0x2D) {
  597. sign = -1;
  598. ch = this.nextChar();
  599. if (ch === 0x2D) {
  600. ch = this.nextChar();
  601. }
  602. } else if (ch === 0x2B) {
  603. ch = this.nextChar();
  604. }
  605. if (ch === 0x2E) {
  606. divideBy = 10;
  607. ch = this.nextChar();
  608. }
  609. if (ch === 0x0A || ch === 0x0D) {
  610. do {
  611. ch = this.nextChar();
  612. } while (ch === 0x0A || ch === 0x0D);
  613. }
  614. if (ch < 0x30 || ch > 0x39) {
  615. throw new _util.FormatError('Invalid number: ' + String.fromCharCode(ch) + ' (charCode ' + ch + ')');
  616. }
  617. var baseValue = ch - 0x30;
  618. var powerValue = 0;
  619. var powerValueSign = 1;
  620. while ((ch = this.nextChar()) >= 0) {
  621. if (0x30 <= ch && ch <= 0x39) {
  622. var currentDigit = ch - 0x30;
  623. if (eNotation) {
  624. powerValue = powerValue * 10 + currentDigit;
  625. } else {
  626. if (divideBy !== 0) {
  627. divideBy *= 10;
  628. }
  629. baseValue = baseValue * 10 + currentDigit;
  630. }
  631. } else if (ch === 0x2E) {
  632. if (divideBy === 0) {
  633. divideBy = 1;
  634. } else {
  635. break;
  636. }
  637. } else if (ch === 0x2D) {
  638. (0, _util.warn)('Badly formatted number');
  639. } else if (ch === 0x45 || ch === 0x65) {
  640. ch = this.peekChar();
  641. if (ch === 0x2B || ch === 0x2D) {
  642. powerValueSign = ch === 0x2D ? -1 : 1;
  643. this.nextChar();
  644. } else if (ch < 0x30 || ch > 0x39) {
  645. break;
  646. }
  647. eNotation = true;
  648. } else {
  649. break;
  650. }
  651. }
  652. if (divideBy !== 0) {
  653. baseValue /= divideBy;
  654. }
  655. if (eNotation) {
  656. baseValue *= Math.pow(10, powerValueSign * powerValue);
  657. }
  658. return sign * baseValue;
  659. },
  660. getString: function Lexer_getString() {
  661. var numParen = 1;
  662. var done = false;
  663. var strBuf = this.strBuf;
  664. strBuf.length = 0;
  665. var ch = this.nextChar();
  666. while (true) {
  667. var charBuffered = false;
  668. switch (ch | 0) {
  669. case -1:
  670. (0, _util.warn)('Unterminated string');
  671. done = true;
  672. break;
  673. case 0x28:
  674. ++numParen;
  675. strBuf.push('(');
  676. break;
  677. case 0x29:
  678. if (--numParen === 0) {
  679. this.nextChar();
  680. done = true;
  681. } else {
  682. strBuf.push(')');
  683. }
  684. break;
  685. case 0x5C:
  686. ch = this.nextChar();
  687. switch (ch) {
  688. case -1:
  689. (0, _util.warn)('Unterminated string');
  690. done = true;
  691. break;
  692. case 0x6E:
  693. strBuf.push('\n');
  694. break;
  695. case 0x72:
  696. strBuf.push('\r');
  697. break;
  698. case 0x74:
  699. strBuf.push('\t');
  700. break;
  701. case 0x62:
  702. strBuf.push('\b');
  703. break;
  704. case 0x66:
  705. strBuf.push('\f');
  706. break;
  707. case 0x5C:
  708. case 0x28:
  709. case 0x29:
  710. strBuf.push(String.fromCharCode(ch));
  711. break;
  712. case 0x30:
  713. case 0x31:
  714. case 0x32:
  715. case 0x33:
  716. case 0x34:
  717. case 0x35:
  718. case 0x36:
  719. case 0x37:
  720. var x = ch & 0x0F;
  721. ch = this.nextChar();
  722. charBuffered = true;
  723. if (ch >= 0x30 && ch <= 0x37) {
  724. x = (x << 3) + (ch & 0x0F);
  725. ch = this.nextChar();
  726. if (ch >= 0x30 && ch <= 0x37) {
  727. charBuffered = false;
  728. x = (x << 3) + (ch & 0x0F);
  729. }
  730. }
  731. strBuf.push(String.fromCharCode(x));
  732. break;
  733. case 0x0D:
  734. if (this.peekChar() === 0x0A) {
  735. this.nextChar();
  736. }
  737. break;
  738. case 0x0A:
  739. break;
  740. default:
  741. strBuf.push(String.fromCharCode(ch));
  742. break;
  743. }
  744. break;
  745. default:
  746. strBuf.push(String.fromCharCode(ch));
  747. break;
  748. }
  749. if (done) {
  750. break;
  751. }
  752. if (!charBuffered) {
  753. ch = this.nextChar();
  754. }
  755. }
  756. return strBuf.join('');
  757. },
  758. getName: function Lexer_getName() {
  759. var ch, previousCh;
  760. var strBuf = this.strBuf;
  761. strBuf.length = 0;
  762. while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
  763. if (ch === 0x23) {
  764. ch = this.nextChar();
  765. if (specialChars[ch]) {
  766. (0, _util.warn)('Lexer_getName: ' + 'NUMBER SIGN (#) should be followed by a hexadecimal number.');
  767. strBuf.push('#');
  768. break;
  769. }
  770. var x = toHexDigit(ch);
  771. if (x !== -1) {
  772. previousCh = ch;
  773. ch = this.nextChar();
  774. var x2 = toHexDigit(ch);
  775. if (x2 === -1) {
  776. (0, _util.warn)('Lexer_getName: Illegal digit (' + String.fromCharCode(ch) + ') in hexadecimal number.');
  777. strBuf.push('#', String.fromCharCode(previousCh));
  778. if (specialChars[ch]) {
  779. break;
  780. }
  781. strBuf.push(String.fromCharCode(ch));
  782. continue;
  783. }
  784. strBuf.push(String.fromCharCode(x << 4 | x2));
  785. } else {
  786. strBuf.push('#', String.fromCharCode(ch));
  787. }
  788. } else {
  789. strBuf.push(String.fromCharCode(ch));
  790. }
  791. }
  792. if (strBuf.length > 127) {
  793. (0, _util.warn)('name token is longer than allowed by the spec: ' + strBuf.length);
  794. }
  795. return _primitives.Name.get(strBuf.join(''));
  796. },
  797. getHexString: function Lexer_getHexString() {
  798. var strBuf = this.strBuf;
  799. strBuf.length = 0;
  800. var ch = this.currentChar;
  801. var isFirstHex = true;
  802. var firstDigit;
  803. var secondDigit;
  804. while (true) {
  805. if (ch < 0) {
  806. (0, _util.warn)('Unterminated hex string');
  807. break;
  808. } else if (ch === 0x3E) {
  809. this.nextChar();
  810. break;
  811. } else if (specialChars[ch] === 1) {
  812. ch = this.nextChar();
  813. continue;
  814. } else {
  815. if (isFirstHex) {
  816. firstDigit = toHexDigit(ch);
  817. if (firstDigit === -1) {
  818. (0, _util.warn)('Ignoring invalid character "' + ch + '" in hex string');
  819. ch = this.nextChar();
  820. continue;
  821. }
  822. } else {
  823. secondDigit = toHexDigit(ch);
  824. if (secondDigit === -1) {
  825. (0, _util.warn)('Ignoring invalid character "' + ch + '" in hex string');
  826. ch = this.nextChar();
  827. continue;
  828. }
  829. strBuf.push(String.fromCharCode(firstDigit << 4 | secondDigit));
  830. }
  831. isFirstHex = !isFirstHex;
  832. ch = this.nextChar();
  833. }
  834. }
  835. return strBuf.join('');
  836. },
  837. getObj: function Lexer_getObj() {
  838. var comment = false;
  839. var ch = this.currentChar;
  840. while (true) {
  841. if (ch < 0) {
  842. return _primitives.EOF;
  843. }
  844. if (comment) {
  845. if (ch === 0x0A || ch === 0x0D) {
  846. comment = false;
  847. }
  848. } else if (ch === 0x25) {
  849. comment = true;
  850. } else if (specialChars[ch] !== 1) {
  851. break;
  852. }
  853. ch = this.nextChar();
  854. }
  855. switch (ch | 0) {
  856. case 0x30:
  857. case 0x31:
  858. case 0x32:
  859. case 0x33:
  860. case 0x34:
  861. case 0x35:
  862. case 0x36:
  863. case 0x37:
  864. case 0x38:
  865. case 0x39:
  866. case 0x2B:
  867. case 0x2D:
  868. case 0x2E:
  869. return this.getNumber();
  870. case 0x28:
  871. return this.getString();
  872. case 0x2F:
  873. return this.getName();
  874. case 0x5B:
  875. this.nextChar();
  876. return _primitives.Cmd.get('[');
  877. case 0x5D:
  878. this.nextChar();
  879. return _primitives.Cmd.get(']');
  880. case 0x3C:
  881. ch = this.nextChar();
  882. if (ch === 0x3C) {
  883. this.nextChar();
  884. return _primitives.Cmd.get('<<');
  885. }
  886. return this.getHexString();
  887. case 0x3E:
  888. ch = this.nextChar();
  889. if (ch === 0x3E) {
  890. this.nextChar();
  891. return _primitives.Cmd.get('>>');
  892. }
  893. return _primitives.Cmd.get('>');
  894. case 0x7B:
  895. this.nextChar();
  896. return _primitives.Cmd.get('{');
  897. case 0x7D:
  898. this.nextChar();
  899. return _primitives.Cmd.get('}');
  900. case 0x29:
  901. this.nextChar();
  902. throw new _util.FormatError('Illegal character: ' + ch);
  903. }
  904. var str = String.fromCharCode(ch);
  905. var knownCommands = this.knownCommands;
  906. var knownCommandFound = knownCommands && knownCommands[str] !== undefined;
  907. while ((ch = this.nextChar()) >= 0 && !specialChars[ch]) {
  908. var possibleCommand = str + String.fromCharCode(ch);
  909. if (knownCommandFound && knownCommands[possibleCommand] === undefined) {
  910. break;
  911. }
  912. if (str.length === 128) {
  913. throw new _util.FormatError('Command token too long: ' + str.length);
  914. }
  915. str = possibleCommand;
  916. knownCommandFound = knownCommands && knownCommands[str] !== undefined;
  917. }
  918. if (str === 'true') {
  919. return true;
  920. }
  921. if (str === 'false') {
  922. return false;
  923. }
  924. if (str === 'null') {
  925. return null;
  926. }
  927. if (str === 'BI') {
  928. this.beginInlineImagePos = this.stream.pos;
  929. }
  930. return _primitives.Cmd.get(str);
  931. },
  932. skipToNextLine: function Lexer_skipToNextLine() {
  933. var ch = this.currentChar;
  934. while (ch >= 0) {
  935. if (ch === 0x0D) {
  936. ch = this.nextChar();
  937. if (ch === 0x0A) {
  938. this.nextChar();
  939. }
  940. break;
  941. } else if (ch === 0x0A) {
  942. this.nextChar();
  943. break;
  944. }
  945. ch = this.nextChar();
  946. }
  947. }
  948. };
  949. return Lexer;
  950. }();
  951. var Linearization = {
  952. create: function LinearizationCreate(stream) {
  953. function getInt(name, allowZeroValue) {
  954. var obj = linDict.get(name);
  955. if (Number.isInteger(obj) && (allowZeroValue ? obj >= 0 : obj > 0)) {
  956. return obj;
  957. }
  958. throw new Error('The "' + name + '" parameter in the linearization ' + 'dictionary is invalid.');
  959. }
  960. function getHints() {
  961. var hints = linDict.get('H'),
  962. hintsLength,
  963. item;
  964. if (Array.isArray(hints) && ((hintsLength = hints.length) === 2 || hintsLength === 4)) {
  965. for (var index = 0; index < hintsLength; index++) {
  966. if (!(Number.isInteger(item = hints[index]) && item > 0)) {
  967. throw new Error('Hint (' + index + ') in the linearization dictionary is invalid.');
  968. }
  969. }
  970. return hints;
  971. }
  972. throw new Error('Hint array in the linearization dictionary is invalid.');
  973. }
  974. var parser = new Parser(new Lexer(stream), false, null);
  975. var obj1 = parser.getObj();
  976. var obj2 = parser.getObj();
  977. var obj3 = parser.getObj();
  978. var linDict = parser.getObj();
  979. var obj, length;
  980. if (!(Number.isInteger(obj1) && Number.isInteger(obj2) && (0, _primitives.isCmd)(obj3, 'obj') && (0, _primitives.isDict)(linDict) && (0, _util.isNum)(obj = linDict.get('Linearized')) && obj > 0)) {
  981. return null;
  982. } else if ((length = getInt('L')) !== stream.length) {
  983. throw new Error('The "L" parameter in the linearization dictionary ' + 'does not equal the stream length.');
  984. }
  985. return {
  986. length: length,
  987. hints: getHints(),
  988. objectNumberFirst: getInt('O'),
  989. endFirst: getInt('E'),
  990. numPages: getInt('N'),
  991. mainXRefEntriesOffset: getInt('T'),
  992. pageFirst: linDict.has('P') ? getInt('P', true) : 0
  993. };
  994. }
  995. };
  996. exports.Lexer = Lexer;
  997. exports.Linearization = Linearization;
  998. exports.Parser = Parser;