15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/utility/extensions/unpacker.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <set>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/files/file_enumerator.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/scoped_temp_dir.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/i18n/rtl.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_file_value_serializer.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/numerics/safe_conversions.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/common/chrome_utility_messages.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/common/extensions/api/i18n/default_locale_handler.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension_file_util.h"
226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/grit/generated_resources.h"
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/child/image_decoder_utils.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/common_param_traits.h"
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/constants.h"
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
27c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/common/extension_l10n_util.h"
28a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/common/file_util.h"
293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "extensions/common/manifest.h"
30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "extensions/common/manifest_constants.h"
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_message_utils.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/file_stream.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "third_party/zlib/google/zip.h"
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/l10n/l10n_util.h"
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "ui/gfx/size.h"
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace extensions {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace errors = manifest_errors;
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace keys = manifest_keys;
44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A limit to stop us passing dangerously large canvases to the browser.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMaxImageCanvas = 4096 * 4096;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)SkBitmap DecodeImage(const base::FilePath& path) {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read the file from disk.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string file_contents;
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::PathExists(path) ||
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      !base::ReadFileToString(path, &file_contents)) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SkBitmap();
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Decode the image using WebKit's image decoder.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const unsigned char* data =
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<const unsigned char*>(file_contents.data());
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  SkBitmap bitmap = content::DecodeImage(data,
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         gfx::Size(),
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         file_contents.length());
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (bitmap.computeSize64() > kMaxImageCanvas)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SkBitmap();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bitmap;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool PathContainsParentDirectory(const base::FilePath& path) {
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath::StringType kSeparators(base::FilePath::kSeparators);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath::StringType kParentDirectory(
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::FilePath::kParentDirectory);
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const size_t npos = base::FilePath::StringType::npos;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  const base::FilePath::StringType& value = path.value();
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (size_t i = 0; i < value.length(); ) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    i = value.find(kParentDirectory, i);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (i != npos) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if ((i == 0 || kSeparators.find(value[i-1]) == npos) &&
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          (i+1 < value.length() || kSeparators.find(value[i+1]) == npos)) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return true;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++i;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
88d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)bool WritePickle(const IPC::Message& pickle, const base::FilePath& dest_path) {
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  int size = base::checked_cast<int>(pickle.size());
90d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  const char* data = static_cast<const char*>(pickle.data());
91a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int bytes_written = base::WriteFile(dest_path, data, size);
92d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return (bytes_written == size);
93d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}  // namespace
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochstruct Unpacker::InternalData {
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DecodedImages decoded_images;
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch};
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Unpacker::Unpacker(const base::FilePath& extension_path,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   const std::string& extension_id,
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   Manifest::Location location,
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   int creation_flags)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : extension_path_(extension_path),
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_id_(extension_id),
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      location_(location),
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      creation_flags_(creation_flags) {
1097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  internal_data_.reset(new InternalData());
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Unpacker::~Unpacker() {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)base::DictionaryValue* Unpacker::ReadManifest() {
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath manifest_path =
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      temp_install_dir_.Append(kManifestFilename);
1187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::PathExists(manifest_path)) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetError(errors::kInvalidManifest);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JSONFileValueSerializer serializer(manifest_path);
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error;
1257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!root.get()) {
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetError(error);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (!root->IsType(base::Value::TYPE_DICTIONARY)) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetError(errors::kInvalidManifest);
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  return static_cast<base::DictionaryValue*>(root.release());
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Unpacker::ReadAllMessageCatalogs(const std::string& default_locale) {
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath locales_path =
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    temp_install_dir_.Append(kLocaleFolder);
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Not all folders under _locales have to be valid locales.
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  base::FileEnumerator locales(locales_path,
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                               false,
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                               base::FileEnumerator::DIRECTORIES);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::set<std::string> all_locales;
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension_l10n_util::GetAllLocales(&all_locales);
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath locale_path;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!(locale_path = locales.Next()).empty()) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (extension_l10n_util::ShouldSkipValidation(locales_path, locale_path,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  all_locales))
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath messages_path = locale_path.Append(kMessagesFilename);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ReadMessageCatalog(messages_path))
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Unpacker::Run() {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DVLOG(1) << "Installing extension " << extension_path_.value();
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // <profile>/Extensions/CRX_INSTALL
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  temp_install_dir_ =
170a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      extension_path_.DirName().AppendASCII(kTempExtensionName);
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!base::CreateDirectory(temp_install_dir_)) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetUTF16Error(
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        l10n_util::GetStringFUTF16(
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            IDS_EXTENSION_PACKAGE_DIRECTORY_ERROR,
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            base::i18n::GetDisplayStringInLTRDirectionality(
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                temp_install_dir_.LossyDisplayName())));
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!zip::Unzip(extension_path_, temp_install_dir_)) {
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetUTF16Error(l10n_util::GetStringUTF16(IDS_EXTENSION_PACKAGE_UNZIP_ERROR));
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse the manifest.
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parsed_manifest_.reset(ReadManifest());
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!parsed_manifest_.get())
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;  // Error was already reported.
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_refptr<Extension> extension(Extension::Create(
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      temp_install_dir_,
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      location_,
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *parsed_manifest_,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      creation_flags_,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extension_id_,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &error));
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!extension.get()) {
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetError(error);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<InstallWarning> warnings;
205a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (!file_util::ValidateExtension(extension.get(), &error, &warnings)) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetError(error);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extension->AddInstallWarnings(warnings);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Decode any images that the browser needs to display.
212c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::set<base::FilePath> image_paths =
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      extension_file_util::GetBrowserImagePaths(extension.get());
2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (std::set<base::FilePath>::iterator it = image_paths.begin();
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != image_paths.end();
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       ++it) {
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!AddDecodedImage(*it))
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;  // Error was already reported.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Parse all message catalogs (if any).
2227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  parsed_catalogs_.reset(new base::DictionaryValue);
223868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!LocaleInfo::GetDefaultLocale(extension.get()).empty()) {
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!ReadAllMessageCatalogs(LocaleInfo::GetDefaultLocale(extension.get())))
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;  // Error was already reported.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Unpacker::DumpImagesToFile() {
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC::Message pickle;  // We use a Message so we can use WriteParam.
2337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  IPC::WriteParam(&pickle, internal_data_->decoded_images);
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path = extension_path_.DirName().AppendASCII(
236a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      kDecodedImagesFilename);
237d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!WritePickle(pickle, path)) {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetError("Could not write image data to disk.");
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool Unpacker::DumpMessageCatalogsToFile() {
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC::Message pickle;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  IPC::WriteParam(&pickle, *parsed_catalogs_.get());
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath path = extension_path_.DirName().AppendASCII(
250a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch      kDecodedMessageCatalogsFilename);
251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (!WritePickle(pickle, path)) {
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetError("Could not write message catalogs to disk.");
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Unpacker::AddDecodedImage(const base::FilePath& path) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure it's not referencing a file outside the extension's subdir.
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (path.IsAbsolute() || PathContainsParentDirectory(path)) {
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetUTF16Error(
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        l10n_util::GetStringFUTF16(
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            IDS_EXTENSION_PACKAGE_IMAGE_PATH_ERROR,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            base::i18n::GetDisplayStringInLTRDirectionality(
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                path.LossyDisplayName())));
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path));
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (image_bitmap.isNull()) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetUTF16Error(
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        l10n_util::GetStringFUTF16(
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            IDS_EXTENSION_PACKAGE_IMAGE_ERROR,
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            base::i18n::GetDisplayStringInLTRDirectionality(
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                path.BaseName().LossyDisplayName())));
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  internal_data_->decoded_images.push_back(MakeTuple(image_bitmap, path));
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Unpacker::ReadMessageCatalog(const base::FilePath& message_path) {
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error;
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JSONFileValueSerializer serializer(message_path);
2877d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  scoped_ptr<base::DictionaryValue> root(static_cast<base::DictionaryValue*>(
2887d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      serializer.Deserialize(NULL, &error)));
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!root.get()) {
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    base::string16 messages_file = message_path.LossyDisplayName();
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (error.empty()) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If file is missing, Deserialize will fail with empty error.
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetError(base::StringPrintf("%s %s", errors::kLocalesMessagesFileMissing,
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  base::UTF16ToUTF8(messages_file).c_str()));
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetError(base::StringPrintf("%s: %s",
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  base::UTF16ToUTF8(messages_file).c_str(),
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  error.c_str()));
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath relative_path;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // message_path was created from temp_install_dir. This should never fail.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!temp_install_dir_.AppendRelativePath(message_path, &relative_path)) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string dir_name = relative_path.DirName().MaybeAsASCII();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (dir_name.empty()) {
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  parsed_catalogs_->Set(dir_name, root.release());
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void Unpacker::SetError(const std::string &error) {
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  SetUTF16Error(base::UTF8ToUTF16(error));
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void Unpacker::SetUTF16Error(const base::string16& error) {
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  error_message_ = error;
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
329