1 // Copyright 2014 The Chromium 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 <string> 6 7 #include "ppapi/c/ppb_file_io.h" 8 #include "ppapi/cpp/file_io.h" 9 #include "ppapi/cpp/file_ref.h" 10 #include "ppapi/cpp/file_system.h" 11 #include "ppapi/cpp/instance.h" 12 #include "ppapi/cpp/module.h" 13 #include "ppapi/cpp/var.h" 14 #include "ppapi/cpp/var_dictionary.h" 15 #include "ppapi/tests/test_utils.h" 16 17 /// The Instance class. Receives the file through HandleMessage(), and returns 18 /// data to the plugin with PostMessage(). 19 class FilePassingInstance : public pp::Instance { 20 public: 21 /// The constructor creates the plugin-side instance. 22 /// @param[in] instance the handle to the browser-side plugin instance. 23 explicit FilePassingInstance(PP_Instance instance); 24 virtual ~FilePassingInstance(); 25 26 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]); 27 28 private: 29 /// Handler for messages coming in from the browser via postMessage(). 30 /// @param[in] var_message The message posted by the browser. 31 virtual void HandleMessage(const pp::Var& var_message); 32 33 /// Takes a fileEntry-dictionary message received from JavaScript and converts 34 /// it into a pp::FileRef. On failure, returns a null FileRef. 35 pp::FileRef ParseMessage(const pp::Var& var_message, std::string* test_type); 36 37 void TestRead(pp::FileRef file_ref); 38 void TestWrite(pp::FileRef file_ref); 39 }; 40 41 FilePassingInstance::FilePassingInstance(PP_Instance instance) 42 : pp::Instance(instance) {} 43 44 FilePassingInstance::~FilePassingInstance() {} 45 46 bool FilePassingInstance::Init(uint32_t argc, 47 const char* argn[], 48 const char* argv[]) { 49 PostMessage("ready"); 50 return true; 51 } 52 53 pp::FileRef FilePassingInstance::ParseMessage(const pp::Var& var_message, 54 std::string* test_type) { 55 if (!var_message.is_dictionary()) { 56 PostMessage("Message was not a dictionary."); 57 return pp::FileRef(); 58 } 59 pp::VarDictionary var_dictionary_message(var_message); 60 pp::Var var_filesystem = var_dictionary_message.Get("filesystem"); 61 pp::Var var_fullpath = var_dictionary_message.Get("fullPath"); 62 pp::Var var_testtype = var_dictionary_message.Get("testType"); 63 64 if (!var_filesystem.is_resource()) { 65 PostMessage("Filesystem was missing or not a resource."); 66 return pp::FileRef(); 67 } 68 pp::Resource resource_filesystem = var_filesystem.AsResource(); 69 if (!var_fullpath.is_string()) { 70 PostMessage("FullPath was missing or not a string."); 71 return pp::FileRef(); 72 } 73 std::string fullpath = var_fullpath.AsString(); 74 if (!var_testtype.is_string()) { 75 PostMessage("TestType was missing or not a string."); 76 return pp::FileRef(); 77 } 78 std::string name_of_test = var_testtype.AsString(); 79 80 if (!pp::FileSystem::IsFileSystem(resource_filesystem)) { 81 PostMessage("Filesystem was not a file system."); 82 return pp::FileRef(); 83 } 84 85 *test_type = name_of_test; 86 pp::FileSystem filesystem(resource_filesystem); 87 // Note: The filesystem is already open (there is no need to call Open again). 88 89 return pp::FileRef(filesystem, fullpath.c_str()); 90 } 91 92 void FilePassingInstance::HandleMessage(const pp::Var& var_message) { 93 // Extract the filesystem and fullPath from the message. 94 std::string test_type; 95 pp::FileRef file_ref = ParseMessage(var_message, &test_type); 96 if (file_ref.is_null()) 97 return; 98 99 if (test_type == "read_test") { 100 TestRead(file_ref); 101 } else if (test_type == "write_test") { 102 TestWrite(file_ref); 103 } else { 104 PostMessage("Unknown test type"); 105 } 106 } 107 108 void FilePassingInstance::TestRead(pp::FileRef file_ref) { 109 pp::FileIO file_io(pp::InstanceHandle(this)); 110 111 { 112 TestCompletionCallback callback(pp_instance(), PP_REQUIRED); 113 callback.WaitForResult( 114 file_io.Open(file_ref, PP_FILEOPENFLAG_READ, callback.GetCallback())); 115 if (callback.result() != PP_OK) { 116 PostMessage("Could not open file"); 117 return; 118 } 119 } 120 { 121 TestCompletionCallbackWithOutput<std::vector<char> > callback(pp_instance(), 122 PP_REQUIRED); 123 callback.WaitForResult( 124 file_io.Read(0, 1024, callback.GetCallback())); 125 if (callback.result() < 0) { 126 PostMessage("Could not read file"); 127 return; 128 } 129 130 if (callback.output().size() != 306) { 131 PostMessage("Read the wrong number of bytes"); 132 return; 133 } 134 } 135 PostMessage("read_success"); 136 } 137 138 void FilePassingInstance::TestWrite(pp::FileRef file_ref) { 139 pp::FileIO file_io(pp::InstanceHandle(this)); 140 TestCompletionCallback callback(pp_instance(), PP_REQUIRED); 141 callback.WaitForResult( 142 file_io.Open(file_ref, PP_FILEOPENFLAG_WRITE, callback.GetCallback())); 143 if (callback.result() != PP_ERROR_NOACCESS) { 144 PostMessage("Opening for write should have failed"); 145 return; 146 } 147 PostMessage("write_success"); 148 } 149 150 class FilePassingModule : public pp::Module { 151 public: 152 FilePassingModule() : pp::Module() {} 153 virtual ~FilePassingModule() {} 154 155 virtual pp::Instance* CreateInstance(PP_Instance instance) { 156 return new FilePassingInstance(instance); 157 } 158 }; 159 160 namespace pp { 161 162 Module* CreateModule() { 163 return new FilePassingModule(); 164 } 165 166 } // namespace pp 167