Chromium Code Reviews| Index: ppapi/shared_impl/file_io_impl.cc |
| diff --git a/ppapi/shared_impl/file_io_impl.cc b/ppapi/shared_impl/file_io_impl.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..075349ce3b8428070ffb2b80de869de28aef8f58 |
| --- /dev/null |
| +++ b/ppapi/shared_impl/file_io_impl.cc |
| @@ -0,0 +1,232 @@ |
| +// 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_io_impl.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; |
| + |
| +FileIOImpl::CallbackEntry::CallbackEntry() |
| + : read_buffer(NULL), |
| + info(NULL) { |
| +} |
| + |
| +FileIOImpl::CallbackEntry::CallbackEntry(const CallbackEntry& entry) |
| + : callback(entry.callback), |
| + read_buffer(entry.read_buffer), |
| + info(entry.info) { |
| +} |
| + |
| +FileIOImpl::CallbackEntry::~CallbackEntry() { |
| +} |
| + |
| +FileIOImpl::FileIOImpl(PP_Instance instance) |
| + : Resource(instance), |
| + file_system_type_(PP_FILESYSTEMTYPE_INVALID), |
| + file_open_(false), |
| + pending_op_(OPERATION_NONE) { |
| +} |
| + |
| +FileIOImpl::FileIOImpl(const HostResource& host_resource) |
| + : Resource(host_resource), |
| + file_system_type_(PP_FILESYSTEMTYPE_INVALID), |
| + file_open_(false), |
| + pending_op_(OPERATION_NONE) { |
| +} |
| + |
| +FileIOImpl::~FileIOImpl() { |
| + // The callbacks list should have been cleared by LastPluginRefWasDeleted. |
| + DCHECK(callbacks_.empty()); |
| +} |
| + |
| +void FileIOImpl::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* FileIOImpl::AsPPB_FileIO_API() { |
| + return this; |
| +} |
| + |
| +int32_t FileIOImpl::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 FileIOImpl::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 FileIOImpl::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 FileIOImpl::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 FileIOImpl::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 FileIOImpl::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 FileIOImpl::Flush(PP_CompletionCallback callback) { |
| + int32_t rv = CommonCallValidation(true, OPERATION_EXCLUSIVE, callback); |
| + if (rv != PP_OK) |
| + return rv; |
| + return FlushValidated(callback); |
| +} |
| + |
| +void FileIOImpl::ExecuteGeneralCallback(int32_t pp_error) { |
| + RunAndRemoveFirstPendingCallback(pp_error); |
| +} |
| + |
| +void FileIOImpl::ExecuteOpenFileCallback(int32_t pp_error) { |
| + if (pp_error == PP_OK) |
| + file_open_ = true; |
| + ExecuteGeneralCallback(pp_error); |
| +} |
| + |
| +void FileIOImpl::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 FileIOImpl::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); |
|
viettrungluu
2011/11/30 23:44:42
include string.h
|
| + RunAndRemoveFirstPendingCallback(pp_error); |
|
viettrungluu
2011/11/30 23:44:42
How do you know you're running the right callback?
brettw
2011/12/01 18:50:15
I don't know. The existing backend worked like thi
yzshen1
2011/12/01 19:01:51
When I wrote this method, I went over the logic to
|
| +} |
| + |
| +int32_t FileIOImpl::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 FileIOImpl::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 FileIOImpl::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 |