2
0

parser.js 31 KB

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