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

Side by Side Diff: ui/file_manager/zip_archiver/unpacker/cpp/module.cc

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 #include <clocale>
6 #include <sstream>
7
8 #include "ppapi/cpp/instance.h"
9 #include "ppapi/cpp/instance_handle.h"
10 #include "ppapi/cpp/logging.h"
11 #include "ppapi/cpp/module.h"
12 #include "ppapi/cpp/var_dictionary.h"
13 #include "ppapi/utility/threading/lock.h"
14 #include "ppapi/utility/threading/simple_thread.h"
15
16 #include "compressor.h"
17 #include "request.h"
18 #include "volume.h"
19
20 namespace {
21
22 typedef std::map<std::string, Volume*>::const_iterator volume_iterator;
23 typedef std::map<int, Compressor*>::const_iterator compressor_iterator;
24
25 // An internal implementation of JavaScriptMessageSenderInterface. This class
26 // handles all communication from the module to the JavaScript code. Thread
27 // safety is ensured only for PNaCl, not NaCl. See crbug.com/412692 and
28 // crbug.com/413513.
29 class JavaScriptMessageSender : public JavaScriptMessageSenderInterface {
30 public:
31 // JavaScriptMessageSender does not own the instance pointer.
32 explicit JavaScriptMessageSender(pp::Instance* instance)
33 : instance_(instance) {}
34
35 virtual void SendFileSystemError(const std::string& file_system_id,
36 const std::string& request_id,
37 const std::string& message) {
38 JavaScriptPostMessage(
39 request::CreateFileSystemError(file_system_id, request_id, message));
40 }
41
42 virtual void SendCompressorError(int compressor_id,
43 const std::string& message) {
44 JavaScriptPostMessage(
45 request::CreateCompressorError(compressor_id, message));
46 }
47
48 virtual void SendFileChunkRequest(const std::string& file_system_id,
49 const std::string& request_id,
50 int64_t offset,
51 int64_t bytes_to_read) {
52 PP_DCHECK(offset >= 0);
53 PP_DCHECK(bytes_to_read > 0);
54 JavaScriptPostMessage(request::CreateReadChunkRequest(
55 file_system_id, request_id, offset, bytes_to_read));
56 }
57
58 virtual void SendPassphraseRequest(const std::string& file_system_id,
59 const std::string& request_id) {
60 JavaScriptPostMessage(request::CreateReadPassphraseRequest(
61 file_system_id, request_id));
62 }
63
64 virtual void SendReadMetadataDone(const std::string& file_system_id,
65 const std::string& request_id,
66 const pp::VarDictionary& metadata) {
67 JavaScriptPostMessage(request::CreateReadMetadataDoneResponse(
68 file_system_id, request_id, metadata));
69 }
70
71 virtual void SendOpenFileDone(const std::string& file_system_id,
72 const std::string& request_id) {
73 JavaScriptPostMessage(
74 request::CreateOpenFileDoneResponse(file_system_id, request_id));
75 }
76
77 virtual void SendCloseFileDone(const std::string& file_system_id,
78 const std::string& request_id,
79 const std::string& open_request_id) {
80 JavaScriptPostMessage(request::CreateCloseFileDoneResponse(
81 file_system_id, request_id, open_request_id));
82 }
83
84 virtual void SendReadFileDone(const std::string& file_system_id,
85 const std::string& request_id,
86 const pp::VarArrayBuffer& array_buffer,
87 bool has_more_data) {
88 JavaScriptPostMessage(request::CreateReadFileDoneResponse(
89 file_system_id, request_id, array_buffer, has_more_data));
90 }
91
92 virtual void SendConsoleLog(const std::string& file_system_id,
93 const std::string& request_id,
94 const std::string& src_file,
95 int src_line,
96 const std::string& src_func,
97 const std::string& message) {
98 JavaScriptPostMessage(request::CreateConsoleLog(
99 file_system_id, request_id, src_file, src_line, src_func, message));
100 }
101
102 virtual void SendCreateArchiveDone(int compressor_id) {
103 JavaScriptPostMessage(request::CreateCreateArchiveDoneResponse(
104 compressor_id));
105 }
106
107 virtual void SendReadFileChunk(int compressor_id, int64_t length) {
108 JavaScriptPostMessage(request::CreateReadFileChunkRequest(
109 compressor_id, length));
110 }
111
112 virtual void SendWriteChunk(int compressor_id,
113 const pp::VarArrayBuffer& array_buffer,
114 int64_t length) {
115 JavaScriptPostMessage(request::CreateWriteChunkRequest(
116 compressor_id, array_buffer, length));
117 }
118
119 virtual void SendAddToArchiveDone(int compressor_id) {
120 JavaScriptPostMessage(request::CreateAddToArchiveDoneResponse(
121 compressor_id));
122 }
123
124 virtual void SendCloseArchiveDone(int compressor_id) {
125 JavaScriptPostMessage(request::CreateCloseArchiveDoneResponse(
126 compressor_id));
127 }
128
129 private:
130 // Posts a message to JavaScript. This is prone to races in case of using
131 // NaCl instead of PNaCl. See crbug.com/413513.
132 void JavaScriptPostMessage(const pp::VarDictionary& message) {
133 instance_->PostMessage(message);
134 }
135
136 pp::Instance* instance_;
137 };
138
139 } // namespace
140
141 // An instance for every "embed" in the web page. For this extension only one
142 // "embed" is necessary.
143 class NaclArchiveInstance : public pp::Instance {
144 public:
145 explicit NaclArchiveInstance(PP_Instance instance)
146 : pp::Instance(instance),
147 instance_handle_(instance),
148 message_sender_(this) {}
149
150 virtual ~NaclArchiveInstance() {
151 for (volume_iterator iterator = volumes_.begin();
152 iterator != volumes_.end();
153 ++iterator) {
154 delete iterator->second;
155 }
156 }
157
158 // Handler for messages coming in from JS via postMessage().
159 virtual void HandleMessage(const pp::Var& var_message) {
160 PP_DCHECK(var_message.is_dictionary());
161 pp::VarDictionary var_dict(var_message);
162
163 PP_DCHECK(var_dict.Get(request::key::kOperation).is_int());
164 int operation = var_dict.Get(request::key::kOperation).AsInt();
165
166 if (request::IsPackRequest(operation))
167 HandlePackMessage(var_dict, operation);
168 else
169 HandleUnpackMessage(var_dict, operation);
170 }
171
172 private:
173
174 // Processes unpack messages.
175 void HandleUnpackMessage(const pp::VarDictionary& var_dict,
176 const int operation) {
177
178 PP_DCHECK(var_dict.Get(request::key::kFileSystemId).is_string());
179 std::string file_system_id =
180 var_dict.Get(request::key::kFileSystemId).AsString();
181
182 PP_DCHECK(var_dict.Get(request::key::kRequestId).is_string());
183 std::string request_id = var_dict.Get(request::key::kRequestId).AsString();
184
185 // Processes operation.
186 switch (operation) {
187 case request::READ_METADATA: {
188 ReadMetadata(var_dict, file_system_id, request_id);
189 break;
190 }
191
192 case request::READ_CHUNK_DONE:
193 ReadChunkDone(var_dict, file_system_id, request_id);
194 break;
195
196 case request::READ_CHUNK_ERROR:
197 ReadChunkError(file_system_id, request_id);
198 break;
199
200 case request::READ_PASSPHRASE_DONE:
201 ReadPassphraseDone(var_dict, file_system_id, request_id);
202 break;
203
204 case request::READ_PASSPHRASE_ERROR:
205 ReadPassphraseError(file_system_id, request_id);
206 break;
207
208 case request::OPEN_FILE:
209 OpenFile(var_dict, file_system_id, request_id);
210 break;
211
212 case request::CLOSE_FILE:
213 CloseFile(var_dict, file_system_id, request_id);
214 break;
215
216 case request::READ_FILE:
217 ReadFile(var_dict, file_system_id, request_id);
218 break;
219
220 case request::CLOSE_VOLUME: {
221 volume_iterator iterator = volumes_.find(file_system_id);
222 PP_DCHECK(iterator != volumes_.end());
223 delete iterator->second;
224 volumes_.erase(file_system_id);
225 break;
226 }
227
228 default:
229 PP_NOTREACHED();
230 }
231 }
232
233 // Processes pack messages.
234 void HandlePackMessage(const pp::VarDictionary& var_dict,
235 const int operation) {
236 PP_DCHECK(var_dict.Get(request::key::kCompressorId).is_int());
237 int compressor_id =
238 var_dict.Get(request::key::kCompressorId).AsInt();
239
240 switch (operation) {
241 case request::CREATE_ARCHIVE: {
242 CreateArchive(compressor_id);
243 break;
244 }
245
246 case request::ADD_TO_ARCHIVE: {
247 AddToArchive(var_dict, compressor_id);
248 break;
249 }
250
251 case request::READ_FILE_CHUNK_DONE: {
252 ReadFileChunkDone(var_dict, compressor_id);
253 break;
254 }
255
256 case request::WRITE_CHUNK_DONE: {
257 WriteChunkDone(var_dict, compressor_id);
258 break;
259 }
260
261 case request::CLOSE_ARCHIVE: {
262 CloseArchive(var_dict, compressor_id);
263 break;
264 }
265
266 default:
267 PP_NOTREACHED();
268 }
269 }
270
271 // Reads the metadata for the corresponding volume for file_system_id. This
272 // should be called only once and before any other operation like OpenFile,
273 // ReadFile, etc.
274 // Reading metadata or opening a file could work even if the Volume exists
275 // or not, but as the JavaScript code doesn't use this feature there is no
276 // reason to allow it. If the logic on JavaScript changes then this can be
277 // updated. But in current design if we read metadata for an existing Volume,
278 // then there is a programmer error on JavaScript side.
279 void ReadMetadata(const pp::VarDictionary& var_dict,
280 const std::string& file_system_id,
281 const std::string& request_id) {
282 // Should not call ReadMetadata for a Volume already present in NaCl.
283 PP_DCHECK(volumes_.find(file_system_id) == volumes_.end());
284
285 Volume* volume =
286 new Volume(instance_handle_, file_system_id, &message_sender_);
287 if (!volume->Init()) {
288 message_sender_.SendFileSystemError(
289 file_system_id,
290 request_id,
291 "Could not create a volume for: " + file_system_id + ".");
292 delete volume;
293 return;
294 }
295 volumes_[file_system_id] = volume;
296
297 PP_DCHECK(var_dict.Get(request::key::kEncoding).is_string());
298 PP_DCHECK(var_dict.Get(request::key::kArchiveSize).is_string());
299
300 volume->ReadMetadata(
301 request_id,
302 var_dict.Get(request::key::kEncoding).AsString(),
303 request::GetInt64FromString(var_dict, request::key::kArchiveSize));
304 }
305
306 void ReadChunkDone(const pp::VarDictionary& var_dict,
307 const std::string& file_system_id,
308 const std::string& request_id) {
309 PP_DCHECK(var_dict.Get(request::key::kChunkBuffer).is_array_buffer());
310 pp::VarArrayBuffer array_buffer(var_dict.Get(request::key::kChunkBuffer));
311
312 PP_DCHECK(var_dict.Get(request::key::kOffset).is_string());
313 int64_t read_offset =
314 request::GetInt64FromString(var_dict, request::key::kOffset);
315
316 volume_iterator iterator = volumes_.find(file_system_id);
317 // Volume was unmounted so ignore the read chunk operation.
318 // Possible scenario for read ahead.
319 if (iterator == volumes_.end())
320 return;
321 iterator->second->ReadChunkDone(request_id, array_buffer, read_offset);
322 }
323
324 void ReadChunkError(const std::string& file_system_id,
325 const std::string& request_id) {
326 volume_iterator iterator = volumes_.find(file_system_id);
327 // Volume was unmounted so ignore the read chunk operation.
328 // Possible scenario for read ahead.
329 if (iterator == volumes_.end())
330 return;
331 iterator->second->ReadChunkError(request_id);
332 }
333
334 void ReadPassphraseDone(const pp::VarDictionary& var_dict,
335 const std::string& file_system_id,
336 const std::string& request_id) {
337 PP_DCHECK(var_dict.Get(request::key::kPassphrase).is_string());
338 std::string passphrase(var_dict.Get(request::key::kPassphrase).AsString());
339
340 volume_iterator iterator = volumes_.find(file_system_id);
341 // Volume was unmounted so ignore the read passphrase operation.
342 if (iterator == volumes_.end())
343 return;
344 iterator->second->ReadPassphraseDone(request_id, passphrase);
345 }
346
347 void ReadPassphraseError(const std::string& file_system_id,
348 const std::string& request_id) {
349 volume_iterator iterator = volumes_.find(file_system_id);
350 // Volume was unmounted so ignore the read chunk operation.
351 if (iterator == volumes_.end())
352 return;
353 iterator->second->ReadPassphraseError(request_id);
354 }
355
356 void OpenFile(const pp::VarDictionary& var_dict,
357 const std::string& file_system_id,
358 const std::string& request_id) {
359 PP_DCHECK(var_dict.Get(request::key::kIndex).is_string());
360 int64_t index =
361 request::GetInt64FromString(var_dict, request::key::kIndex);
362
363 PP_DCHECK(var_dict.Get(request::key::kEncoding).is_string());
364 std::string encoding(var_dict.Get(request::key::kEncoding).AsString());
365
366 PP_DCHECK(var_dict.Get(request::key::kArchiveSize).is_string());
367 int64_t archive_size =
368 request::GetInt64FromString(var_dict, request::key::kArchiveSize);
369
370 volume_iterator iterator = volumes_.find(file_system_id);
371 PP_DCHECK(iterator != volumes_.end()); // Should call OpenFile after
372 // ReadMetadata.
373 iterator->second->OpenFile(request_id, index, encoding, archive_size);
374 }
375
376 void CloseFile(const pp::VarDictionary& var_dict,
377 const std::string& file_system_id,
378 const std::string& request_id) {
379 PP_DCHECK(var_dict.Get(request::key::kOpenRequestId).is_string());
380 std::string open_request_id(
381 var_dict.Get(request::key::kOpenRequestId).AsString());
382
383 volume_iterator iterator = volumes_.find(file_system_id);
384 PP_DCHECK(iterator !=
385 volumes_.end()); // Should call CloseFile after OpenFile.
386
387 iterator->second->CloseFile(request_id, open_request_id);
388 }
389
390 void ReadFile(const pp::VarDictionary& var_dict,
391 const std::string& file_system_id,
392 const std::string& request_id) {
393 PP_DCHECK(var_dict.Get(request::key::kOpenRequestId).is_string());
394 PP_DCHECK(var_dict.Get(request::key::kOffset).is_string());
395 PP_DCHECK(var_dict.Get(request::key::kLength).is_string());
396
397 volume_iterator iterator = volumes_.find(file_system_id);
398 PP_DCHECK(iterator !=
399 volumes_.end()); // Should call ReadFile after OpenFile.
400
401 // Passing the entire dictionary because pp::CompletionCallbackFactory
402 // cannot create callbacks with more than 3 parameters. Here we need 4:
403 // request_id, open_request_id, offset and length.
404 iterator->second->ReadFile(request_id, var_dict);
405 }
406
407 // Requests libarchive to create an archive object for the given compressor_id .
408 void CreateArchive(int compressor_id) {
409 Compressor* compressor =
410 new Compressor(instance_handle_, compressor_id, &message_sender_);
411 if (!compressor->Init()) {
412 std::stringstream ss;
413 ss << compressor_id;
414 message_sender_.SendCompressorError(
415 compressor_id,
416 "Could not create a compressor for compressor id: " + ss.str() + ".");
417 delete compressor;
418 return;
419 }
420 compressors_[compressor_id] = compressor;
421
422 compressor->CreateArchive();
423 }
424
425 void AddToArchive(const pp::VarDictionary& var_dict,
426 int compressor_id) {
427 compressor_iterator iterator = compressors_.find(compressor_id);
428 PP_DCHECK(iterator != compressors_.end());
429
430 iterator->second->AddToArchive(var_dict);
431 }
432
433 void ReadFileChunkDone(const pp::VarDictionary& var_dict,
434 const int compressor_id) {
435 compressor_iterator iterator = compressors_.find(compressor_id);
436 PP_DCHECK(iterator != compressors_.end());
437
438 iterator->second->ReadFileChunkDone(var_dict);
439 }
440
441 void WriteChunkDone(const pp::VarDictionary& var_dict,
442 int compressor_id) {
443 compressor_iterator iterator = compressors_.find(compressor_id);
444 PP_DCHECK(iterator != compressors_.end());
445
446 iterator->second->WriteChunkDone(var_dict);
447 }
448
449 void CloseArchive(const pp::VarDictionary& var_dict,
450 int compressor_id) {
451 compressor_iterator iterator = compressors_.find(compressor_id);
452
453 if (iterator != compressors_.end())
454 iterator->second->CloseArchive(var_dict);
455 }
456
457 // A map that holds for every opened archive its instance. The key is the file
458 // system id of the archive.
459 std::map<std::string, Volume*> volumes_;
460
461 // A map from compressor ids to compressors.
462 std::map<int, Compressor*> compressors_;
463
464 // An pp::InstanceHandle used to create pp::SimpleThread in Volume.
465 pp::InstanceHandle instance_handle_;
466
467 // An object used to send messages to JavaScript.
468 JavaScriptMessageSender message_sender_;
469 };
470
471 // The Module class. The browser calls the CreateInstance() method to create
472 // an instance of your NaCl module on the web page. The browser creates a new
473 // instance for each <embed> tag with type="application/x-pnacl" or
474 // type="application/x-nacl".
475 class NaclArchiveModule : public pp::Module {
476 public:
477 NaclArchiveModule() : pp::Module() {}
478 virtual ~NaclArchiveModule() {}
479
480 // Create and return a NaclArchiveInstance object.
481 // @param[in] instance The browser-side instance.
482 // @return the plugin-side instance.
483 virtual pp::Instance* CreateInstance(PP_Instance instance) {
484 return new NaclArchiveInstance(instance);
485 }
486 };
487
488 namespace pp {
489
490 // Factory function called by the browser when the module is first loaded.
491 // The browser keeps a singleton of this module. It calls the
492 // CreateInstance() method on the object you return to make instances. There
493 // is one instance per <embed> tag on the page. This is the main binding
494 // point for your NaCl module with the browser.
495 Module* CreateModule() {
496 std::setlocale(LC_ALL, "en_US.UTF-8");
497 return new NaclArchiveModule();
498 }
499
500 } // namespace pp
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698