parser.js 26 KB

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