From d3b38429460f931488af4b0a13b03eca78e1ee0a Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sun, 8 Jan 2012 14:03:00 -0600 Subject: [PATCH 1/2] fetch/getEntry returns null if the entry is free --- src/obj.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/obj.js b/src/obj.js index a0c1fdc8a..ef7932546 100644 --- a/src/obj.js +++ b/src/obj.js @@ -120,11 +120,11 @@ var Catalog = (function CatalogClosure() { return shadow(this, 'toplevelPagesDict', xrefObj); }, get documentOutline() { - var obj = this.catDict.get('Outlines'); var xref = this.xref; + var obj = xref.fetchIfRef(this.catDict.get('Outlines')); var root = { items: [] }; - if (isRef(obj)) { - obj = xref.fetch(obj).get('First'); + if (isDict(obj)) { + obj = obj.get('First'); var processed = new RefSet(); if (isRef(obj)) { var queue = [{obj: obj, parent: root}]; @@ -552,9 +552,7 @@ var XRef = (function XRefClosure() { }, getEntry: function xRefGetEntry(i) { var e = this.entries[i]; - if (e.free) - error('reading an XRef stream not implemented yet'); - return e; + return e.free ? null : e; // returns null is the entry is free }, fetchIfRef: function xRefFetchIfRef(obj) { if (!isRef(obj)) @@ -563,11 +561,15 @@ var XRef = (function XRefClosure() { }, fetch: function xRefFetch(ref, suppressEncryption) { var num = ref.num; - var e = this.cache[num]; - if (e) - return e; + if (num in this.cache) + return this.cache[num]; + + var e = this.getEntry(num); + + // the referenced entry can be free + if (e === null) + return (this.cache[num] = e); - e = this.getEntry(num); var gen = ref.gen; var stream, parser; if (e.uncompressed) { From 50a16573ad0ed53fbc32369236689d0e6d214157 Mon Sep 17 00:00:00 2001 From: notmasteryet Date: Sun, 8 Jan 2012 18:26:01 -0600 Subject: [PATCH 2/2] Add unit tests for calculateMD5, ARCFourCipher, and PredictorStream --- test/unit/crypto_spec.js | 187 +++++++++++++++++++++++++++++++++++++++ test/unit/stream_spec.js | 25 ++++++ test/unit/unit_test.html | 2 + 3 files changed, 214 insertions(+) create mode 100644 test/unit/crypto_spec.js create mode 100644 test/unit/stream_spec.js diff --git a/test/unit/crypto_spec.js b/test/unit/crypto_spec.js new file mode 100644 index 000000000..0b82b5ccb --- /dev/null +++ b/test/unit/crypto_spec.js @@ -0,0 +1,187 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +'use strict'; + +describe('crypto', function() { + function string2binary(s) { + var n = s.length, i; + var result = new Uint8Array(n); + for (i = 0; i < n; ++i) + result[i] = s.charCodeAt(i) % 0xFF; + return result; + } + + function hex2binary(s) { + var digits = '0123456789ABCDEF'; + s = s.toUpperCase(); + var n = s.length >> 1, i, j; + var result = new Uint8Array(n); + for (i = 0, j = 0; i < n; ++i) { + var d1 = s.charAt(j++); + var d2 = s.charAt(j++); + var value = (digits.indexOf(d1) << 4) | (digits.indexOf(d2)); + result[i] = value; + } + return result; + } + + // RFC 1321, A.5 Test suite + describe('calculateMD5', function() { + it('should pass RFC 1321 test #1', function() { + var input, result, expected; + input = string2binary(''); + result = calculateMD5(input, 0, input.length); + expected = hex2binary('d41d8cd98f00b204e9800998ecf8427e'); + expect(result).toEqual(expected); + }); + it('should pass RFC 1321 test #2', function() { + var input, result, expected; + input = string2binary('a'); + result = calculateMD5(input, 0, input.length); + expected = hex2binary('0cc175b9c0f1b6a831c399e269772661'); + expect(result).toEqual(expected); + }); + it('should pass RFC 1321 test #3', function() { + var input, result, expected; + input = string2binary('abc'); + result = calculateMD5(input, 0, input.length); + expected = hex2binary('900150983cd24fb0d6963f7d28e17f72'); + expect(result).toEqual(expected); + }); + it('should pass RFC 1321 test #4', function() { + var input, result, expected; + input = string2binary('message digest'); + result = calculateMD5(input, 0, input.length); + expected = hex2binary('f96b697d7cb7938d525a2f31aaf161d0'); + expect(result).toEqual(expected); + }); + it('should pass RFC 1321 test #5', function() { + var input, result, expected; + input = string2binary('abcdefghijklmnopqrstuvwxyz'); + result = calculateMD5(input, 0, input.length); + expected = hex2binary('c3fcd3d76192e4007dfb496cca67e13b'); + expect(result).toEqual(expected); + }); + it('should pass RFC 1321 test #6', function() { + var input, result, expected; + input = string2binary('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv' + + 'wxyz0123456789'); + result = calculateMD5(input, 0, input.length); + expected = hex2binary('d174ab98d277d9f5a5611c2c9f419d9f'); + expect(result).toEqual(expected); + }); + it('should pass RFC 1321 test #7', function() { + var input, result, expected; + input = string2binary('123456789012345678901234567890123456789012345678' + + '90123456789012345678901234567890'); + result = calculateMD5(input, 0, input.length); + expected = hex2binary('57edf4a22be3c955ac49da2e2107b67a'); + expect(result).toEqual(expected); + }); + }); + + // http://www.freemedialibrary.com/index.php/RC4_test_vectors are used + describe('ARCFourCipher', function() { + it('should pass test #1', function() { + var key, input, result, expected, cipher; + key = hex2binary('0123456789abcdef'); + input = hex2binary('0123456789abcdef'); + cipher = new ARCFourCipher(key); + result = cipher.encryptBlock(input); + expected = hex2binary('75b7878099e0c596'); + expect(result).toEqual(expected); + }); + it('should pass test #2', function() { + var key, input, result, expected, cipher; + key = hex2binary('0123456789abcdef'); + input = hex2binary('0000000000000000'); + cipher = new ARCFourCipher(key); + result = cipher.encryptBlock(input); + expected = hex2binary('7494c2e7104b0879'); + expect(result).toEqual(expected); + }); + it('should pass test #3', function() { + var key, input, result, expected, cipher; + key = hex2binary('0000000000000000'); + input = hex2binary('0000000000000000'); + cipher = new ARCFourCipher(key); + result = cipher.encryptBlock(input); + expected = hex2binary('de188941a3375d3a'); + expect(result).toEqual(expected); + }); + it('should pass test #4', function() { + var key, input, result, expected, cipher; + key = hex2binary('ef012345'); + input = hex2binary('00000000000000000000'); + cipher = new ARCFourCipher(key); + result = cipher.encryptBlock(input); + expected = hex2binary('d6a141a7ec3c38dfbd61'); + expect(result).toEqual(expected); + }); + it('should pass test #5', function() { + var key, input, result, expected, cipher; + key = hex2binary('0123456789abcdef'); + input = hex2binary('010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '10101010101010101010101010101010101010101010101010101010101010101010' + + '101010101010101010101'); + cipher = new ARCFourCipher(key); + result = cipher.encryptBlock(input); + expected = hex2binary('7595c3e6114a09780c4ad452338e1ffd9a1be9498f813d76' + + '533449b6778dcad8c78a8d2ba9ac66085d0e53d59c26c2d1c490c1ebbe0ce66d1b6b' + + '1b13b6b919b847c25a91447a95e75e4ef16779cde8bf0a95850e32af9689444fd377' + + '108f98fdcbd4e726567500990bcc7e0ca3c4aaa304a387d20f3b8fbbcd42a1bd311d' + + '7a4303dda5ab078896ae80c18b0af66dff319616eb784e495ad2ce90d7f772a81747' + + 'b65f62093b1e0db9e5ba532fafec47508323e671327df9444432cb7367cec82f5d44' + + 'c0d00b67d650a075cd4b70dedd77eb9b10231b6b5b741347396d62897421d43df9b4' + + '2e446e358e9c11a9b2184ecbef0cd8e7a877ef968f1390ec9b3d35a5585cb009290e' + + '2fcde7b5ec66d9084be44055a619d9dd7fc3166f9487f7cb272912426445998514c1' + + '5d53a18c864ce3a2b7555793988126520eacf2e3066e230c91bee4dd5304f5fd0405' + + 'b35bd99c73135d3d9bc335ee049ef69b3867bf2d7bd1eaa595d8bfc0066ff8d31509' + + 'eb0c6caa006c807a623ef84c3d33c195d23ee320c40de0558157c822d4b8c569d849' + + 'aed59d4e0fd7f379586b4b7ff684ed6a189f7486d49b9c4bad9ba24b96abf924372c' + + '8a8fffb10d55354900a77a3db5f205e1b99fcd8660863a159ad4abe40fa48934163d' + + 'dde542a6585540fd683cbfd8c00f12129a284deacc4cdefe58be7137541c047126c8' + + 'd49e2755ab181ab7e940b0c0'); + expect(result).toEqual(expected); + }); + it('should pass test #6', function() { + var key, input, result, expected, cipher; + key = hex2binary('fb029e3031323334'); + input = hex2binary('aaaa0300000008004500004e661a00008011be640a0001220af' + + 'fffff00890089003a000080a601100001000000000000204543454a4548454346434' + + '550464545494546464343414341434143414341414100002000011bd0b604'); + cipher = new ARCFourCipher(key); + result = cipher.encryptBlock(input); + expected = hex2binary('f69c5806bd6ce84626bcbefb9474650aad1f7909b0f64d5f' + + '58a503a258b7ed22eb0ea64930d3a056a55742fcce141d485f8aa836dea18df42c53' + + '80805ad0c61a5d6f58f41040b24b7d1a693856ed0d4398e7aee3bf0e2a2ca8f7'); + expect(result).toEqual(expected); + }); + it('should pass test #7', function() { + var key, input, result, expected, cipher; + key = hex2binary('0123456789abcdef'); + input = hex2binary('123456789abcdef0123456789abcdef0123456789abcdef0123' + + '45678'); + cipher = new ARCFourCipher(key); + result = cipher.encryptBlock(input); + expected = hex2binary('66a0949f8af7d6891f7f832ba833c00c892ebe30143ce287' + + '40011ecf'); + expect(result).toEqual(expected); + }); + }); +}); + diff --git a/test/unit/stream_spec.js b/test/unit/stream_spec.js new file mode 100644 index 000000000..1dab8e42c --- /dev/null +++ b/test/unit/stream_spec.js @@ -0,0 +1,25 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +'use strict'; + +describe('stream', function() { + + describe('PredictorStream', function() { + it('should decode simple predictor data', function() { + var dict = new Dict(); + dict.set('Predictor', 12); + dict.set('Colors', 1); + dict.set('BitsPerComponent', 8); + dict.set('Columns', 2); + + var input = new Stream(new Uint8Array([2, 100, 3, 2, 1, 255, 2, 1, 255]), + 0, 9, dict); + var predictor = new PredictorStream(input, dict); + var result = predictor.getBytes(6); + + expect(result).toEqual(new Uint8Array([100, 3, 101, 2, 102, 1])); + }); + }); +}); + diff --git a/test/unit/unit_test.html b/test/unit/unit_test.html index 8d0af03d6..2f7bb3edd 100644 --- a/test/unit/unit_test.html +++ b/test/unit/unit_test.html @@ -12,6 +12,8 @@ + +