| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/common/extensions/extension_unpacker.h" | 5 #include "chrome/common/extensions/extension_unpacker.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/scoped_handle.h" | 8 #include "base/scoped_handle.h" |
| 9 #include "base/scoped_temp_dir.h" | 9 #include "base/scoped_temp_dir.h" |
| 10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
| 11 #include "base/thread.h" | 11 #include "base/thread.h" |
| 12 #include "base/values.h" | 12 #include "base/values.h" |
| 13 #include "net/base/file_stream.h" | 13 #include "net/base/file_stream.h" |
| 14 #include "chrome/browser/extensions/extension_file_util.h" | 14 #include "chrome/browser/extensions/extension_file_util.h" |
| 15 #include "chrome/common/common_param_traits.h" | 15 #include "chrome/common/common_param_traits.h" |
| 16 #include "chrome/common/extensions/extension.h" | 16 #include "chrome/common/extensions/extension.h" |
| 17 #include "chrome/common/extensions/extension_constants.h" | 17 #include "chrome/common/extensions/extension_constants.h" |
| 18 #include "chrome/common/json_value_serializer.h" | 18 #include "chrome/common/json_value_serializer.h" |
| 19 #include "chrome/common/notification_service.h" | 19 #include "chrome/common/notification_service.h" |
| 20 #include "chrome/common/url_constants.h" | 20 #include "chrome/common/url_constants.h" |
| 21 #include "chrome/common/zip.h" | 21 #include "chrome/common/zip.h" |
| 22 #include "ipc/ipc_message_utils.h" | 22 #include "ipc/ipc_message_utils.h" |
| 23 #include "third_party/skia/include/core/SkBitmap.h" | 23 #include "third_party/skia/include/core/SkBitmap.h" |
| 24 #include "webkit/glue/image_decoder.h" | 24 #include "webkit/glue/image_decoder.h" |
| 25 | 25 |
| 26 namespace errors = extension_manifest_errors; |
| 27 namespace keys = extension_manifest_keys; |
| 28 |
| 26 namespace { | 29 namespace { |
| 27 // The name of a temporary directory to install an extension into for | 30 // The name of a temporary directory to install an extension into for |
| 28 // validation before finalizing install. | 31 // validation before finalizing install. |
| 29 const char kTempExtensionName[] = "TEMP_INSTALL"; | 32 const char kTempExtensionName[] = "TEMP_INSTALL"; |
| 30 | 33 |
| 31 // The file to write our decoded images to, relative to the extension_path. | 34 // The file to write our decoded images to, relative to the extension_path. |
| 32 const char kDecodedImagesFilename[] = "DECODED_IMAGES"; | 35 const char kDecodedImagesFilename[] = "DECODED_IMAGES"; |
| 33 | 36 |
| 34 // Errors | 37 // Errors |
| 35 const char* kCouldNotCreateDirectoryError = | 38 const char* kCouldNotCreateDirectoryError = |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 } | 83 } |
| 81 } | 84 } |
| 82 | 85 |
| 83 return false; | 86 return false; |
| 84 } | 87 } |
| 85 | 88 |
| 86 DictionaryValue* ExtensionUnpacker::ReadManifest() { | 89 DictionaryValue* ExtensionUnpacker::ReadManifest() { |
| 87 FilePath manifest_path = | 90 FilePath manifest_path = |
| 88 temp_install_dir_.AppendASCII(Extension::kManifestFilename); | 91 temp_install_dir_.AppendASCII(Extension::kManifestFilename); |
| 89 if (!file_util::PathExists(manifest_path)) { | 92 if (!file_util::PathExists(manifest_path)) { |
| 90 SetError(extension_manifest_errors::kInvalidManifest); | 93 SetError(errors::kInvalidManifest); |
| 91 return NULL; | 94 return NULL; |
| 92 } | 95 } |
| 93 | 96 |
| 94 JSONFileValueSerializer serializer(manifest_path); | 97 JSONFileValueSerializer serializer(manifest_path); |
| 95 std::string error; | 98 std::string error; |
| 96 scoped_ptr<Value> root(serializer.Deserialize(&error)); | 99 scoped_ptr<Value> root(serializer.Deserialize(&error)); |
| 97 if (!root.get()) { | 100 if (!root.get()) { |
| 98 SetError(error); | 101 SetError(error); |
| 99 return NULL; | 102 return NULL; |
| 100 } | 103 } |
| 101 | 104 |
| 102 if (!root->IsType(Value::TYPE_DICTIONARY)) { | 105 if (!root->IsType(Value::TYPE_DICTIONARY)) { |
| 103 SetError(extension_manifest_errors::kInvalidManifest); | 106 SetError(errors::kInvalidManifest); |
| 104 return NULL; | 107 return NULL; |
| 105 } | 108 } |
| 106 | 109 |
| 107 return static_cast<DictionaryValue*>(root.release()); | 110 return static_cast<DictionaryValue*>(root.release()); |
| 108 } | 111 } |
| 109 | 112 |
| 113 bool ExtensionUnpacker::ReadAllMessageCatalogs( |
| 114 const std::string& default_locale) { |
| 115 FilePath locales_path = |
| 116 temp_install_dir_.AppendASCII(Extension::kLocaleFolder); |
| 117 |
| 118 // Treat all folders under _locales as valid locales. |
| 119 file_util::FileEnumerator locales(locales_path, |
| 120 false, |
| 121 file_util::FileEnumerator::DIRECTORIES); |
| 122 |
| 123 FilePath locale_path = locales.Next(); |
| 124 do { |
| 125 // Since we use this string as a key in a DictionaryValue, be paranoid about |
| 126 // skipping any strings with '.'. This happens sometimes, for example with |
| 127 // '.svn' directories. |
| 128 FilePath relative_path; |
| 129 // message_path was created from temp_install_dir. This should never fail. |
| 130 if (!temp_install_dir_.AppendRelativePath(locale_path, &relative_path)) |
| 131 NOTREACHED(); |
| 132 std::wstring subdir(relative_path.ToWStringHack()); |
| 133 if (std::find(subdir.begin(), subdir.end(), L'.') != subdir.end()) |
| 134 continue; |
| 135 |
| 136 FilePath messages_path = |
| 137 locale_path.AppendASCII(Extension::kMessagesFilename); |
| 138 |
| 139 if (!ReadMessageCatalog(messages_path)) |
| 140 return false; |
| 141 } while (!(locale_path = locales.Next()).empty()); |
| 142 |
| 143 return true; |
| 144 } |
| 145 |
| 110 bool ExtensionUnpacker::Run() { | 146 bool ExtensionUnpacker::Run() { |
| 111 LOG(INFO) << "Installing extension " << extension_path_.value(); | 147 LOG(INFO) << "Installing extension " << extension_path_.value(); |
| 112 | 148 |
| 113 // <profile>/Extensions/INSTALL_TEMP/<version> | 149 // <profile>/Extensions/INSTALL_TEMP/<version> |
| 114 temp_install_dir_ = | 150 temp_install_dir_ = |
| 115 extension_path_.DirName().AppendASCII(kTempExtensionName); | 151 extension_path_.DirName().AppendASCII(kTempExtensionName); |
| 116 if (!file_util::CreateDirectory(temp_install_dir_)) { | 152 if (!file_util::CreateDirectory(temp_install_dir_)) { |
| 117 SetError(kCouldNotCreateDirectoryError); | 153 SetError(kCouldNotCreateDirectoryError); |
| 118 return false; | 154 return false; |
| 119 } | 155 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 147 } | 183 } |
| 148 | 184 |
| 149 // Decode any images that the browser needs to display. | 185 // Decode any images that the browser needs to display. |
| 150 std::set<FilePath> image_paths = extension.GetBrowserImages(); | 186 std::set<FilePath> image_paths = extension.GetBrowserImages(); |
| 151 for (std::set<FilePath>::iterator it = image_paths.begin(); | 187 for (std::set<FilePath>::iterator it = image_paths.begin(); |
| 152 it != image_paths.end(); ++it) { | 188 it != image_paths.end(); ++it) { |
| 153 if (!AddDecodedImage(*it)) | 189 if (!AddDecodedImage(*it)) |
| 154 return false; // Error was already reported. | 190 return false; // Error was already reported. |
| 155 } | 191 } |
| 156 | 192 |
| 193 // Parse all message catalogs (if any). |
| 194 parsed_catalogs_.reset(new DictionaryValue); |
| 195 if (!extension.default_locale().empty()) { |
| 196 if (!ReadAllMessageCatalogs(extension.default_locale())) |
| 197 return false; // Error was already reported. |
| 198 } |
| 199 |
| 157 return true; | 200 return true; |
| 158 } | 201 } |
| 159 | 202 |
| 160 bool ExtensionUnpacker::DumpImagesToFile() { | 203 bool ExtensionUnpacker::DumpImagesToFile() { |
| 161 IPC::Message pickle; // We use a Message so we can use WriteParam. | 204 IPC::Message pickle; // We use a Message so we can use WriteParam. |
| 162 IPC::WriteParam(&pickle, decoded_images_); | 205 IPC::WriteParam(&pickle, decoded_images_); |
| 163 | 206 |
| 164 FilePath path = extension_path_.DirName().AppendASCII(kDecodedImagesFilename); | 207 FilePath path = extension_path_.DirName().AppendASCII(kDecodedImagesFilename); |
| 165 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()), | 208 if (!file_util::WriteFile(path, static_cast<const char*>(pickle.data()), |
| 166 pickle.size())) { | 209 pickle.size())) { |
| (...skipping 27 matching lines...) Expand all Loading... |
| 194 SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path)); | 237 SkBitmap image_bitmap = DecodeImage(temp_install_dir_.Append(path)); |
| 195 if (image_bitmap.isNull()) { | 238 if (image_bitmap.isNull()) { |
| 196 SetError(kCouldNotDecodeImageError); | 239 SetError(kCouldNotDecodeImageError); |
| 197 return false; | 240 return false; |
| 198 } | 241 } |
| 199 | 242 |
| 200 decoded_images_.push_back(MakeTuple(image_bitmap, path)); | 243 decoded_images_.push_back(MakeTuple(image_bitmap, path)); |
| 201 return true; | 244 return true; |
| 202 } | 245 } |
| 203 | 246 |
| 247 bool ExtensionUnpacker::ReadMessageCatalog(const FilePath& message_path) { |
| 248 std::string error; |
| 249 JSONFileValueSerializer serializer(message_path); |
| 250 DictionaryValue* root = |
| 251 static_cast<DictionaryValue*>(serializer.Deserialize(&error)); |
| 252 if (!root) { |
| 253 std::string messages_file = WideToASCII(message_path.ToWStringHack()); |
| 254 if (error.empty()) { |
| 255 // If file is missing, Deserialize will fail with empty error. |
| 256 SetError(StringPrintf("%s %s", errors::kLocalesMessagesFileMissing, |
| 257 messages_file.c_str())); |
| 258 } else { |
| 259 SetError(StringPrintf("%s: %s", messages_file.c_str(), error.c_str())); |
| 260 } |
| 261 return false; |
| 262 } |
| 263 |
| 264 FilePath relative_path; |
| 265 // message_path was created from temp_install_dir. This should never fail. |
| 266 if (!temp_install_dir_.AppendRelativePath(message_path, &relative_path)) |
| 267 NOTREACHED(); |
| 268 |
| 269 parsed_catalogs_->Set(relative_path.DirName().ToWStringHack(), root); |
| 270 |
| 271 return true; |
| 272 } |
| 273 |
| 204 void ExtensionUnpacker::SetError(const std::string &error) { | 274 void ExtensionUnpacker::SetError(const std::string &error) { |
| 205 error_message_ = error; | 275 error_message_ = error; |
| 206 } | 276 } |
| OLD | NEW |