From 353a43cb46e34ee82b3458df1138952282973aec Mon Sep 17 00:00:00 2001 From: asraniel Date: Sun, 6 May 2012 21:24:42 +0200 Subject: [PATCH 01/27] Add first API change, not working yet --- src/api.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/api.js b/src/api.js index bbab680ce..b3415c08e 100644 --- a/src/api.js +++ b/src/api.js @@ -8,10 +8,10 @@ * e.g. No cross domain requests without CORS. * * @param {string|TypedAray} source Either a url to a PDF is located or a - * typed array already populated with data. + * typed array (Uint8Array) already populated with data. * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object. */ -PDFJS.getDocument = function getDocument(source) { +PDFJS.getDocument = function getDocument(source, headers) { var promise = new PDFJS.Promise(); var transport = new WorkerTransport(promise); if (typeof source === 'string') { @@ -29,7 +29,8 @@ PDFJS.getDocument = function getDocument(source) { error: function getPDFError(e) { promise.reject('Unexpected server response of ' + e.target.status + '.'); - } + }, + headers: headers }, function getPDFLoad(data) { transport.sendData(data); From 315071ca28ab1bdba6f1a27558f507f41a48d962 Mon Sep 17 00:00:00 2001 From: asraniel Date: Sun, 6 May 2012 21:32:30 +0200 Subject: [PATCH 02/27] Add stub for the last piece of the puzzle --- src/core.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core.js b/src/core.js index 6a5ec275c..908ba63af 100644 --- a/src/core.js +++ b/src/core.js @@ -31,6 +31,11 @@ function getPdf(arg, callback) { params = { url: arg }; var xhr = new XMLHttpRequest(); + + if(params.headers){ + //TODO: Code this, use xhr.setRequestHeader(key, value); + } + xhr.open('GET', params.url); xhr.mozResponseType = xhr.responseType = 'arraybuffer'; var protocol = params.url.indexOf(':') < 0 ? window.location.protocol : From 7786e4fefbc4bc2f5f8301b8aaa89c8180ff8999 Mon Sep 17 00:00:00 2001 From: beat Date: Mon, 7 May 2012 09:17:00 +0200 Subject: [PATCH 03/27] Make authentication work --- src/api.js | 2 ++ src/core.js | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/api.js b/src/api.js index b3415c08e..0c4865841 100644 --- a/src/api.js +++ b/src/api.js @@ -9,6 +9,8 @@ * * @param {string|TypedAray} source Either a url to a PDF is located or a * typed array (Uint8Array) already populated with data. + * @param {Object} headers An object containing the http headers like this: + * { Authorization: "BASIC XXX" } * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object. */ PDFJS.getDocument = function getDocument(source, headers) { diff --git a/src/core.js b/src/core.js index 908ba63af..e999550ca 100644 --- a/src/core.js +++ b/src/core.js @@ -32,11 +32,14 @@ function getPdf(arg, callback) { var xhr = new XMLHttpRequest(); - if(params.headers){ - //TODO: Code this, use xhr.setRequestHeader(key, value); - } - xhr.open('GET', params.url); + if(params.headers){ + for(var property in params.headers){ + if(typeof(params.headers[property]) !== undefined){ + xhr.setRequestHeader(property, params.headers[property]); + } + } + } xhr.mozResponseType = xhr.responseType = 'arraybuffer'; var protocol = params.url.indexOf(':') < 0 ? window.location.protocol : params.url.substring(0, params.url.indexOf(':') + 1); From 93a1f9c01b628fa2bc40e9cd9ddb61877948b181 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Szcz=C4=99sny?= Date: Tue, 8 May 2012 13:14:47 +0200 Subject: [PATCH 04/27] Added Polish translation --- l10n/pl/metadata.inc | 8 ++++++++ l10n/pl/viewer.properties | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 l10n/pl/metadata.inc create mode 100644 l10n/pl/viewer.properties diff --git a/l10n/pl/metadata.inc b/l10n/pl/metadata.inc new file mode 100644 index 000000000..8d9d94b04 --- /dev/null +++ b/l10n/pl/metadata.inc @@ -0,0 +1,8 @@ + + + en-US + PDF Viewer + Uses HTML5 to display PDF files directly in Firefox. + + + diff --git a/l10n/pl/viewer.properties b/l10n/pl/viewer.properties new file mode 100644 index 000000000..ed632b17a --- /dev/null +++ b/l10n/pl/viewer.properties @@ -0,0 +1,42 @@ +bookmark.title=Current view (copy or open in new window) +previous.title=Previous Page +next.title=Next Page +print.title=Print +download.title=Download +zoom_out.title=Zoom Out +zoom_in.title=Zoom In +error_more_info=More Information +error_less_info=Less Information +error_close=Close +error_build=PDF.JS Build: {{build}} +error_message=Message: {{message}} +error_stack=Stack: {{stack}} +error_file=File: {{file}} +error_line=Line: {{line}} +page_scale_width=Page Width +page_scale_fit=Page Fit +page_scale_auto=Automatic Zoom +page_scale_actual=Actual Size +toggle_slider.title=Toggle Slider +thumbs.title=Show Thumbnails +outline.title=Show Document Outline +loading=Loading... {{percent}}% +loading_error_indicator=Error +loading_error=An error occurred while loading the PDF. +rendering_error=An error occurred while rendering the page. +page_label=Page: +page_of=of {{pageCount}} +no_outline=No Outline Available +open_file.title=Open File +text_annotation_type=[{{type}} Annotation] +toggle_slider_label=Toggle Slider +thumbs_label=Thumbnails +outline_label=Document Outline +bookmark_label=Current View +previous_label=Previous +next_label=Next +print_label=Print +download_label=Download +zoom_out_label=Zoom Out +zoom_in_label=Zoom In +zoom.title=Zoom From e11cad884c1c0af012e422e26c8b45905548361a Mon Sep 17 00:00:00 2001 From: beat Date: Tue, 8 May 2012 14:17:51 +0200 Subject: [PATCH 05/27] code style fixes --- src/api.js | 4 ++-- src/core.js | 14 +++++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/api.js b/src/api.js index 0c4865841..1efb22caa 100644 --- a/src/api.js +++ b/src/api.js @@ -10,7 +10,7 @@ * @param {string|TypedAray} source Either a url to a PDF is located or a * typed array (Uint8Array) already populated with data. * @param {Object} headers An object containing the http headers like this: - * { Authorization: "BASIC XXX" } + * { Authorization: "BASIC XXX" }. * @return {Promise} A promise that is resolved with {PDFDocumentProxy} object. */ PDFJS.getDocument = function getDocument(source, headers) { @@ -32,7 +32,7 @@ PDFJS.getDocument = function getDocument(source, headers) { promise.reject('Unexpected server response of ' + e.target.status + '.'); }, - headers: headers + headers: headers }, function getPDFLoad(data) { transport.sendData(data); diff --git a/src/core.js b/src/core.js index e999550ca..c6d8b743c 100644 --- a/src/core.js +++ b/src/core.js @@ -33,13 +33,17 @@ function getPdf(arg, callback) { var xhr = new XMLHttpRequest(); xhr.open('GET', params.url); - if(params.headers){ - for(var property in params.headers){ - if(typeof(params.headers[property]) !== undefined){ - xhr.setRequestHeader(property, params.headers[property]); - } + + var headers = params.headers; + if (headers) { + for (var property in headers) { + if (typeof headers[property] === 'undefined') + continue; + + xhr.setRequestHeader(property, params.headers[property]); } } + xhr.mozResponseType = xhr.responseType = 'arraybuffer'; var protocol = params.url.indexOf(':') < 0 ? window.location.protocol : params.url.substring(0, params.url.indexOf(':') + 1); From 5f47140721db0bc30f0ec5de16a19b73349ad20c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Szcz=C4=99sny?= Date: Tue, 8 May 2012 16:31:27 +0200 Subject: [PATCH 06/27] Translation into Polish --- l10n/pl/metadata.inc | 6 +-- l10n/pl/viewer.properties | 84 +++++++++++++++++++-------------------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/l10n/pl/metadata.inc b/l10n/pl/metadata.inc index 8d9d94b04..0cc701d69 100644 --- a/l10n/pl/metadata.inc +++ b/l10n/pl/metadata.inc @@ -1,8 +1,8 @@ - en-US - PDF Viewer - Uses HTML5 to display PDF files directly in Firefox. + pl + Przeglądarka PDF + Używa HTML5 do wyświetlania plików PDF bezpośrednio w Firefoksie. diff --git a/l10n/pl/viewer.properties b/l10n/pl/viewer.properties index ed632b17a..9fbd5e3c1 100644 --- a/l10n/pl/viewer.properties +++ b/l10n/pl/viewer.properties @@ -1,42 +1,42 @@ -bookmark.title=Current view (copy or open in new window) -previous.title=Previous Page -next.title=Next Page -print.title=Print -download.title=Download -zoom_out.title=Zoom Out -zoom_in.title=Zoom In -error_more_info=More Information -error_less_info=Less Information -error_close=Close -error_build=PDF.JS Build: {{build}} -error_message=Message: {{message}} -error_stack=Stack: {{stack}} -error_file=File: {{file}} -error_line=Line: {{line}} -page_scale_width=Page Width -page_scale_fit=Page Fit -page_scale_auto=Automatic Zoom -page_scale_actual=Actual Size -toggle_slider.title=Toggle Slider -thumbs.title=Show Thumbnails -outline.title=Show Document Outline -loading=Loading... {{percent}}% -loading_error_indicator=Error -loading_error=An error occurred while loading the PDF. -rendering_error=An error occurred while rendering the page. -page_label=Page: -page_of=of {{pageCount}} -no_outline=No Outline Available -open_file.title=Open File -text_annotation_type=[{{type}} Annotation] -toggle_slider_label=Toggle Slider -thumbs_label=Thumbnails -outline_label=Document Outline -bookmark_label=Current View -previous_label=Previous -next_label=Next -print_label=Print -download_label=Download -zoom_out_label=Zoom Out -zoom_in_label=Zoom In -zoom.title=Zoom +bookmark.title=Aktualny widok (kopiuj lub otwórz w nowym oknie) +previous.title=Poprzednia strona +next.title=Następna strona +print.title=Drukuj +download.title=Pobierz +zoom_out.title=Pomniejsz +zoom_in.title=Powiększ +error_more_info=Więcej informacji +error_less_info=Mniej informacji +error_close=Zamknij +error_build=Wersja PDF.JS: {{build}} +error_message=Wiadomość: {{message}} +error_stack=Stos: {{stack}} +error_file=Plik: {{file}} +error_line=Linia: {{line}} +page_scale_width=Szerokość strony +page_scale_fit=Cała strona +page_scale_auto=Automatyczne dopasowanie +page_scale_actual=Rzeczywisty rozmiar +toggle_slider.title=Włącz/wyłącz suwak +thumbs.title=Wyświetl miniatury +outline.title=Wyświetl konspekt dokumentu +loading=Wczytywanie... {{percent}}% +loading_error_indicator=Błąd +loading_error=Wystąpił błąd podczas wczytywania pliku PDF. +rendering_error=Wystąpił błąd podczas wyświetlania strony. +page_label=Strona: +page_of=z {{pageCount}} +no_outline=Konspekt nie jest dostępny +open_file.title=Otwórz plik +text_annotation_type=[Komentarz {{type}}] +toggle_slider_label=Przełącz suwak +thumbs_label=Miniatury +outline_label=Konspekt dokumentu +bookmark_label=Aktualny widok +previous_label=Wstecz +next_label=Dalej +print_label=Drukuj +download_label=Pobierz +zoom_out_label=Pomniejsz +zoom_in_label=Powiększ +zoom.title=Powiększenie From e1146b64adf3d9408e8679d06136aab6db6978f8 Mon Sep 17 00:00:00 2001 From: beat Date: Tue, 8 May 2012 16:34:46 +0200 Subject: [PATCH 07/27] fix 4 lint errors --- src/core.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core.js b/src/core.js index c6d8b743c..99a8dd161 100644 --- a/src/core.js +++ b/src/core.js @@ -31,19 +31,19 @@ function getPdf(arg, callback) { params = { url: arg }; var xhr = new XMLHttpRequest(); - + xhr.open('GET', params.url); - + var headers = params.headers; if (headers) { for (var property in headers) { if (typeof headers[property] === 'undefined') continue; - + xhr.setRequestHeader(property, params.headers[property]); } } - + xhr.mozResponseType = xhr.responseType = 'arraybuffer'; var protocol = params.url.indexOf(':') < 0 ? window.location.protocol : params.url.substring(0, params.url.indexOf(':') + 1); From 792f5080410e405640f5a28685c4c324cf9f1f6a Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Tue, 8 May 2012 14:40:08 -0500 Subject: [PATCH 08/27] Accessibility labels for page previews --- l10n/en-US/viewer.properties | 2 ++ l10n/xx/viewer.properties | 2 ++ web/viewer.js | 5 ++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/l10n/en-US/viewer.properties b/l10n/en-US/viewer.properties index ed632b17a..c8dbe4aba 100644 --- a/l10n/en-US/viewer.properties +++ b/l10n/en-US/viewer.properties @@ -40,3 +40,5 @@ download_label=Download zoom_out_label=Zoom Out zoom_in_label=Zoom In zoom.title=Zoom +thumb_page_title=Page {{page}} +thumb_page_canvas=Thumbnail of Page {{page}} diff --git a/l10n/xx/viewer.properties b/l10n/xx/viewer.properties index 5b9971d0b..e26f79422 100644 --- a/l10n/xx/viewer.properties +++ b/l10n/xx/viewer.properties @@ -40,3 +40,5 @@ download_label=<<<_ÐOẂпḻOãÐ_>>> zoom_out_label=<<<_ƩOOм Oȗţ_>>> zoom_in_label=<<<_ƩOOм iп_>>> zoom.title=<<<_ƩOOм_>>> +thumb_page_title=<<<_Þãģε {{page}}_>>> +thumb_page_canvas=<<<_ţНȗмьпãiḻ O£ Þãģε {{page}}_>>> diff --git a/web/viewer.js b/web/viewer.js index e8eb9ad3b..dcbfcf14e 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -1070,7 +1070,8 @@ var PageView = function pageView(container, pdfPage, id, scale, var ThumbnailView = function thumbnailView(container, pdfPage, id) { var anchor = document.createElement('a'); anchor.href = PDFView.getAnchorUrl('#page=' + id); - anchor.onclick = function stopNivigation() { + anchor.title = mozL10n.get('thumb_page_title', {page: id}, 'Page {{page}}'); + anchor.onclick = function stopNavigation() { PDFView.page = id; return false; }; @@ -1103,6 +1104,8 @@ var ThumbnailView = function thumbnailView(container, pdfPage, id) { canvas.width = canvasWidth; canvas.height = canvasHeight; canvas.className = 'thumbnailImage'; + canvas.setAttribute('aria-label', mozL10n.get('thumb_page_canvas', + {page: id}, 'Thumbnail of Page {{page}}')); div.setAttribute('data-loaded', true); From 982c7a0f7e59e6ef09766202dec9a40c201ebc8a Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 8 May 2012 13:05:33 -0700 Subject: [PATCH 09/27] Add fallback option for the extension. --- .../firefox/components/PdfStreamConverter.js | 36 +++++++++++++++++++ web/viewer.html | 8 +++-- web/viewer.js | 10 ++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index af9cf41b8..5d7ac69ea 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -16,6 +16,7 @@ const MAX_DATABASE_LENGTH = 4096; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); +Cu.import('resource://gre/modules/NetUtil.jsm'); let application = Cc['@mozilla.org/fuel/application;1'] .getService(Ci.fuelIApplication); @@ -45,6 +46,41 @@ ChromeActions.prototype = { download: function(data) { Services.wm.getMostRecentWindow('navigator:browser').saveURL(data); }, + fallback: function(data) { + let mimeService = Cc['@mozilla.org/mime;1'].getService(Ci.nsIMIMEService); + var handlerInfo = mimeService. + getFromTypeAndExtension('application/pdf', 'pdf'); + var uri = NetUtil.newURI(data); + var filename = Services.wm.getMostRecentWindow('navigator:browser'). + getDefaultFileName('document.pdf', uri); + // Create a temporary file to output to. + var file = Cc['@mozilla.org/file/directory_service;1']. + getService(Ci.nsIProperties). + get('TmpD', Ci.nsIFile); + file.append(filename); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt('0666', 8)); + + var ostream = Cc['@mozilla.org/network/file-output-stream;1']. + createInstance(Ci.nsIFileOutputStream); + ostream.init(file, -1, -1, 0); + + // Fetch the file and once it's ready attempt to open it with the system's + // default pdf handler. + NetUtil.asyncFetch(uri, function(istream, aResult) { + if (!Components.isSuccessCode(aResult)) { + log('Error: Fetching file failed with code ' + aResult); + return; + } + NetUtil.asyncCopy(istream, ostream, function(aResult) { + if (!Components.isSuccessCode(aResult)) { + log('Error: Copying file failed with code: ' + aResult); + return; + } + handlerInfo.preferredAction = Ci.nsIHandlerInfo.useSystemDefault; + handlerInfo.launchWithFile(file); + }); + }); + }, setDatabase: function(data) { if (this.inPrivateBrowswing) return; diff --git a/web/viewer.html b/web/viewer.html index 0ec05e031..fa836fdab 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -101,12 +101,14 @@ Print --> - - + - Current View + Current View
diff --git a/web/viewer.js b/web/viewer.js index e8eb9ad3b..b15b123a4 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -374,6 +374,13 @@ var PDFView = { } }, + fallback: function pdfViewDownload() { + if (!PDFJS.isFirefoxExtension) + return; // can't do this with regular viewer + var url = this.url.split('#')[0]; + FirefoxCom.request('fallback', url); + }, + navigateTo: function pdfViewNavigateTo(dest) { if (typeof dest === 'string') dest = this.destinations[dest]; @@ -1352,6 +1359,9 @@ window.addEventListener('load', function webViewerLoad(evt) { document.getElementById('fileInput').value = null; } + if (PDFJS.isFirefoxExtension) + document.getElementById('fallback').removeAttribute('hidden'); + // Special debugging flags in the hash section of the URL. var hash = document.location.hash.substring(1); var hashParams = PDFView.parseQueryString(hash); From c1f73b96a40bd7d3d0ac17001509ff884df2c034 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 8 May 2012 16:11:50 -0700 Subject: [PATCH 10/27] Use open with/save as dialog for fallback and download. --- .../firefox/components/PdfStreamConverter.js | 55 +++++++++---------- web/viewer.html | 8 +-- web/viewer.js | 5 +- 3 files changed, 29 insertions(+), 39 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 5d7ac69ea..f723c69e4 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -44,42 +44,37 @@ function ChromeActions() { } ChromeActions.prototype = { download: function(data) { - Services.wm.getMostRecentWindow('navigator:browser').saveURL(data); - }, - fallback: function(data) { let mimeService = Cc['@mozilla.org/mime;1'].getService(Ci.nsIMIMEService); var handlerInfo = mimeService. getFromTypeAndExtension('application/pdf', 'pdf'); var uri = NetUtil.newURI(data); - var filename = Services.wm.getMostRecentWindow('navigator:browser'). - getDefaultFileName('document.pdf', uri); - // Create a temporary file to output to. - var file = Cc['@mozilla.org/file/directory_service;1']. - getService(Ci.nsIProperties). - get('TmpD', Ci.nsIFile); - file.append(filename); - file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt('0666', 8)); - var ostream = Cc['@mozilla.org/network/file-output-stream;1']. - createInstance(Ci.nsIFileOutputStream); - ostream.init(file, -1, -1, 0); - - // Fetch the file and once it's ready attempt to open it with the system's - // default pdf handler. - NetUtil.asyncFetch(uri, function(istream, aResult) { - if (!Components.isSuccessCode(aResult)) { - log('Error: Fetching file failed with code ' + aResult); - return; + var extHelperAppSvc = + Cc['@mozilla.org/uriloader/external-helper-app-service;1']. + getService(Ci.nsIExternalHelperAppService); + var frontWindow = Cc['@mozilla.org/embedcomp/window-watcher;1']. + getService(Ci.nsIWindowWatcher).activeWindow; + var ioService = Services.io; + var channel = ioService.newChannel(data, null, null); + var listener = { + extListener: null, + onStartRequest: function(aRequest, aContext) { + this.extListener = extHelperAppSvc.doContent('application/pdf', + aRequest, frontWindow, false); + this.extListener.onStartRequest(aRequest, aContext); + }, + onStopRequest: function(aRequest, aContext, aStatusCode) { + if (this.extListener) + this.extListener.onStopRequest(aRequest, aContext, aStatusCode); + }, + onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, + aCount) { + this.extListener.onDataAvailable(aRequest, aContext, aInputStream, + aOffset, aCount); } - NetUtil.asyncCopy(istream, ostream, function(aResult) { - if (!Components.isSuccessCode(aResult)) { - log('Error: Copying file failed with code: ' + aResult); - return; - } - handlerInfo.preferredAction = Ci.nsIHandlerInfo.useSystemDefault; - handlerInfo.launchWithFile(file); - }); - }); + }; + + channel.asyncOpen(listener, null); }, setDatabase: function(data) { if (this.inPrivateBrowswing) diff --git a/web/viewer.html b/web/viewer.html index fa836fdab..0ec05e031 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -101,14 +101,12 @@ Print --> - - - Current View + Current View
diff --git a/web/viewer.js b/web/viewer.js index b15b123a4..857429c5e 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -375,9 +375,9 @@ var PDFView = { }, fallback: function pdfViewDownload() { + var url = this.url.split('#')[0]; if (!PDFJS.isFirefoxExtension) return; // can't do this with regular viewer - var url = this.url.split('#')[0]; FirefoxCom.request('fallback', url); }, @@ -1359,9 +1359,6 @@ window.addEventListener('load', function webViewerLoad(evt) { document.getElementById('fileInput').value = null; } - if (PDFJS.isFirefoxExtension) - document.getElementById('fallback').removeAttribute('hidden'); - // Special debugging flags in the hash section of the URL. var hash = document.location.hash.substring(1); var hashParams = PDFView.parseQueryString(hash); From cb7d6e81ab1019106b86337fa672a2878ac48fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionu=C8=9B=20G=2E=20Stan?= Date: Wed, 9 May 2012 13:45:28 +0300 Subject: [PATCH 11/27] Add Romanian localization files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thanks @xhr and @silviupostavaru for helping with this. commit fcadb2cc7891d33214213011091e2bc8e29bdb51 Author: Ionuț G. Stan Date: Wed May 9 13:41:35 2012 +0300 Change Romanian localization for "bookmark" commit b0f152fe88d7591492d09d094608b73605985859 Author: Ionuț G. Stan Date: Wed May 9 13:40:25 2012 +0300 Don't use titlecase for the Romanian localization commit f312dd76314db685cc2b4a7e3ae7ecdbc8ca36f0 Author: Ionuț G. Stan Date: Wed May 9 13:38:35 2012 +0300 Change Romanian localization for "print" commit 242b1ff9970790b3ec2557239dcdba9a5ef77028 Author: Ionuț G. Stan Date: Wed May 9 13:32:41 2012 +0300 Add Romanian localization files --- l10n/ro/metadata.inc | 8 ++++++++ l10n/ro/viewer.properties | 42 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 l10n/ro/metadata.inc create mode 100644 l10n/ro/viewer.properties diff --git a/l10n/ro/metadata.inc b/l10n/ro/metadata.inc new file mode 100644 index 000000000..e2c72eca5 --- /dev/null +++ b/l10n/ro/metadata.inc @@ -0,0 +1,8 @@ + + + ro + Cititor PDF + Afișează fișierele PDF direct în Firefox. + + + diff --git a/l10n/ro/viewer.properties b/l10n/ro/viewer.properties new file mode 100644 index 000000000..c3f29144c --- /dev/null +++ b/l10n/ro/viewer.properties @@ -0,0 +1,42 @@ +bookmark.title=Vederea curentă (copiază sau deschide în fereastră nouă) +previous.title=Pagina precedentă +next.title=Pagina următoare +print.title=Tipărește +download.title=Descarcă +zoom_out.title=Mărește +zoom_in.title=Micșorează +error_more_info=Detaliat +error_less_info=Sumarizat +error_close=Închide +error_build=PDF.JS Build: {{build}} +error_message=Message: {{message}} +error_stack=Stack: {{stack}} +error_file=File: {{file}} +error_line=Line: {{line}} +page_scale_width=După lățime +page_scale_fit=Toată pagina +page_scale_auto=Mărime automată +page_scale_actual=Mărime originală +toggle_slider.title=Vedere de ansamblu +thumbs.title=Miniaturi +outline.title=Cuprins +loading=Încărcare... {{percent}}% +loading_error_indicator=Eroare +loading_error=S-a produs o eroare în timpul încărcării documentului. +rendering_error=S-a produs o eroare în timpul procesării paginii. +page_label=Pagina: +page_of=din {{pageCount}} +no_outline=Cuprins indisponibil +open_file.title=Deschide fișier +text_annotation_type=[Adnotare {{type}}] +toggle_slider_label=Vedere de ansamblu +thumbs_label=Miniaturi +outline_label=Cuprins +bookmark_label=Vederea curentă +previous_label=Înapoi +next_label=Înainte +print_label=Tipărește +download_label=Descarcă +zoom_out_label=Mărește +zoom_in_label=Micșorează +zoom.title=Mărime From bf79d63dd42e8d4a938527e850ab3e0fe84d3e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionu=C8=9B=20G=2E=20Stan?= Date: Wed, 9 May 2012 15:38:00 +0300 Subject: [PATCH 12/27] Swap Romanian translations for zooming in/out --- l10n/ro/viewer.properties | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/l10n/ro/viewer.properties b/l10n/ro/viewer.properties index c3f29144c..5b79b2f51 100644 --- a/l10n/ro/viewer.properties +++ b/l10n/ro/viewer.properties @@ -3,8 +3,8 @@ previous.title=Pagina precedentă next.title=Pagina următoare print.title=Tipărește download.title=Descarcă -zoom_out.title=Mărește -zoom_in.title=Micșorează +zoom_out.title=Micșorează +zoom_in.title=Mărește error_more_info=Detaliat error_less_info=Sumarizat error_close=Închide @@ -37,6 +37,6 @@ previous_label=Înapoi next_label=Înainte print_label=Tipărește download_label=Descarcă -zoom_out_label=Mărește -zoom_in_label=Micșorează +zoom_out_label=Micșorează +zoom_in_label=Mărește zoom.title=Mărime From 0cb1a088233b663785cfb2ead478c40774b050f4 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 9 May 2012 09:02:41 -0700 Subject: [PATCH 13/27] Remove fallback function. --- web/viewer.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/web/viewer.js b/web/viewer.js index 857429c5e..e8eb9ad3b 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -374,13 +374,6 @@ var PDFView = { } }, - fallback: function pdfViewDownload() { - var url = this.url.split('#')[0]; - if (!PDFJS.isFirefoxExtension) - return; // can't do this with regular viewer - FirefoxCom.request('fallback', url); - }, - navigateTo: function pdfViewNavigateTo(dest) { if (typeof dest === 'string') dest = this.destinations[dest]; From 6acdf1791cdb8775024db1d7e6b87181fc9cbf83 Mon Sep 17 00:00:00 2001 From: Dmitry Kataev Date: Wed, 9 May 2012 21:29:50 +0400 Subject: [PATCH 14/27] Two or more operations can be combined together like qqBT --- src/evaluator.js | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/src/evaluator.js b/src/evaluator.js index 23c9d1f65..ae443fa81 100644 --- a/src/evaluator.js +++ b/src/evaluator.js @@ -112,14 +112,33 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { }; function splitCombinedOperations(operations) { - // Two operations can be combined together, trying to find which two + // Two or more operations can be combined together, trying to find which // operations were concatenated. - for (var i = operations.length - 1; i > 0; i--) { - var op1 = operations.substring(0, i), op2 = operations.substring(i); - if (op1 in OP_MAP && op2 in OP_MAP) - return [op1, op2]; // operations found + var result = []; + var opIndex = 0; + + if (!operations) { + return null; } - return null; + + while (opIndex < operations.length) { + var currentOp = ''; + for (var op in OP_MAP) { + if (op == operations.substr(opIndex, op.length) && + op.length > currentOp.length) { + currentOp = op; + } + } + + if (currentOp.length > 0) { + result.push(operations.substr(opIndex, currentOp.length)); + opIndex += currentOp.length; + } else { + return null; + } + } + + return result; } PartialEvaluator.prototype = { @@ -267,14 +286,14 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { var patterns = resources.get('Pattern') || new Dict(); var parser = new Parser(new Lexer(stream), false, xref); var res = resources; - var hasNextObj = false, nextObj; + var hasNextObj = false, nextObjs; var args = [], obj; var TILING_PATTERN = 1, SHADING_PATTERN = 2; while (true) { if (hasNextObj) { - obj = nextObj; - hasNextObj = false; + obj = nextObjs.pop(); + hasNextObj = (nextObjs.length > 0); } else { obj = parser.getObj(); if (isEOF(obj)) @@ -290,9 +309,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() { if (cmds) { cmd = cmds[0]; fn = OP_MAP[cmd]; - // feeding other command on the next interation + // feeding other command on the next iteration hasNextObj = true; - nextObj = Cmd.get(cmds[1]); + nextObjs = []; + for (var idx = 1; idx < cmds.length; idx++) { + nextObjs.push(Cmd.get(cmds[idx])); + } } } assertWellFormed(fn, 'Unknown command "' + cmd + '"'); From b6071473681b7fa177be8393a0b45ac9344d819e Mon Sep 17 00:00:00 2001 From: Gavin Sharp Date: Wed, 9 May 2012 17:04:52 -0700 Subject: [PATCH 15/27] Issue 1682: don't use FUEL in pdf.js --- extensions/firefox/bootstrap.js | 21 ++++++++--- .../firefox/components/PdfStreamConverter.js | 35 +++++++++++++++---- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/extensions/firefox/bootstrap.js b/extensions/firefox/bootstrap.js index d03812bcb..af9c5c1b2 100644 --- a/extensions/firefox/bootstrap.js +++ b/extensions/firefox/bootstrap.js @@ -10,13 +10,26 @@ let Cc = Components.classes; let Ci = Components.interfaces; let Cm = Components.manager; let Cu = Components.utils; -let application = Cc['@mozilla.org/fuel/application;1'] - .getService(Ci.fuelIApplication); Cu.import('resource://gre/modules/Services.jsm'); +function getBoolPref(pref, default) { + try { + return Services.prefs.getBoolPref(pref); + } catch (ex) { + return default; + } +} + +function setStringPref(pref, value) { + let str = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + str.data = value; + Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str); +} + function log(str) { - if (!application.prefs.getValue(EXT_PREFIX + '.pdfBugEnabled', false)) + if (!getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false)) return; dump(str + '\n'); } @@ -93,6 +106,6 @@ function install(aData, aReason) { } function uninstall(aData, aReason) { - application.prefs.setValue(EXT_PREFIX + '.database', '{}'); + setStringPref(EXT_PREFIX + '.database', '{}'); } diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index af9cf41b8..bfffd0bc1 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -17,14 +17,35 @@ const MAX_DATABASE_LENGTH = 4096; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); -let application = Cc['@mozilla.org/fuel/application;1'] - .getService(Ci.fuelIApplication); let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1'] .getService(Ci.nsIPrivateBrowsingService); let inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled; +function getBoolPref(pref, default) { + try { + return Services.prefs.getBoolPref(pref); + } catch (ex) { + return default; + } +} + +function setStringPref(pref, value) { + let str = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + str.data = value; + Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str); +} + +function getStringPref(pref, default) { + try { + return Services.prefs.getComplexValue(pref, Ci.nsISupportsString).data; + } catch (ex) { + return default; + } +} + function log(aMsg) { - if (!application.prefs.getValue(EXT_PREFIX + '.pdfBugEnabled', false)) + if (!getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false)) return; let msg = 'PdfStreamConverter.js: ' + (aMsg.join ? aMsg.join('') : aMsg); Services.console.logStringMessage(msg); @@ -51,18 +72,18 @@ ChromeActions.prototype = { // Protect against something sending tons of data to setDatabase. if (data.length > MAX_DATABASE_LENGTH) return; - application.prefs.setValue(EXT_PREFIX + '.database', data); + setStringPref(EXT_PREFIX + '.database', data); }, getDatabase: function() { if (this.inPrivateBrowswing) return '{}'; - return application.prefs.getValue(EXT_PREFIX + '.database', '{}'); + return getStringPref(EXT_PREFIX + '.database', '{}'); }, getLocale: function() { - return application.prefs.getValue('general.useragent.locale', 'en-US'); + return getStringPref('general.useragent.locale', 'en-US'); }, pdfBugEnabled: function() { - return application.prefs.getValue(EXT_PREFIX + '.pdfBugEnabled', false); + return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false); } }; From 117582b2eaa1d8ce3e040da24c4fe8962a0c353a Mon Sep 17 00:00:00 2001 From: Gavin Sharp Date: Thu, 10 May 2012 10:05:24 -0700 Subject: [PATCH 16/27] fix review comments from bdahl --- extensions/firefox/bootstrap.js | 6 +++--- extensions/firefox/components/PdfStreamConverter.js | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/extensions/firefox/bootstrap.js b/extensions/firefox/bootstrap.js index af9c5c1b2..5bf66d444 100644 --- a/extensions/firefox/bootstrap.js +++ b/extensions/firefox/bootstrap.js @@ -13,16 +13,16 @@ let Cu = Components.utils; Cu.import('resource://gre/modules/Services.jsm'); -function getBoolPref(pref, default) { +function getBoolPref(pref, def) { try { return Services.prefs.getBoolPref(pref); } catch (ex) { - return default; + return def; } } function setStringPref(pref, value) { - let str = Cc["@mozilla.org/supports-string;1"] + let str = Cc['@mozilla.org/supports-string;1'] .createInstance(Ci.nsISupportsString); str.data = value; Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str); diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index bfffd0bc1..deeb112f6 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -21,26 +21,26 @@ let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1'] .getService(Ci.nsIPrivateBrowsingService); let inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled; -function getBoolPref(pref, default) { +function getBoolPref(pref, def) { try { return Services.prefs.getBoolPref(pref); } catch (ex) { - return default; + return def; } } function setStringPref(pref, value) { - let str = Cc["@mozilla.org/supports-string;1"] + let str = Cc['@mozilla.org/supports-string;1'] .createInstance(Ci.nsISupportsString); str.data = value; Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str); } -function getStringPref(pref, default) { +function getStringPref(pref, def) { try { return Services.prefs.getComplexValue(pref, Ci.nsISupportsString).data; } catch (ex) { - return default; + return def; } } From 324b867183f3c9b6cff15129644570b1d7047209 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Thu, 10 May 2012 16:11:27 -0500 Subject: [PATCH 17/27] Adds evaluator tests --- test/unit/evaluator_spec.js | 83 +++++++++++++++++++++++++++++++++++++ test/unit/unit_test.html | 1 + 2 files changed, 84 insertions(+) create mode 100644 test/unit/evaluator_spec.js diff --git a/test/unit/evaluator_spec.js b/test/unit/evaluator_spec.js new file mode 100644 index 000000000..4ee0768a7 --- /dev/null +++ b/test/unit/evaluator_spec.js @@ -0,0 +1,83 @@ +/* -*- 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('evaluator', function() { + function XrefMock(queue) { + this.queue = queue; + } + XrefMock.prototype = { + fetchIfRef: function() { + return this.queue.shift(); + } + }; + function HandlerMock() { + this.inputs = []; + } + HandlerMock.prototype = { + send: function(name, data) { + this.inputs({name: name, data: data}); + } + }; + function ResourcesMock() { } + ResourcesMock.prototype = { + get: function(name) { + return this[name]; + } + }; + + describe('splitCombinedOperations', function() { + it('should reject unknown operations', function() { + var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(), + 'prefix'); + var stream = new StringStream('qTT'); + var thrown = false; + try { + evaluator.getOperatorList(stream, new ResourcesMock(), []); + } catch (e) { + thrown = e; + } + expect(thrown).toNotEqual(false); + }); + + it('should handle one operations', function() { + var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(), + 'prefix'); + var stream = new StringStream('Q'); + var result = evaluator.getOperatorList(stream, new ResourcesMock(), []); + + expect(!!result.fnArray && !!result.argsArray).toEqual(true); + expect(result.fnArray.length).toEqual(1); + expect(result.fnArray[0]).toEqual('restore'); + }); + + it('should handle two glued operations', function() { + var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(), + 'prefix'); + var resources = new ResourcesMock(); + resources.Res1 = {}; + var stream = new StringStream('/Res1 DoQ'); + var result = evaluator.getOperatorList(stream, resources, []); + + expect(!!result.fnArray && !!result.argsArray).toEqual(true); + expect(result.fnArray.length).toEqual(2); + expect(result.fnArray[0]).toEqual('paintXObject'); + expect(result.fnArray[1]).toEqual('restore'); + }); + + it('should handle tree glued operations', function() { + var evaluator = new PartialEvaluator(new XrefMock(), new HandlerMock(), + 'prefix'); + var stream = new StringStream('qqq'); + var result = evaluator.getOperatorList(stream, new ResourcesMock(), []); + + expect(!!result.fnArray && !!result.argsArray).toEqual(true); + expect(result.fnArray.length).toEqual(3); + expect(result.fnArray[0]).toEqual('save'); + expect(result.fnArray[1]).toEqual('save'); + expect(result.fnArray[2]).toEqual('save'); + }); + }); +}); + diff --git a/test/unit/unit_test.html b/test/unit/unit_test.html index cdd0c297f..ca0a1aed1 100644 --- a/test/unit/unit_test.html +++ b/test/unit/unit_test.html @@ -39,6 +39,7 @@ + From 6323c8e084c8e263953dc2d5684859ee6f01b843 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 14:39:11 -0500 Subject: [PATCH 18/27] Loading extension resources via stringbundle --- extensions/chrome/.gitignore | 1 + extensions/firefox/.gitignore | 2 + extensions/firefox/chrome.manifest | 3 + .../firefox/components/PdfStreamConverter.js | 39 +++++++++++++ make.js | 55 +++++++++++-------- web/viewer.js | 11 ++-- 6 files changed, 84 insertions(+), 27 deletions(-) create mode 100644 extensions/chrome/.gitignore create mode 100644 extensions/firefox/chrome.manifest diff --git a/extensions/chrome/.gitignore b/extensions/chrome/.gitignore new file mode 100644 index 000000000..3eb92306c --- /dev/null +++ b/extensions/chrome/.gitignore @@ -0,0 +1 @@ +content/ diff --git a/extensions/firefox/.gitignore b/extensions/firefox/.gitignore index 08a23850c..6eec9a7f2 100644 --- a/extensions/firefox/.gitignore +++ b/extensions/firefox/.gitignore @@ -1,2 +1,4 @@ content/ metadata.inc +chrome.manifest.inc +locale/ diff --git a/extensions/firefox/chrome.manifest b/extensions/firefox/chrome.manifest new file mode 100644 index 000000000..97b76306b --- /dev/null +++ b/extensions/firefox/chrome.manifest @@ -0,0 +1,3 @@ +# Additional resources for pdf.js + +# PDFJS_SUPPORTED_LOCALES diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 49fd134ae..d84f19e58 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -4,6 +4,10 @@ 'use strict'; var EXPORTED_SYMBOLS = ['PdfStreamConverter']; +var DEFAULT_LOCALE = 'en-US'; + +var IS_MOZCENTRAL = false; // PDFJS_SUPPORTED_LOCALES +var SUPPORTED_LOCALES = [DEFAULT_LOCALE]; // PDFJS_SUPPORTED_LOCALES const Cc = Components.classes; const Ci = Components.interfaces; @@ -59,6 +63,28 @@ function getDOMWindow(aChannel) { return win; } +function getLocalizedStrings(path) { + var stringBundle = Cc["@mozilla.org/intl/stringbundle;1"]. + getService(Ci.nsIStringBundleService). + createBundle("chrome://pdfviewer/locale/" + path); + + var map = {}; + var enumerator = stringBundle.getSimpleEnumeration(); + while (enumerator.hasMoreElements()) { + var string = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement); + var key = string.key, property = 'textContent'; + var i = key.lastIndexOf('.'); + if (i >= 0) { + property = key.substring(i + 1); + key = key.substring(0, i); + } + if (!(key in map)) + map[key] = {}; + map[key][property] = string.value; + } + return map; +} + // All the priviledged actions. function ChromeActions() { this.inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled; @@ -113,6 +139,19 @@ ChromeActions.prototype = { getLocale: function() { return getStringPref('general.useragent.locale', 'en-US'); }, + getStrings: function(data) { + try { + // Lazy initialization of localizedStrings + if (!('localizedStrings' in this)) + this.localizedStrings = getLocalizedStrings('viewer.properties'); + + var result = this.localizedStrings[data]; + return JSON.stringify(result || null) + } catch (e) { + log('Unable to retrive localized strings: ' + e); + return 'null'; + } + }, pdfBugEnabled: function() { return getBoolPref(EXT_PREFIX + '.pdfBugEnabled', false); } diff --git a/make.js b/make.js index 0a39e0b07..34dc27c9b 100755 --- a/make.js +++ b/make.js @@ -6,6 +6,7 @@ var ROOT_DIR = __dirname + '/', // absolute path to project's root BUILD_TARGET = BUILD_DIR + 'pdf.js', FIREFOX_BUILD_DIR = BUILD_DIR + '/firefox/', EXTENSION_SRC_DIR = 'extensions/', + LOCALE_SRC_DIR = 'l10n/', GH_PAGES_DIR = BUILD_DIR + 'gh-pages/', REPO = 'git@github.com:mozilla/pdf.js.git', PYTHON_BIN = 'python2.7'; @@ -67,8 +68,9 @@ target.web = function() { // Creates localized resources for the viewer and extension. // target.locale = function() { - var L10N_PATH = 'l10n'; var METADATA_OUTPUT = 'extensions/firefox/metadata.inc'; + var CHROME_MANIFEST_OUTPUT = 'extensions/firefox/chrome.manifest.inc'; + var EXTENSION_LOCALE_OUTPUT = 'extensions/firefox/locale'; var VIEWER_OUTPUT = 'web/locale.properties'; var DEFAULT_LOCALE = 'en-US'; @@ -76,13 +78,17 @@ target.locale = function() { echo(); echo('### Building localization files'); - var subfolders = ls(L10N_PATH); + rm('-rf', EXTENSION_LOCALE_OUTPUT); + mkdir('-p', EXTENSION_LOCALE_OUTPUT); + + var subfolders = ls(LOCALE_SRC_DIR); subfolders.sort(); var metadataContent = ''; + var chromeManifestContent = ''; var viewerOutput = ''; for (var i = 0; i < subfolders.length; i++) { var locale = subfolders[i]; - var path = L10N_PATH + '/' + locale; + var path = LOCALE_SRC_DIR + locale; if (!test('-d', path)) continue; @@ -91,12 +97,13 @@ target.locale = function() { continue; } + mkdir('-p', EXTENSION_LOCALE_OUTPUT + '/' + locale); + chromeManifestContent += 'locale pdfviewer ' + locale + ' locale/' + locale + '/\n'; + if (test('-f', path + '/viewer.properties')) { var properties = cat(path + '/viewer.properties'); - if (locale == DEFAULT_LOCALE) - viewerOutput = '[*]\n' + properties + '\n' + viewerOutput; - else - viewerOutput = viewerOutput + '[' + locale + ']\n' + properties + '\n'; + viewerOutput += '[' + locale + ']\n' + properties + '\n'; + cp(path + '/viewer.properties', EXTENSION_LOCALE_OUTPUT + '/' + locale); } if (test('-f', path + '/metadata.inc')) { @@ -106,6 +113,7 @@ target.locale = function() { } viewerOutput.to(VIEWER_OUTPUT); metadataContent.to(METADATA_OUTPUT); + chromeManifestContent.to(CHROME_MANIFEST_OUTPUT); }; // @@ -227,7 +235,7 @@ var EXTENSION_WEB_FILES = 'web/viewer.css', 'web/viewer.js', 'web/viewer.html', - 'external/webL10n/l10n.js', + 'extensions/firefox/tools/l10n.js', 'web/viewer-production.html'], EXTENSION_BASE_VERSION = 'f0f0418a9c6637981fe1182b9212c2d592774c7d', EXTENSION_VERSION_PREFIX = '0.3.', @@ -277,21 +285,23 @@ target.firefox = function() { '*.rdf', '*.svg', '*.png', + '*.manifest', 'components', + 'locale', '../../LICENSE'], FIREFOX_EXTENSION_FILES = ['bootstrap.js', 'install.rdf', + 'chrome.manifest', 'icon.png', 'icon64.png', 'components', 'content', + 'locale', 'LICENSE'], FIREFOX_EXTENSION_NAME = 'pdf.js.xpi', FIREFOX_AMO_EXTENSION_NAME = 'pdf.js.amo.xpi'; - var LOCALE_CONTENT = cat('web/locale.properties'); - target.production(); target.buildnumber(); cd(ROOT_DIR); @@ -310,7 +320,6 @@ target.firefox = function() { // Copy a standalone version of pdf.js inside the content directory cp(BUILD_TARGET, FIREFOX_BUILD_CONTENT_DIR + BUILD_DIR); cp('-R', EXTENSION_WEB_FILES, FIREFOX_BUILD_CONTENT_DIR + '/web'); - cp('web/locale.properties', FIREFOX_BUILD_CONTENT_DIR + '/web'); rm(FIREFOX_BUILD_CONTENT_DIR + '/web/viewer-production.html'); // Copy over the firefox extension snippet so we can inline pdf.js in it @@ -319,7 +328,6 @@ target.firefox = function() { // Modify the viewer so it does all the extension-only stuff. cd(FIREFOX_BUILD_CONTENT_DIR + '/web'); sed('-i', /.*PDFJSSCRIPT_INCLUDE_BUNDLE.*\n/, cat(ROOT_DIR + BUILD_TARGET), 'viewer-snippet-firefox-extension.html'); - sed('-i', /.*PDFJSSCRIPT_LOCALE_DATA.*\n/, LOCALE_CONTENT, 'viewer-snippet-firefox-extension.html'); sed('-i', /.*PDFJSSCRIPT_REMOVE_CORE.*\n/g, '', 'viewer.html'); sed('-i', /.*PDFJSSCRIPT_REMOVE_FIREFOX_EXTENSION.*\n/g, '', 'viewer.html'); sed('-i', /.*PDFJSSCRIPT_INCLUDE_FIREFOX_EXTENSION.*\n/, cat('viewer-snippet-firefox-extension.html'), 'viewer.html'); @@ -328,7 +336,6 @@ target.firefox = function() { // We don't need pdf.js anymore since its inlined rm('-Rf', FIREFOX_BUILD_CONTENT_DIR + BUILD_DIR); rm(FIREFOX_BUILD_CONTENT_DIR + '/web/viewer-snippet-firefox-extension.html'); - rm(FIREFOX_BUILD_CONTENT_DIR + '/web/locale.properties'); // Remove '.DS_Store' and other hidden files find(FIREFOX_BUILD_DIR).forEach(function(file) { if (file.match(/^\./)) @@ -342,6 +349,8 @@ target.firefox = function() { // Update localized metadata var localizedMetadata = cat(EXTENSION_SRC_DIR + '/firefox/metadata.inc'); sed('-i', /.*PDFJS_LOCALIZED_METADATA.*\n/, localizedMetadata, FIREFOX_BUILD_DIR + '/install.rdf'); + var chromeManifest = cat(EXTENSION_SRC_DIR + '/firefox/chrome.manifest.inc'); + sed('-i', /.*PDFJS_SUPPORTED_LOCALES.*\n/, chromeManifest, FIREFOX_BUILD_DIR + '/chrome.manifest'); // Create the xpi cd(FIREFOX_BUILD_DIR); @@ -365,25 +374,27 @@ target.mozcentral = function() { echo(); echo('### Building mozilla-central extension'); - var MOZCENTRAL_DIR = BUILD_DIR + '/mozcentral', - MOZCENTRAL_CONTENT_DIR = MOZCENTRAL_DIR + '/content/', - MOZCENTRAL_L10N_DIR = MOZCENTRAL_DIR + '/l10n/', + var MOZCENTRAL_DIR = BUILD_DIR + 'mozcentral/', + MOZCENTRAL_EXTENSION_DIR = MOZCENTRAL_DIR + 'browser/app/profile/extensions/uriloader@pdf.js/', + MOZCENTRAL_CONTENT_DIR = MOZCENTRAL_EXTENSION_DIR + 'content/', + MOZCENTRAL_L10N_DIR = MOZCENTRAL_DIR + 'browser/locales/en-US/pdfviewer/', FIREFOX_CONTENT_DIR = EXTENSION_SRC_DIR + '/firefox/content/', FIREFOX_EXTENSION_FILES_TO_COPY = ['*.js', '*.svg', '*.png', + '*.manifest', 'install.rdf.in', 'README.mozilla', 'components', '../../LICENSE'], DEFAULT_LOCALE_FILES = - ['l10n/en-US/viewer.properties', - 'l10n/en-US/metadata.inc'], + [LOCALE_SRC_DIR + 'en-US/viewer.properties'], FIREFOX_MC_EXTENSION_FILES = ['bootstrap.js', 'icon.png', 'icon64.png', + 'chrome.manifest', 'components', 'content', 'LICENSE']; @@ -401,7 +412,7 @@ target.mozcentral = function() { // Copy extension files cd('extensions/firefox'); - cp('-R', FIREFOX_EXTENSION_FILES_TO_COPY, ROOT_DIR + MOZCENTRAL_DIR); + cp('-R', FIREFOX_EXTENSION_FILES_TO_COPY, ROOT_DIR + MOZCENTRAL_EXTENSION_DIR); cd(ROOT_DIR); // Copy a standalone version of pdf.js inside the content directory @@ -433,11 +444,11 @@ target.mozcentral = function() { cp(DEFAULT_LOCALE_FILES, MOZCENTRAL_L10N_DIR); // Update the build version number - sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_DIR + '/install.rdf.in'); - sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_DIR + '/README.mozilla'); + sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_EXTENSION_DIR + 'install.rdf.in'); + sed('-i', /PDFJSSCRIPT_VERSION/, EXTENSION_VERSION, MOZCENTRAL_EXTENSION_DIR + 'README.mozilla'); // List all files for mozilla-central - cd(MOZCENTRAL_DIR); + cd(MOZCENTRAL_EXTENSION_DIR); var extensionFiles = ''; find(FIREFOX_MC_EXTENSION_FILES).forEach(function(file){ if (test('-f', file)) diff --git a/web/viewer.js b/web/viewer.js index dcbfcf14e..dd267065a 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -1362,11 +1362,12 @@ window.addEventListener('load', function webViewerLoad(evt) { if ('disableWorker' in hashParams) PDFJS.disableWorker = (hashParams['disableWorker'] === 'true'); - var locale = !PDFJS.isFirefoxExtension ? navigator.language : - FirefoxCom.request('getLocale', null); - if ('locale' in hashParams) - locale = hashParams['locale']; - mozL10n.language.code = locale; + if (!PDFJS.isFirefoxExtension) { + var locale = navigator.language; + if ('locale' in hashParams) + locale = hashParams['locale']; + mozL10n.language.code = locale; + } if ('disableTextLayer' in hashParams) PDFJS.disableTextLayer = (hashParams['disableTextLayer'] === 'true'); From 56b3a7086e94775ff0cd3d03135d78965e0da066 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 14:42:20 -0500 Subject: [PATCH 19/27] Remove unused code --- extensions/firefox/components/PdfStreamConverter.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index d84f19e58..898058004 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -4,10 +4,6 @@ 'use strict'; var EXPORTED_SYMBOLS = ['PdfStreamConverter']; -var DEFAULT_LOCALE = 'en-US'; - -var IS_MOZCENTRAL = false; // PDFJS_SUPPORTED_LOCALES -var SUPPORTED_LOCALES = [DEFAULT_LOCALE]; // PDFJS_SUPPORTED_LOCALES const Cc = Components.classes; const Ci = Components.interfaces; From 5ca12d549e5d9d0ea1162e33067d5da7bf2389f9 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 15:14:50 -0500 Subject: [PATCH 20/27] Missing file --- extensions/firefox/tools/l10n.js | 113 +++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 extensions/firefox/tools/l10n.js diff --git a/extensions/firefox/tools/l10n.js b/extensions/firefox/tools/l10n.js new file mode 100644 index 000000000..ad3b4ab95 --- /dev/null +++ b/extensions/firefox/tools/l10n.js @@ -0,0 +1,113 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + +'use strict'; + +// Small subset of the webL10n API by Fabien Cazenave for pdf.js extension. +(function(window) { + var gLanguage = ''; + + // fetch an l10n objects + function getL10nData(key) { + var response = FirefoxCom.request('getStrings', key); + var data = JSON.parse(response); + if (!data) + console.warn('[l10n] #' + key + ' missing for [' + gLanguage + ']'); + return data; + } + + // replace {{arguments}} with their values + function substArguments(text, args) { + if (!args) + return text; + + return text.replace(/\{\{\s*(\w+)\s*\}\}/g, function(all, name) { + return name in args ? args[name] : '{{' + name + '}}'; + }); + } + + // translate a string + function translateString(key, args, fallback) { + var data = getL10nData(key); + if (!data && fallback) + data = {textContent: fallback}; + if (!data) + return '{{' + key + '}}'; + return substArguments(data.textContent, args); + } + + // translate an HTML element + function translateElement(element) { + if (!element || !element.dataset) + return; + + // get the related l10n object + var data = getL10nData(element.dataset.l10nId); + if (!data) + return; + + // get arguments (if any) + // TODO: more flexible parser? + var args; + if (element.dataset.l10nArgs) try { + args = JSON.parse(element.dataset.l10nArgs); + } catch (e) { + console.warn('[l10n] could not parse arguments for #' + key + ''); + } + + // translate element + // TODO: security check? + for (var k in data) + element[k] = substArguments(data[k], args); + } + + + // translate an HTML subtree + function translateFragment(element) { + element = element || document.querySelector('html'); + + // check all translatable children (= w/ a `data-l10n-id' attribute) + var children = element.querySelectorAll('*[data-l10n-id]'); + var elementCount = children.length; + for (var i = 0; i < elementCount; i++) + translateElement(children[i]); + + // translate element itself if necessary + if (element.dataset.l10nId) + translateElement(element); + } + + window.addEventListener('DOMContentLoaded', function() { + gLanguage = FirefoxCom.request('getLocale', null); + + translateFragment(); + + // fire a 'localized' DOM event + var evtObject = document.createEvent('Event'); + evtObject.initEvent('localized', false, false); + evtObject.language = gLanguage; + window.dispatchEvent(evtObject); + }); + + // Public API + document.mozL10n = { + // get a localized string + get: translateString, + + // get|set the document language and direction + get language() { + return { + // get|set the document language (ISO-639-1) + get code() { return gLanguage; }, + + // get the direction (ltr|rtl) of the current language + get direction() { + // http://www.w3.org/International/questions/qa-scripts + // Arabic, Hebrew, Farsi, Pashto, Urdu + var rtlList = ['ar', 'he', 'fa', 'ps', 'ur']; + return (rtlList.indexOf(gLanguage) >= 0) ? 'rtl' : 'ltr'; + } + }; + } + }; +})(this); \ No newline at end of file From 7d648cfa130203392b34d0c93aefddde433ae855 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 15:18:46 -0500 Subject: [PATCH 21/27] Lint errors --- extensions/firefox/components/PdfStreamConverter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 898058004..6ed755554 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -60,9 +60,9 @@ function getDOMWindow(aChannel) { } function getLocalizedStrings(path) { - var stringBundle = Cc["@mozilla.org/intl/stringbundle;1"]. + var stringBundle = Cc['@mozilla.org/intl/stringbundle;1']. getService(Ci.nsIStringBundleService). - createBundle("chrome://pdfviewer/locale/" + path); + createBundle('chrome://pdfviewer/locale/' + path); var map = {}; var enumerator = stringBundle.getSimpleEnumeration(); @@ -142,7 +142,7 @@ ChromeActions.prototype = { this.localizedStrings = getLocalizedStrings('viewer.properties'); var result = this.localizedStrings[data]; - return JSON.stringify(result || null) + return JSON.stringify(result || null); } catch (e) { log('Unable to retrive localized strings: ' + e); return 'null'; From d9f995f9caa149aa3e8334092e02e3a04aad61ce Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 17:35:43 -0500 Subject: [PATCH 22/27] Change pdfviewer->pdf.js for chrome://;new line --- extensions/firefox/components/PdfStreamConverter.js | 2 +- extensions/firefox/tools/l10n.js | 3 ++- make.js | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 6ed755554..4a6cd9eca 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -62,7 +62,7 @@ function getDOMWindow(aChannel) { function getLocalizedStrings(path) { var stringBundle = Cc['@mozilla.org/intl/stringbundle;1']. getService(Ci.nsIStringBundleService). - createBundle('chrome://pdfviewer/locale/' + path); + createBundle('chrome://pdf.js/locale/' + path); var map = {}; var enumerator = stringBundle.getSimpleEnumeration(); diff --git a/extensions/firefox/tools/l10n.js b/extensions/firefox/tools/l10n.js index ad3b4ab95..b16636e31 100644 --- a/extensions/firefox/tools/l10n.js +++ b/extensions/firefox/tools/l10n.js @@ -110,4 +110,5 @@ }; } }; -})(this); \ No newline at end of file +})(this); + diff --git a/make.js b/make.js index 34dc27c9b..90ccfb347 100755 --- a/make.js +++ b/make.js @@ -98,7 +98,7 @@ target.locale = function() { } mkdir('-p', EXTENSION_LOCALE_OUTPUT + '/' + locale); - chromeManifestContent += 'locale pdfviewer ' + locale + ' locale/' + locale + '/\n'; + chromeManifestContent += 'locale pdf.js ' + locale + ' locale/' + locale + '/\n'; if (test('-f', path + '/viewer.properties')) { var properties = cat(path + '/viewer.properties'); From 085723a7b2daf548a148d64d26a024c6b7834ef0 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 11 May 2012 18:12:48 -0500 Subject: [PATCH 23/27] make the locale stuff a precondition for make extension --- make.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/make.js b/make.js index 90ccfb347..88f7c69a0 100755 --- a/make.js +++ b/make.js @@ -250,6 +250,7 @@ target.extension = function() { echo(); echo('### Building extensions'); + target.locale(); target.production(); target.firefox(); target.chrome(); @@ -302,6 +303,7 @@ target.firefox = function() { FIREFOX_EXTENSION_NAME = 'pdf.js.xpi', FIREFOX_AMO_EXTENSION_NAME = 'pdf.js.amo.xpi'; + target.locale(); target.production(); target.buildnumber(); cd(ROOT_DIR); From 4583221f1c292f2af8cd61958606277712e7b898 Mon Sep 17 00:00:00 2001 From: Jakob Miland Date: Sat, 12 May 2012 15:00:43 +0200 Subject: [PATCH 24/27] Merge branch 'master', remote-tracking branch 'origin/master' From bf64240dc315ed4974769995716e93592f5010eb Mon Sep 17 00:00:00 2001 From: Jakob Miland Date: Sat, 12 May 2012 15:16:53 +0200 Subject: [PATCH 25/27] SeaMonkey support without SMILE --- .../firefox/components/PdfStreamConverter.js | 23 ++++++++++++++----- extensions/firefox/install.rdf | 11 +++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/extensions/firefox/components/PdfStreamConverter.js b/extensions/firefox/components/PdfStreamConverter.js index 49fd134ae..39376a791 100644 --- a/extensions/firefox/components/PdfStreamConverter.js +++ b/extensions/firefox/components/PdfStreamConverter.js @@ -13,14 +13,25 @@ const PDFJS_EVENT_ID = 'pdf.js.message'; const PDF_CONTENT_TYPE = 'application/pdf'; const EXT_PREFIX = 'extensions.uriloader@pdf.js'; const MAX_DATABASE_LENGTH = 4096; +const FIREFOX_ID = '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}'; +const SEAMONKEY_ID = '{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}'; Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import('resource://gre/modules/Services.jsm'); Cu.import('resource://gre/modules/NetUtil.jsm'); -let privateBrowsing = Cc['@mozilla.org/privatebrowsing;1'] - .getService(Ci.nsIPrivateBrowsingService); -let inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled; +let appInfo = Cc['@mozilla.org/xre/app-info;1'] + .getService(Ci.nsIXULAppInfo); +let privateBrowsing, inPrivateBrowsing; + +if (appInfo.ID === FIREFOX_ID) { + privateBrowsing = Cc['@mozilla.org/privatebrowsing;1'] + .getService(Ci.nsIPrivateBrowsingService); + inPrivateBrowsing = privateBrowsing.privateBrowsingEnabled; +} else if (appInfo.ID === SEAMONKEY_ID) { + privateBrowsing = null; + inPrivateBrowsing = false; +} function getBoolPref(pref, def) { try { @@ -61,8 +72,8 @@ function getDOMWindow(aChannel) { // All the priviledged actions. function ChromeActions() { - this.inPrivateBrowswing = privateBrowsing.privateBrowsingEnabled; } + ChromeActions.prototype = { download: function(data) { let mimeService = Cc['@mozilla.org/mime;1'].getService(Ci.nsIMIMEService); @@ -98,7 +109,7 @@ ChromeActions.prototype = { channel.asyncOpen(listener, null); }, setDatabase: function(data) { - if (this.inPrivateBrowswing) + if (inPrivateBrowsing) return; // Protect against something sending tons of data to setDatabase. if (data.length > MAX_DATABASE_LENGTH) @@ -106,7 +117,7 @@ ChromeActions.prototype = { setStringPref(EXT_PREFIX + '.database', data); }, getDatabase: function() { - if (this.inPrivateBrowswing) + if (inPrivateBrowsing) return '{}'; return getStringPref(EXT_PREFIX + '.database', '{}'); }, diff --git a/extensions/firefox/install.rdf b/extensions/firefox/install.rdf index d7eea9319..a8177834e 100644 --- a/extensions/firefox/install.rdf +++ b/extensions/firefox/install.rdf @@ -8,6 +8,8 @@ PDF Viewer PDFJSSCRIPT_VERSION + + {ec8030f7-c20a-464f-9b0e-13a3a9e97384} @@ -15,6 +17,15 @@ 14.0a1 + + + + + {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} + 2.1.* + 2.9.* + + true Mozilla Uses HTML5 to display PDF files directly in Firefox. From 7b5c69cac5aee49df014bd9e93aa559f8aed0e38 Mon Sep 17 00:00:00 2001 From: Jakob Miland Date: Sat, 12 May 2012 19:42:27 +0200 Subject: [PATCH 26/27] Updated Firefox and SeaMonkey's maxVersion --- extensions/firefox/install.rdf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/firefox/install.rdf b/extensions/firefox/install.rdf index a8177834e..a5094c19a 100644 --- a/extensions/firefox/install.rdf +++ b/extensions/firefox/install.rdf @@ -14,7 +14,7 @@ {ec8030f7-c20a-464f-9b0e-13a3a9e97384} 6.0 - 14.0a1 + 15.0a1 @@ -23,7 +23,7 @@ {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} 2.1.* - 2.9.* + 2.12a1 true From 910ba0b91fa13e543916386ff72b33413640d502 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Sat, 12 May 2012 21:34:32 -0500 Subject: [PATCH 27/27] Fixes user and owner passwords logic --- src/crypto.js | 84 ++++++++++++++++++++++++++++++++-------- test/unit/crypto_spec.js | 63 ++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 17 deletions(-) diff --git a/src/crypto.js b/src/crypto.js index 038c0e332..dcd820554 100644 --- a/src/crypto.js +++ b/src/crypto.js @@ -419,13 +419,14 @@ var CipherTransform = (function CipherTransformClosure() { })(); var CipherTransformFactory = (function CipherTransformFactoryClosure() { + var defaultPasswordBytes = new Uint8Array([ + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, + 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, + 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]); + function prepareKeyData(fileId, password, ownerPassword, userPassword, flags, revision, keyLength, encryptMetadata) { - var defaultPasswordBytes = new Uint8Array([ - 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, - 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, - 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, - 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A]); var hashData = new Uint8Array(100), i = 0, j, n; if (password) { n = Math.min(32, password.length); @@ -462,9 +463,8 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { var cipher, checkData; if (revision >= 3) { - // padded password in hashData, we can use this array for user - // password check - i = 32; + for (i = 0; i < 32; ++i) + hashData[i] = defaultPasswordBytes[i]; for (j = 0, n = fileId.length; j < n; ++j) hashData[i++] = fileId[j]; cipher = new ARCFourCipher(encryptionKey); @@ -477,16 +477,53 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { cipher = new ARCFourCipher(derivedKey); checkData = cipher.encryptBlock(checkData); } + for (j = 0, n = checkData.length; j < n; ++j) { + if (userPassword[j] != checkData[j]) + return null; + } } else { cipher = new ARCFourCipher(encryptionKey); - checkData = cipher.encryptBlock(hashData.subarray(0, 32)); - } - for (j = 0, n = checkData.length; j < n; ++j) { - if (userPassword[j] != checkData[j]) - error('incorrect password'); + checkData = cipher.encryptBlock(defaultPasswordBytes); + for (j = 0, n = checkData.length; j < n; ++j) { + if (userPassword[j] != checkData[j]) + return null; + } } return encryptionKey; } + function decodeUserPassword(password, ownerPassword, revision, keyLength) { + var hashData = new Uint8Array(32), i = 0, j, n; + n = Math.min(32, password.length); + for (; i < n; ++i) + hashData[i] = password[i]; + j = 0; + while (i < 32) { + hashData[i++] = defaultPasswordBytes[j++]; + } + var hash = calculateMD5(hashData, 0, i); + var keyLengthInBytes = keyLength >> 3; + if (revision >= 3) { + for (j = 0; j < 50; ++j) { + hash = calculateMD5(hash, 0, hash.length); + } + } + + var cipher, userPassword; + if (revision >= 3) { + userPassword = ownerPassword; + var derivedKey = new Uint8Array(keyLengthInBytes), k; + for (j = 19; j >= 0; j--) { + for (k = 0; k < keyLengthInBytes; ++k) + derivedKey[k] = hash[k] ^ j; + cipher = new ARCFourCipher(derivedKey); + userPassword = cipher.encryptBlock(userPassword); + } + } else { + cipher = new ARCFourCipher(hash.subarray(0, keyLengthInBytes)); + userPassword = cipher.encryptBlock(ownerPassword); + } + return userPassword; + } var identityName = new Name('Identity'); @@ -516,10 +553,23 @@ var CipherTransformFactory = (function CipherTransformFactoryClosure() { if (password) passwordBytes = stringToBytes(password); - this.encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, - ownerPassword, userPassword, - flags, revision, - keyLength, encryptMetadata); + var encryptionKey = prepareKeyData(fileIdBytes, passwordBytes, + ownerPassword, userPassword, flags, + revision, keyLength, encryptMetadata); + if (!encryptionKey && password) { + // Attempting use the password as an owner password + var decodedPassword = decodeUserPassword(passwordBytes, ownerPassword, + revision, keyLength); + encryptionKey = prepareKeyData(fileIdBytes, decodedPassword, + ownerPassword, userPassword, flags, + revision, keyLength, encryptMetadata); + } + + if (!encryptionKey) + error('incorrect password or encryption data'); + + this.encryptionKey = encryptionKey; + if (algorithm == 4) { this.cf = dict.get('CF'); this.stmf = dict.get('StmF') || identityName; diff --git a/test/unit/crypto_spec.js b/test/unit/crypto_spec.js index 0b82b5ccb..28dc4c872 100644 --- a/test/unit/crypto_spec.js +++ b/test/unit/crypto_spec.js @@ -185,3 +185,66 @@ describe('crypto', function() { }); }); +describe('CipherTransformFactory', function() { + function DictMock(map) { + this.map = map; + } + DictMock.prototype = { + get: function(key) { + return this.map[key]; + } + }; + + var map1 = { + Filter: new Name('Standard'), + V: 2, + Length: 128, + O: unescape('%80%C3%04%96%91o%20sl%3A%E6%1B%13T%91%F2%0DV%12%E3%FF%5E%BB%' + + 'E9VO%D8k%9A%CA%7C%5D'), + U: unescape('j%0C%8D%3EY%19%00%BCjd%7D%91%BD%AA%00%18%00%00%00%00%00%00%0' + + '0%00%00%00%00%00%00%00%00%00'), + P: -1028, + R: 3 + }; + var fileID1 = unescape('%F6%C6%AF%17%F3rR%8DRM%9A%80%D1%EF%DF%18'); + + var map2 = { + Filter: new Name('Standard'), + V: 4, + Length: 128, + O: unescape('sF%14v.y5%27%DB%97%0A5%22%B3%E1%D4%AD%BD%9B%3C%B4%A5%89u%15%' + + 'B2Y%F1h%D9%E9%F4'), + U: unescape('%93%04%89%A9%BF%8AE%A6%88%A2%DB%C2%A0%A8gn%00%00%00%00%00%00' + + '%00%00%00%00%00%00%00%00%00%00'), + P: -1084, + R: 4 + }; + var fileID2 = unescape('%3CL_%3AD%96%AF@%9A%9D%B3%3Cx%1Cv%AC'); + + describe('#ctor', function() { + it('should accept user password', function() { + var factory = new CipherTransformFactory(new DictMock(map1), fileID1, + '123456'); + }); + + it('should accept owner password', function() { + var factory = new CipherTransformFactory(new DictMock(map1), fileID1, + '654321'); + }); + + it('should not accept wrong password', function() { + var thrown = false; + try { + var factory = new CipherTransformFactory(new DictMock(map1), fileID1, + 'wrong'); + } catch (e) { + thrown = true; + } + expect(thrown).toEqual(true); + }); + + it('should accept no password', function() { + var factory = new CipherTransformFactory(new DictMock(map2), fileID2); + }); + }); +});