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/file_handlers/file_handlers_parser.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 "chrome/common/extensions/extension_manifest_constants.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/manifest.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/error_utils.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace keys = extension_manifest_keys;
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace extensions {
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlerInfo::FileHandlerInfo() {}
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlerInfo::~FileHandlerInfo() {}
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlers::FileHandlers() {}
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlers::~FileHandlers() {}
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<FileHandlerInfo>* FileHandlers::GetFileHandlers(
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const Extension* extension) {
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FileHandlers* info = static_cast<FileHandlers*>(
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      extension->GetManifestData(extension_manifest_keys::kFileHandlers));
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return info ? &info->file_handlers : NULL;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlersParser::FileHandlersParser() {
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)FileHandlersParser::~FileHandlersParser() {
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool LoadFileHandler(const std::string& handler_id,
407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                     const base::DictionaryValue& handler_info,
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     std::vector<FileHandlerInfo>* file_handlers,
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     string16* error) {
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(error);
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FileHandlerInfo handler;
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  handler.id = handler_id;
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::ListValue* mime_types = NULL;
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (handler_info.HasKey(keys::kFileHandlerTypes) &&
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !handler_info.GetList(keys::kFileHandlerTypes, &mime_types)) {
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *error = ErrorUtils::FormatErrorMessageUTF16(
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extension_manifest_errors::kInvalidFileHandlerType, handler_id);
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
567d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::ListValue* file_extensions = NULL;
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (handler_info.HasKey(keys::kFileHandlerExtensions) &&
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      !handler_info.GetList(keys::kFileHandlerExtensions, &file_extensions)) {
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *error = ErrorUtils::FormatErrorMessageUTF16(
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        extension_manifest_errors::kInvalidFileHandlerExtension, handler_id);
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if ((!mime_types || mime_types->GetSize() == 0) &&
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      (!file_extensions || file_extensions->GetSize() == 0)) {
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    *error = ErrorUtils::FormatErrorMessageUTF16(
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        extension_manifest_errors::kInvalidFileHandlerNoTypeOrExtension,
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        handler_id);
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return false;
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (handler_info.HasKey(keys::kFileHandlerTitle) &&
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      !handler_info.GetString(keys::kFileHandlerTitle, &handler.title)) {
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *error = ASCIIToUTF16(extension_manifest_errors::kInvalidFileHandlerTitle);
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (mime_types) {
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string type;
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (size_t i = 0; i < mime_types->GetSize(); ++i) {
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!mime_types->GetString(i, &type)) {
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        *error = ErrorUtils::FormatErrorMessageUTF16(
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            extension_manifest_errors::kInvalidFileHandlerTypeElement,
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            handler_id,
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            std::string(base::IntToString(i)));
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      handler.types.insert(type);
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (file_extensions) {
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string file_extension;
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (size_t i = 0; i < file_extensions->GetSize(); ++i) {
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (!file_extensions->GetString(i, &file_extension)) {
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        *error = ErrorUtils::FormatErrorMessageUTF16(
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            extension_manifest_errors::kInvalidFileHandlerExtensionElement,
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            handler_id,
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            std::string(base::IntToString(i)));
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      handler.extensions.insert(file_extension);
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  file_handlers->push_back(handler);
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool FileHandlersParser::Parse(Extension* extension, string16* error) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<FileHandlers> info(new FileHandlers);
1127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  const base::DictionaryValue* all_handlers = NULL;
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!extension->manifest()->GetDictionary(keys::kFileHandlers,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                            &all_handlers)) {
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *error = ASCIIToUTF16(extension_manifest_errors::kInvalidFileHandlers);
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(extension->is_platform_app());
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  for (base::DictionaryValue::Iterator iter(*all_handlers); !iter.IsAtEnd();
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       iter.Advance()) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // A file handler entry is a title and a list of MIME types to handle.
1247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const base::DictionaryValue* handler = NULL;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (iter.value().GetAsDictionary(&handler)) {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (!LoadFileHandler(iter.key(), *handler, &info->file_handlers, error))
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *error = ASCIIToUTF16(extension_manifest_errors::kInvalidFileHandlers);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extension->SetManifestData(keys::kFileHandlers, info.release());
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::vector<std::string> FileHandlersParser::Keys() const {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return SingleKey(keys::kFileHandlers);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace extensions
143