Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(302)

Side by Side Diff: ui/file_manager/zip_archiver/unpacker/js/decompressor.js

Issue 2804453002: Move files from zip_archiver/unpacker/ to zip_archiver/. (Closed)
Patch Set: Move files from zip_archiver/unpacker/ to zip_archiver/. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 /**
8 * A class that takes care of communication between NaCl and archive volume.
9 * Its job is to handle communication with the naclModule.
10 * @constructor
11 * @param {!Object} naclModule The nacl module with which the decompressor
12 * communicates.
13 * @param {!unpacker.types.FileSystemId} fileSystemId The file system id of for
14 * the archive volume to decompress.
15 * @param {!Blob} blob The correspondent file blob for fileSystemId.
16 * @param {!unpacker.PassphraseManager} passphraseManager Passphrase manager.
17 */
18 unpacker.Decompressor = function(naclModule, fileSystemId, blob,
19 passphraseManager) {
20 /**
21 * @private {!Object}
22 * @const
23 */
24 this.naclModule_ = naclModule;
25
26 /**
27 * @private {!unpacker.types.FileSystemId}
28 * @const
29 */
30 this.fileSystemId_ = fileSystemId;
31
32 /**
33 * @private {!Blob}
34 * @const
35 */
36 this.blob_ = blob;
37
38 /**
39 * @public {!unpacker.PassphraseManager}
40 * @const
41 */
42 this.passphraseManager = passphraseManager;
43
44 /**
45 * Requests in progress. No need to save them onSuspend for now as metadata
46 * reads are restarted from start.
47 * @public {!Object<!unpacker.types.RequestId, !Object>}
48 * @const
49 */
50 this.requestsInProgress = {};
51 };
52
53 /**
54 * @return {boolean} True if there is any request in progress.
55 */
56 unpacker.Decompressor.prototype.hasRequestsInProgress = function() {
57 return Object.keys(this.requestsInProgress).length > 0;
58 };
59
60 /**
61 * Sends a request to NaCl and mark it as a request in progress. onSuccess and
62 * onError are the callbacks used when receiving an answer from NaCl.
63 * @param {!unpacker.types.RequestId} requestId The operation request id, which
64 * should be unique per every volume.
65 * @param {function(...)} onSuccess Callback to execute on success.
66 * @param {function(!ProviderError)} onError Callback to execute on error.
67 * @param {!Object} naclRequest A request that must be sent to NaCl using
68 * postMessage.
69 * @private
70 */
71 unpacker.Decompressor.prototype.addRequest_ = function(requestId, onSuccess,
72 onError, naclRequest) {
73 console.assert(!this.requestsInProgress[requestId],
74 'There is already a request with the id ' + requestId + '.');
75
76 this.requestsInProgress[requestId] = {
77 onSuccess: onSuccess,
78 onError: onError
79 };
80
81 this.naclModule_.postMessage(naclRequest);
82 };
83
84 /**
85 * Creates a request for reading metadata.
86 * @param {!unpacker.types.RequestId} requestId
87 * @param {string} encoding Default encoding for the archive's headers.
88 * @param {function(!Object<string, !Object>)} onSuccess Callback to execute
89 * once the metadata is obtained from NaCl. It has one parameter, which is
90 * the metadata itself. The metadata has as key the full path to an entry
91 * and as value information about the entry.
92 * @param {function(!ProviderError)} onError Callback to execute on error.
93 */
94 unpacker.Decompressor.prototype.readMetadata = function(requestId, encoding,
95 onSuccess, onError) {
96 this.addRequest_(
97 requestId, onSuccess, onError,
98 unpacker.request.createReadMetadataRequest(this.fileSystemId_, requestId,
99 encoding, this.blob_.size));
100 };
101
102 /**
103 * Sends an open file request to NaCl.
104 * @param {!unpacker.types.RequestId} requestId
105 * @param {number} index Index of the file in the header list.
106 * @param {string} encoding Default encoding for the archive's headers.
107 * @param {function()} onSuccess Callback to execute on successful open.
108 * @param {function(!ProviderError)} onError Callback to execute on error.
109 */
110 unpacker.Decompressor.prototype.openFile = function(requestId, index, encoding,
111 onSuccess, onError) {
112 this.addRequest_(
113 requestId, onSuccess, onError,
114 unpacker.request.createOpenFileRequest(this.fileSystemId_, requestId,
115 index, encoding, this.blob_.size));
116 };
117
118 /**
119 * Sends a close file request to NaCl.
120 * @param {!unpacker.types.RequestId} requestId
121 * @param {!unpacker.types.RequestId} openRequestId The request id of the
122 * corresponding open file operation for the file to close.
123 * @param {function()} onSuccess Callback to execute on successful open.
124 * @param {function(!ProviderError)} onError Callback to execute on error.
125 */
126 unpacker.Decompressor.prototype.closeFile = function(requestId, openRequestId,
127 onSuccess, onError) {
128 this.addRequest_(requestId, onSuccess, onError,
129 unpacker.request.createCloseFileRequest(
130 this.fileSystemId_, requestId, openRequestId));
131 };
132
133 /**
134 * Sends a read file request to NaCl.
135 * @param {!unpacker.types.RequestId} requestId
136 * @param {!unpacker.types.RequestId} openRequestId The request id of the
137 * corresponding open file operation for the file to read.
138 * @param {number} offset The offset from where read operation should start.
139 * @param {number} length The number of bytes to read.
140 * @param {function(!ArrayBuffer, boolean)} onSuccess Callback to execute on
141 * success.
142 * @param {function(!ProviderError)} onError Callback to execute on error.
143 */
144 unpacker.Decompressor.prototype.readFile = function(
145 requestId, openRequestId, offset, length, onSuccess, onError) {
146 this.addRequest_(
147 requestId, onSuccess, onError,
148 unpacker.request.createReadFileRequest(this.fileSystemId_, requestId,
149 openRequestId, offset, length));
150 };
151
152 /**
153 * Processes messages from NaCl module.
154 * @param {!Object} data The data contained in the message from NaCl. Its
155 * types depend on the operation of the request.
156 * @param {!unpacker.request.Operation} operation An operation from request.js.
157 * @param {number} requestId The request id, which should be unique per every
158 * volume.
159 */
160 unpacker.Decompressor.prototype.processMessage = function(data, operation,
161 requestId) {
162 // Create a request reference for asynchronous calls as sometimes we delete
163 // some requestsInProgress from this.requestsInProgress.
164 var requestInProgress = this.requestsInProgress[requestId];
165 console.assert(requestInProgress, 'No request with id <' + requestId +
166 '> for: ' + this.fileSystemId_ + '.');
167
168 switch (operation) {
169 case unpacker.request.Operation.READ_METADATA_DONE:
170 var metadata = data[unpacker.request.Key.METADATA];
171 console.assert(metadata, 'No metadata.');
172 requestInProgress.onSuccess(metadata);
173 break;
174
175 case unpacker.request.Operation.READ_CHUNK:
176 this.readChunk_(data, requestId);
177 // this.requestsInProgress_[requestId] should be valid as long as NaCL
178 // can still make READ_CHUNK requests.
179 return;
180
181 case unpacker.request.Operation.READ_PASSPHRASE:
182 this.readPassphrase_(data, requestId);
183 // this.requestsInProgress_[requestId] should be valid as long as NaCL
184 // can still make READ_PASSPHRASE requests.
185 return;
186
187 case unpacker.request.Operation.OPEN_FILE_DONE:
188 requestInProgress.onSuccess();
189 // this.requestsInProgress_[requestId] should be valid until closing the
190 // file so NaCL can make READ_CHUNK requests.
191 return;
192
193 case unpacker.request.Operation.CLOSE_FILE_DONE:
194 var openRequestId = data[unpacker.request.Key.OPEN_REQUEST_ID];
195 console.assert(openRequestId, 'No open request id.');
196
197 openRequestId = Number(openRequestId); // Received as string.
198 delete this.requestsInProgress[openRequestId];
199 requestInProgress.onSuccess();
200 break;
201
202 case unpacker.request.Operation.READ_FILE_DONE:
203 var buffer = data[unpacker.request.Key.READ_FILE_DATA];
204 console.assert(buffer, 'No buffer for read file operation.');
205 var hasMoreData = data[unpacker.request.Key.HAS_MORE_DATA];
206 console.assert(buffer !== undefined,
207 'No HAS_MORE_DATA boolean value for file operation.');
208
209 requestInProgress.onSuccess(buffer, hasMoreData /* Last call. */);
210 if (hasMoreData)
211 return; // Do not delete requestInProgress.
212 break;
213
214 case unpacker.request.Operation.FILE_SYSTEM_ERROR:
215 console.error('File system error for <' + this.fileSystemId_ + '>: ' +
216 data[unpacker.request.Key.ERROR]); // The error contains
217 // the '.' at the end.
218 requestInProgress.onError('FAILED');
219 break;
220
221 case unpacker.request.Operation.CONSOLE_LOG:
222 case unpacker.request.Operation.CONSOLE_DEBUG:
223 var src_file = data[unpacker.request.Key.SRC_FILE];
224 var src_line = data[unpacker.request.Key.SRC_LINE];
225 var src_func = data[unpacker.request.Key.SRC_FUNC];
226 var msg = data[unpacker.request.Key.MESSAGE];
227 var log = operation == unpacker.request.Operation.CONSOLE_LOG ?
228 console.log : console.debug;
229 log(src_file + ':' + src_func + ':' + src_line + ': ' + msg);
230 break;
231
232 default:
233 console.error('Invalid NaCl operation: ' + operation + '.');
234 requestInProgress.onError('FAILED');
235 }
236 delete this.requestsInProgress[requestId];
237 };
238
239 /**
240 * Reads a chunk of data from this.blob_ for READ_CHUNK operation.
241 * @param {!Object} data The data received from the NaCl module.
242 * @param {number} requestId The request id, which should be unique per every
243 * volume.
244 * @private
245 */
246 unpacker.Decompressor.prototype.readChunk_ = function(data, requestId) {
247 // Offset and length are received as strings. See request.js.
248 var offset_str = data[unpacker.request.Key.OFFSET];
249 var length_str = data[unpacker.request.Key.LENGTH];
250
251 // Explicit check if offset is undefined as it can be 0.
252 console.assert(offset_str !== undefined && !isNaN(offset_str) &&
253 Number(offset_str) >= 0 &&
254 Number(offset_str) < this.blob_.size,
255 'Invalid offset.');
256 console.assert(length_str && !isNaN(length_str) && Number(length_str) > 0,
257 'Invalid length.');
258
259 var offset = Number(offset_str);
260 var length = Math.min(this.blob_.size - offset, Number(length_str));
261
262 // Read a chunk from offset to offset + length.
263 var blob = this.blob_.slice(offset, offset + length);
264 var fileReader = new FileReader();
265
266 fileReader.onload = function(event) {
267 this.naclModule_.postMessage(unpacker.request.createReadChunkDoneResponse(
268 this.fileSystemId_, requestId, event.target.result, offset));
269 }.bind(this);
270
271 fileReader.onerror = function(event) {
272 console.error('Failed to read a chunk of data from the archive.');
273 this.naclModule_.postMessage(unpacker.request.createReadChunkErrorResponse(
274 this.fileSystemId_, requestId));
275 // Reading from the source file failed. Assume that the file is gone and
276 // unmount the archive.
277 // TODO(523195): Show a notification that the source file is gone.
278 unpacker.app.unmountVolume(this.fileSystemId_, true);
279 }.bind(this);
280
281 fileReader.readAsArrayBuffer(blob);
282 };
283
284 /**
285 * Reads a passphrase from user input for READ_PASSPHRASE operation.
286 * @param {!Object} data The data received from the NaCl module.
287 * @param {number} requestId The request id, which should be unique per every
288 * volume.
289 * @private
290 */
291 unpacker.Decompressor.prototype.readPassphrase_ = function(data, requestId) {
292 this.passphraseManager.getPassphrase()
293 .then(function(passphrase) {
294 this.naclModule_.postMessage(
295 unpacker.request.createReadPassphraseDoneResponse(
296 this.fileSystemId_, requestId, passphrase));
297 }.bind(this))
298 .catch(function(error) {
299 console.error(error.stack || error);
300 this.naclModule_.postMessage(
301 unpacker.request.createReadPassphraseErrorResponse(
302 this.fileSystemId_, requestId));
303 // TODO(mtomasz): Instead of unmounting just let the current operation
304 // fail and ask for password for another files. This is however
305 // impossible for now due to a bug in libarchive.
306 unpacker.app.unmountVolume(this.fileSystemId_, true);
307 }.bind(this));
308 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698