// 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 "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(IPC::Message* m, const PP_Flash_Menu* menu); PP_Flash_Menu* ReadMenu(int depth, const IPC::Message* m, 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(IPC::Message* 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::ParamTraits::Write(m, menu_item->enabled); IPC::ParamTraits::Write(m, menu_item->checked); if (type == PP_FLASH_MENUITEM_TYPE_SUBMENU) WriteMenu(m, menu_item->submenu); } void WriteMenu(IPC::Message* 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 IPC::Message* m, PickleIterator* iter, PP_Flash_MenuItem* menu_item) { uint32_t type; if (!m->ReadUInt32(iter, &type)) return false; if (type > PP_FLASH_MENUITEM_TYPE_SUBMENU) return false; menu_item->type = static_cast(type); std::string name; if (!m->ReadString(iter, &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 (!m->ReadInt(iter, &menu_item->id)) return false; if (!IPC::ParamTraits::Read(m, iter, &menu_item->enabled)) return false; if (!IPC::ParamTraits::Read(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 IPC::Message* m, PickleIterator* iter) { if (depth > kMaxMenuDepth) return NULL; ++depth; PP_Flash_Menu* menu = new PP_Flash_Menu; menu->items = NULL; if (!m->ReadUInt32(iter, &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(IPC::Message* m) const { WriteMenu(m, pp_menu_); } bool SerializedFlashMenu::ReadFromMessage(const IPC::Message* m, 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