From 20dd225e40ecbf4e28257df00581a7ce45f467d9 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Sat, 24 Mar 2012 19:59:51 +0100 Subject: [PATCH 01/15] Metadata parsing/serialization --- Makefile | 1 + make.js | 3 +- src/metadata.js | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ src/obj.js | 21 +++++++++++++ web/viewer.html | 1 + web/viewer.js | 8 +++++ 6 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/metadata.js diff --git a/Makefile b/Makefile index 62565670a..3cc423350 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,7 @@ PDF_JS_FILES = \ ../external/jpgjs/jpg.js \ jpx.js \ bidi.js \ + metadata.js \ $(NULL) # make server diff --git a/make.js b/make.js index 33771aeb7..69732667f 100755 --- a/make.js +++ b/make.js @@ -97,7 +97,8 @@ target.bundle = function() { 'worker.js', '../external/jpgjs/jpg.js', 'jpx.js', - 'bidi.js']; + 'bidi.js', + 'metadata-js']; if (!exists(BUILD_DIR)) mkdir(BUILD_DIR); diff --git a/src/metadata.js b/src/metadata.js new file mode 100644 index 000000000..68b19764b --- /dev/null +++ b/src/metadata.js @@ -0,0 +1,80 @@ +var Metadata = (function MetadataClosure() { + function Metadata(meta) { + if (typeof meta === 'string') { + var parser = new DOMParser(); + meta = parser.parseFromString(meta, 'application/xml'); + } else if (!(meta instanceof Document)) { + error('Metadata: Invalid metadata object'); + } + + this.metaDocument = meta; + this.metadata = {}; + this.parse(); + } + + Metadata.prototype = { + parse: function() { + var doc = this.metaDocument; + var rdf = doc.documentElement; + if (rdf.tagName.toLowerCase() !== 'rdf:rdf') { // Wrapped in + rdf = rdf.firstChild; + while (rdf.nodeName && rdf.nodeName.toLowerCase() !== 'rdf:rdf') { + rdf = rdf.nextSibling; + } + } + if (rdf.nodeName.toLowerCase() !== 'rdf:rdf' || !rdf.hasChildNodes()) { + return; + } + + var childNodes = rdf.childNodes, desc, namespace, entries, entry; + + for (var i = 0, length = childNodes.length; i < length; i++) { + desc = childNodes[i]; + if (desc.nodeName.toLowerCase() !== 'rdf:description') { + continue; + } + + entries = []; + for (var ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) { + if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') { + entries.push(desc.childNodes[ii]); + } + } + + for (ii = 0, iLength = entries.length; ii < iLength; ii++) { + var entry = entries[ii]; + var name = entry.nodeName.toLowerCase(); + var entryName = name.split(':'); + entryName = (entryName.length > 1) ? entryName[1] : entryName[0]; + switch (name) { + case 'pdf:moddate': + case 'xap:createdate': + case 'xap:metadatadate': + case 'xap:modifydate': + this.metadata[entryName] = new Date(entry.textContent.trim()); + break; + + default: + // For almost all entries we just add them to the metadata object + if (this.metadata[entryName]) { + this.metadata[name] = entry.textContent.trim(); + } else { + this.metadata[entryName] = entry.textContent.trim(); + } + break; + } + } + } + }, + + get: function(name) { + return this.metadata[name] || null; + }, + + has: function(name) { + return typeof this.metadata[name] !== 'undefined'; + } + }; + + return Metadata; +})(); diff --git a/src/obj.js b/src/obj.js index 3c649fb06..144a3a377 100644 --- a/src/obj.js +++ b/src/obj.js @@ -111,6 +111,27 @@ var Catalog = (function CatalogClosure() { } Catalog.prototype = { + get metadata() { + var ref = this.catDict.get('Metadata'); + if (!ref) { + return null; + } + + var stream = this.xref.fetch(ref); + var dict = stream.dict; + if (isDict(dict)) { + var type = dict.get('Type'); + var subtype = dict.get('Subtype'); + + if(isName(type) && isName(subtype) && + type.name === 'Metadata' && subtype.name === 'XML') { + var metadata = stringToPDFString(bytesToString(stream.getbytes())); + return metadata; + } + } + + return null; + }, get toplevelPagesDict() { var pagesObj = this.catDict.get('Pages'); assertWellFormed(isRef(pagesObj), 'invalid top-level pages reference'); diff --git a/web/viewer.html b/web/viewer.html index 34b2e77cb..2806d3a7e 100644 --- a/web/viewer.html +++ b/web/viewer.html @@ -11,6 +11,7 @@ + diff --git a/web/viewer.js b/web/viewer.js index 67ef67e97..68577ad34 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -499,6 +499,14 @@ var PDFView = { // Setting the default one. this.parseScale(kDefaultScale, true); } + + var metadata = pdf.catalog.metadata; + if (metadata) { + this.metadata = metadata = new Metadata(metadata); + if (metadata.has('title')) { + document.title = metadata.get('title'); + } + } }, setHash: function pdfViewSetHash(hash) { From 9dbcc74d41d8319701d62e42f42bcd35acbee863 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Sat, 24 Mar 2012 20:02:20 +0100 Subject: [PATCH 02/15] lint.. --- src/obj.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/obj.js b/src/obj.js index 144a3a377..d4187b4fa 100644 --- a/src/obj.js +++ b/src/obj.js @@ -123,7 +123,7 @@ var Catalog = (function CatalogClosure() { var type = dict.get('Type'); var subtype = dict.get('Subtype'); - if(isName(type) && isName(subtype) && + if (isName(type) && isName(subtype) && type.name === 'Metadata' && subtype.name === 'XML') { var metadata = stringToPDFString(bytesToString(stream.getbytes())); return metadata; From ab198e89cc17029de066cda769afffe6709d7ed5 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Sat, 24 Mar 2012 23:39:03 +0100 Subject: [PATCH 03/15] Typo from git'ing around --- src/obj.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/obj.js b/src/obj.js index d4187b4fa..21f20c3fb 100644 --- a/src/obj.js +++ b/src/obj.js @@ -125,7 +125,7 @@ var Catalog = (function CatalogClosure() { if (isName(type) && isName(subtype) && type.name === 'Metadata' && subtype.name === 'XML') { - var metadata = stringToPDFString(bytesToString(stream.getbytes())); + var metadata = stringToPDFString(bytesToString(stream.getBytes())); return metadata; } } From edc169462062ed5fedb70f56263f57f057d57683 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 26 Mar 2012 23:48:04 +0200 Subject: [PATCH 04/15] Now also fetch 'Document Info Dictionary', and expose 'raw' metadata attributes --- src/core.js | 22 +++++++++++++++------- src/metadata.js | 20 +------------------- web/viewer.js | 15 +++++++++++++-- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/core.js b/src/core.js index ecc2c94a5..890563f4e 100644 --- a/src/core.js +++ b/src/core.js @@ -587,13 +587,15 @@ var PDFDocModel = (function PDFDocModelClosure() { this.mainXRefEntriesOffset); this.xref = xref; this.catalog = new Catalog(xref); - if (xref.trailer && xref.trailer.has('ID')) { - var fileID = ''; - var id = xref.fetchIfRef(xref.trailer.get('ID'))[0]; - id.split('').forEach(function(el) { - fileID += Number(el.charCodeAt(0)).toString(16); - }); - this.fileID = fileID; + if (xref.trailer) { + if (xref.trailer.has('ID')) { + var fileID = ''; + var id = xref.fetchIfRef(xref.trailer.get('ID'))[0]; + id.split('').forEach(function(el) { + fileID += Number(el.charCodeAt(0)).toString(16); + }); + this.fileID = fileID; + } } }, get numPages() { @@ -602,6 +604,11 @@ var PDFDocModel = (function PDFDocModelClosure() { // shadow the prototype getter return shadow(this, 'numPages', num); }, + getDocumentInfo: function pdfDocGetDocumentInfo() { + if (this.xref.trailer.has('Info')) { + return this.xref.fetch(this.xref.trailer.get('Info')); + } + }, getFingerprint: function pdfDocGetFingerprint() { if (this.fileID) { return this.fileID; @@ -645,6 +652,7 @@ var PDFDoc = (function PDFDocClosure() { this.stream = stream; this.pdfModel = new PDFDocModel(stream); this.fingerprint = this.pdfModel.getFingerprint(); + this.info = this.pdfModel.getDocumentInfo(); this.catalog = this.pdfModel.catalog; this.objs = new PDFObjects(); diff --git a/src/metadata.js b/src/metadata.js index 68b19764b..a46077f56 100644 --- a/src/metadata.js +++ b/src/metadata.js @@ -44,25 +44,7 @@ var Metadata = (function MetadataClosure() { for (ii = 0, iLength = entries.length; ii < iLength; ii++) { var entry = entries[ii]; var name = entry.nodeName.toLowerCase(); - var entryName = name.split(':'); - entryName = (entryName.length > 1) ? entryName[1] : entryName[0]; - switch (name) { - case 'pdf:moddate': - case 'xap:createdate': - case 'xap:metadatadate': - case 'xap:modifydate': - this.metadata[entryName] = new Date(entry.textContent.trim()); - break; - - default: - // For almost all entries we just add them to the metadata object - if (this.metadata[entryName]) { - this.metadata[name] = entry.textContent.trim(); - } else { - this.metadata[entryName] = entry.textContent.trim(); - } - break; - } + this.metadata[name] = entry.textContent.trim(); } } }, diff --git a/web/viewer.js b/web/viewer.js index 68577ad34..838de20d3 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -501,12 +501,23 @@ var PDFView = { } var metadata = pdf.catalog.metadata; + var info = pdf.info; + var pdfTitle; + if (metadata) { this.metadata = metadata = new Metadata(metadata); - if (metadata.has('title')) { - document.title = metadata.get('title'); + if (metadata.has('dc:title')) { + pdfTitle = metadata.get('dc:title'); } } + + if (info && info.has('Title') && !pdfTitle) { + pdfTitle = info.get('Title'); + } + + if (pdfTitle) { + document.title = pdfTitle; + } }, setHash: function pdfViewSetHash(hash) { From 878854f7cfc4809aa35303453c4b51b54eb894af Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Mon, 26 Mar 2012 23:53:51 +0200 Subject: [PATCH 05/15] wrong filename in make.js --- make.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make.js b/make.js index 69732667f..19dea7b82 100755 --- a/make.js +++ b/make.js @@ -98,7 +98,7 @@ target.bundle = function() { '../external/jpgjs/jpg.js', 'jpx.js', 'bidi.js', - 'metadata-js']; + 'metadata.js']; if (!exists(BUILD_DIR)) mkdir(BUILD_DIR); From 94a155884397bc7d7b4e5fb6ad1271fb1bef36f3 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Tue, 27 Mar 2012 00:05:14 +0200 Subject: [PATCH 06/15] refactor and shadow --- src/obj.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/obj.js b/src/obj.js index 21f20c3fb..2eb9c6f1d 100644 --- a/src/obj.js +++ b/src/obj.js @@ -113,24 +113,19 @@ var Catalog = (function CatalogClosure() { Catalog.prototype = { get metadata() { var ref = this.catDict.get('Metadata'); - if (!ref) { - return null; - } - - var stream = this.xref.fetch(ref); - var dict = stream.dict; - if (isDict(dict)) { - var type = dict.get('Type'); - var subtype = dict.get('Subtype'); + var stream = this.xref.fetchIfRef(ref); + var metadata; + if (stream && isDict(stream.dict)) { + var type = stream.dict.get('Type'); + var subtype = stream.dict.get('Subtype'); if (isName(type) && isName(subtype) && type.name === 'Metadata' && subtype.name === 'XML') { - var metadata = stringToPDFString(bytesToString(stream.getBytes())); - return metadata; + metadata = stringToPDFString(bytesToString(stream.getBytes())); } } - return null; + return shadow(this, 'metadata', metadata); }, get toplevelPagesDict() { var pagesObj = this.catDict.get('Pages'); From 4703a6cfcd4d989cc5faff3165b44df5f927c645 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Tue, 27 Mar 2012 00:14:59 +0200 Subject: [PATCH 07/15] refactor getFingerprint --- src/core.js | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/core.js b/src/core.js index 890563f4e..dffdbd44e 100644 --- a/src/core.js +++ b/src/core.js @@ -587,16 +587,6 @@ var PDFDocModel = (function PDFDocModelClosure() { this.mainXRefEntriesOffset); this.xref = xref; this.catalog = new Catalog(xref); - if (xref.trailer) { - if (xref.trailer.has('ID')) { - var fileID = ''; - var id = xref.fetchIfRef(xref.trailer.get('ID'))[0]; - id.split('').forEach(function(el) { - fileID += Number(el.charCodeAt(0)).toString(16); - }); - this.fileID = fileID; - } - } }, get numPages() { var linearization = this.linearization; @@ -610,20 +600,25 @@ var PDFDocModel = (function PDFDocModelClosure() { } }, getFingerprint: function pdfDocGetFingerprint() { - if (this.fileID) { - return this.fileID; + var xref = this.xref, fileID; + if (xref.trailer.has('ID')) { + fileID = ''; + var id = xref.fetchIfRef(xref.trailer.get('ID'))[0]; + id.split('').forEach(function(el) { + fileID += Number(el.charCodeAt(0)).toString(16); + }); } else { // If we got no fileID, then we generate one, // from the first 100 bytes of PDF var data = this.stream.bytes.subarray(0, 100); var hash = calculateMD5(data, 0, data.length); - var strHash = ''; + fileID = ''; for (var i = 0, length = hash.length; i < length; i++) { - strHash += Number(hash[i]).toString(16); + fileID += Number(hash[i]).toString(16); } - - return strHash; } + + return shadow(this, 'getFingerprint', fileID); }, getPage: function pdfDocGetPage(n) { return this.catalog.getPage(n); From e283a60d7b51b11a2dd018983d2fd80eca7f871c Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Tue, 27 Mar 2012 00:16:16 +0200 Subject: [PATCH 08/15] return and shadow for getDocumentInfo --- src/core.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core.js b/src/core.js index dffdbd44e..3e10e6586 100644 --- a/src/core.js +++ b/src/core.js @@ -595,9 +595,12 @@ var PDFDocModel = (function PDFDocModelClosure() { return shadow(this, 'numPages', num); }, getDocumentInfo: function pdfDocGetDocumentInfo() { + var info; if (this.xref.trailer.has('Info')) { - return this.xref.fetch(this.xref.trailer.get('Info')); + info = this.xref.fetch(this.xref.trailer.get('Info')); } + + return shadow(this, 'getDocumentInfo', info); }, getFingerprint: function pdfDocGetFingerprint() { var xref = this.xref, fileID; From 2bb5a9e5450f7f6af32c00667587b0987494d43c Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Tue, 27 Mar 2012 00:17:57 +0200 Subject: [PATCH 09/15] moving \!pdfTitle to front --- web/viewer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/viewer.js b/web/viewer.js index 838de20d3..cf30d2978 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -511,7 +511,7 @@ var PDFView = { } } - if (info && info.has('Title') && !pdfTitle) { + if (!pdfTitle && info && info.has('Title')) { pdfTitle = info.get('Title'); } From e6277784f1b452d7018a28abe5824b0ec8a2bb8e Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Tue, 27 Mar 2012 22:32:35 +0200 Subject: [PATCH 10/15] fix to follow syntax style guidelines --- src/core.js | 3 +-- web/viewer.js | 10 ++++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/core.js b/src/core.js index 3e10e6586..7c996fc4a 100644 --- a/src/core.js +++ b/src/core.js @@ -596,9 +596,8 @@ var PDFDocModel = (function PDFDocModelClosure() { }, getDocumentInfo: function pdfDocGetDocumentInfo() { var info; - if (this.xref.trailer.has('Info')) { + if (this.xref.trailer.has('Info')) info = this.xref.fetch(this.xref.trailer.get('Info')); - } return shadow(this, 'getDocumentInfo', info); }, diff --git a/web/viewer.js b/web/viewer.js index cf30d2978..af34f6192 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -506,18 +506,16 @@ var PDFView = { if (metadata) { this.metadata = metadata = new Metadata(metadata); - if (metadata.has('dc:title')) { + + if (metadata.has('dc:title')) pdfTitle = metadata.get('dc:title'); - } } - if (!pdfTitle && info && info.has('Title')) { + if (!pdfTitle && info && info.has('Title')) pdfTitle = info.get('Title'); - } - if (pdfTitle) { + if (pdfTitle) document.title = pdfTitle; - } }, setHash: function pdfViewSetHash(hash) { From 89c1873fd8d4b89a4d7cfd054b3f8c3f4f7374dc Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Tue, 27 Mar 2012 22:37:02 +0200 Subject: [PATCH 11/15] more one-line fixes --- src/metadata.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/metadata.js b/src/metadata.js index a46077f56..ba87f7b84 100644 --- a/src/metadata.js +++ b/src/metadata.js @@ -18,27 +18,24 @@ var Metadata = (function MetadataClosure() { var rdf = doc.documentElement; if (rdf.tagName.toLowerCase() !== 'rdf:rdf') { // Wrapped in rdf = rdf.firstChild; - while (rdf.nodeName && rdf.nodeName.toLowerCase() !== 'rdf:rdf') { + while (rdf.nodeName && rdf.nodeName.toLowerCase() !== 'rdf:rdf') rdf = rdf.nextSibling; - } } - if (rdf.nodeName.toLowerCase() !== 'rdf:rdf' || !rdf.hasChildNodes()) { + + if (rdf.nodeName.toLowerCase() !== 'rdf:rdf' || !rdf.hasChildNodes()) return; - } var childNodes = rdf.childNodes, desc, namespace, entries, entry; for (var i = 0, length = childNodes.length; i < length; i++) { desc = childNodes[i]; - if (desc.nodeName.toLowerCase() !== 'rdf:description') { + if (desc.nodeName.toLowerCase() !== 'rdf:description') continue; - } entries = []; for (var ii = 0, iLength = desc.childNodes.length; ii < iLength; ii++) { - if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') { + if (desc.childNodes[ii].nodeName.toLowerCase() !== '#text') entries.push(desc.childNodes[ii]); - } } for (ii = 0, iLength = entries.length; ii < iLength; ii++) { From 1181ef2778d995f39a5b36497d83875ca0735821 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Wed, 28 Mar 2012 19:15:59 +0200 Subject: [PATCH 12/15] Fix throwing errors --- src/metadata.js | 8 +++++--- web/viewer.js | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/metadata.js b/src/metadata.js index ba87f7b84..56ac792ca 100644 --- a/src/metadata.js +++ b/src/metadata.js @@ -16,13 +16,15 @@ var Metadata = (function MetadataClosure() { parse: function() { var doc = this.metaDocument; var rdf = doc.documentElement; - if (rdf.tagName.toLowerCase() !== 'rdf:rdf') { // Wrapped in + + if (rdf.nodeName.toLowerCase() !== 'rdf:rdf') { // Wrapped in rdf = rdf.firstChild; - while (rdf.nodeName && rdf.nodeName.toLowerCase() !== 'rdf:rdf') + while (rdf && rdf.nodeName.toLowerCase() !== 'rdf:rdf') rdf = rdf.nextSibling; } - if (rdf.nodeName.toLowerCase() !== 'rdf:rdf' || !rdf.hasChildNodes()) + var nodeName = (rdf) ? rdf.nodeName.toLowerCase() : null; + if (!rdf || nodeName !== 'rdf:rdf' || !rdf.hasChildNodes()) return; var childNodes = rdf.childNodes, desc, namespace, entries, entry; diff --git a/web/viewer.js b/web/viewer.js index af34f6192..df3bf8e10 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -500,6 +500,7 @@ var PDFView = { this.parseScale(kDefaultScale, true); } + this.metadata = null; var metadata = pdf.catalog.metadata; var info = pdf.info; var pdfTitle; From 102469d20cd4a62f3f2a4b69cecccc657e2e6836 Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Wed, 28 Mar 2012 19:29:05 +0200 Subject: [PATCH 13/15] expose documentInfo in viewer --- web/viewer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/viewer.js b/web/viewer.js index df3bf8e10..c477ddb4f 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -502,7 +502,7 @@ var PDFView = { this.metadata = null; var metadata = pdf.catalog.metadata; - var info = pdf.info; + var info = this.documentInfo = pdf.info; var pdfTitle; if (metadata) { From 10fb0dc3833c9c48878dca712ed112479bea1afd Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Wed, 28 Mar 2012 20:07:37 +0200 Subject: [PATCH 14/15] Use strict and expose in build version --- src/metadata.js | 4 +++- web/viewer.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/metadata.js b/src/metadata.js index 56ac792ca..48bc902a9 100644 --- a/src/metadata.js +++ b/src/metadata.js @@ -1,4 +1,6 @@ -var Metadata = (function MetadataClosure() { +'use strict'; + +var Metadata = PDFJS.Metadata = (function MetadataClosure() { function Metadata(meta) { if (typeof meta === 'string') { var parser = new DOMParser(); diff --git a/web/viewer.js b/web/viewer.js index c477ddb4f..d3f0a329b 100644 --- a/web/viewer.js +++ b/web/viewer.js @@ -506,7 +506,7 @@ var PDFView = { var pdfTitle; if (metadata) { - this.metadata = metadata = new Metadata(metadata); + this.metadata = metadata = new PDFJS.Metadata(metadata); if (metadata.has('dc:title')) pdfTitle = metadata.get('dc:title'); From e9b52056125de88cb1670b3defa71ade92558f1c Mon Sep 17 00:00:00 2001 From: Saebekassebil Date: Wed, 28 Mar 2012 20:09:03 +0200 Subject: [PATCH 15/15] File header --- src/metadata.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/metadata.js b/src/metadata.js index 48bc902a9..7f3f24a86 100644 --- a/src/metadata.js +++ b/src/metadata.js @@ -1,3 +1,6 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ + 'use strict'; var Metadata = PDFJS.Metadata = (function MetadataClosure() {