1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
/* You may find the license in the LICENSE file */
const EXPORTED_SYMBOLS = ['Decompressor'];
const BUFFER_SIZE = 5 * 1024 * 1024;
const FREQ = 250;
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
const Ctor = Components.Constructor;
const module = Cu.import;
const Exception = Components.Exception;
const DTA = {};
module("resource://dta/utils.jsm");
module("resource://dta/api.jsm", DTA);
module("resource://dta/support/timers.jsm");
const IOService = DTA.IOService;
const Prefs = DTA.Preferences;
const LocalFile = new Ctor('@mozilla.org/file/local;1', 'nsILocalFile', 'initWithPath');
const FileOutputStream = new Ctor('@mozilla.org/network/file-output-stream;1', 'nsIFileOutputStream', 'init');
const BinaryOutputStream = new Ctor('@mozilla.org/binaryoutputstream;1', 'nsIBinaryOutputStream', 'setOutputStream');
const BufferedOutputStream = new Ctor('@mozilla.org/network/buffered-output-stream;1', 'nsIBufferedOutputStream', 'init');
const BinaryInputStream = new Ctor('@mozilla.org/binaryinputstream;1', 'nsIBinaryInputStream', 'setInputStream');
const Timers = new TimerManager();
function Decompressor(download) {
this.download = download;
this.to = new LocalFile(download.destinationFile);
this.from = download.tmpFile.clone();
try {
this._outStream = new FileOutputStream(this.to, 0x04 | 0x08, Prefs.getExt('permissions', 384), 0);
this.outStream = new BinaryOutputStream(new BufferedOutputStream(this._outStream, BUFFER_SIZE));
let converter = Cc["@mozilla.org/streamconv;1?from=" + download.compression + "&to=uncompressed"]
.createInstance(Ci.nsIStreamConverter);
converter.asyncConvertData(
download.compression,
"uncompressed",
this,
null
);
IOService.newChannelFromURI(IOService.newFileURI(this.from)).asyncOpen(converter, null);
}
catch (ex) {
try {
if (this.outStream) {
outStream.close();
}
if (this.to.exists()) {
this.to.remove(false);
}
if (this.from.exists()) {
this.from.remove(false);
}
}
catch (exx) {
// XXX: what now?
}
Debug.log("err. :p", ex);
download.complete(ex);
}
}
Decompressor.prototype = {
exception: null,
QueryInterface: function(iid) {
if (iid.equals(Ci.nsISupports) || iid.equals(Ci.nsIStreamListener) || iid.equals(cI.nsIRequestObserver)) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
},
onStartRequest: function(r, c) {
this._timer = Timers.createRepeating(FREQ, this.download.invalidate, this.download);
},
onStopRequest: function(request, c) {
Timers.killTimer(this._timer);
// important, or else we don't write out the last buffer and truncate too early. :p
this.outStream.flush();
try {
this._outStream.QueryInterface(Ci.nsISeekableStream).setEOF();
}
catch (ex) {
this.exception = ex;
}
try {
this.outStream.close();
this._outStream.close();
}
catch (ex) {
// huh?
Debug.log("Decompressor: close streams", ex);
}
if (this.exception) {
try {
this.to.remove(false);
}
catch (ex) {
// no-op: we're already bad :p
}
}
try {
this.from.remove(false);
}
catch (ex) {
Debug.log("Failed to remove tmpFile", ex);
}
this.download.complete(this.exception);
},
onDataAvailable: function(request, c, stream, offset, count) {
try {
var binStream = new BinaryInputStream(stream);
if (count != this.outStream.write(binStream.readBytes(count), count)) {
throw new Exception("Failed to write!");
}
this.download.partialSize = offset;
}
catch (ex) {
this.exception = ex;
var reason = 0x804b0002; // NS_BINDING_ABORTED;
request.cancel(reason);
}
}
};
|