363 lines
18 KiB
C++
363 lines
18 KiB
C++
/**
|
|
* @file lldir.h
|
|
* @brief Definition of directory utilities class
|
|
*
|
|
* $LicenseInfo:firstyear=2000&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#ifndef LL_LLDIR_H
|
|
#define LL_LLDIR_H
|
|
|
|
// these numbers are read from settings_files.xml, so we need to be explicit
|
|
typedef enum ELLPath
|
|
{
|
|
LL_PATH_NONE = 0,
|
|
LL_PATH_USER_SETTINGS = 1,
|
|
LL_PATH_APP_SETTINGS = 2,
|
|
LL_PATH_PER_SL_ACCOUNT = 3, // returns/expands to blank string if we don't know the account name yet
|
|
LL_PATH_CACHE = 4,
|
|
LL_PATH_CHARACTER = 5,
|
|
LL_PATH_HELP = 6,
|
|
LL_PATH_LOGS = 7,
|
|
LL_PATH_TEMP = 8,
|
|
LL_PATH_SKINS = 9,
|
|
LL_PATH_TOP_SKIN = 10,
|
|
LL_PATH_CHAT_LOGS = 11,
|
|
LL_PATH_PER_ACCOUNT_CHAT_LOGS = 12,
|
|
LL_PATH_USER_SKIN = 14,
|
|
LL_PATH_LOCAL_ASSETS = 15,
|
|
LL_PATH_EXECUTABLE = 16,
|
|
LL_PATH_DEFAULT_SKIN = 17,
|
|
LL_PATH_FONTS = 18,
|
|
LL_PATH_DUMP = 19,
|
|
// [SL:KB] - Patch: Viewer-Skins | mS: 2010-10-19 (Catznip-2.4)
|
|
LL_PATH_TOP_SKINTHEME = 20,
|
|
// [/SL:KB]
|
|
// <FS:TT> Firestorm data
|
|
LL_PATH_FS_RESOURCES = 21,
|
|
// </FS:TT>
|
|
// <FS:Ansariel> Sound cache
|
|
LL_PATH_FS_SOUND_CACHE = 22,
|
|
// </FS:Ansariel>
|
|
LL_PATH_LAST
|
|
} ELLPath;
|
|
|
|
/// Directory operations
|
|
class LLDir
|
|
{
|
|
public:
|
|
LLDir();
|
|
virtual ~LLDir();
|
|
|
|
// app_name - Usually SecondLife, used for creating settings directories
|
|
// in OS-specific location, such as C:\Documents and Settings
|
|
// app_read_only_data_dir - Usually the source code directory, used
|
|
// for test applications to read newview data files.
|
|
virtual void initAppDirs(const std::string &app_name,
|
|
const std::string& app_read_only_data_dir = "") = 0;
|
|
|
|
virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask);
|
|
U32 deleteDirAndContents(const std::string& dir_name);
|
|
std::vector<std::string> getFilesInDir(const std::string &dirname);
|
|
// pure virtual functions
|
|
virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0;
|
|
|
|
/// Walk the files in a directory, with file pattern matching
|
|
// <AO> Used by LGG Selection beams, do not remove
|
|
virtual bool getNextFileInDir(const std::string& dirname, ///< directory path - must end in trailing slash!
|
|
const std::string& mask, ///< file pattern string (use "*" for all)
|
|
std::string& fname ///< output: found file name
|
|
) = 0;
|
|
// </AO>
|
|
/**<
|
|
* @returns true if a file was found, false if the entire directory has been scanned.
|
|
*
|
|
* @note that this function is NOT thread safe
|
|
*
|
|
* This function may not be used to scan part of a directory, then start a new search of a different
|
|
* directory, and then restart the first search where it left off; the entire search must run to
|
|
* completion or be abandoned - there is no restart.
|
|
*
|
|
* @bug: See http://jira.secondlife.com/browse/VWR-23697
|
|
* and/or the tests in test/lldir_test.cpp
|
|
* This is known to fail with patterns that have both:
|
|
* a wildcard left of a . and more than one sequential ? right of a .
|
|
* the pattern foo.??x appears to work
|
|
* but *.??x or foo?.??x do not
|
|
*
|
|
* @todo this really should be rewritten as an iterator object, and the
|
|
* filtering should be done in a platform-independent way.
|
|
*/
|
|
|
|
virtual std::string getCurPath() = 0;
|
|
virtual bool fileExists(const std::string &filename) const = 0;
|
|
|
|
const std::string findFile(const std::string& filename, const std::vector<std::string> filenames) const;
|
|
const std::string findFile(const std::string& filename, const std::string& searchPath1 = "", const std::string& searchPath2 = "", const std::string& searchPath3 = "") const;
|
|
|
|
virtual std::string getLLPluginLauncher() = 0; // full path and name for the plugin shell
|
|
virtual std::string getLLPluginFilename(std::string base_name) = 0; // full path and name to the plugin DSO for this base_name (i.e. 'FOO' -> '/bar/baz/libFOO.so')
|
|
|
|
const std::string &getExecutablePathAndName() const; // Full pathname of the executable
|
|
const std::string &getAppName() const; // install directory under progams/ ie "SecondLife"
|
|
const std::string &getExecutableDir() const; // Directory where the executable is located
|
|
const std::string &getExecutableFilename() const;// Filename of .exe
|
|
const std::string &getWorkingDir() const; // Current working directory
|
|
const std::string &getAppRODataDir() const; // Location of read-only data files
|
|
const std::string &getOSUserDir() const; // Location of the os-specific user dir
|
|
const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir
|
|
const std::string &getLindenUserDir() const; // Location of the Linden user dir.
|
|
const std::string &getChatLogsDir() const; // Location of the chat logs dir.
|
|
const std::string &getDumpDir() const; // Location of the per-run dump dir.
|
|
bool dumpDirExists() const;
|
|
const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir.
|
|
const std::string &getTempDir() const; // Common temporary directory
|
|
const std::string getCacheDir(bool get_default = false) const; // Location of the cache.
|
|
const std::string &getOSCacheDir() const; // location of OS-specific cache folder (may be empty string)
|
|
const std::string &getCAFile() const; // File containing TLS certificate authorities
|
|
const std::string &getDirDelimiter() const; // directory separator for platform (ie. '\' or '/' or ':')
|
|
const std::string &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default
|
|
const std::string &getSkinDir() const; // User-specified skin folder.
|
|
// [SL:KB] - Patch: Viewer-Skins | Checked: 2010-10-20 (Catznip-2.2)
|
|
const std::string &getSkinThemeDir() const; // User-specified skin theme override folder.
|
|
// [/SL:KB]
|
|
const std::string &getUserDefaultSkinDir() const; // dir with user modifications to default skin
|
|
const std::string &getUserSkinDir() const; // User-specified skin folder with user modifications. e.g. c:\documents and settings\username\application data\second life\skins\curskin
|
|
const std::string getSkinBaseDir() const; // folder that contains all installed skins (not user modifications). e.g. c:\program files\second life\skins
|
|
const std::string &getLLPluginDir() const; // Directory containing plugins and plugin shell
|
|
const std::string &getUserName() const;
|
|
// <FS:Ansariel> Sound cache
|
|
const std::string &getSoundCacheDir() const;
|
|
// </FS:Ansariel>
|
|
|
|
// Expanded filename
|
|
std::string getExpandedFilename(ELLPath location, const std::string &filename) const;
|
|
std::string getExpandedFilename(ELLPath location, const std::string &subdir, const std::string &filename) const;
|
|
std::string getExpandedFilename(ELLPath location, const std::string &subdir1, const std::string &subdir2, const std::string &filename) const;
|
|
|
|
// Base and Directory name extraction
|
|
std::string getBaseFileName(const std::string& filepath, bool strip_exten = false) const;
|
|
std::string getDirName(const std::string& filepath) const;
|
|
std::string getExtension(const std::string& filepath) const; // Excludes '.', e.g getExtension("foo.wav") == "wav"
|
|
|
|
// these methods search the various skin paths for the specified file in the following order:
|
|
// getUserSkinDir(), getUserDefaultSkinDir(), getSkinThemeDir(), getSkinDir(), getDefaultSkinDir()
|
|
/// param value for findSkinnedFilenames(), explained below
|
|
enum ESkinConstraint { CURRENT_SKIN, ALL_SKINS };
|
|
/**
|
|
* Given a filename within skin, return an ordered sequence of paths to
|
|
* search. Nonexistent files will be filtered out -- which means that the
|
|
* vector might be empty.
|
|
*
|
|
* @param subdir Identify top-level skin subdirectory by passing one of
|
|
* LLDir::XUI (file lives under "xui" subtree), LLDir::TEXTURES (file
|
|
* lives under "textures" subtree), LLDir::SKINBASE (file lives at top
|
|
* level of skin subdirectory).
|
|
* @param filename Desired filename within subdir within skin, e.g.
|
|
* "panel_login.xml". DO NOT prepend (e.g.) "xui" or the desired language.
|
|
* @param constraint Callers perform two different kinds of processing.
|
|
* When fetching a XUI file, for instance, the existence of @a filename in
|
|
* the specified skin completely supercedes any @a filename in the default
|
|
* skin. For that case, leave the default @a constraint=CURRENT_SKIN. The
|
|
* returned vector will contain only
|
|
* ".../<i>current_skin</i>/xui/en/<i>filename</i>",
|
|
* ".../<i>current_skin</i>/xui/<i>current_language</i>/<i>filename</i>".
|
|
* But for (e.g.) "strings.xml", we want a given skin to be able to
|
|
* override only specific entries from the default skin. Any string not
|
|
* defined in the specified skin will be sought in the default skin. For
|
|
* that case, pass @a constraint=ALL_SKINS. The returned vector will
|
|
* contain at least ".../default/xui/en/strings.xml",
|
|
* ".../default/xui/<i>current_language</i>/strings.xml",
|
|
* ".../<i>current_skin</i>/xui/en/strings.xml",
|
|
* ".../<i>current_skin</i>/xui/<i>current_language</i>/strings.xml".
|
|
*/
|
|
std::vector<std::string> findSkinnedFilenames(const std::string& subdir,
|
|
const std::string& filename,
|
|
ESkinConstraint constraint=CURRENT_SKIN) const;
|
|
/// Values for findSkinnedFilenames(subdir) parameter
|
|
static const char *XUI, *TEXTURES, *SKINBASE;
|
|
/**
|
|
* Return the base-language pathname from findSkinnedFilenames(), or
|
|
* the empty string if no such file exists. Parameters are identical to
|
|
* findSkinnedFilenames(). This is shorthand for capturing the vector
|
|
* returned by findSkinnedFilenames(), checking for empty() and then
|
|
* returning front().
|
|
*/
|
|
std::string findSkinnedFilenameBaseLang(const std::string &subdir,
|
|
const std::string &filename,
|
|
ESkinConstraint constraint=CURRENT_SKIN) const;
|
|
/**
|
|
* Return the "most localized" pathname from findSkinnedFilenames(), or
|
|
* the empty string if no such file exists. Parameters are identical to
|
|
* findSkinnedFilenames(). This is shorthand for capturing the vector
|
|
* returned by findSkinnedFilenames(), checking for empty() and then
|
|
* returning back().
|
|
*/
|
|
std::string findSkinnedFilename(const std::string &subdir,
|
|
const std::string &filename,
|
|
ESkinConstraint constraint=CURRENT_SKIN) const;
|
|
|
|
// random filename in common temporary directory
|
|
std::string getTempFilename() const;
|
|
|
|
static std::string getDumpLogsDirPath(const std::string &file_name = "");
|
|
|
|
// For producing safe download file names from potentially unsafe ones
|
|
static std::string getScrubbedFileName(std::string_view uncleanFileName);
|
|
static std::string getForbiddenFileChars();
|
|
void setDumpDir( const std::string& path );
|
|
|
|
|
|
virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir
|
|
// <FS:CR> Seperate user directories per grid
|
|
//virtual void setPerAccountChatLogsDir(const std::string &username); // Set the per user chat log directory.
|
|
//virtual void setLindenUserDir(const std::string &username); // Set the linden user dir to this user's dir
|
|
virtual void setPerAccountChatLogsDir(const std::string &username, const std::string &gridname);
|
|
virtual void setLindenUserDir(const std::string &username, const std::string &gridname);
|
|
// </FS:CR>
|
|
// [SL:KB] - Patch: Viewer-Skins | Checked: 2010-10-20 (Catznip-3.4)
|
|
virtual void setSkinFolder(const std::string& skin_folder, const std::string& theme_folder, const std::string& language);
|
|
// [/SL:KB]
|
|
// virtual void setSkinFolder(const std::string &skin_folder, const std::string& language);
|
|
virtual std::string getSkinFolder() const;
|
|
// [SL:KB] - Patch: Viewer-Skins | Checked: 2012-12-26 (Catznip-3.4)
|
|
virtual std::string getSkinThemeFolder() const;
|
|
// [/SL:KB]
|
|
virtual std::string getLanguage() const;
|
|
virtual bool setCacheDir(const std::string &path);
|
|
virtual void updatePerAccountChatLogsDir();
|
|
// <FS:Ansariel> Sound cache
|
|
virtual bool setSoundCacheDir(const std::string& path);
|
|
// </FS:Ansariel>
|
|
|
|
virtual void dumpCurrentDirectories(LLError::ELevel level = LLError::LEVEL_DEBUG);
|
|
|
|
// Utility routine
|
|
std::string buildSLOSCacheDir() const;
|
|
|
|
/// Append specified @a name to @a destpath, separated by getDirDelimiter()
|
|
/// if both are non-empty.
|
|
void append(std::string& destpath, const std::string& name) const;
|
|
/// Variadic form: append @a name0 and @a name1 and arbitrary other @a
|
|
/// names to @a destpath, separated by getDirDelimiter() as needed.
|
|
template <typename... NAMES>
|
|
void append(std::string& destpath, const std::string& name0, const std::string& name1,
|
|
const NAMES& ... names) const
|
|
{
|
|
// In a typical recursion case, we'd accept (destpath, name0, names).
|
|
// We accept (destpath, name0, name1, names) because it's important to
|
|
// delegate the two-argument case to the non-template implementation.
|
|
append(destpath, name0);
|
|
append(destpath, name1, names...);
|
|
}
|
|
|
|
/// Append specified @a names to @a path, separated by getDirDelimiter()
|
|
/// as needed. Return result, leaving @a path unmodified.
|
|
template <typename... NAMES>
|
|
std::string add(const std::string& path, const NAMES& ... names) const
|
|
{
|
|
std::string destpath(path);
|
|
append(destpath, names...);
|
|
return destpath;
|
|
}
|
|
|
|
protected:
|
|
// Does an add() or append() call need a directory delimiter?
|
|
typedef std::pair<bool, unsigned short> SepOff;
|
|
SepOff needSep(const std::string& path, const std::string& name) const;
|
|
// build mSearchSkinDirs without adding duplicates
|
|
void addSearchSkinDir(const std::string& skindir);
|
|
|
|
// Internal to findSkinnedFilenames()
|
|
template <typename FUNCTION>
|
|
void walkSearchSkinDirs(const std::string& subdir,
|
|
const std::vector<std::string>& subsubdirs,
|
|
const std::string& filename,
|
|
const FUNCTION& function) const;
|
|
|
|
std::string mAppName; // install directory under progams/ ie "SecondLife"
|
|
std::string mExecutablePathAndName; // full path + Filename of .exe
|
|
std::string mExecutableFilename; // Filename of .exe
|
|
std::string mExecutableDir; // Location of executable
|
|
std::string mWorkingDir; // Current working directory
|
|
std::string mAppRODataDir; // Location for static app data
|
|
std::string mOSUserDir; // OS Specific user directory
|
|
std::string mOSUserAppDir; // OS Specific user app directory
|
|
std::string mLindenUserDir; // Location for Linden user-specific data
|
|
std::string mPerAccountChatLogsDir; // Location for chat logs.
|
|
std::string mChatLogsDir; // Location for chat logs.
|
|
std::string mCAFile; // Location of the TLS certificate authority PEM file.
|
|
std::string mTempDir;
|
|
std::string mCacheDir; // cache directory as set by user preference
|
|
std::string mDefaultCacheDir; // default cache diretory
|
|
std::string mOSCacheDir; // operating system cache dir
|
|
std::string mDirDelimiter;
|
|
std::string mSkinName; // caller-specified skin name
|
|
// [SL:KB] - Patch: Viewer-Skins | Checked: 2012-12-26 (Catznip-3.4)
|
|
std::string mSkinThemeName; // Location for current skin theme override
|
|
// [/SL:KB]
|
|
std::string mSkinBaseDir; // Base for skins paths.
|
|
std::string mDefaultSkinDir; // Location for default skin info.
|
|
std::string mSkinDir; // Location for current skin info.
|
|
// [SL:KB] - Patch: Viewer-Skins | Checked: 2010-10-20 (Catznip-2.2)
|
|
std::string mSkinThemeDir; // Location for current skin theme override
|
|
// [/SL:KB]
|
|
std::string mUserDefaultSkinDir; // Location for default skin info.
|
|
std::string mUserSkinDir; // Location for user-modified skin info.
|
|
// Skin directories to search, most general to most specific. This order
|
|
// works well for composing fine-grained files, in which an individual item
|
|
// in a specific file overrides the corresponding item in more general
|
|
// files. Of course, for a file-level search, iterate backwards.
|
|
std::vector<std::string> mSearchSkinDirs;
|
|
std::string mLanguage; // Current viewer language
|
|
std::string mLLPluginDir; // Location for plugins and plugin shell
|
|
static std::string sDumpDir; // Per-run crash report subdir of log directory.
|
|
std::string mUserName; // Current user name
|
|
// <FS:Ansariel> Sound cache
|
|
std::string mSoundCacheDir; // Sound cache
|
|
// </FS:Ansariel>
|
|
|
|
// <FS:ND> To avoid doing IO calls (expensive) in walkdSearchedSkinDirs cache results.
|
|
struct SkinDirFile
|
|
{
|
|
std::string mName;
|
|
mutable bool mExists;
|
|
|
|
SkinDirFile( std::string const &aName, bool aExists )
|
|
: mName( aName )
|
|
, mExists( aExists )
|
|
{ }
|
|
|
|
bool operator<( SkinDirFile const &aRHS ) const
|
|
{ return mName < aRHS.mName; }
|
|
};
|
|
|
|
typedef std::set< SkinDirFile > tSkinDirCache;
|
|
mutable tSkinDirCache mSkinDirCache;
|
|
};
|
|
|
|
void dir_exists_or_crash(const std::string &dir_name);
|
|
|
|
extern LLDir *gDirUtilp;
|
|
|
|
#endif // LL_LLDIR_H
|