12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/strings/string_number_conversions.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/error_utils.h"
123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "extensions/common/manifest_constants.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace extensions {
17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace keys = manifest_keys;
19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace errors = manifest_errors;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)struct TtsVoices : public Extension::ManifestData {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TtsVoices() {}
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~TtsVoices() {}
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<extensions::TtsVoice> voices;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
320f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)TtsVoice::TtsVoice() : remote(false) {}
330f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TtsVoice::~TtsVoice() {}
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<TtsVoice>* TtsVoice::GetTtsVoices(
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Extension* extension) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  TtsVoices* info = static_cast<TtsVoices*>(
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension->GetManifestData(keys::kTtsVoices));
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return info ? &info->voices : NULL;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TtsEngineManifestHandler::TtsEngineManifestHandler() {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TtsEngineManifestHandler::~TtsEngineManifestHandler() {
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool TtsEngineManifestHandler::Parse(Extension* extension,
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     base::string16* error) {
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<TtsVoices> info(new TtsVoices);
537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::DictionaryValue* tts_dict = NULL;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!extension->manifest()->GetDictionary(keys::kTtsEngine, &tts_dict)) {
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *error = base::ASCIIToUTF16(errors::kInvalidTts);
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!tts_dict->HasKey(keys::kTtsVoices))
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::ListValue* tts_voices = NULL;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    *error = base::ASCIIToUTF16(errors::kInvalidTtsVoices);
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (size_t i = 0; i < tts_voices->GetSize(); i++) {
697d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const base::DictionaryValue* one_tts_voice = NULL;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!tts_voices->GetDictionary(i, &one_tts_voice)) {
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      *error = base::ASCIIToUTF16(errors::kInvalidTtsVoices);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    TtsVoice voice_data;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (one_tts_voice->HasKey(keys::kTtsVoicesVoiceName)) {
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!one_tts_voice->GetString(
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              keys::kTtsVoicesVoiceName, &voice_data.voice_name)) {
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *error = base::ASCIIToUTF16(errors::kInvalidTtsVoicesVoiceName);
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (one_tts_voice->HasKey(keys::kTtsVoicesLang)) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!one_tts_voice->GetString(
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              keys::kTtsVoicesLang, &voice_data.lang) ||
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          !l10n_util::IsValidLocaleSyntax(voice_data.lang)) {
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *error = base::ASCIIToUTF16(errors::kInvalidTtsVoicesLang);
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (one_tts_voice->HasKey(keys::kTtsVoicesGender)) {
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!one_tts_voice->GetString(
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              keys::kTtsVoicesGender, &voice_data.gender) ||
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          (voice_data.gender != keys::kTtsGenderMale &&
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)           voice_data.gender != keys::kTtsGenderFemale)) {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *error = base::ASCIIToUTF16(errors::kInvalidTtsVoicesGender);
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1000f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    if (one_tts_voice->HasKey(keys::kTtsVoicesRemote)) {
1010f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      if (!one_tts_voice->GetBoolean(
1020f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)              keys::kTtsVoicesRemote, &voice_data.remote)) {
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *error = base::ASCIIToUTF16(errors::kInvalidTtsVoicesRemote);
1040f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        return false;
1050f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)      }
1060f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    }
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (one_tts_voice->HasKey(keys::kTtsVoicesEventTypes)) {
1087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      const base::ListValue* event_types_list;
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!one_tts_voice->GetList(
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              keys::kTtsVoicesEventTypes,
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)              &event_types_list)) {
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        *error = base::ASCIIToUTF16(
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            errors::kInvalidTtsVoicesEventTypes);
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      for (size_t i = 0; i < event_types_list->GetSize(); i++) {
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        std::string event_type;
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (!event_types_list->GetString(i, &event_type)) {
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          *error = base::ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return false;
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (event_type != keys::kTtsVoicesEventTypeEnd &&
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            event_type != keys::kTtsVoicesEventTypeError &&
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            event_type != keys::kTtsVoicesEventTypeMarker &&
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            event_type != keys::kTtsVoicesEventTypeSentence &&
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            event_type != keys::kTtsVoicesEventTypeStart &&
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            event_type != keys::kTtsVoicesEventTypeWord) {
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          *error = base::ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return false;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (voice_data.event_types.find(event_type) !=
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            voice_data.event_types.end()) {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          *error = base::ASCIIToUTF16(errors::kInvalidTtsVoicesEventTypes);
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          return false;
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        voice_data.event_types.insert(event_type);
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info->voices.push_back(voice_data);
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extension->SetManifestData(keys::kTtsVoices, info.release());
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<std::string> TtsEngineManifestHandler::Keys() const {
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return SingleKey(keys::kTtsEngine);
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
152