diff --git a/src/rime/resource_resolver.cc b/src/rime/resource_resolver.cc index 507e36bdb..a479268d0 100644 --- a/src/rime/resource_resolver.cc +++ b/src/rime/resource_resolver.cc @@ -13,4 +13,18 @@ boost::filesystem::path ResourceResolver::ResolvePath(const string& resource_id) root_path_); } +boost::filesystem::path +FallbackResourceResolver::ResolvePath(const string& resource_id) { + auto default_path = ResourceResolver::ResolvePath(resource_id); + if (!boost::filesystem::exists(default_path)) { + auto fallback_path = boost::filesystem::absolute( + boost::filesystem::path(type_.prefix + resource_id + type_.suffix), + fallback_root_path_); + if (boost::filesystem::exists(fallback_path)) { + return fallback_path; + } + } + return default_path; +} + } // namespace rime diff --git a/src/rime/resource_resolver.h b/src/rime/resource_resolver.h index 8837086c4..1f5aa366b 100644 --- a/src/rime/resource_resolver.h +++ b/src/rime/resource_resolver.h @@ -23,18 +23,34 @@ class ResourceResolver { public: explicit ResourceResolver(const ResourceType type) : type_(type) { } - boost::filesystem::path ResolvePath(const string& resource_id); + virtual ~ResourceResolver() { + } + virtual boost::filesystem::path ResolvePath(const string& resource_id); void set_root_path(const boost::filesystem::path& root_path) { root_path_ = root_path; } boost::filesystem::path root_path() const { return root_path_; } - private: + protected: const ResourceType type_; boost::filesystem::path root_path_; }; +// try fallback path if target file doesn't exist in root path +class FallbackResourceResolver : public ResourceResolver { + public: + explicit FallbackResourceResolver(const ResourceType& type) + : ResourceResolver(type) { + } + boost::filesystem::path ResolvePath(const string& resource_id) override; + void set_fallback_root_path(const boost::filesystem::path& fallback_root_path) { + fallback_root_path_ = fallback_root_path; + } + private: + boost::filesystem::path fallback_root_path_; +}; + } // namespace rime #endif // RIME_RESOURCE_RESOLVER_H_ diff --git a/test/resource_resolver_test.cc b/test/resource_resolver_test.cc index 9a0aafcab..a9d9b8a6e 100644 --- a/test/resource_resolver_test.cc +++ b/test/resource_resolver_test.cc @@ -3,15 +3,48 @@ using namespace rime; +static const ResourceType kMineralsType = ResourceType{ + "minerals", + "not_", + ".minerals", +}; + TEST(RimeResourceResolverTest, ResolvePath) { - const auto type = ResourceType{ - "minerals", - "not_", - ".minerals", - }; - the rr(new ResourceResolver(type)); - rr->set_root_path("/starcraft"); - auto actual = rr->ResolvePath("enough"); + ResourceResolver rr(kMineralsType); + rr.set_root_path("/starcraft"); + auto actual = rr.ResolvePath("enough"); boost::filesystem::path expected = "/starcraft/not_enough.minerals"; + EXPECT_TRUE(actual.is_absolute()); EXPECT_TRUE(expected == actual); } + +TEST(RimeResourceResolverTest, FallbackRootPath) { + FallbackResourceResolver rr(kMineralsType); + rr.set_fallback_root_path("fallback"); + boost::filesystem::create_directory("fallback"); + { + boost::filesystem::path nonexistent_default = "not_present.minerals"; + boost::filesystem::remove(nonexistent_default); + auto fallback = boost::filesystem::absolute("fallback/not_present.minerals"); + boost::filesystem::ofstream(fallback).close(); + auto actual = rr.ResolvePath("present"); + EXPECT_TRUE(fallback == actual); + boost::filesystem::remove(fallback); + } + { + auto existent_default = boost::filesystem::absolute("not_falling_back.minerals"); + boost::filesystem::ofstream(existent_default).close(); + auto actual = rr.ResolvePath("falling_back"); + EXPECT_TRUE(existent_default == actual); + boost::filesystem::remove(existent_default); + } + { + auto nonexistent_default = boost::filesystem::absolute("not_any.minerals"); + boost::filesystem::remove(nonexistent_default); + auto nonexistent_fallback = boost::filesystem::absolute("fallback/not_any.minerals"); + boost::filesystem::remove(nonexistent_fallback); + auto actual = rr.ResolvePath("any"); + EXPECT_TRUE(nonexistent_default == actual); + } + boost::filesystem::remove_all("fallback"); +}