Support unmodified Xpdf binaries
Use stdout redirection scripts for pdfinfo and, on Windows, a script to run pdftotext hidden, which together allow for all unmodified binaries (including, probably, symlinked system ones, though I didn't test that). On Windows, using a .vbs does cause a brief wait cursor. The stock pdfinfo needs the redirection script anyway, so that's unavoidable, but on the async branch I think we'll be able to switch to pdf.js for the page count, at which point maybe I'll try to remember how I modified the Windows binaries to be hidden and use a modified version of pdftotext to avoid VBScript. (We use the stock pdftotext elsewhere already.)
This commit is contained in:
parent
aa7c1b6fd6
commit
a9ca6e0857
6 changed files with 267 additions and 133 deletions
|
@ -162,46 +162,40 @@ Zotero_Preferences.Search = {
|
|||
* if a newer version is available
|
||||
*/
|
||||
checkPDFToolsDownloadVersion: function () {
|
||||
var url = Zotero.Fulltext.pdfToolsDownloadBaseURL
|
||||
+ Zotero.platform.replace(' ', '-') + '.latest';
|
||||
var url = Zotero.Fulltext.pdfToolsDownloadBaseURL + 'latest.json';
|
||||
|
||||
// Find latest version for this platform
|
||||
var self = this;
|
||||
var sent = Zotero.HTTP.doGet(url, function (xmlhttp) {
|
||||
try {
|
||||
if (xmlhttp.status == 200) {
|
||||
if (xmlhttp.status != 200) {
|
||||
throw new Error("Unexpected response code " + xmlhttp.status);
|
||||
}
|
||||
|
||||
var platform = Zotero.platform.replace(/\s/g, '-');
|
||||
var json = JSON.parse(xmlhttp.responseText);
|
||||
var latestVersion = json[platform] || json['default'];
|
||||
|
||||
Zotero.debug("Latest PDF tools version for " + platform + " is " + latestVersion);
|
||||
|
||||
var converterIsRegistered = Zotero.Fulltext.pdfConverterIsRegistered();
|
||||
var infoIsRegistered = Zotero.Fulltext.pdfInfoIsRegistered();
|
||||
var bothRegistered = converterIsRegistered && infoIsRegistered;
|
||||
|
||||
var converterVersion = xmlhttp.responseText.split(/\s/)[0];
|
||||
var infoVersion = xmlhttp.responseText.split(/\s/)[1];
|
||||
|
||||
// Install if not installed, version unknown, Xpdf 3.02 (to upgrade to Poppler),
|
||||
// or outdated
|
||||
var converterVersionAvailable = converterVersion &&
|
||||
(!converterIsRegistered ||
|
||||
// Install if not installed, version unknown, outdated, or
|
||||
// Xpdf 3.02/3.04 (to upgrade to Poppler),
|
||||
var converterVersionAvailable = (!converterIsRegistered ||
|
||||
Zotero.Fulltext.pdfConverterVersion == 'UNKNOWN'
|
||||
|| (converterVersion != '3.02' && Zotero.Fulltext.pdfConverterVersion == '3.02')
|
||||
|| converterVersion > Zotero.Fulltext.pdfConverterVersion);
|
||||
var infoVersionAvailable = infoVersion &&
|
||||
(!infoIsRegistered ||
|
||||
|| latestVersion > Zotero.Fulltext.pdfConverterVersion
|
||||
|| (latestVersion != '3.02' && Zotero.Fulltext.pdfConverterVersion == '3.02')
|
||||
|| (latestVersion != '3.02' && latestVersion != '3.04' && Zotero.Fulltext.pdfConverterVersion == '3.04'));
|
||||
var infoVersionAvailable = (!infoIsRegistered ||
|
||||
Zotero.Fulltext.pdfInfoVersion == 'UNKNOWN'
|
||||
|| (infoVersion != '3.02' && Zotero.Fulltext.pdfInfoVersion == '3.02')
|
||||
|| infoVersion > Zotero.Fulltext.pdfInfoVersion);
|
||||
|| latestVersion > Zotero.Fulltext.pdfInfoVersion
|
||||
|| (latestVersion != '3.02' && Zotero.Fulltext.pdfInfoVersion == '3.02')
|
||||
|| (latestVersion != '3.02' && latestVersion != '3.04' && Zotero.Fulltext.pdfInfoVersion == '3.04'));
|
||||
var bothAvailable = converterVersionAvailable && infoVersionAvailable;
|
||||
|
||||
/*
|
||||
Zotero.debug(converterIsRegistered);
|
||||
Zotero.debug(infoIsRegistered);
|
||||
Zotero.debug(converterVersion);
|
||||
Zotero.debug(infoVersion);
|
||||
Zotero.debug(Zotero.Fulltext.pdfConverterVersion);
|
||||
Zotero.debug(Zotero.Fulltext.pdfInfoVersion);
|
||||
Zotero.debug(converterVersionAvailable);
|
||||
Zotero.debug(infoVersionAvailable);
|
||||
*/
|
||||
|
||||
// Up to date -- disable update button
|
||||
if (!converterVersionAvailable && !infoVersionAvailable) {
|
||||
var button = document.getElementById('pdftools-update-button');
|
||||
|
@ -221,12 +215,12 @@ Zotero_Preferences.Search = {
|
|||
|
||||
if (converterVersionAvailable) {
|
||||
let tvp = Zotero.getString('zotero.preferences.search.pdf.toolVersionPlatform',
|
||||
[Zotero.Fulltext.pdfConverterName, converterVersion]);
|
||||
[Zotero.Fulltext.pdfConverterName, latestVersion]);
|
||||
msg += '- ' + tvp + '\n';
|
||||
}
|
||||
if (infoVersionAvailable) {
|
||||
let tvp = Zotero.getString('zotero.preferences.search.pdf.toolVersionPlatform',
|
||||
[Zotero.Fulltext.pdfInfoName, infoVersion]);
|
||||
[Zotero.Fulltext.pdfInfoName, latestVersion]);
|
||||
msg += '- ' + tvp + '\n';
|
||||
}
|
||||
msg += '\n';
|
||||
|
@ -244,24 +238,17 @@ Zotero_Preferences.Search = {
|
|||
null, null, null, {});
|
||||
|
||||
if (index == 0) {
|
||||
var installVersions = {
|
||||
converter: converterVersionAvailable ?
|
||||
converterVersion : null,
|
||||
info: infoVersionAvailable ?
|
||||
infoVersion : null
|
||||
};
|
||||
|
||||
document.getElementById('pdftools-update-button').disabled = true;
|
||||
var str = Zotero.getString('zotero.preferences.search.pdf.downloading');
|
||||
document.getElementById('pdftools-update-button').setAttribute('label', str);
|
||||
|
||||
if (converterVersionAvailable && infoVersionAvailable) {
|
||||
Zotero.Fulltext.downloadPDFTool('converter', converterVersion, function (success) {
|
||||
Zotero.Fulltext.downloadPDFTool('converter', latestVersion, function (success) {
|
||||
if (!success) {
|
||||
self.onPDFToolsDownloadError("Error downloading pdftotext");
|
||||
return;
|
||||
}
|
||||
Zotero.Fulltext.downloadPDFTool('info', infoVersion, function (success) {
|
||||
Zotero.Fulltext.downloadPDFTool('info', latestVersion, function (success) {
|
||||
if (!success) {
|
||||
self.onPDFToolsDownloadError("Error downloading pdfinfo");
|
||||
return;
|
||||
|
@ -271,7 +258,7 @@ Zotero_Preferences.Search = {
|
|||
});
|
||||
}
|
||||
else if (converterVersionAvailable) {
|
||||
Zotero.Fulltext.downloadPDFTool('converter', converterVersion, function (success) {
|
||||
Zotero.Fulltext.downloadPDFTool('converter', latestVersion, function (success) {
|
||||
if (!success) {
|
||||
self.onPDFToolsDownloadError("Error downloading pdftotext");
|
||||
return;
|
||||
|
@ -280,7 +267,7 @@ Zotero_Preferences.Search = {
|
|||
});
|
||||
}
|
||||
else {
|
||||
Zotero.Fulltext.downloadPDFTool('info', infoVersion, function (success) {
|
||||
Zotero.Fulltext.downloadPDFTool('info', latestVersion, function (success) {
|
||||
if (!success) {
|
||||
self.onPDFToolsDownloadError("Error downloading pdfinfo");
|
||||
return;
|
||||
|
@ -291,11 +278,6 @@ Zotero_Preferences.Search = {
|
|||
}
|
||||
}
|
||||
}
|
||||
// Version not found for platform
|
||||
else if (xmlhttp.status == 404) {
|
||||
self.onPDFToolsDownloadError(404);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
self.onPDFToolsDownloadError(e);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ Zotero.Fulltext = new function(){
|
|||
//this.clearItemContent = clearItemContent;
|
||||
this.purgeUnusedWords = purgeUnusedWords;
|
||||
|
||||
this.__defineGetter__("pdfToolsDownloadBaseURL", function() { return 'http://www.zotero.org/download/xpdf/'; });
|
||||
this.__defineGetter__("pdfToolsDownloadBaseURL", function() { return 'https://www.zotero.org/download/xpdf/'; });
|
||||
this.__defineGetter__("pdfToolsName", function() { return 'Xpdf'; });
|
||||
this.__defineGetter__("pdfToolsURL", function() { return 'http://www.foolabs.com/xpdf/'; });
|
||||
this.__defineGetter__("pdfConverterName", function() { return 'pdftotext'; });
|
||||
|
@ -82,9 +82,11 @@ Zotero.Fulltext = new function(){
|
|||
|
||||
var _pdfConverterVersion = null;
|
||||
var _pdfConverterFileName = null;
|
||||
var _pdfConverterScript = null; // nsIFile of hidden window script on Windows
|
||||
var _pdfConverter = null; // nsIFile to executable
|
||||
var _pdfInfoVersion = null;
|
||||
var _pdfInfoFileName = null;
|
||||
var _pdfInfoScript = null; // nsIFile of redirection script
|
||||
var _pdfInfo = null; // nsIFile to executable
|
||||
|
||||
var _idleObserverIsRegistered = false;
|
||||
|
@ -179,7 +181,7 @@ Zotero.Fulltext = new function(){
|
|||
var fileName = this.pdfInfoFileName;
|
||||
}
|
||||
|
||||
var spec = this.pdfToolsDownloadBaseURL + fileName + '-' + version;
|
||||
var spec = this.pdfToolsDownloadBaseURL + version + "/" + fileName;
|
||||
var uri = ioService.newURI(spec, null, null);
|
||||
|
||||
var file = Zotero.getTempDirectory();
|
||||
|
@ -202,15 +204,43 @@ Zotero.Fulltext = new function(){
|
|||
|
||||
Zotero.File.putContentsAsync(file, is)
|
||||
.then(function () {
|
||||
var scriptExt = _getScriptExtension();
|
||||
// On Windows, write out script to hide pdftotext console window
|
||||
if (tool == 'converter') {
|
||||
if (Zotero.isWin) {
|
||||
var content = Zotero.File.getContentsFromURL('resource://zotero/hide.' + scriptExt);
|
||||
var scriptFile = Zotero.getTempDirectory();
|
||||
scriptFile.append('pdftotext.' + scriptExt);
|
||||
Zotero.File.putContents(scriptFile, content);
|
||||
}
|
||||
}
|
||||
// Write out output redirection script for pdfinfo
|
||||
else if (tool == 'info') {
|
||||
var content = Zotero.File.getContentsFromURL('resource://zotero/redirect.' + scriptExt);
|
||||
var scriptFile = Zotero.getTempDirectory();
|
||||
scriptFile.append('pdfinfo.' + scriptExt);
|
||||
Zotero.File.putContents(scriptFile, content);
|
||||
}
|
||||
|
||||
// Set permissions to 755
|
||||
if (Zotero.isMac) {
|
||||
file.permissions = 33261;
|
||||
if (scriptFile) {
|
||||
scriptFile.permissions = 33261;
|
||||
}
|
||||
}
|
||||
else if (Zotero.isLinux) {
|
||||
file.permissions = 493;
|
||||
if (scriptFile) {
|
||||
scriptFile.permissions = 493;
|
||||
}
|
||||
}
|
||||
|
||||
var destDir = Zotero.getZoteroDirectory()
|
||||
// Move redirect script and executable into data dir
|
||||
if (scriptFile) {
|
||||
scriptFile.moveTo(destDir, null);
|
||||
}
|
||||
file.moveTo(destDir, null);
|
||||
|
||||
// Write the version number to a file
|
||||
|
@ -223,6 +253,11 @@ Zotero.Fulltext = new function(){
|
|||
if (callback) {
|
||||
callback(true);
|
||||
}
|
||||
})
|
||||
.catch(function (e) {
|
||||
Zotero.debug(e, 1);
|
||||
Components.utils.reportError(e);
|
||||
callback(false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -274,11 +309,43 @@ Zotero.Fulltext = new function(){
|
|||
return false;
|
||||
}
|
||||
|
||||
// If scripts exist, use those instead
|
||||
switch (tool) {
|
||||
case 'converter':
|
||||
if (Zotero.isWin) {
|
||||
var script = Zotero.getZoteroDirectory();
|
||||
script.append('pdftotext.' + _getScriptExtension())
|
||||
if (script.exists()) {
|
||||
Zotero.debug(script.leafName + " registered");
|
||||
_pdfConverterScript = script;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'info':
|
||||
var script = Zotero.getZoteroDirectory();
|
||||
script.append('pdfinfo.' + _getScriptExtension())
|
||||
// The redirection script is necessary to run pdfinfo
|
||||
if (!script.exists()) {
|
||||
Zotero.debug(script.leafName + " not found -- PDF statistics disabled");
|
||||
return false;
|
||||
}
|
||||
Zotero.debug(toolName + " redirection script registered");
|
||||
_pdfInfoScript = script;
|
||||
break;
|
||||
}
|
||||
|
||||
var versionFile = exec.parent;
|
||||
versionFile.append(fileName + '.version');
|
||||
if (versionFile.exists()) {
|
||||
try {
|
||||
var version = Zotero.File.getSample(versionFile).split(/[\r\n\s]/)[0];
|
||||
}
|
||||
catch (e) {
|
||||
Zotero.debug(e, 1);
|
||||
Components.utils.reportError(e);
|
||||
}
|
||||
}
|
||||
if (!version) {
|
||||
var version = 'UNKNOWN';
|
||||
}
|
||||
|
@ -295,7 +362,7 @@ Zotero.Fulltext = new function(){
|
|||
break;
|
||||
}
|
||||
|
||||
Zotero.debug(toolName + ' version ' + version + ' registered at ' + exec.path);
|
||||
Zotero.debug(toolName + ' version ' + version + ' registered');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -529,16 +596,19 @@ Zotero.Fulltext = new function(){
|
|||
}
|
||||
cacheFile.append(this.pdfConverterCacheFile);
|
||||
|
||||
if (_pdfInfo) {
|
||||
if (_pdfInfoScript) {
|
||||
var infoFile = cacheFile.parent;
|
||||
infoFile.append(this.pdfInfoCacheFile);
|
||||
Zotero.debug('Running pdfinfo "' + file.path + '" "' + infoFile.path + '"');
|
||||
|
||||
var proc = Components.classes["@mozilla.org/process/util;1"].
|
||||
createInstance(Components.interfaces.nsIProcess);
|
||||
proc.init(_pdfInfo);
|
||||
var args = [_pdfInfo.path, file.path, infoFile.path];
|
||||
|
||||
Zotero.debug("Running " + _pdfInfoScript.path + ' '
|
||||
+ args.map(arg => "'" + arg + "'").join(' '));
|
||||
|
||||
var proc = Components.classes["@mozilla.org/process/util;1"]
|
||||
.createInstance(Components.interfaces.nsIProcess);
|
||||
proc.init(_pdfInfoScript);
|
||||
|
||||
var args = [file.path, infoFile.path];
|
||||
try {
|
||||
proc.runw(true, args, args.length);
|
||||
var totalPages = this.getTotalPagesFromFile(itemID);
|
||||
|
@ -551,15 +621,12 @@ Zotero.Fulltext = new function(){
|
|||
Zotero.debug(this.pdfInfoName + " is not available");
|
||||
}
|
||||
|
||||
Zotero.debug('Running pdftotext -enc UTF-8 -nopgbrk '
|
||||
+ (allPages ? '' : '-l ' + maxPages) + ' "' + file.path + '" "'
|
||||
+ cacheFile.path + '"');
|
||||
var args = []
|
||||
if (_pdfConverterScript) {
|
||||
args.push(_pdfConverter.path);
|
||||
}
|
||||
args.push('-enc', 'UTF-8', '-nopgbrk');
|
||||
|
||||
var proc = Components.classes["@mozilla.org/process/util;1"].
|
||||
createInstance(Components.interfaces.nsIProcess);
|
||||
proc.init(_pdfConverter);
|
||||
|
||||
var args = ['-enc', 'UTF-8', '-nopgbrk'];
|
||||
if (allPages) {
|
||||
if (totalPages) {
|
||||
var pagesIndexed = totalPages;
|
||||
|
@ -570,6 +637,20 @@ Zotero.Fulltext = new function(){
|
|||
var pagesIndexed = Math.min(maxPages, totalPages);
|
||||
}
|
||||
args.push(file.path, cacheFile.path);
|
||||
|
||||
var proc = Components.classes["@mozilla.org/process/util;1"]
|
||||
.createInstance(Components.interfaces.nsIProcess);
|
||||
if (_pdfConverterScript) {
|
||||
Zotero.debug("Running " + _pdfConverterScript.path + ' '
|
||||
+ args.map(arg => "'" + arg + "'").join(' '));
|
||||
proc.init(_pdfConverterScript);
|
||||
}
|
||||
else {
|
||||
Zotero.debug("Running " + _pdfConverter.path + ' '
|
||||
+ args.map(arg => "'" + arg + "'").join(' '));
|
||||
proc.init(_pdfConverter);
|
||||
}
|
||||
|
||||
try {
|
||||
proc.runw(true, args, args.length);
|
||||
}
|
||||
|
@ -1679,4 +1760,9 @@ Zotero.Fulltext = new function(){
|
|||
return w;
|
||||
});
|
||||
}
|
||||
|
||||
function _getScriptExtension() {
|
||||
return Zotero.isWin ? 'vbs' : 'sh';
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1590,6 +1590,9 @@ Zotero.Schema = new function(){
|
|||
var styleUpdates = xmlhttp.responseXML.getElementsByTagName('style');
|
||||
|
||||
var updatePDFTools = function () {
|
||||
// No updates for PPC
|
||||
if (Zotero.platform == 'MacPPC') return;
|
||||
|
||||
let pdfToolsUpdates = xmlhttp.responseXML.getElementsByTagName('pdftools');
|
||||
if (pdfToolsUpdates.length) {
|
||||
let availableVersion = pdfToolsUpdates[0].getAttribute('version');
|
||||
|
|
24
resource/hide.vbs
Normal file
24
resource/hide.vbs
Normal file
|
@ -0,0 +1,24 @@
|
|||
Option Explicit
|
||||
|
||||
Dim WshShell, fso, exe, args, I
|
||||
|
||||
Set WshShell = Wscript.CreateObject("Wscript.Shell")
|
||||
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
|
||||
|
||||
If WScript.Arguments.Count = 0 Then
|
||||
WScript.Echo "Usage: hidden.vbs program.exe [args...]"
|
||||
WScript.Quit 1
|
||||
End If
|
||||
|
||||
exe = WScript.Arguments(0)
|
||||
If Not(fso.FileExists(exe)) Then
|
||||
WScript.Echo "Executable not found: " & exe
|
||||
WScript.Quit 1
|
||||
End If
|
||||
|
||||
args = ""
|
||||
For I = 1 to WScript.Arguments.Count - 1
|
||||
args = args & " " & chr(34) & WScript.Arguments(I) & chr(34)
|
||||
Next
|
||||
|
||||
WshShell.Run exe & args, 0, true
|
6
resource/redirect.sh
Normal file
6
resource/redirect.sh
Normal file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ]; then
|
||||
echo "Usage: $0 cmd source output.txt"
|
||||
exit 1
|
||||
fi
|
||||
"$1" "$2" > "$3"
|
33
resource/redirect.vbs
Normal file
33
resource/redirect.vbs
Normal file
|
@ -0,0 +1,33 @@
|
|||
Option Explicit
|
||||
|
||||
Dim WshShell
|
||||
Dim fso
|
||||
Dim exe, src, dest
|
||||
|
||||
Set WshShell = Wscript.CreateObject("Wscript.Shell")
|
||||
Set fso = WScript.CreateObject("Scripting.FileSystemObject")
|
||||
|
||||
If Not(Wscript.Arguments.Count = 3) Then
|
||||
Wscript.Echo "Usage: redirect.vbs <.exe file> <source file> <text file>"
|
||||
WScript.Quit 1
|
||||
End If
|
||||
|
||||
exe = WScript.Arguments(0)
|
||||
src = WScript.Arguments(1)
|
||||
dest = WScript.Arguments(2)
|
||||
If Not(fso.FileExists(exe)) Then
|
||||
WScript.Echo "Executable not found: " & exe
|
||||
WScript.Quit 1
|
||||
End If
|
||||
|
||||
If Not(fso.FileExists(src)) Then
|
||||
WScript.Echo "Source file not found: " & src
|
||||
WScript.Quit 1
|
||||
End If
|
||||
|
||||
If Not(fso.FolderExists(Left(dest, InstrRev(dest, "\")))) Then
|
||||
WScript.Echo "Destination folder not found: " & Left(dest, InstrRev(dest, "\"))
|
||||
WScript.Quit 1
|
||||
End If
|
||||
|
||||
WshShell.Run "%comspec% /c " & exe & " " & chr(34) & src & chr(34) & " > " & chr(34) & dest & chr(34), 0, true
|
Loading…
Reference in a new issue