diff --git a/atom.gyp b/atom.gyp index a01d89fa9c7d..826248c54d37 100644 --- a/atom.gyp +++ b/atom.gyp @@ -216,6 +216,8 @@ 'atom/common/api/object_life_monitor.h', 'atom/common/asar/archive.cc', 'atom/common/asar/archive.h', + 'atom/common/asar/asar_util.cc', + 'atom/common/asar/asar_util.h', 'atom/common/asar/scoped_temporary_file.cc', 'atom/common/asar/scoped_temporary_file.h', 'atom/common/common_message_generator.cc', diff --git a/atom/browser/net/asar/asar_protocol_handler.cc b/atom/browser/net/asar/asar_protocol_handler.cc index b2c16b896e1a..0daa6f427e8f 100644 --- a/atom/browser/net/asar/asar_protocol_handler.cc +++ b/atom/browser/net/asar/asar_protocol_handler.cc @@ -6,6 +6,7 @@ #include "atom/browser/net/asar/url_request_asar_job.h" #include "atom/common/asar/archive.h" +#include "atom/common/asar/asar_util.h" #include "net/base/filename_util.h" #include "net/base/net_errors.h" #include "net/url_request/url_request_error_job.h" @@ -13,35 +14,6 @@ namespace asar { -namespace { - -const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar"); - -// Get the relative path in asar archive. -bool GetAsarPath(const base::FilePath& full_path, - base::FilePath* asar_path, - base::FilePath* relative_path) { - base::FilePath iter = full_path; - while (true) { - base::FilePath dirname = iter.DirName(); - if (iter.MatchesExtension(kAsarExtension)) - break; - else if (iter == dirname) - return false; - iter = dirname; - } - - base::FilePath tail; - if (!iter.AppendRelativePath(full_path, &tail)) - return false; - - *asar_path = iter; - *relative_path = tail; - return true; -} - -} // namespace - AsarProtocolHandler::AsarProtocolHandler( const scoped_refptr& file_task_runner) : file_task_runner_(file_task_runner) {} @@ -49,19 +21,6 @@ AsarProtocolHandler::AsarProtocolHandler( AsarProtocolHandler::~AsarProtocolHandler() { } -Archive* AsarProtocolHandler::GetOrCreateAsarArchive( - const base::FilePath& path) const { - if (!archives_.contains(path)) { - scoped_ptr archive(new Archive(path)); - if (!archive->Init()) - return nullptr; - - archives_.set(path, archive.Pass()); - } - - return archives_.get(path); -} - net::URLRequestJob* AsarProtocolHandler::MaybeCreateJob( net::URLRequest* request, net::NetworkDelegate* network_delegate) const { @@ -71,11 +30,11 @@ net::URLRequestJob* AsarProtocolHandler::MaybeCreateJob( // Create asar:// job when the path contains "xxx.asar/", otherwise treat the // URL request as file://. base::FilePath asar_path, relative_path; - if (!GetAsarPath(full_path, &asar_path, &relative_path)) + if (!GetAsarArchivePath(full_path, &asar_path, &relative_path)) return new net::URLRequestFileJob(request, network_delegate, full_path, file_task_runner_); - Archive* archive = GetOrCreateAsarArchive(asar_path); + std::shared_ptr archive = GetOrCreateAsarArchive(asar_path); if (!archive) return new net::URLRequestErrorJob(request, network_delegate, net::ERR_FILE_NOT_FOUND); diff --git a/atom/browser/net/asar/asar_protocol_handler.h b/atom/browser/net/asar/asar_protocol_handler.h index cbfc95b8f778..e0cb74d5d1bf 100644 --- a/atom/browser/net/asar/asar_protocol_handler.h +++ b/atom/browser/net/asar/asar_protocol_handler.h @@ -5,8 +5,6 @@ #ifndef ATOM_BROWSER_NET_ASAR_ASAR_PROTOCOL_HANDLER_H_ #define ATOM_BROWSER_NET_ASAR_ASAR_PROTOCOL_HANDLER_H_ -#include "base/containers/scoped_ptr_hash_map.h" -#include "base/files/file_path.h" #include "base/memory/ref_counted.h" #include "net/url_request/url_request_job_factory.h" @@ -16,16 +14,12 @@ class TaskRunner; namespace asar { -class Archive; - class AsarProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { public: explicit AsarProtocolHandler( const scoped_refptr& file_task_runner); virtual ~AsarProtocolHandler(); - Archive* GetOrCreateAsarArchive(const base::FilePath& path) const; - // net::URLRequestJobFactory::ProtocolHandler: net::URLRequestJob* MaybeCreateJob( net::URLRequest* request, @@ -35,8 +29,6 @@ class AsarProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { private: const scoped_refptr file_task_runner_; - mutable base::ScopedPtrHashMap archives_; - DISALLOW_COPY_AND_ASSIGN(AsarProtocolHandler); }; diff --git a/atom/browser/net/asar/url_request_asar_job.cc b/atom/browser/net/asar/url_request_asar_job.cc index aeaab646a9d4..82cade53c6f7 100644 --- a/atom/browser/net/asar/url_request_asar_job.cc +++ b/atom/browser/net/asar/url_request_asar_job.cc @@ -17,7 +17,7 @@ namespace asar { URLRequestAsarJob::URLRequestAsarJob( net::URLRequest* request, net::NetworkDelegate* network_delegate, - Archive* archive, + std::shared_ptr archive, const base::FilePath& file_path, const scoped_refptr& file_task_runner) : net::URLRequestJob(request, network_delegate), diff --git a/atom/browser/net/asar/url_request_asar_job.h b/atom/browser/net/asar/url_request_asar_job.h index 899976471f0e..dc23e327cdff 100644 --- a/atom/browser/net/asar/url_request_asar_job.h +++ b/atom/browser/net/asar/url_request_asar_job.h @@ -5,6 +5,7 @@ #ifndef ATOM_BROWSER_NET_ASAR_URL_REQUEST_ASAR_JOB_H_ #define ATOM_BROWSER_NET_ASAR_URL_REQUEST_ASAR_JOB_H_ +#include #include #include "atom/common/asar/archive.h" @@ -27,7 +28,7 @@ class URLRequestAsarJob : public net::URLRequestJob { public: URLRequestAsarJob(net::URLRequest* request, net::NetworkDelegate* network_delegate, - Archive* archive, + std::shared_ptr archive, const base::FilePath& file_path, const scoped_refptr& file_task_runner); @@ -53,7 +54,7 @@ class URLRequestAsarJob : public net::URLRequestJob { // Callback after data is asynchronously read from the file into |buf|. void DidRead(scoped_refptr buf, int result); - Archive* archive_; + std::shared_ptr archive_; Archive::FileInfo file_info_; base::FilePath file_path_; diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 6b873fa7f55a..a57ff221a424 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -7,11 +7,11 @@ #include #include +#include "atom/common/asar/asar_util.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "base/base64.h" -#include "base/files/file_util.h" #include "base/strings/string_util.h" #include "native_mate/dictionary.h" #include "native_mate/object_template_builder.h" @@ -86,7 +86,7 @@ bool AddImageSkiaRep(gfx::ImageSkia* image, const base::FilePath& path, double scale_factor) { std::string file_contents; - if (!base::ReadFileToString(path, &file_contents)) + if (!asar::ReadFileToString(path, &file_contents)) return false; const unsigned char* data = diff --git a/atom/common/asar/asar_util.cc b/atom/common/asar/asar_util.cc new file mode 100644 index 000000000000..43e2601ac456 --- /dev/null +++ b/atom/common/asar/asar_util.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/common/asar/asar_util.h" + +#include +#include + +#include "atom/common/asar/archive.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/lazy_instance.h" +#include "base/stl_util.h" + +namespace asar { + +namespace { + +// The global instance of ArchiveMap, will be destroyed on exit. +typedef std::map> ArchiveMap; +static base::LazyInstance g_archive_map = LAZY_INSTANCE_INITIALIZER; + +const base::FilePath::CharType kAsarExtension[] = FILE_PATH_LITERAL(".asar"); + +} // namespace + +std::shared_ptr GetOrCreateAsarArchive(const base::FilePath& path) { + ArchiveMap& archive_map = *g_archive_map.Pointer(); + if (!ContainsKey(archive_map, path)) { + std::shared_ptr archive(new Archive(path)); + if (!archive->Init()) + return nullptr; + archive_map[path] = archive; + } + return archive_map[path]; +} + +bool GetAsarArchivePath(const base::FilePath& full_path, + base::FilePath* asar_path, + base::FilePath* relative_path) { + base::FilePath iter = full_path; + while (true) { + base::FilePath dirname = iter.DirName(); + if (iter.MatchesExtension(kAsarExtension)) + break; + else if (iter == dirname) + return false; + iter = dirname; + } + + base::FilePath tail; + if (!iter.AppendRelativePath(full_path, &tail)) + return false; + + *asar_path = iter; + *relative_path = tail; + return true; +} + +bool ReadFileToString(const base::FilePath& path, std::string* contents) { + base::FilePath asar_path, relative_path; + if (!GetAsarArchivePath(path, &asar_path, &relative_path)) + return base::ReadFileToString(path, contents); + + std::shared_ptr archive = GetOrCreateAsarArchive(asar_path); + if (!archive) + return false; + + Archive::FileInfo info; + if (!archive->GetFileInfo(relative_path, &info)) + return false; + + base::File src(asar_path, base::File::FLAG_OPEN | base::File::FLAG_READ); + if (!src.IsValid()) + return false; + + contents->resize(info.size); + return static_cast(info.size) == src.Read( + info.offset, const_cast(contents->data()), contents->size()); +} + +} // namespace asar diff --git a/atom/common/asar/asar_util.h b/atom/common/asar/asar_util.h new file mode 100644 index 000000000000..4cb5b88e0483 --- /dev/null +++ b/atom/common/asar/asar_util.h @@ -0,0 +1,32 @@ +// Copyright (c) 2015 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef ATOM_COMMON_ASAR_ASAR_UTIL_H_ +#define ATOM_COMMON_ASAR_ASAR_UTIL_H_ + +#include +#include + +namespace base { +class FilePath; +} + +namespace asar { + +class Archive; + +// Gets or creates a new Archive from the path. +std::shared_ptr GetOrCreateAsarArchive(const base::FilePath& path); + +// Separates the path to Archive out. +bool GetAsarArchivePath(const base::FilePath& full_path, + base::FilePath* asar_path, + base::FilePath* relative_path); + +// Same with base::ReadFileToString but supports asar Archive. +bool ReadFileToString(const base::FilePath& path, std::string* contents); + +} // namespace asar + +#endif // ATOM_COMMON_ASAR_ASAR_UTIL_H_ diff --git a/spec/asar-spec.coffee b/spec/asar-spec.coffee index ab96d7ee3d6f..222faf9a5e2e 100644 --- a/spec/asar-spec.coffee +++ b/spec/asar-spec.coffee @@ -430,3 +430,9 @@ describe 'asar package', -> it 'does not touch global fs object', -> assert.notEqual fs.readdir, gfs.readdir + + describe 'native-image', -> + it 'reads image from asar archive', -> + p = path.join fixtures, 'asar', 'logo.asar', 'logo.png' + logo = require('native-image').createFromPath p + assert.deepEqual logo.getSize(), {width: 55, height: 55} diff --git a/spec/fixtures/asar/logo.asar b/spec/fixtures/asar/logo.asar new file mode 100644 index 000000000000..fe21fd9ab7b3 Binary files /dev/null and b/spec/fixtures/asar/logo.asar differ