| // Copyright (c) 2012 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/proxy/serialized_flash_menu.h" | |
| #include <stdint.h> | |
| #include "ipc/ipc_message.h" | |
| #include "ppapi/c/private/ppb_flash_menu.h" | |
| #include "ppapi/proxy/ppapi_param_traits.h" | |
| namespace ppapi { | |
| namespace proxy { | |
| namespace { | |
| // Maximum depth of submenus allowed (e.g., 1 indicates that submenus are | |
| // allowed, but not sub-submenus). | |
| const int kMaxMenuDepth = 2; | |
| const uint32_t kMaxMenuEntries = 1000; | |
| bool CheckMenu(int depth, const PP_Flash_Menu* menu); | |
| void FreeMenu(const PP_Flash_Menu* menu); | |
| void WriteMenu(base::Pickle* m, const PP_Flash_Menu* menu); | |
| PP_Flash_Menu* ReadMenu(int depth, | |
| const base::Pickle* m, | |
| base::PickleIterator* iter); | |
| bool CheckMenuItem(int depth, const PP_Flash_MenuItem* item) { | |
| if (item->type == PP_FLASH_MENUITEM_TYPE_SUBMENU) | |
| return CheckMenu(depth, item->submenu); | |
| return true; | |
| } | |
| bool CheckMenu(int depth, const PP_Flash_Menu* menu) { | |
| if (depth > kMaxMenuDepth || !menu) | |
| return false; | |
| ++depth; | |
| if (menu->count && !menu->items) | |
| return false; | |
| for (uint32_t i = 0; i < menu->count; ++i) { | |
| if (!CheckMenuItem(depth, menu->items + i)) | |
| return false; | |
| } | |
| return true; | |
| } | |
| void WriteMenuItem(base::Pickle* m, const PP_Flash_MenuItem* menu_item) { | |
| PP_Flash_MenuItem_Type type = menu_item->type; | |
| m->WriteUInt32(type); | |
| m->WriteString(menu_item->name ? menu_item->name : ""); | |
| m->WriteInt(menu_item->id); | |
| IPC::WriteParam(m, menu_item->enabled); | |
| IPC::WriteParam(m, menu_item->checked); | |
| if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) | |
| WriteMenu(m, menu_item->submenu); | |
| } | |
| void WriteMenu(base::Pickle* m, const PP_Flash_Menu* menu) { | |
| m->WriteUInt32(menu->count); | |
| for (uint32_t i = 0; i < menu->count; ++i) | |
| WriteMenuItem(m, menu->items + i); | |
| } | |
| void FreeMenuItem(const PP_Flash_MenuItem* menu_item) { | |
| if (menu_item->name) | |
| delete [] menu_item->name; | |
| if (menu_item->submenu) | |
| FreeMenu(menu_item->submenu); | |
| } | |
| void FreeMenu(const PP_Flash_Menu* menu) { | |
| if (menu->items) { | |
| for (uint32_t i = 0; i < menu->count; ++i) | |
| FreeMenuItem(menu->items + i); | |
| delete [] menu->items; | |
| } | |
| delete menu; | |
| } | |
| bool ReadMenuItem(int depth, | |
| const base::Pickle* m, | |
| base::PickleIterator* iter, | |
| PP_Flash_MenuItem* menu_item) { | |
| uint32_t type; | |
| if (!iter->ReadUInt32(&type)) | |
| return false; | |
| if (type > PP_FLASH_MENUITEM_TYPE_SUBMENU) | |
| return false; | |
| menu_item->type = static_cast<PP_Flash_MenuItem_Type>(type); | |
| std::string name; | |
| if (!iter->ReadString(&name)) | |
| return false; | |
| menu_item->name = new char[name.size() + 1]; | |
| std::copy(name.begin(), name.end(), menu_item->name); | |
| menu_item->name[name.size()] = 0; | |
| if (!iter->ReadInt(&menu_item->id)) | |
| return false; | |
| if (!IPC::ReadParam(m, iter, &menu_item->enabled)) | |
| return false; | |
| if (!IPC::ReadParam(m, iter, &menu_item->checked)) | |
| return false; | |
| if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) { | |
| menu_item->submenu = ReadMenu(depth, m, iter); | |
| if (!menu_item->submenu) | |
| return false; | |
| } | |
| return true; | |
| } | |
| PP_Flash_Menu* ReadMenu(int depth, | |
| const base::Pickle* m, | |
| base::PickleIterator* iter) { | |
| if (depth > kMaxMenuDepth) | |
| return NULL; | |
| ++depth; | |
| PP_Flash_Menu* menu = new PP_Flash_Menu; | |
| menu->items = NULL; | |
| if (!iter->ReadUInt32(&menu->count)) { | |
| FreeMenu(menu); | |
| return NULL; | |
| } | |
| if (menu->count == 0) | |
| return menu; | |
| if (menu->count > kMaxMenuEntries) { | |
| FreeMenu(menu); | |
| return NULL; | |
| } | |
| menu->items = new PP_Flash_MenuItem[menu->count]; | |
| memset(menu->items, 0, sizeof(PP_Flash_MenuItem) * menu->count); | |
| for (uint32_t i = 0; i < menu->count; ++i) { | |
| if (!ReadMenuItem(depth, m, iter, menu->items + i)) { | |
| FreeMenu(menu); | |
| return NULL; | |
| } | |
| } | |
| return menu; | |
| } | |
| } // anonymous namespace | |
| SerializedFlashMenu::SerializedFlashMenu() | |
| : pp_menu_(NULL), | |
| own_menu_(false) { | |
| } | |
| SerializedFlashMenu::~SerializedFlashMenu() { | |
| if (own_menu_) | |
| FreeMenu(pp_menu_); | |
| } | |
| bool SerializedFlashMenu::SetPPMenu(const PP_Flash_Menu* menu) { | |
| DCHECK(!pp_menu_); | |
| if (!CheckMenu(0, menu)) | |
| return false; | |
| pp_menu_ = menu; | |
| own_menu_ = false; | |
| return true; | |
| } | |
| void SerializedFlashMenu::WriteToMessage(base::Pickle* m) const { | |
| WriteMenu(m, pp_menu_); | |
| } | |
| bool SerializedFlashMenu::ReadFromMessage(const base::Pickle* m, | |
| base::PickleIterator* iter) { | |
| DCHECK(!pp_menu_); | |
| pp_menu_ = ReadMenu(0, m, iter); | |
| if (!pp_menu_) | |
| return false; | |
| own_menu_ = true; | |
| return true; | |
| } | |
| } // namespace proxy | |
| } // namespace ppapi |