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

Side by Side Diff: ui/file_manager/zip_archiver/unpacker/js/volume.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 * Converts a c/c++ time_t variable to Date.
9 * @param {number} timestamp A c/c++ time_t variable.
10 * @return {!Date}
11 */
12 function DateFromTimeT(timestamp) {
13 return new Date(1000 * timestamp);
14 }
15
16 /**
17 * Corrects metadata entries fields in order for them to be sent to Files.app.
18 * This function runs recursively for every entry in a directory.
19 * @param {!Object<string, !EntryMetadata>} entryMetadata The metadata to
20 * correct.
21 */
22 function correctMetadata(entryMetadata) {
23 entryMetadata.index = parseInt(entryMetadata.index, 10);
24 entryMetadata.size = parseInt(entryMetadata.size, 10);
25 entryMetadata.modificationTime =
26 DateFromTimeT(entryMetadata.modificationTime);
27 if (entryMetadata.isDirectory) {
28 console.assert(entryMetadata.entries,
29 'The field "entries" is mandatory for dictionaries.');
30 for (var entry in entryMetadata.entries) {
31 correctMetadata(entryMetadata.entries[entry]);
32 }
33 }
34 }
35
36 /**
37 * Defines a volume object that contains information about archives' contents
38 * and performs operations on these contents.
39 * @constructor
40 * @param {!unpacker.Decompressor} decompressor The decompressor used to obtain
41 * data from archives.
42 * @param {!Entry} entry The entry corresponding to the volume's archive.
43 */
44 unpacker.Volume = function(decompressor, entry) {
45 /**
46 * Used for restoring the opened file entry after resuming the event page.
47 * @type {!Entry}
48 */
49 this.entry = entry;
50
51 /**
52 * @type {!unpacker.Decompressor}
53 */
54 this.decompressor = decompressor;
55
56 /**
57 * The volume's metadata. The key is the full path to the file on this volume.
58 * For more details see
59 * https://developer.chrome.com/apps/fileSystemProvider#type-EntryMetadata
60 * @type {?Object<string, !EntryMetadata>}
61 */
62 this.metadata = null;
63
64 /**
65 * A map with currently opened files. The key is a requestId value from the
66 * openFileRequested event and the value is the open file options.
67 * @type {!Object<!unpacker.types.RequestId,
68 * !unpacker.types.OpenFileRequestedOptions>}
69 */
70 this.openedFiles = {};
71
72 /**
73 * Default encoding set for this archive. If empty, then not known.
74 * @type {string}
75 */
76 this.encoding =
77 unpacker.Volume.ENCODING_TABLE[chrome.i18n.getUILanguage()] || '';
78
79 /**
80 * The default read metadata request id. -1 is ok as the request ids used by
81 * flleSystemProvider are greater than 0.
82 * @type {number}
83 */
84 this.DEFAULT_READ_METADATA_REQUEST_ID = -1;
85 };
86
87 /**
88 * The default read metadata request id. -1 is ok as the request ids used by
89 * flleSystemProvider are greater than 0.
90 * @const {number}
91 */
92 unpacker.Volume.DEFAULT_READ_METADATA_REQUEST_ID = -1;
93
94 /**
95 * Map from language codes to default charset encodings.
96 * @const {!Object<string, string>}
97 */
98 unpacker.Volume.ENCODING_TABLE = {
99 ar: 'CP1256',
100 bg: 'CP1251',
101 ca: 'CP1252',
102 cs: 'CP1250',
103 da: 'CP1252',
104 de: 'CP1252',
105 el: 'CP1253',
106 en: 'CP1250',
107 en_GB: 'CP1250',
108 es: 'CP1252',
109 es_419: 'CP1252',
110 et: 'CP1257',
111 fa: 'CP1256',
112 fi: 'CP1252',
113 fil: 'CP1252',
114 fr: 'CP1252',
115 he: 'CP1255',
116 hi: 'UTF-8', // Another one may be better.
117 hr: 'CP1250',
118 hu: 'CP1250',
119 id: 'CP1252',
120 it: 'CP1252',
121 ja: 'CP932', // Alternatively SHIFT-JIS.
122 ko: 'CP949', // Alternatively EUC-KR.
123 lt: 'CP1257',
124 lv: 'CP1257',
125 ms: 'CP1252',
126 nl: 'CP1252',
127 no: 'CP1252',
128 pl: 'CP1250',
129 pt_BR: 'CP1252',
130 pt_PT: 'CP1252',
131 ro: 'CP1250',
132 ru: 'CP1251',
133 sk: 'CP1250',
134 sl: 'CP1250',
135 sr: 'CP1251',
136 sv: 'CP1252',
137 th: 'CP874', // Confirm!
138 tr: 'CP1254',
139 uk: 'CP1251',
140 vi: 'CP1258',
141 zh_CN: 'CP936',
142 zh_TW: 'CP950'
143 };
144
145 /**
146 * @return {boolean} True if volume is ready to be used.
147 */
148 unpacker.Volume.prototype.isReady = function() {
149 return !!this.metadata;
150 };
151
152 /**
153 * @return {boolean} True if volume is in use.
154 */
155 unpacker.Volume.prototype.inUse = function() {
156 return this.decompressor.hasRequestsInProgress() ||
157 Object.keys(this.openedFiles).length > 0;
158 };
159
160 /**
161 * Initializes the volume by reading its metadata.
162 * @param {function()} onSuccess Callback to execute on success.
163 * @param {function(!ProviderError)} onError Callback to execute on error.
164 */
165 unpacker.Volume.prototype.initialize = function(onSuccess, onError) {
166 var requestId = unpacker.Volume.DEFAULT_READ_METADATA_REQUEST_ID;
167 this.decompressor.readMetadata(requestId, this.encoding, function(metadata) {
168 // Make a deep copy of metadata.
169 this.metadata = /** @type {!Object<string, !EntryMetadata>} */ (JSON.parse(
170 JSON.stringify(metadata)));
171 correctMetadata(this.metadata);
172
173 onSuccess();
174 }.bind(this), onError);
175 };
176
177 /**
178 * Obtains the metadata for a single entry in the archive. Assumes metadata is
179 * loaded.
180 * @param {!unpacker.types.GetMetadataRequestedOptions} options Options for
181 * getting the metadata of an entry.
182 * @param {function(!EntryMetadata)} onSuccess Callback to execute on success.
183 * @param {function(!ProviderError)} onError Callback to execute on error.
184 */
185 unpacker.Volume.prototype.onGetMetadataRequested = function(options, onSuccess,
186 onError) {
187 console.assert(this.isReady(), 'Metadata must be loaded.');
188 var entryMetadata = this.getEntryMetadata_(options.entryPath);
189 if (!entryMetadata)
190 onError('NOT_FOUND');
191 else
192 onSuccess(entryMetadata);
193 };
194
195 /**
196 * Reads a directory contents from metadata. Assumes metadata is loaded.
197 * @param {!unpacker.types.ReadDirectoryRequestedOptions} options Options
198 * for reading the contents of a directory.
199 * @param {function(!Array<!EntryMetadata>, boolean)} onSuccess Callback to
200 * execute on success.
201 * @param {function(!ProviderError)} onError Callback to execute on error.
202 */
203 unpacker.Volume.prototype.onReadDirectoryRequested = function(
204 options, onSuccess, onError) {
205 console.assert(this.isReady(), 'Metadata must be loaded.');
206 var directoryMetadata = this.getEntryMetadata_(options.directoryPath);
207 if (!directoryMetadata) {
208 onError('NOT_FOUND');
209 return;
210 }
211 if (!directoryMetadata.isDirectory) {
212 onError('NOT_A_DIRECTORY');
213 return;
214 }
215
216 // Convert dictionary entries to an array.
217 var entries = [];
218 for (var entry in directoryMetadata.entries) {
219 entries.push(directoryMetadata.entries[entry]);
220 }
221
222 onSuccess(entries, false /* Last call. */);
223 };
224
225 /**
226 * Opens a file for read or write.
227 * @param {!unpacker.types.OpenFileRequestedOptions} options Options for
228 * opening a file.
229 * @param {function()} onSuccess Callback to execute on success.
230 * @param {function(!ProviderError)} onError Callback to execute on error.
231 */
232 unpacker.Volume.prototype.onOpenFileRequested = function(options, onSuccess,
233 onError) {
234 console.assert(this.isReady(), 'Metadata must be loaded.');
235 if (options.mode != 'READ') {
236 onError('INVALID_OPERATION');
237 return;
238 }
239
240 var metadata = this.getEntryMetadata_(options.filePath);
241 if (!metadata) {
242 onError('NOT_FOUND');
243 return;
244 }
245
246 this.openedFiles[options.requestId] = options;
247
248 this.decompressor.openFile(
249 options.requestId, metadata.index, this.encoding, function() {
250 onSuccess();
251 }.bind(this), function(error) {
252 delete this.openedFiles[options.requestId];
253 onError('FAILED');
254 }.bind(this));
255 };
256
257 /**
258 * Closes a file identified by options.openRequestId.
259 * @param {!unpacker.types.CloseFileRequestedOptions} options Options for
260 * closing a file.
261 * @param {function()} onSuccess Callback to execute on success.
262 * @param {function(!ProviderError)} onError Callback to execute on error.
263 */
264 unpacker.Volume.prototype.onCloseFileRequested = function(options, onSuccess,
265 onError) {
266 console.assert(this.isReady(), 'Metadata must be loaded.');
267 var openRequestId = options.openRequestId;
268 var openOptions = this.openedFiles[openRequestId];
269 if (!openOptions) {
270 onError('INVALID_OPERATION');
271 return;
272 }
273
274 this.decompressor.closeFile(options.requestId, openRequestId, function() {
275 delete this.openedFiles[openRequestId];
276 onSuccess();
277 }.bind(this), onError);
278 };
279
280 /**
281 * Reads the contents of a file identified by options.openRequestId.
282 * @param {!unpacker.types.ReadFileRequestedOptions} options Options for
283 * reading a file's contents.
284 * @param {function(!ArrayBuffer, boolean)} onSuccess Callback to execute on
285 * success.
286 * @param {function(!ProviderError)} onError Callback to execute on error.
287 */
288 unpacker.Volume.prototype.onReadFileRequested = function(options, onSuccess,
289 onError) {
290 console.assert(this.isReady(), 'Metadata must be loaded.');
291 var openOptions = this.openedFiles[options.openRequestId];
292 if (!openOptions) {
293 onError('INVALID_OPERATION');
294 return;
295 }
296
297 var offset = options.offset;
298 var length = options.length;
299 // Offset and length should be validated by the API.
300 console.assert(offset >= 0, 'Offset should be >= 0.');
301 console.assert(length >= 0, 'Length should be >= 0.');
302
303 var fileSize = this.getEntryMetadata_(openOptions.filePath).size;
304 if (offset >= fileSize || length == 0) { // No more data.
305 onSuccess(new ArrayBuffer(0), false /* Last call. */);
306 return;
307 }
308 length = Math.min(length, fileSize - offset);
309
310 this.decompressor.readFile(options.requestId, options.openRequestId,
311 offset, length, onSuccess, onError);
312 };
313
314 /**
315 * Gets the metadata for an entry based on its path.
316 * @param {string} entryPath The full path to the entry.
317 * @return {?Object} The correspondent metadata.
318 * @private
319 */
320 unpacker.Volume.prototype.getEntryMetadata_ = function(entryPath) {
321 var pathArray = entryPath.split('/');
322
323 // Remove empty strings resulted after split. As paths start with '/' we will
324 // have an empty string at the beginning of pathArray and possible an
325 // empty string at the end for directories (e.g. /path/to/dir/). The code
326 // assumes entryPath cannot have consecutive '/'.
327 pathArray.splice(0, 1);
328
329 if (pathArray.length > 0) { // In case of 0 this is root directory.
330 var lastIndex = pathArray.length - 1;
331 if (pathArray[lastIndex] == '')
332 pathArray.splice(lastIndex);
333 }
334
335 // Get the actual metadata by iterating through every directory metadata
336 // on the path to the entry.
337 var entryMetadata = this.metadata;
338 for (var i = 0, limit = pathArray.length; i < limit; i++) {
339 if (!entryMetadata ||
340 !entryMetadata.isDirectory && i != limit - 1 /* Parent directory. */)
341 return null;
342 entryMetadata = entryMetadata.entries[pathArray[i]];
343 }
344
345 return entryMetadata;
346 };
OLDNEW
« no previous file with comments | « ui/file_manager/zip_archiver/unpacker/js/unpacker.js ('k') | ui/file_manager/zip_archiver/unpacker/manifest.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698