diff --git a/chrome/content/zotero/xpcom/file.js b/chrome/content/zotero/xpcom/file.js index 18b23b3a68..42d816fff8 100644 --- a/chrome/content/zotero/xpcom/file.js +++ b/chrome/content/zotero/xpcom/file.js @@ -398,11 +398,11 @@ Zotero.File = new function(){ * Write data to a file asynchronously * * @param {String|nsIFile} - String path or nsIFile to write to - * @param {String|nsIInputStream} data - The string or nsIInputStream to write to the file + * @param {String|nsIInputStream|ArrayBuffer} data - The data to write to the file * @param {String} [charset] - The character set; defaults to UTF-8 * @return {Promise} - A promise that is resolved when the file has been written */ - this.putContentsAsync = function (path, data, charset) { + this.putContentsAsync = async function (path, data, charset) { if (path instanceof Ci.nsIFile) { path = path.path; } @@ -418,16 +418,33 @@ Zotero.File = new function(){ )); } - var deferred = Zotero.Promise.defer(); - var os = FileUtils.openSafeFileOutputStream(new FileUtils.File(path)); - NetUtil.asyncCopy(data, os, function(inputStream, status) { - if (!Components.isSuccessCode(status)) { - deferred.reject(new Components.Exception("File write operation failed", status)); - return; - } - deferred.resolve(); + // If Blob, feed that to an input stream + // + // data instanceof Blob doesn't work in XPCOM + if (typeof data.size != 'undefined' && typeof data.slice == 'function') { + let arrayBuffer = await new Zotero.Promise(function (resolve) { + let fr = new FileReader(); + fr.addEventListener("loadend", function() { + resolve(fr.result); + }); + fr.readAsArrayBuffer(data); + }); + let is = Components.classes["@mozilla.org/io/arraybuffer-input-stream;1"] + .createInstance(Components.interfaces.nsIArrayBufferInputStream); + is.setData(arrayBuffer, 0, arrayBuffer.byteLength); + data = is; + } + + await new Zotero.Promise(function (resolve, reject) { + var os = FileUtils.openSafeFileOutputStream(new FileUtils.File(path)); + NetUtil.asyncCopy(data, os, function(inputStream, status) { + if (!Components.isSuccessCode(status)) { + reject(new Components.Exception("File write operation failed", status)); + return; + } + resolve(); + }); }); - return deferred.promise; }; diff --git a/chrome/content/zotero/xpcom/translation/translators.js b/chrome/content/zotero/xpcom/translation/translators.js index 3936466127..7b50cce6f9 100644 --- a/chrome/content/zotero/xpcom/translation/translators.js +++ b/chrome/content/zotero/xpcom/translation/translators.js @@ -519,7 +519,7 @@ Zotero.Translators = new function() { Zotero.debug("Saving translator '" + metadata.label + "'"); Zotero.debug(metadata); - return Zotero.File.putContentsAsync(destFile, str).return(destFile); + return Zotero.File.putContentsAsync(destFile, str).then(() => destFile); }); this.cacheInDB = function(fileName, metadataJSON, lastModifiedTime) { diff --git a/test/tests/fileTest.js b/test/tests/fileTest.js index 224d83afc7..ad05a17c1a 100644 --- a/test/tests/fileTest.js +++ b/test/tests/fileTest.js @@ -83,6 +83,31 @@ describe("Zotero.File", function () { }); describe("#putContentsAsync()", function () { + it("should save a text string", async function () { + var tmpDir = await getTempDirectory(); + var destFile = OS.Path.join(tmpDir, 'test'); + var str = 'A'; + await Zotero.File.putContentsAsync(destFile, str); + assert.equal(await Zotero.File.getContentsAsync(destFile), str); + }); + + it("should save a Blob", async function () { + var srcFile = OS.Path.join(getTestDataDirectory().path, 'test.pdf'); + var tmpDir = await getTempDirectory(); + var destFile = OS.Path.join(tmpDir, 'test.pdf'); + + var blob = await File.createFromFileName(srcFile); + await Zotero.File.putContentsAsync(destFile, blob); + + var destContents = await Zotero.File.getBinaryContentsAsync(destFile); + assert.equal( + await Zotero.File.getBinaryContentsAsync(srcFile), + destContents + ); + + assert.equal(destContents.substr(0, 4), '%PDF'); + }); + it("should save via .tmp file", function* () { var tmpDir = yield getTempDirectory(); var destFile = OS.Path.join(tmpDir, 'test.txt') @@ -91,7 +116,7 @@ describe("Zotero.File", function () { assert.isTrue(yield OS.File.exists(tmpFile)); yield Zotero.File.putContentsAsync(destFile, 'B'); assert.isFalse(yield OS.File.exists(tmpFile)); - // Make sure .tmp file created when creating temp file was deleted too + // Make sure .tmp file was deleted assert.isFalse(yield OS.File.exists(tmpFile + '.tmp')); }); });