File: decompressor.jsm

package info (click to toggle)
downthemall 2.0.13-2
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 4,284 kB
  • sloc: xml: 927; makefile: 8
file content (133 lines) | stat: -rw-r--r-- 3,819 bytes parent folder | download
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);
		}
	}
};