2
0

parser.js 31 KB

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