1// Copyright (c) 2012 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.
4
5#include "chrome/common/extensions/api/input_ime/input_components_handler.h"
6
7#include "base/memory/scoped_ptr.h"
8#include "base/strings/string_number_conversions.h"
9#include "base/strings/string_util.h"
10#include "base/strings/utf_string_conversions.h"
11#include "base/values.h"
12#include "chrome/common/extensions/manifest_url_handler.h"
13#include "extensions/common/error_utils.h"
14#include "extensions/common/extension.h"
15#include "extensions/common/manifest.h"
16#include "extensions/common/manifest_constants.h"
17
18namespace extensions {
19
20namespace keys = manifest_keys;
21namespace errors = manifest_errors;
22
23InputComponentInfo::InputComponentInfo()
24    : type(INPUT_COMPONENT_TYPE_NONE),
25      shortcut_alt(false),
26      shortcut_ctrl(false),
27      shortcut_shift(false) {
28}
29
30InputComponentInfo::~InputComponentInfo() {}
31
32InputComponents::InputComponents() {}
33InputComponents::~InputComponents() {}
34
35// static
36const std::vector<InputComponentInfo>* InputComponents::GetInputComponents(
37    const Extension* extension) {
38  InputComponents* info = static_cast<InputComponents*>(
39      extension->GetManifestData(keys::kInputComponents));
40  return info ? &info->input_components : NULL;
41}
42
43InputComponentsHandler::InputComponentsHandler() {
44}
45
46InputComponentsHandler::~InputComponentsHandler() {
47}
48
49bool InputComponentsHandler::Parse(Extension* extension,
50                                   base::string16* error) {
51  scoped_ptr<InputComponents> info(new InputComponents);
52  const base::ListValue* list_value = NULL;
53  if (!extension->manifest()->GetList(keys::kInputComponents, &list_value)) {
54    *error = base::ASCIIToUTF16(errors::kInvalidInputComponents);
55    return false;
56  }
57  for (size_t i = 0; i < list_value->GetSize(); ++i) {
58    const base::DictionaryValue* module_value = NULL;
59    std::string name_str;
60    InputComponentType type;
61    std::string id_str;
62    std::string description_str;
63    std::set<std::string> languages;
64    std::set<std::string> layouts;
65    std::string shortcut_keycode_str;
66    GURL input_view_url;
67    GURL options_page_url;
68    bool shortcut_alt = false;
69    bool shortcut_ctrl = false;
70    bool shortcut_shift = false;
71
72    if (!list_value->GetDictionary(i, &module_value)) {
73      *error = base::ASCIIToUTF16(errors::kInvalidInputComponents);
74      return false;
75    }
76
77    // Get input_components[i].name.
78    if (!module_value->GetString(keys::kName, &name_str)) {
79      *error = ErrorUtils::FormatErrorMessageUTF16(
80          errors::kInvalidInputComponentName,
81          base::IntToString(i));
82      return false;
83    }
84
85    // Get input_components[i].type.
86    std::string type_str;
87    if (module_value->GetString(keys::kType, &type_str)) {
88      if (type_str == "ime") {
89        type = INPUT_COMPONENT_TYPE_IME;
90      } else {
91        *error = ErrorUtils::FormatErrorMessageUTF16(
92            errors::kInvalidInputComponentType,
93            base::IntToString(i));
94        return false;
95      }
96    } else {
97      *error = ErrorUtils::FormatErrorMessageUTF16(
98          errors::kInvalidInputComponentType,
99          base::IntToString(i));
100      return false;
101    }
102
103    // Get input_components[i].id.
104    if (!module_value->GetString(keys::kId, &id_str)) {
105      id_str = "";
106    }
107
108    // Get input_components[i].description.
109    if (!module_value->GetString(keys::kDescription, &description_str)) {
110      *error = ErrorUtils::FormatErrorMessageUTF16(
111          errors::kInvalidInputComponentDescription,
112          base::IntToString(i));
113      return false;
114    }
115
116    // Get input_components[i].language.
117    // Both string and list of string are allowed to be compatibile with old
118    // input_ime manifest specification.
119    const base::Value* language_value = NULL;
120    if (module_value->Get(keys::kLanguage, &language_value)) {
121      if (language_value->GetType() == base::Value::TYPE_STRING) {
122        std::string language_str;
123        language_value->GetAsString(&language_str);
124        languages.insert(language_str);
125      } else if (language_value->GetType() == base::Value::TYPE_LIST) {
126        const base::ListValue* language_list = NULL;
127        language_value->GetAsList(&language_list);
128        for (size_t j = 0; j < language_list->GetSize(); ++j) {
129          std::string language_str;
130          if (language_list->GetString(j, &language_str))
131            languages.insert(language_str);
132        }
133      }
134    }
135
136    // Get input_components[i].layouts.
137    const base::ListValue* layouts_value = NULL;
138    if (module_value->GetList(keys::kLayouts, &layouts_value)) {
139      for (size_t j = 0; j < layouts_value->GetSize(); ++j) {
140        std::string layout_name_str;
141        if (!layouts_value->GetString(j, &layout_name_str)) {
142          *error = ErrorUtils::FormatErrorMessageUTF16(
143              errors::kInvalidInputComponentLayoutName,
144              base::IntToString(i), base::IntToString(j));
145          return false;
146        }
147        layouts.insert(layout_name_str);
148      }
149    }
150
151    if (module_value->HasKey(keys::kShortcutKey)) {
152      const base::DictionaryValue* shortcut_value = NULL;
153      if (!module_value->GetDictionary(keys::kShortcutKey,
154          &shortcut_value)) {
155        *error = ErrorUtils::FormatErrorMessageUTF16(
156            errors::kInvalidInputComponentShortcutKey,
157            base::IntToString(i));
158        return false;
159      }
160
161      // Get input_components[i].shortcut_keycode.
162      if (!shortcut_value->GetString(keys::kKeycode, &shortcut_keycode_str)) {
163        *error = ErrorUtils::FormatErrorMessageUTF16(
164            errors::kInvalidInputComponentShortcutKeycode,
165            base::IntToString(i));
166        return false;
167      }
168
169      // Get input_components[i].shortcut_alt.
170      if (!shortcut_value->GetBoolean(keys::kAltKey, &shortcut_alt)) {
171        shortcut_alt = false;
172      }
173
174      // Get input_components[i].shortcut_ctrl.
175      if (!shortcut_value->GetBoolean(keys::kCtrlKey, &shortcut_ctrl)) {
176        shortcut_ctrl = false;
177      }
178
179      // Get input_components[i].shortcut_shift.
180      if (!shortcut_value->GetBoolean(keys::kShiftKey, &shortcut_shift)) {
181        shortcut_shift = false;
182      }
183    }
184
185    // Get input_components[i].input_view_url.
186    // Note: 'input_view' is optional in manifest.
187    std::string input_view_str;
188    if (module_value->GetString(keys::kInputView, &input_view_str)) {
189      input_view_url = extension->GetResourceURL(input_view_str);
190      if (!input_view_url.is_valid()) {
191        *error = ErrorUtils::FormatErrorMessageUTF16(
192            errors::kInvalidInputView,
193            base::IntToString(i));
194        return false;
195      }
196    }
197
198    // Get input_components[i].options_page_url.
199    // Note: 'options_page' is optional in manifest.
200    std::string options_page_str;
201    if (module_value->GetString(keys::kImeOptionsPage, &options_page_str)) {
202      options_page_url = extension->GetResourceURL(options_page_str);
203      if (!options_page_url.is_valid()) {
204        *error = ErrorUtils::FormatErrorMessageUTF16(
205            errors::kInvalidOptionsPage,
206            base::IntToString(i));
207        return false;
208      }
209    } else {
210      // Fall back to extension's options page for backward compatibility.
211      options_page_url = extensions::ManifestURL::GetOptionsPage(extension);
212    }
213
214    info->input_components.push_back(InputComponentInfo());
215    info->input_components.back().name = name_str;
216    info->input_components.back().type = type;
217    info->input_components.back().id = id_str;
218    info->input_components.back().description = description_str;
219    info->input_components.back().languages = languages;
220    info->input_components.back().layouts.insert(layouts.begin(),
221        layouts.end());
222    info->input_components.back().shortcut_keycode = shortcut_keycode_str;
223    info->input_components.back().shortcut_alt = shortcut_alt;
224    info->input_components.back().shortcut_ctrl = shortcut_ctrl;
225    info->input_components.back().shortcut_shift = shortcut_shift;
226    info->input_components.back().options_page_url = options_page_url;
227    info->input_components.back().input_view_url = input_view_url;
228  }
229  extension->SetManifestData(keys::kInputComponents, info.release());
230  return true;
231}
232
233const std::vector<std::string>
234InputComponentsHandler::PrerequisiteKeys() const {
235  return SingleKey(keys::kOptionsPage);
236}
237
238const std::vector<std::string> InputComponentsHandler::Keys() const {
239  return SingleKey(keys::kInputComponents);
240}
241
242}  // namespace extensions
243