chrome: bluetooth: hook up the AdapterAdded signal
[chromium-blink-merge.git] / ppapi / proxy / ppb_flash_file_proxy.cc
blob08490535e2474069ee114122f5fdd40e44ee2d8f
1 // Copyright (c) 2011 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.
5 #include "ppapi/proxy/ppb_flash_file_proxy.h"
7 #include <map>
8 #include <set>
9 #include <vector>
11 #include "base/bind.h"
12 #include "base/logging.h"
13 #include "base/message_loop_proxy.h"
14 #include "base/synchronization/lock.h"
15 #include "base/synchronization/waitable_event.h"
16 #include "build/build_config.h"
17 #include "ipc/ipc_channel_proxy.h"
18 #include "ipc/ipc_message.h"
19 #include "ipc/ipc_sync_message.h"
20 #include "ppapi/c/pp_errors.h"
21 #include "ppapi/c/pp_file_info.h"
22 #include "ppapi/c/private/ppb_flash_file.h"
23 #include "ppapi/proxy/plugin_dispatcher.h"
24 #include "ppapi/proxy/ppapi_messages.h"
25 #include "ppapi/shared_impl/ppapi_globals.h"
26 #include "ppapi/shared_impl/resource.h"
27 #include "ppapi/shared_impl/resource_tracker.h"
29 namespace ppapi {
30 namespace proxy {
32 namespace {
34 // Given an error code and a handle result from a Pepper API call, converts to a
35 // PlatformFileForTransit by sharing with the other side, closing the original
36 // handle, possibly also updating the error value if an error occurred.
37 IPC::PlatformFileForTransit PlatformFileToPlatformFileForTransit(
38 Dispatcher* dispatcher,
39 int32_t* error,
40 base::PlatformFile file) {
41 if (*error != PP_OK)
42 return IPC::InvalidPlatformFileForTransit();
43 IPC::PlatformFileForTransit out_handle =
44 dispatcher->ShareHandleWithRemote(file, true);
45 if (out_handle == IPC::InvalidPlatformFileForTransit())
46 *error = PP_ERROR_NOACCESS;
47 return out_handle;
50 void FreeDirContents(PP_Instance /* instance */,
51 PP_DirContents_Dev* contents) {
52 for (int32_t i = 0; i < contents->count; ++i)
53 delete[] contents->entries[i].name;
54 delete[] contents->entries;
55 delete contents;
58 } // namespace
60 // ModuleLocalThreadAdapter ----------------------------------------------------
61 // TODO(yzshen): Refactor to use IPC::SyncMessageFilter.
62 class ModuleLocalThreadAdapter
63 : public base::RefCountedThreadSafe<ModuleLocalThreadAdapter> {
64 class Filter;
65 public:
66 ModuleLocalThreadAdapter();
68 void AddInstanceRouting(PP_Instance instance, Dispatcher* dispatcher);
69 void ClearInstanceRouting(PP_Instance instance);
70 void ClearFilter(Dispatcher* dispatcher, Filter* filter);
72 bool OnModuleLocalMessageReceived(const IPC::Message& msg);
74 // Called on the I/O thread when the channel is being destroyed and the
75 // given message will never be issued a reply.
76 void OnModuleLocalMessageFailed(int message_id);
78 bool Send(PP_Instance instance, IPC::Message* msg);
80 private:
81 class Filter : public IPC::ChannelProxy::MessageFilter {
82 public:
83 explicit Filter(Dispatcher* dispatcher);
84 ~Filter();
86 void Send(IPC::Message* msg);
88 virtual void OnFilterAdded(IPC::Channel* channel);
89 virtual void OnFilterRemoved();
90 virtual bool OnMessageReceived(const IPC::Message& message);
92 private:
93 // DO NOT DEREFERENCE! This is used only for tracking.
94 Dispatcher* dispatcher_;
96 IPC::Channel* channel_;
98 // Holds the IPC messages that were sent before the channel was connected.
99 // These will be sent ASAP.
100 std::vector<IPC::Message*> pre_connect_pending_messages_;
102 // Holds the IDs of the sync messages we're currently waiting on for this
103 // channel. This tracking allows us to cancel those requests if the
104 // remote process crashes and we're cleaning up this filter (without just
105 // deadlocking the waiting thread(s).
106 std::set<int> pending_requests_for_filter_;
109 void SendFromIOThread(Dispatcher* dispatcher, IPC::Message* msg);
111 // Internal version of OnModuleLocalMessageFailed which assumes the lock
112 // is already held.
113 void OnModuleLocalMessageFailedLocked(int message_id);
115 base::Lock lock_;
117 scoped_refptr<base::MessageLoopProxy> main_thread_;
119 // Will be NULL before an instance routing is added.
120 scoped_refptr<base::MessageLoopProxy> io_thread_;
122 typedef std::map<PP_Instance, Dispatcher*> InstanceToDispatcher;
123 InstanceToDispatcher instance_to_dispatcher_;
125 // The filters are owned by the channel.
126 typedef std::map<Dispatcher*, Filter*> DispatcherToFilter;
127 DispatcherToFilter dispatcher_to_filter_;
129 // Tracks all messages with currently waiting threads. This does not own
130 // the pointer, the pointer lifetime is managed by Send().
131 typedef std::map<int, IPC::PendingSyncMsg*> SyncRequestMap;
132 SyncRequestMap pending_sync_requests_;
135 ModuleLocalThreadAdapter* g_module_local_thread_adapter = NULL;
137 ModuleLocalThreadAdapter::Filter::Filter(Dispatcher* dispatcher)
138 : dispatcher_(dispatcher), channel_(NULL) {
141 ModuleLocalThreadAdapter::Filter::~Filter() {
144 void ModuleLocalThreadAdapter::Filter::Send(IPC::Message* msg) {
145 if (channel_) {
146 int message_id = IPC::SyncMessage::GetMessageId(*msg);
147 if (channel_->Send(msg))
148 pending_requests_for_filter_.insert(message_id);
149 else // Message lost, notify adapter so it can unblock.
150 g_module_local_thread_adapter->OnModuleLocalMessageFailed(message_id);
151 } else {
152 // No channel, save this message for when it's connected.
153 pre_connect_pending_messages_.push_back(msg);
157 void ModuleLocalThreadAdapter::Filter::OnFilterAdded(IPC::Channel* channel) {
158 DCHECK(!channel_);
159 channel_ = channel;
161 // Now that we have a channel, process all pending messages.
162 for (size_t i = 0; i < pre_connect_pending_messages_.size(); i++)
163 Send(pre_connect_pending_messages_[i]);
164 pre_connect_pending_messages_.clear();
167 void ModuleLocalThreadAdapter::Filter::OnFilterRemoved() {
168 DCHECK(channel_);
169 channel_ = NULL;
170 g_module_local_thread_adapter->ClearFilter(dispatcher_, this);
172 for (std::set<int>::iterator i = pending_requests_for_filter_.begin();
173 i != pending_requests_for_filter_.end(); ++i) {
174 g_module_local_thread_adapter->OnModuleLocalMessageFailed(*i);
178 bool ModuleLocalThreadAdapter::Filter::OnMessageReceived(
179 const IPC::Message& message) {
180 if (!message.is_reply() ||
181 message.routing_id() != API_ID_PPB_FLASH_FILE_MODULELOCAL)
182 return false;
184 if (g_module_local_thread_adapter->OnModuleLocalMessageReceived(message)) {
185 // The message was consumed, this means we can remove the message ID from
186 // the list of messages this channel is waiting on.
187 pending_requests_for_filter_.erase(IPC::SyncMessage::GetMessageId(message));
188 return true;
190 return false;
193 ModuleLocalThreadAdapter::ModuleLocalThreadAdapter()
194 : main_thread_(base::MessageLoopProxy::current()) {
197 void ModuleLocalThreadAdapter::AddInstanceRouting(PP_Instance instance,
198 Dispatcher* dispatcher) {
199 base::AutoLock lock(lock_);
201 // Now that we've had contact with a dispatcher, we can set up the IO thread.
202 DCHECK(main_thread_->BelongsToCurrentThread());
203 if (!io_thread_.get())
204 io_thread_ = dispatcher->GetIPCMessageLoop();
206 // Set up the instance -> dispatcher routing.
207 DCHECK(instance_to_dispatcher_.find(instance) ==
208 instance_to_dispatcher_.end());
209 instance_to_dispatcher_[instance] = dispatcher;
211 DispatcherToFilter::iterator found_filter =
212 dispatcher_to_filter_.find(dispatcher);
213 if (found_filter == dispatcher_to_filter_.end()) {
214 // Need to set up a filter for this dispatcher to intercept the messages.
215 Filter* filter = new Filter(dispatcher);
216 dispatcher_to_filter_[dispatcher] = filter;
217 dispatcher->AddIOThreadMessageFilter(filter);
221 void ModuleLocalThreadAdapter::ClearInstanceRouting(PP_Instance instance) {
222 // The dispatcher->filter mapping is cleaned up by ClearFilter which is
223 // initiated by the channel.
224 instance_to_dispatcher_.erase(instance);
227 void ModuleLocalThreadAdapter::ClearFilter(Dispatcher* dispatcher,
228 Filter* filter) {
229 // DANGER! Don't dereference the dispatcher, it's just used to identify
230 // which filter to remove. The dispatcher may not even exist any more.
232 // Since the dispatcher may be gone, there's a potential for ambiguity if
233 // another one is created on the main thread before this code runs on the
234 // I/O thread. So we check that the filter matches to avoid this rare case.
235 base::AutoLock lock(lock_);
236 if (dispatcher_to_filter_[dispatcher] == filter)
237 dispatcher_to_filter_.erase(dispatcher);
240 bool ModuleLocalThreadAdapter::OnModuleLocalMessageReceived(
241 const IPC::Message& msg) {
242 base::AutoLock lock(lock_);
244 int message_id = IPC::SyncMessage::GetMessageId(msg);
245 SyncRequestMap::iterator found = pending_sync_requests_.find(message_id);
246 if (found == pending_sync_requests_.end()) {
247 // Not waiting for this event. This will happen for sync messages to the
248 // main thread which use the "regular" sync channel code path.
249 return false;
252 IPC::PendingSyncMsg& info = *found->second;
254 if (!msg.is_reply_error())
255 info.deserializer->SerializeOutputParameters(msg);
256 info.done_event->Signal();
257 return true;
260 void ModuleLocalThreadAdapter::OnModuleLocalMessageFailed(int message_id) {
261 base::AutoLock lock(lock_);
262 OnModuleLocalMessageFailedLocked(message_id);
265 bool ModuleLocalThreadAdapter::Send(PP_Instance instance, IPC::Message* msg) {
266 // Compute the dispatcher corresponding to this message.
267 Dispatcher* dispatcher = NULL;
269 base::AutoLock lock(lock_);
270 InstanceToDispatcher::iterator found =
271 instance_to_dispatcher_.find(instance);
272 if (found == instance_to_dispatcher_.end()) {
273 NOTREACHED();
274 delete msg;
275 return false;
277 dispatcher = found->second;
280 if (main_thread_->BelongsToCurrentThread()) {
281 // Easy case: We're on the same thread as the dispatcher, so we don't need
282 // a lock to access it, and we can just use the normal sync channel stuff
283 // to handle the message. Actually, we MUST use the normal sync channel
284 // stuff since there may be incoming sync messages that need processing.
285 // The code below doesn't handle any nested message loops.
286 return dispatcher->Send(msg);
289 // Background thread case
290 // ----------------------
291 // 1. Generate tracking info, stick in pending_sync_messages_map.
292 // 2. Kick off the request. This is done on the I/O thread.
293 // 3. Filter on the I/O thread notices reply, writes the reply data and
294 // signals the event. We block on the event while this is happening.
295 // 4. Remove tracking info.
297 // Generate the tracking info. and copied
298 IPC::SyncMessage* sync_msg = static_cast<IPC::SyncMessage*>(msg);
299 int message_id = IPC::SyncMessage::GetMessageId(*sync_msg);
300 base::WaitableEvent event(true, false);
301 scoped_ptr<IPC::MessageReplyDeserializer> deserializer(
302 sync_msg->GetReplyDeserializer()); // We own this pointer once retrieved.
303 IPC::PendingSyncMsg info(message_id, deserializer.get(), &event);
305 // Add the tracking information to our map.
307 base::AutoLock lock(lock_);
308 pending_sync_requests_[message_id] = &info;
311 // This is a bit dangerous. We use the dispatcher pointer as the routing
312 // ID for this message. While we don't dereference it, there is an
313 // exceedingly remote possibility that while this is going to the background
314 // thread the connection will be shut down and a new one will be created with
315 // a dispatcher at the same address. It could potentially get sent to a
316 // random place, but it should actually still work (since the Flash file
317 // operations are global).
318 io_thread_->PostTask(FROM_HERE,
319 base::Bind(&ModuleLocalThreadAdapter::SendFromIOThread, this,
320 dispatcher, msg));
322 // Now we block the current thread waiting for the reply.
323 event.Wait();
326 // Clear our tracking info for this message now that we're done.
327 base::AutoLock lock(lock_);
328 DCHECK(pending_sync_requests_.find(message_id) !=
329 pending_sync_requests_.end());
330 pending_sync_requests_.erase(message_id);
333 return true;
336 void ModuleLocalThreadAdapter::SendFromIOThread(Dispatcher* dispatcher,
337 IPC::Message* msg) {
338 // DO NOT DEREFERENCE DISPATCHER. Used as a lookup only.
339 base::AutoLock lock(lock_);
340 DispatcherToFilter::iterator found = dispatcher_to_filter_.find(dispatcher);
342 // The dispatcher could have been destroyed by the time we got here since
343 // we're on another thread. Need to unblock the caller.
344 if (found == dispatcher_to_filter_.end()) {
345 OnModuleLocalMessageFailedLocked(IPC::SyncMessage::GetMessageId(*msg));
346 delete msg;
347 return;
350 // Takes ownership of pointer.
351 found->second->Send(msg);
354 void ModuleLocalThreadAdapter::OnModuleLocalMessageFailedLocked(
355 int message_id) {
356 lock_.AssertAcquired();
358 // Unblock the thread waiting for the message that will never come.
359 SyncRequestMap::iterator found = pending_sync_requests_.find(message_id);
360 if (found == pending_sync_requests_.end()) {
361 NOTREACHED();
362 return;
364 found->second->done_event->Signal();
367 // PPB_Flash_File_ModuleLocal --------------------------------------------------
369 namespace {
371 bool CreateThreadAdapterForInstance(PP_Instance instance) {
372 if (!g_module_local_thread_adapter) {
373 g_module_local_thread_adapter = new ModuleLocalThreadAdapter();
374 g_module_local_thread_adapter->AddRef(); // Leaked, this object is global.
377 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
378 if (!dispatcher) {
379 NOTREACHED();
380 return false;
382 g_module_local_thread_adapter->AddInstanceRouting(instance, dispatcher);
383 return true;
386 void ClearThreadAdapterForInstance(PP_Instance instance) {
387 if (g_module_local_thread_adapter)
388 g_module_local_thread_adapter->ClearInstanceRouting(instance);
391 int32_t OpenModuleLocalFile(PP_Instance instance,
392 const char* path,
393 int32_t mode,
394 PP_FileHandle* file) {
395 if (!g_module_local_thread_adapter)
396 return PP_ERROR_FAILED;
398 int32_t result = PP_ERROR_FAILED;
399 IPC::PlatformFileForTransit transit;
400 g_module_local_thread_adapter->Send(instance,
401 new PpapiHostMsg_PPBFlashFile_ModuleLocal_OpenFile(
402 API_ID_PPB_FLASH_FILE_MODULELOCAL,
403 instance, path, mode, &transit, &result));
404 *file = IPC::PlatformFileForTransitToPlatformFile(transit);
405 return result;
408 int32_t RenameModuleLocalFile(PP_Instance instance,
409 const char* from_path,
410 const char* to_path) {
411 if (!g_module_local_thread_adapter)
412 return PP_ERROR_FAILED;
414 int32_t result = PP_ERROR_FAILED;
415 g_module_local_thread_adapter->Send(instance,
416 new PpapiHostMsg_PPBFlashFile_ModuleLocal_RenameFile(
417 API_ID_PPB_FLASH_FILE_MODULELOCAL,
418 instance, from_path, to_path, &result));
419 return result;
422 int32_t DeleteModuleLocalFileOrDir(PP_Instance instance,
423 const char* path,
424 PP_Bool recursive) {
425 if (!g_module_local_thread_adapter)
426 return PP_ERROR_FAILED;
428 int32_t result = PP_ERROR_FAILED;
429 g_module_local_thread_adapter->Send(instance,
430 new PpapiHostMsg_PPBFlashFile_ModuleLocal_DeleteFileOrDir(
431 API_ID_PPB_FLASH_FILE_MODULELOCAL,
432 instance, path, recursive, &result));
433 return result;
436 int32_t CreateModuleLocalDir(PP_Instance instance, const char* path) {
437 if (!g_module_local_thread_adapter)
438 return PP_ERROR_FAILED;
440 int32_t result = PP_ERROR_FAILED;
441 g_module_local_thread_adapter->Send(instance,
442 new PpapiHostMsg_PPBFlashFile_ModuleLocal_CreateDir(
443 API_ID_PPB_FLASH_FILE_MODULELOCAL, instance, path, &result));
444 return result;
447 int32_t QueryModuleLocalFile(PP_Instance instance,
448 const char* path,
449 PP_FileInfo* info) {
450 if (!g_module_local_thread_adapter)
451 return PP_ERROR_FAILED;
453 int32_t result = PP_ERROR_FAILED;
454 g_module_local_thread_adapter->Send(instance,
455 new PpapiHostMsg_PPBFlashFile_ModuleLocal_QueryFile(
456 API_ID_PPB_FLASH_FILE_MODULELOCAL, instance, path,
457 info, &result));
458 return result;
461 int32_t GetModuleLocalDirContents(PP_Instance instance,
462 const char* path,
463 PP_DirContents_Dev** contents) {
464 if (!g_module_local_thread_adapter)
465 return PP_ERROR_FAILED;
467 int32_t result = PP_ERROR_FAILED;
468 std::vector<SerializedDirEntry> entries;
469 g_module_local_thread_adapter->Send(instance,
470 new PpapiHostMsg_PPBFlashFile_ModuleLocal_GetDirContents(
471 API_ID_PPB_FLASH_FILE_MODULELOCAL,
472 instance, path, &entries, &result));
474 if (result != PP_OK)
475 return result;
477 // Copy the serialized dir entries to the output struct.
478 *contents = new PP_DirContents_Dev;
479 (*contents)->count = static_cast<int32_t>(entries.size());
480 (*contents)->entries = new PP_DirEntry_Dev[entries.size()];
481 for (size_t i = 0; i < entries.size(); i++) {
482 const SerializedDirEntry& source = entries[i];
483 PP_DirEntry_Dev* dest = &(*contents)->entries[i];
485 char* name_copy = new char[source.name.size() + 1];
486 memcpy(name_copy, source.name.c_str(), source.name.size() + 1);
487 dest->name = name_copy;
488 dest->is_dir = PP_FromBool(source.is_dir);
491 return result;
494 const PPB_Flash_File_ModuleLocal flash_file_modulelocal_interface = {
495 &CreateThreadAdapterForInstance,
496 &ClearThreadAdapterForInstance,
497 &OpenModuleLocalFile,
498 &RenameModuleLocalFile,
499 &DeleteModuleLocalFileOrDir,
500 &CreateModuleLocalDir,
501 &QueryModuleLocalFile,
502 &GetModuleLocalDirContents,
503 &FreeDirContents,
506 InterfaceProxy* CreateFlashFileModuleLocalProxy(Dispatcher* dispatcher) {
507 return new PPB_Flash_File_ModuleLocal_Proxy(dispatcher);
510 } // namespace
512 PPB_Flash_File_ModuleLocal_Proxy::PPB_Flash_File_ModuleLocal_Proxy(
513 Dispatcher* dispatcher)
514 : InterfaceProxy(dispatcher),
515 ppb_flash_file_module_local_impl_(NULL) {
516 if (!dispatcher->IsPlugin()) {
517 ppb_flash_file_module_local_impl_ =
518 static_cast<const PPB_Flash_File_ModuleLocal*>(
519 dispatcher->local_get_interface()(
520 PPB_FLASH_FILE_MODULELOCAL_INTERFACE));
524 PPB_Flash_File_ModuleLocal_Proxy::~PPB_Flash_File_ModuleLocal_Proxy() {
527 // static
528 const PPB_Flash_File_ModuleLocal*
529 PPB_Flash_File_ModuleLocal_Proxy::GetInterface() {
530 return &flash_file_modulelocal_interface;
533 bool PPB_Flash_File_ModuleLocal_Proxy::OnMessageReceived(
534 const IPC::Message& msg) {
535 bool handled = true;
536 IPC_BEGIN_MESSAGE_MAP(PPB_Flash_File_ModuleLocal_Proxy, msg)
537 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_OpenFile,
538 OnMsgOpenFile)
539 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_RenameFile,
540 OnMsgRenameFile)
541 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_DeleteFileOrDir,
542 OnMsgDeleteFileOrDir)
543 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_CreateDir,
544 OnMsgCreateDir)
545 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_QueryFile,
546 OnMsgQueryFile)
547 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_ModuleLocal_GetDirContents,
548 OnMsgGetDirContents)
549 IPC_MESSAGE_UNHANDLED(handled = false)
550 IPC_END_MESSAGE_MAP()
551 // TODO(brettw) handle bad messages!
552 return handled;
555 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgOpenFile(
556 PP_Instance instance,
557 const std::string& path,
558 int32_t mode,
559 IPC::PlatformFileForTransit* file_handle,
560 int32_t* result) {
561 base::PlatformFile file;
562 *result = ppb_flash_file_module_local_impl_->OpenFile(
563 instance, path.c_str(), mode, &file);
564 *file_handle = PlatformFileToPlatformFileForTransit(
565 dispatcher(), result, file);
568 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgRenameFile(
569 PP_Instance instance,
570 const std::string& from_path,
571 const std::string& to_path,
572 int32_t* result) {
573 *result = ppb_flash_file_module_local_impl_->RenameFile(
574 instance, from_path.c_str(), to_path.c_str());
577 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgDeleteFileOrDir(
578 PP_Instance instance,
579 const std::string& path,
580 PP_Bool recursive,
581 int32_t* result) {
582 *result = ppb_flash_file_module_local_impl_->DeleteFileOrDir(
583 instance, path.c_str(), recursive);
586 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgCreateDir(PP_Instance instance,
587 const std::string& path,
588 int32_t* result) {
589 *result = ppb_flash_file_module_local_impl_->CreateDir(
590 instance, path.c_str());
593 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgQueryFile(PP_Instance instance,
594 const std::string& path,
595 PP_FileInfo* info,
596 int32_t* result) {
597 *result = ppb_flash_file_module_local_impl_->QueryFile(
598 instance, path.c_str(), info);
601 void PPB_Flash_File_ModuleLocal_Proxy::OnMsgGetDirContents(
602 PP_Instance instance,
603 const std::string& path,
604 std::vector<SerializedDirEntry>* entries,
605 int32_t* result) {
606 PP_DirContents_Dev* contents = NULL;
607 *result = ppb_flash_file_module_local_impl_->GetDirContents(
608 instance, path.c_str(), &contents);
609 if (*result != PP_OK)
610 return;
612 // Convert the list of entries to the serialized version.
613 entries->resize(contents->count);
614 for (int32_t i = 0; i < contents->count; i++) {
615 (*entries)[i].name.assign(contents->entries[i].name);
616 (*entries)[i].is_dir = PP_ToBool(contents->entries[i].is_dir);
618 ppb_flash_file_module_local_impl_->FreeDirContents(instance, contents);
621 // PPB_Flash_File_FileRef ------------------------------------------------------
623 namespace {
625 int32_t OpenFileRefFile(PP_Resource file_ref_id,
626 int32_t mode,
627 PP_FileHandle* file) {
628 Resource* file_ref =
629 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_ref_id);
630 if (!file_ref)
631 return PP_ERROR_BADRESOURCE;
633 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(file_ref);
634 if (!dispatcher)
635 return PP_ERROR_BADARGUMENT;
637 int32_t result = PP_ERROR_FAILED;
638 IPC::PlatformFileForTransit transit;
639 dispatcher->Send(new PpapiHostMsg_PPBFlashFile_FileRef_OpenFile(
640 API_ID_PPB_FLASH_FILE_FILEREF,
641 file_ref->host_resource(), mode, &transit, &result));
642 *file = IPC::PlatformFileForTransitToPlatformFile(transit);
643 return result;
646 int32_t QueryFileRefFile(PP_Resource file_ref_id,
647 PP_FileInfo* info) {
648 Resource* file_ref =
649 PpapiGlobals::Get()->GetResourceTracker()->GetResource(file_ref_id);
650 if (!file_ref)
651 return PP_ERROR_BADRESOURCE;
653 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(file_ref);
654 if (!dispatcher)
655 return PP_ERROR_BADARGUMENT;
657 int32_t result = PP_ERROR_FAILED;
658 dispatcher->Send(new PpapiHostMsg_PPBFlashFile_FileRef_QueryFile(
659 API_ID_PPB_FLASH_FILE_FILEREF,
660 file_ref->host_resource(), info, &result));
661 return result;
664 const PPB_Flash_File_FileRef flash_file_fileref_interface = {
665 &OpenFileRefFile,
666 &QueryFileRefFile,
669 InterfaceProxy* CreateFlashFileFileRefProxy(Dispatcher* dispatcher) {
670 return new PPB_Flash_File_FileRef_Proxy(dispatcher);
673 } // namespace
675 PPB_Flash_File_FileRef_Proxy::PPB_Flash_File_FileRef_Proxy(
676 Dispatcher* dispatcher)
677 : InterfaceProxy(dispatcher),
678 ppb_flash_file_fileref_impl_(NULL) {
679 if (!dispatcher->IsPlugin()) {
680 ppb_flash_file_fileref_impl_ = static_cast<const PPB_Flash_File_FileRef*>(
681 dispatcher->local_get_interface()(PPB_FLASH_FILE_FILEREF_INTERFACE));
685 PPB_Flash_File_FileRef_Proxy::~PPB_Flash_File_FileRef_Proxy() {
688 // static
689 const PPB_Flash_File_FileRef* PPB_Flash_File_FileRef_Proxy::GetInterface() {
690 return &flash_file_fileref_interface;
693 bool PPB_Flash_File_FileRef_Proxy::OnMessageReceived(
694 const IPC::Message& msg) {
695 bool handled = true;
696 IPC_BEGIN_MESSAGE_MAP(PPB_Flash_File_FileRef_Proxy, msg)
697 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_FileRef_OpenFile,
698 OnMsgOpenFile)
699 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBFlashFile_FileRef_QueryFile,
700 OnMsgQueryFile)
701 IPC_MESSAGE_UNHANDLED(handled = false)
702 IPC_END_MESSAGE_MAP()
703 // TODO(brettw) handle bad messages!
704 return handled;
707 void PPB_Flash_File_FileRef_Proxy::OnMsgOpenFile(
708 const HostResource& host_resource,
709 int32_t mode,
710 IPC::PlatformFileForTransit* file_handle,
711 int32_t* result) {
712 base::PlatformFile file;
713 *result = ppb_flash_file_fileref_impl_->OpenFile(
714 host_resource.host_resource(), mode, &file);
715 *file_handle = PlatformFileToPlatformFileForTransit(
716 dispatcher(), result, file);
719 void PPB_Flash_File_FileRef_Proxy::OnMsgQueryFile(
720 const HostResource& host_resource,
721 PP_FileInfo* info,
722 int32_t* result) {
723 *result = ppb_flash_file_fileref_impl_->QueryFile(
724 host_resource.host_resource(), info);
727 } // namespace proxy
728 } // namespace ppapi