1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
28ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Use of this source code is governed by a BSD-style license that can be
38ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// found in the LICENSE file.
48ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
58ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension_unpacker.h"
68ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <set>
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
98ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "base/file_util.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_handle.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_temp_dir.h"
128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "base/string_util.h"
133f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "base/utf_string_conversions.h"
158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "base/values.h"
168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "net/base/file_stream.h"
178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension.h"
188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension_constants.h"
198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension_file_util.h"
208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/extensions/extension_l10n_util.h"
218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/url_constants.h"
228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "chrome/common/zip.h"
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/common_param_traits.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/json_value_serializer.h"
258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "ipc/ipc_message_utils.h"
268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "third_party/skia/include/core/SkBitmap.h"
278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#include "webkit/glue/image_decoder.h"
288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsennamespace errors = extension_manifest_errors;
308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsennamespace keys = extension_manifest_keys;
318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsennamespace filenames = extension_filenames;
328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsennamespace {
348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// Errors
368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenconst char* kCouldNotCreateDirectoryError =
378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    "Could not create directory for unzipping: ";
388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenconst char* kCouldNotDecodeImageError = "Could not decode theme image.";
398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenconst char* kCouldNotUnzipExtension = "Could not unzip extension.";
408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenconst char* kPathNamesMustBeAbsoluteOrLocalError =
418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    "Path names must not be absolute or contain '..'.";
428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// A limit to stop us passing dangerously large canvases to the browser.
448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenconst int kMaxImageCanvas = 4096 * 4096;
458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
468ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenSkBitmap DecodeImage(const FilePath& path) {
478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // Read the file from disk.
488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  std::string file_contents;
498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!file_util::PathExists(path) ||
508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      !file_util::ReadFileToString(path, &file_contents)) {
518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return SkBitmap();
528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // Decode the image using WebKit's image decoder.
558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  const unsigned char* data =
568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      reinterpret_cast<const unsigned char*>(file_contents.data());
578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  webkit_glue::ImageDecoder decoder;
588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  SkBitmap bitmap = decoder.Decode(data, file_contents.length());
598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  Sk64 bitmap_size = bitmap.getSize64();
608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!bitmap_size.is32() || bitmap_size.get32() > kMaxImageCanvas)
618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return SkBitmap();
628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return bitmap;
638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool PathContainsParentDirectory(const FilePath& path) {
668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  const FilePath::StringType kSeparators(FilePath::kSeparators);
678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  const FilePath::StringType kParentDirectory(FilePath::kParentDirectory);
688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  const size_t npos = FilePath::StringType::npos;
698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  const FilePath::StringType& value = path.value();
708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  for (size_t i = 0; i < value.length(); ) {
728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    i = value.find(kParentDirectory, i);
738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (i != npos) {
748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      if ((i == 0 || kSeparators.find(value[i-1]) == npos) &&
758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen          (i+1 < value.length() || kSeparators.find(value[i+1]) == npos)) {
768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen        return true;
778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      }
788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      ++i;
798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return false;
838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}  // namespace
868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
878ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenExtensionUnpacker::ExtensionUnpacker(const FilePath& extension_path)
888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    : extension_path_(extension_path) {
898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
918ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenExtensionUnpacker::~ExtensionUnpacker() {
928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
948ae428e0fb7feea16d79853f29447469a93bedffKristian MonsenDictionaryValue* ExtensionUnpacker::ReadManifest() {
958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  FilePath manifest_path =
968ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      temp_install_dir_.Append(Extension::kManifestFilename);
978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!file_util::PathExists(manifest_path)) {
988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError(errors::kInvalidManifest);
998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return NULL;
1008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  JSONFileValueSerializer serializer(manifest_path);
1038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  std::string error;
1048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
1058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!root.get()) {
1068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError(error);
1078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return NULL;
1088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!root->IsType(Value::TYPE_DICTIONARY)) {
1118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError(errors::kInvalidManifest);
1128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return NULL;
1138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return static_cast<DictionaryValue*>(root.release());
1168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
1178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool ExtensionUnpacker::ReadAllMessageCatalogs(
1198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    const std::string& default_locale) {
1208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  FilePath locales_path =
1218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    temp_install_dir_.Append(Extension::kLocaleFolder);
1228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // Not all folders under _locales have to be valid locales.
1248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  file_util::FileEnumerator locales(locales_path,
1258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen                                    false,
1268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen                                    file_util::FileEnumerator::DIRECTORIES);
1278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  std::set<std::string> all_locales;
1298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  extension_l10n_util::GetAllLocales(&all_locales);
1308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  FilePath locale_path;
1318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  while (!(locale_path = locales.Next()).empty()) {
1328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (extension_l10n_util::ShouldSkipValidation(locales_path, locale_path,
1338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen                                                  all_locales))
1348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      continue;
1358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    FilePath messages_path =
1378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      locale_path.Append(Extension::kMessagesFilename);
1388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (!ReadMessageCatalog(messages_path))
1408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      return false;
1418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return true;
1448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
1458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool ExtensionUnpacker::Run() {
147731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  VLOG(1) << "Installing extension " << extension_path_.value();
1488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // <profile>/Extensions/INSTALL_TEMP/<version>
1508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  temp_install_dir_ =
1518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    extension_path_.DirName().AppendASCII(filenames::kTempExtensionName);
1528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!file_util::CreateDirectory(temp_install_dir_)) {
1548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#if defined(OS_WIN)
1558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    std::string dir_string = WideToUTF8(temp_install_dir_.value());
1568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#else
1578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    std::string dir_string = temp_install_dir_.value();
1588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen#endif
1598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError(kCouldNotCreateDirectoryError + dir_string);
1618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
1628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!Unzip(extension_path_, temp_install_dir_)) {
1658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError(kCouldNotUnzipExtension);
1668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
1678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // Parse the manifest.
1708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  parsed_manifest_.reset(ReadManifest());
1718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!parsed_manifest_.get())
1728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;  // Error was already reported.
1738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // NOTE: Since the unpacker doesn't have the extension's public_id, the
1758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // InitFromValue is allowed to generate a temporary id for the extension.
1768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // ANY CODE THAT FOLLOWS SHOULD NOT DEPEND ON THE CORRECT ID OF THIS
1778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // EXTENSION.
1788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  std::string error;
179513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  scoped_refptr<Extension> extension(Extension::Create(
180dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      temp_install_dir_,
181dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      Extension::INVALID,
182dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      *parsed_manifest_,
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      Extension::NO_FLAGS,
184dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      &error));
185513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!extension.get()) {
1868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError(error);
1878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
1888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
190513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!extension_file_util::ValidateExtension(extension.get(), &error)) {
1918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError(error);
1928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
1938ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
1948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
1958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // Decode any images that the browser needs to display.
196513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  std::set<FilePath> image_paths = extension->GetBrowserImages();
1978ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  for (std::set<FilePath>::iterator it = image_paths.begin();
1988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen       it != image_paths.end(); ++it) {
1998ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (!AddDecodedImage(*it))
2008ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      return false;  // Error was already reported.
2018ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
2028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // Parse all message catalogs (if any).
2048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  parsed_catalogs_.reset(new DictionaryValue);
205513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch  if (!extension->default_locale().empty()) {
206513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (!ReadAllMessageCatalogs(extension->default_locale()))
2078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      return false;  // Error was already reported.
2088ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
2098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2108ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return true;
2118ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2138ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool ExtensionUnpacker::DumpImagesToFile() {
2148ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  IPC::Message pickle;  // We use a Message so we can use WriteParam.
2158ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  IPC::WriteParam(&pickle, decoded_images_);
2168ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2178ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  FilePath path = extension_path_.DirName().AppendASCII(
2188ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      filenames::kDecodedImagesFilename);
2198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
2208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen                            pickle.size())) {
2218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError("Could not write image data to disk.");
2228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
2238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
2248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return true;
2268ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2278ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2288ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool ExtensionUnpacker::DumpMessageCatalogsToFile() {
2298ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  IPC::Message pickle;
2308ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  IPC::WriteParam(&pickle, *parsed_catalogs_.get());
2318ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2328ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  FilePath path = extension_path_.DirName().AppendASCII(
2338ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      filenames::kDecodedMessageCatalogsFilename);
2348ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()),
2358ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen                            pickle.size())) {
2368ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError("Could not write message catalogs to disk.");
2378ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
2388ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
2398ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2408ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return true;
2418ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2428ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2438ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// static
2448ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool ExtensionUnpacker::ReadImagesFromFile(const FilePath& extension_path,
2458ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen                                           DecodedImages* images) {
2468ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  FilePath path = extension_path.AppendASCII(filenames::kDecodedImagesFilename);
2478ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  std::string file_str;
2488ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!file_util::ReadFileToString(path, &file_str))
2498ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
2508ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2518ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  IPC::Message pickle(file_str.data(), file_str.size());
2528ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  void* iter = NULL;
2538ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return IPC::ReadParam(&pickle, &iter, images);
2548ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2558ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2568ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen// static
2578ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool ExtensionUnpacker::ReadMessageCatalogsFromFile(
2588ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    const FilePath& extension_path, DictionaryValue* catalogs) {
2598ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  FilePath path = extension_path.AppendASCII(
2608ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      filenames::kDecodedMessageCatalogsFilename);
2618ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  std::string file_str;
2628ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!file_util::ReadFileToString(path, &file_str))
2638ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
2648ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2658ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  IPC::Message pickle(file_str.data(), file_str.size());
2668ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  void* iter = NULL;
2678ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return IPC::ReadParam(&pickle, &iter, catalogs);
2688ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2698ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2708ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool ExtensionUnpacker::AddDecodedImage(const FilePath& path) {
2718ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // Make sure it's not referencing a file outside the extension's subdir.
2728ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (path.IsAbsolute() || PathContainsParentDirectory(path)) {
2738ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError(kPathNamesMustBeAbsoluteOrLocalError);
2748ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
2758ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
2768ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2778ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path));
2788ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (image_bitmap.isNull()) {
2798ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    SetError(kCouldNotDecodeImageError);
2808ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
2818ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
2828ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2838ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  decoded_images_.push_back(MakeTuple(image_bitmap, path));
2848ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return true;
2858ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
2868ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
2878ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenbool ExtensionUnpacker::ReadMessageCatalog(const FilePath& message_path) {
2888ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  std::string error;
2898ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  JSONFileValueSerializer serializer(message_path);
2908ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  scoped_ptr<DictionaryValue> root(
2918ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      static_cast<DictionaryValue*>(serializer.Deserialize(NULL, &error)));
2928ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  if (!root.get()) {
293dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    string16 messages_file = message_path.LossyDisplayName();
2948ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    if (error.empty()) {
2958ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen      // If file is missing, Deserialize will fail with empty error.
296513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      SetError(base::StringPrintf("%s %s", errors::kLocalesMessagesFileMissing,
297dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  UTF16ToUTF8(messages_file).c_str()));
2988ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    } else {
299dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      SetError(base::StringPrintf("%s: %s",
300dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  UTF16ToUTF8(messages_file).c_str(),
301513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                  error.c_str()));
3028ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    }
3038ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    return false;
3048ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  }
3058ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3068ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  FilePath relative_path;
3078ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  // message_path was created from temp_install_dir. This should never fail.
308dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (!temp_install_dir_.AppendRelativePath(message_path, &relative_path)) {
3098ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen    NOTREACHED();
310dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
311dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
3128ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
313dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::string dir_name = relative_path.DirName().MaybeAsASCII();
314dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (dir_name.empty()) {
315dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    NOTREACHED();
316dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
317dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
318dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  parsed_catalogs_->Set(dir_name, root.release());
3198ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3208ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  return true;
3218ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
3228ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen
3238ae428e0fb7feea16d79853f29447469a93bedffKristian Monsenvoid ExtensionUnpacker::SetError(const std::string &error) {
3248ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen  error_message_ = error;
3258ae428e0fb7feea16d79853f29447469a93bedffKristian Monsen}
326