summaryrefslogtreecommitdiff
path: root/indra/llvfs/lldir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llvfs/lldir.cpp')
-rw-r--r--indra/llvfs/lldir.cpp132
1 files changed, 87 insertions, 45 deletions
diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index 4c0978b39e..5e5aeefba1 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -46,6 +46,8 @@
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/assign/list_of.hpp>
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
#include <algorithm>
using boost::assign::list_of;
@@ -569,6 +571,43 @@ std::string LLDir::findSkinnedFilename(const std::string &subdir,
return found.back();
}
+// This method exists because the two code paths for
+// findSkinnedFilenames(ALL_SKINS) and findSkinnedFilenames(CURRENT_SKIN) must
+// generate the list of candidate pathnames in identical ways. The only
+// difference is in the body of the inner loop.
+template <typename FUNCTION>
+void LLDir::walkSearchSkinDirs(const std::string& subdir,
+ const std::vector<std::string>& subsubdirs,
+ const std::string& filename,
+ const FUNCTION& function) const
+{
+ BOOST_FOREACH(std::string skindir, mSearchSkinDirs)
+ {
+ std::string subdir_path(add(skindir, subdir));
+ BOOST_FOREACH(std::string subsubdir, subsubdirs)
+ {
+ std::string full_path(add(add(subdir_path, subsubdir), filename));
+ if (fileExists(full_path))
+ {
+ function(subsubdir, full_path);
+ }
+ }
+ }
+}
+
+// ridiculous little helper function that should go away when we can use lambda
+inline void push_back(std::vector<std::string>& vector, const std::string& value)
+{
+ vector.push_back(value);
+}
+
+typedef std::map<std::string, std::string> StringMap;
+// ridiculous little helper function that should go away when we can use lambda
+inline void store_in_map(StringMap& map, const std::string& key, const std::string& value)
+{
+ map[key] = value;
+}
+
std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir,
const std::string& filename,
ESkinConstraint constraint) const
@@ -587,11 +626,10 @@ std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir,
// Cache the default language directory for each subdir we've encountered.
// A cache entry whose value is the empty string means "not localized,
// don't bother checking again."
- typedef std::map<std::string, std::string> LocalizedMap;
- static LocalizedMap sLocalized;
+ static StringMap sLocalized;
// Check whether we've already discovered if this subdir is localized.
- LocalizedMap::const_iterator found = sLocalized.find(subdir);
+ StringMap::const_iterator found = sLocalized.find(subdir);
if (found == sLocalized.end())
{
// We have not yet determined that. Is it one of the subdirs "known"
@@ -599,7 +637,7 @@ std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir,
if (sUnlocalized.find(subdir) != sUnlocalized.end())
{
// This subdir is known to be unlocalized. Remember that.
- found = sLocalized.insert(LocalizedMap::value_type(subdir, "")).first;
+ found = sLocalized.insert(StringMap::value_type(subdir, "")).first;
}
else
{
@@ -608,20 +646,20 @@ std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir,
if (fileExists(add(subdir_path, "en")))
{
// defaultSkinDir/subdir contains subdir "en". That's our
- // default language; this subdir is localized.
- found = sLocalized.insert(LocalizedMap::value_type(subdir, "en")).first;
+ // default language; this subdir is localized.
+ found = sLocalized.insert(StringMap::value_type(subdir, "en")).first;
}
else if (fileExists(add(subdir_path, "en-us")))
{
// defaultSkinDir/subdir contains subdir "en-us" but not "en".
// Set as default language; this subdir is localized.
- found = sLocalized.insert(LocalizedMap::value_type(subdir, "en-us")).first;
+ found = sLocalized.insert(StringMap::value_type(subdir, "en-us")).first;
}
else
{
// defaultSkinDir/subdir contains neither "en" nor "en-us".
// Assume it's not localized. Remember that assumption.
- found = sLocalized.insert(LocalizedMap::value_type(subdir, "")).first;
+ found = sLocalized.insert(StringMap::value_type(subdir, "")).first;
}
}
}
@@ -648,48 +686,52 @@ std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir,
subsubdirs.push_back(mLanguage);
}
}
- // Code below relies on subsubdirs not being empty: more specifically, on
- // front() being valid. There may or may not be additional entries, but we
- // have at least one. For an unlocalized subdir, it's the only one; for a
- // localized subdir, it's the default one.
- llassert(! subsubdirs.empty());
// Build results vector.
std::vector<std::string> results;
- BOOST_FOREACH(std::string skindir, mSearchSkinDirs)
- {
- std::string subdir_path(add(skindir, subdir));
- // Does subdir_path/subsubdirs[0]/filename exist? If there's more than
- // one entry in subsubdirs, the first is the default language ("en"),
- // the second is the current language. A skin that contains
- // subdir/language/filename without also containing subdir/en/filename
- // is ill-formed: skip any such skin. So to decide whether to keep
- // this skin dir or skip it, we need only check for the existence of
- // the first subsubdir entry ("en" or only).
- std::string subsubdir_path(add(add(subdir_path, subsubdirs.front()), filename));
- if (! fileExists(subsubdir_path))
- continue;
-
- // Here the desired filename exists in the first subsubdir. That means
- // this is a skindir we want to record in results. But if the caller
- // passed constraint=CURRENT_SKIN, we must discard all previous skindirs.
- if (constraint == CURRENT_SKIN)
- {
- results.clear();
- }
-
- // Now add every subsubdir in which filename exists. We already know
- // it exists in the first one.
- results.push_back(subsubdir_path);
-
- // Append all remaining subsubdirs in which filename exists.
- for (std::vector<std::string>::const_iterator ssdi(subsubdirs.begin() + 1), ssdend(subsubdirs.end());
- ssdi != ssdend; ++ssdi)
+ // The process we use depends on 'constraint'.
+ if (constraint != CURRENT_SKIN) // meaning ALL_SKINS
+ {
+ // ALL_SKINS is simpler: just return every pathname generated by
+ // walkSearchSkinDirs(). Tricky bit: walkSearchSkinDirs() passes its
+ // FUNCTION the subsubdir as well as the full pathname. We just want
+ // the full pathname.
+ walkSearchSkinDirs(subdir, subsubdirs, filename,
+ boost::bind(push_back, boost::ref(results), _2));
+ }
+ else // CURRENT_SKIN
+ {
+ // CURRENT_SKIN turns out to be a bit of a misnomer because we might
+ // still return files from two different skins. In any case, this
+ // value of 'constraint' means we will return at most two paths: one
+ // for the default language, one for the current language (supposing
+ // those differ).
+ // It is important to allow a user to override only the localization
+ // for a particular file, for all viewer installs, without also
+ // overriding the default-language file.
+ // It is important to allow a user to override only the default-
+ // language file, for all viewer installs, without also overriding the
+ // applicable localization of that file.
+ // Therefore, treat the default language and the current language as
+ // two separate cases. For each, capture the most-specialized file
+ // that exists.
+ // Use a map keyed by subsubdir (i.e. language code). This allows us
+ // to handle the case of a single subsubdirs entry with the same logic
+ // that handles two. For every real file path generated by
+ // walkSearchSkinDirs(), update the map entry for its subsubdir.
+ StringMap path_for;
+ walkSearchSkinDirs(subdir, subsubdirs, filename,
+ boost::bind(store_in_map, boost::ref(path_for), _1, _2));
+ // Now that we have a path for each of the default language and the
+ // current language, copy them -- in proper order -- into results.
+ // Don't drive this by walking the map itself: it matters that we
+ // generate results in the same order as subsubdirs.
+ BOOST_FOREACH(std::string subsubdir, subsubdirs)
{
- subsubdir_path = add(add(subdir_path, *ssdi), filename);
- if (fileExists(subsubdir_path))
+ StringMap::const_iterator found(path_for.find(subsubdir));
+ if (found != path_for.end())
{
- results.push_back(subsubdir_path);
+ results.push_back(found->second);
}
}
}