diff options
author | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-08 21:02:32 +0000 |
---|---|---|
committer | brettw@chromium.org <brettw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-12-08 21:02:32 +0000 |
commit | 4f95dd7ca9883879dc642c2f61cff2edad412b38 (patch) | |
tree | 48daa9a31f86f5029ebe4e33ca5255e3436cd596 /ppapi/shared_impl | |
parent | 7b0d86deed914f1dcf5d206259699b5f692c6d3c (diff) | |
download | chromium_src-4f95dd7ca9883879dc642c2f61cff2edad412b38.zip chromium_src-4f95dd7ca9883879dc642c2f61cff2edad412b38.tar.gz chromium_src-4f95dd7ca9883879dc642c2f61cff2edad412b38.tar.bz2 |
Implement a proxy for Pepper FileIO.
This splits apart the old in-process implementation into a new object in shared_impl that does most of the general tracking. This alllows that code to be shared by the proxy.
BUG=http://crbug.com/101154
Review URL: http://codereview.chromium.org/8764003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113656 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi/shared_impl')
-rw-r--r-- | ppapi/shared_impl/api_id.h | 1 | ||||
-rw-r--r-- | ppapi/shared_impl/file_type_conversion.cc | 74 | ||||
-rw-r--r-- | ppapi/shared_impl/file_type_conversion.h | 23 | ||||
-rw-r--r-- | ppapi/shared_impl/ppb_file_io_shared.cc | 237 | ||||
-rw-r--r-- | ppapi/shared_impl/ppb_file_io_shared.h | 157 |
5 files changed, 492 insertions, 0 deletions
diff --git a/ppapi/shared_impl/api_id.h b/ppapi/shared_impl/api_id.h index c8c9362..73654b0 100644 --- a/ppapi/shared_impl/api_id.h +++ b/ppapi/shared_impl/api_id.h @@ -21,6 +21,7 @@ enum ApiID { API_ID_PPB_CORE, API_ID_PPB_CURSORCONTROL, API_ID_PPB_FILE_CHOOSER, + API_ID_PPB_FILE_IO, API_ID_PPB_FILE_REF, API_ID_PPB_FILE_SYSTEM, API_ID_PPB_FLASH, diff --git a/ppapi/shared_impl/file_type_conversion.cc b/ppapi/shared_impl/file_type_conversion.cc new file mode 100644 index 0000000..a9bd435 --- /dev/null +++ b/ppapi/shared_impl/file_type_conversion.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/shared_impl/file_type_conversion.h" + +#include "ppapi/c/pp_errors.h" +#include "ppapi/c/ppb_file_io.h" + +namespace ppapi { + +int PlatformFileErrorToPepperError(base::PlatformFileError error_code) { + switch (error_code) { + case base::PLATFORM_FILE_OK: + return PP_OK; + case base::PLATFORM_FILE_ERROR_EXISTS: + return PP_ERROR_FILEEXISTS; + case base::PLATFORM_FILE_ERROR_NOT_FOUND: + return PP_ERROR_FILENOTFOUND; + case base::PLATFORM_FILE_ERROR_ACCESS_DENIED: + case base::PLATFORM_FILE_ERROR_SECURITY: + return PP_ERROR_NOACCESS; + case base::PLATFORM_FILE_ERROR_NO_MEMORY: + return PP_ERROR_NOMEMORY; + case base::PLATFORM_FILE_ERROR_NO_SPACE: + return PP_ERROR_NOSPACE; + case base::PLATFORM_FILE_ERROR_NOT_A_DIRECTORY: + return PP_ERROR_FAILED; + default: + return PP_ERROR_FAILED; + } +} + +bool PepperFileOpenFlagsToPlatformFileFlags(int32_t pp_open_flags, + int* flags_out) { + if (!flags_out) + return false; + + bool pp_read = !!(pp_open_flags & PP_FILEOPENFLAG_READ); + bool pp_write = !!(pp_open_flags & PP_FILEOPENFLAG_WRITE); + bool pp_create = !!(pp_open_flags & PP_FILEOPENFLAG_CREATE); + bool pp_truncate = !!(pp_open_flags & PP_FILEOPENFLAG_TRUNCATE); + bool pp_exclusive = !!(pp_open_flags & PP_FILEOPENFLAG_EXCLUSIVE); + + int flags = 0; + if (pp_read) + flags |= base::PLATFORM_FILE_READ; + if (pp_write) { + flags |= base::PLATFORM_FILE_WRITE; + flags |= base::PLATFORM_FILE_WRITE_ATTRIBUTES; + } + + if (pp_truncate && !pp_write) + return false; + + if (pp_create) { + if (pp_exclusive) { + flags |= base::PLATFORM_FILE_CREATE; + } else if (pp_truncate) { + flags |= base::PLATFORM_FILE_CREATE_ALWAYS; + } else { + flags |= base::PLATFORM_FILE_OPEN_ALWAYS; + } + } else if (pp_truncate) { + flags |= base::PLATFORM_FILE_OPEN_TRUNCATED; + } else { + flags |= base::PLATFORM_FILE_OPEN; + } + + *flags_out = flags; + return true; +} + +} // namespace ppapi diff --git a/ppapi/shared_impl/file_type_conversion.h b/ppapi/shared_impl/file_type_conversion.h new file mode 100644 index 0000000..3ecd404 --- /dev/null +++ b/ppapi/shared_impl/file_type_conversion.h @@ -0,0 +1,23 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_SHARED_IMPL_FILE_TYPE_CONVERSION_H_ +#define PPAPI_SHARED_IMPL_FILE_TYPE_CONVERSION_H_ + +#include "base/platform_file.h" +#include "ppapi/c/pp_stdint.h" + +namespace ppapi { + +int PlatformFileErrorToPepperError(base::PlatformFileError error_code); + +// Converts a PP_FileOpenFlags_Dev flag combination into a corresponding +// PlatformFileFlags flag combination. +// Returns |true| if okay. +bool PepperFileOpenFlagsToPlatformFileFlags(int32_t pp_open_flags, + int* flags_out); + +} // namespace ppapi + +#endif // PPAPI_SHARED_IMPL_FILE_TYPE_CONVERSION_H_ diff --git a/ppapi/shared_impl/ppb_file_io_shared.cc b/ppapi/shared_impl/ppb_file_io_shared.cc new file mode 100644 index 0000000..a51c33f --- /dev/null +++ b/ppapi/shared_impl/ppb_file_io_shared.cc @@ -0,0 +1,237 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ppapi/shared_impl/ppb_file_io_shared.h" + +#include <string.h> + +#include "base/bind.h" +#include "base/logging.h" +#include "base/message_loop.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/shared_impl/file_type_conversion.h" +#include "ppapi/shared_impl/time_conversion.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_file_ref_api.h" + +namespace ppapi { + +using thunk::EnterResourceNoLock; +using thunk::PPB_FileIO_API; +using thunk::PPB_FileRef_API; + +PPB_FileIO_Shared::CallbackEntry::CallbackEntry() + : read_buffer(NULL), + info(NULL) { +} + +PPB_FileIO_Shared::CallbackEntry::CallbackEntry(const CallbackEntry& entry) + : callback(entry.callback), + read_buffer(entry.read_buffer), + info(entry.info) { +} + +PPB_FileIO_Shared::CallbackEntry::~CallbackEntry() { +} + +PPB_FileIO_Shared::PPB_FileIO_Shared(PP_Instance instance) + : Resource(instance), + file_system_type_(PP_FILESYSTEMTYPE_INVALID), + file_open_(false), + pending_op_(OPERATION_NONE) { +} + +PPB_FileIO_Shared::PPB_FileIO_Shared(const HostResource& host_resource) + : Resource(host_resource), + file_system_type_(PP_FILESYSTEMTYPE_INVALID), + file_open_(false), + pending_op_(OPERATION_NONE) { +} + +PPB_FileIO_Shared::~PPB_FileIO_Shared() { + // The callbacks list should have been cleared by LastPluginRefWasDeleted. + DCHECK(callbacks_.empty()); +} + +void PPB_FileIO_Shared::LastPluginRefWasDeleted() { + // Abort all pending callbacks. Do this by posting a task to avoid reentering + // the plugin's Release() call that probably deleted this object. + for (size_t i = 0; i < callbacks_.size(); i++) { + MessageLoop::current()->PostTask(FROM_HERE, base::Bind( + callbacks_[i].callback.func, callbacks_[i].callback.user_data, + static_cast<int32_t>(PP_ERROR_ABORTED))); + } + callbacks_.erase(callbacks_.begin(), callbacks_.end()); +} + +thunk::PPB_FileIO_API* PPB_FileIO_Shared::AsPPB_FileIO_API() { + return this; +} + +int32_t PPB_FileIO_Shared::Open(PP_Resource file_ref, + int32_t open_flags, + PP_CompletionCallback callback) { + EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, true); + if (enter.failed()) + return PP_ERROR_BADRESOURCE; + + int32_t rv = CommonCallValidation(false, OPERATION_EXCLUSIVE, callback); + if (rv != PP_OK) + return rv; + + PP_FileSystemType type = enter.object()->GetFileSystemType(); + if (type != PP_FILESYSTEMTYPE_LOCALPERSISTENT && + type != PP_FILESYSTEMTYPE_LOCALTEMPORARY && + type != PP_FILESYSTEMTYPE_EXTERNAL) + return PP_ERROR_FAILED; + file_system_type_ = type; + + return OpenValidated(file_ref, enter.object(), open_flags, callback); +} + +int32_t PPB_FileIO_Shared::Query(PP_FileInfo* info, + PP_CompletionCallback callback) { + int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); + if (rv != PP_OK) + return rv; + if (!info) + return PP_ERROR_BADARGUMENT; + return QueryValidated(info, callback); +} + +int32_t PPB_FileIO_Shared::Touch(PP_Time last_access_time, + PP_Time last_modified_time, + PP_CompletionCallback callback) { + int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); + if (rv != PP_OK) + return rv; + return TouchValidated(last_access_time, last_modified_time, callback); +} + +int32_t PPB_FileIO_Shared::Read(int64_t offset, + char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) { + int32_t rv = CommonCallValidation(true, OPERATION_READ, callback); + if (rv != PP_OK) + return rv; + return ReadValidated(offset, buffer, bytes_to_read, callback); +} + +int32_t PPB_FileIO_Shared::Write(int64_t offset, + const char* buffer, + int32_t bytes_to_write, + PP_CompletionCallback callback) { + int32_t rv = CommonCallValidation(true, OPERATION_WRITE, callback); + if (rv != PP_OK) + return rv; + return WriteValidated(offset, buffer, bytes_to_write, callback); +} + +int32_t PPB_FileIO_Shared::SetLength(int64_t length, + PP_CompletionCallback callback) { + int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); + if (rv != PP_OK) + return rv; + return SetLengthValidated(length, callback); +} + +int32_t PPB_FileIO_Shared::Flush(PP_CompletionCallback callback) { + int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); + if (rv != PP_OK) + return rv; + return FlushValidated(callback); +} + +void PPB_FileIO_Shared::ExecuteGeneralCallback(int32_t pp_error) { + RunAndRemoveFirstPendingCallback(pp_error); +} + +void PPB_FileIO_Shared::ExecuteOpenFileCallback(int32_t pp_error) { + if (pp_error == PP_OK) + file_open_ = true; + ExecuteGeneralCallback(pp_error); +} + +void PPB_FileIO_Shared::ExecuteQueryCallback(int32_t pp_error, + const PP_FileInfo& info) { + if (pending_op_ != OPERATION_EXCLUSIVE || callbacks_.empty() || + !callbacks_.front().info) { + NOTREACHED(); + return; + } + *callbacks_.front().info = info; + RunAndRemoveFirstPendingCallback(pp_error); +} + +void PPB_FileIO_Shared::ExecuteReadCallback(int32_t pp_error, + const char* data) { + if (pending_op_ != OPERATION_READ || callbacks_.empty()) { + NOTREACHED(); + return; + } + + char* read_buffer = callbacks_.front().read_buffer; + DCHECK(data); + DCHECK(read_buffer); + + // The result code contains the number of bytes if it's positive. + if (pp_error > 0) + memcpy(read_buffer, data, pp_error); + RunAndRemoveFirstPendingCallback(pp_error); +} + +int32_t PPB_FileIO_Shared::CommonCallValidation( + bool should_be_open, + OperationType new_op, + PP_CompletionCallback callback) { + // Only asynchronous operation is supported. + if (!callback.func) + return PP_ERROR_BLOCKS_MAIN_THREAD; + + if (should_be_open) { + if (!file_open_) + return PP_ERROR_FAILED; + } else { + if (file_open_) + return PP_ERROR_FAILED; + } + + if (pending_op_ != OPERATION_NONE && + (pending_op_ != new_op || pending_op_ == OPERATION_EXCLUSIVE)) { + return PP_ERROR_INPROGRESS; + } + + return PP_OK; +} + +void PPB_FileIO_Shared::RegisterCallback(OperationType op, + PP_CompletionCallback callback, + char* read_buffer, + PP_FileInfo* info) { + DCHECK(callback.func); + DCHECK(pending_op_ == OPERATION_NONE || + (pending_op_ != OPERATION_EXCLUSIVE && pending_op_ == op)); + + CallbackEntry entry; + entry.callback = callback; + entry.read_buffer = read_buffer; + entry.info = info; + callbacks_.push_back(entry); + + pending_op_ = op; +} + +void PPB_FileIO_Shared::RunAndRemoveFirstPendingCallback(int32_t result) { + DCHECK(!callbacks_.empty()); + + CallbackEntry front = callbacks_.front(); + callbacks_.pop_front(); + if (callbacks_.empty()) + pending_op_ = OPERATION_NONE; + + PP_RunCompletionCallback(&front.callback, result); +} + +} // namespace ppapi diff --git a/ppapi/shared_impl/ppb_file_io_shared.h b/ppapi/shared_impl/ppb_file_io_shared.h new file mode 100644 index 0000000..341db46 --- /dev/null +++ b/ppapi/shared_impl/ppb_file_io_shared.h @@ -0,0 +1,157 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_SHARED_IMPL_PPB_FILE_IO_SHARED_H_ +#define PPAPI_SHARED_IMPL_PPB_FILE_IO_SHARED_H_ + +#include <deque> + +#include "base/compiler_specific.h" +#include "ppapi/shared_impl/ppapi_shared_export.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/thunk/ppb_file_io_api.h" + +namespace ppapi { + +namespace thunk { +class PPB_FileRef_API; +} + +class PPAPI_SHARED_EXPORT PPB_FileIO_Shared : public Resource, + public thunk::PPB_FileIO_API { + public: + PPB_FileIO_Shared(PP_Instance instance); + PPB_FileIO_Shared(const HostResource& host_resource); + ~PPB_FileIO_Shared(); + + // Resource overrides. + virtual void LastPluginRefWasDeleted() OVERRIDE; + virtual thunk::PPB_FileIO_API* AsPPB_FileIO_API() OVERRIDE; + + // PPB_FileIO_API implementation. + virtual int32_t Open(PP_Resource file_ref, + int32_t open_flags, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Query(PP_FileInfo* info, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Touch(PP_Time last_access_time, + PP_Time last_modified_time, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Read(int64_t offset, + char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Write(int64_t offset, + const char* buffer, + int32_t bytes_to_write, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t SetLength(int64_t length, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Flush(PP_CompletionCallback callback) OVERRIDE; + + // Callback handler for different types of operations. + void ExecuteGeneralCallback(int32_t pp_error); + void ExecuteOpenFileCallback(int32_t pp_error); + void ExecuteQueryCallback(int32_t pp_error, const PP_FileInfo& info); + void ExecuteReadCallback(int32_t pp_error, const char* data); + + protected: + struct CallbackEntry { + CallbackEntry(); + CallbackEntry(const CallbackEntry& entry); + ~CallbackEntry(); + + PP_CompletionCallback callback; + + // Pointer back to the caller's read buffer; only used by |Read()|, NULL + // for non-read operations. Not owned. + char* read_buffer; + + // Pointer back to the caller's PP_FileInfo structure for Query operations. + // NULL for non-query operations. Not owned. + PP_FileInfo* info; + }; + + enum OperationType { + // There is no pending operation right now. + OPERATION_NONE, + + // If there are pending reads, any other kind of async operation is not + // allowed. + OPERATION_READ, + + // If there are pending writes, any other kind of async operation is not + // allowed. + OPERATION_WRITE, + + // If there is a pending operation that is neither read nor write, no + // further async operation is allowed. + OPERATION_EXCLUSIVE + }; + + // Validated versions of the FileIO API. Subclasses in the proxy and impl + // implement these so the common error checking stays here. + virtual int32_t OpenValidated(PP_Resource file_ref_resource, + thunk::PPB_FileRef_API* file_ref_api, + int32_t open_flags, + PP_CompletionCallback callback) = 0; + virtual int32_t QueryValidated(PP_FileInfo* info, + PP_CompletionCallback callback) = 0; + virtual int32_t TouchValidated(PP_Time last_access_time, + PP_Time last_modified_time, + PP_CompletionCallback callback) = 0; + virtual int32_t ReadValidated(int64_t offset, + char* buffer, + int32_t bytes_to_read, + PP_CompletionCallback callback) = 0; + virtual int32_t WriteValidated(int64_t offset, + const char* buffer, + int32_t bytes_to_write, + PP_CompletionCallback callback) = 0; + virtual int32_t SetLengthValidated(int64_t length, + PP_CompletionCallback callback) = 0; + virtual int32_t FlushValidated(PP_CompletionCallback callback) = 0; + + // Called for every "Validated" function. + // + // This verifies that the callback is valid and that no callback is already + // pending, or it is a read(write) request and currently the pending + // operations are reads(writes). + // + // Returns |PP_OK| to indicate that everything is valid or |PP_ERROR_...| if + // the call should be aborted and that code returned to the plugin. + int32_t CommonCallValidation(bool should_be_open, + OperationType new_op, + PP_CompletionCallback callback); + + // Sets up a pending callback. This should only be called once it is certain + // that |PP_OK_COMPLETIONPENDING| will be returned. + // + // |read_buffer| is only used by read operations, |info| is used only by + // query operations. + void RegisterCallback(OperationType op, + PP_CompletionCallback callback, + char* read_buffer, + PP_FileInfo* info); + + // Pops the oldest callback from the queue and runs it. + void RunAndRemoveFirstPendingCallback(int32_t result); + + // The file system type specified in the Open() call. This will be + // PP_FILESYSTEMTYPE_INVALID before open was called. This value does not + // indicate that the open command actually succeeded. + PP_FileSystemType file_system_type_; + + // Set to true when the file has been successfully opened. + bool file_open_; + + std::deque<CallbackEntry> callbacks_; + OperationType pending_op_; + + DISALLOW_COPY_AND_ASSIGN(PPB_FileIO_Shared); +}; + +} // namespace ppapi + +#endif // PPAPI_SHARED_IMPL_PPB_FILE_IO_SHARED_H_ |