From 219061c095d84ba24bdb5857a1cd7319927f3ea7 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Thu, 17 Jan 2013 20:32:53 -0800 Subject: [PATCH] Add plFilesystem module, which replaces previous filesystem APIs with a plFileName-based one --- Sources/Plasma/CoreLib/CMakeLists.txt | 2 + Sources/Plasma/CoreLib/hsStream.h | 2 +- Sources/Plasma/CoreLib/plFileSystem.cpp | 367 ++++++++++++++++++++++++ Sources/Plasma/CoreLib/plFileSystem.h | 284 ++++++++++++++++++ Sources/Plasma/CoreLib/plString.cpp | 107 ------- Sources/Plasma/CoreLib/plString.h | 136 +-------- 6 files changed, 655 insertions(+), 243 deletions(-) create mode 100644 Sources/Plasma/CoreLib/plFileSystem.cpp create mode 100644 Sources/Plasma/CoreLib/plFileSystem.h diff --git a/Sources/Plasma/CoreLib/CMakeLists.txt b/Sources/Plasma/CoreLib/CMakeLists.txt index 865db60a..8ffe5708 100644 --- a/Sources/Plasma/CoreLib/CMakeLists.txt +++ b/Sources/Plasma/CoreLib/CMakeLists.txt @@ -41,6 +41,7 @@ set(CoreLib_SOURCES hsThread.cpp hsWide.cpp pcSmallRect.cpp + plFileSystem.cpp plGeneric.cpp plLoadMask.cpp plProduct.cpp @@ -85,6 +86,7 @@ set(CoreLib_HEADERS hsWide.h hsWindows.h pcSmallRect.h + plFileSystem.h plGeneric.h plLoadMask.h plProduct.h diff --git a/Sources/Plasma/CoreLib/hsStream.h b/Sources/Plasma/CoreLib/hsStream.h index b7980289..f74d294a 100644 --- a/Sources/Plasma/CoreLib/hsStream.h +++ b/Sources/Plasma/CoreLib/hsStream.h @@ -46,7 +46,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "HeadSpin.h" #include "hsMemory.h" -#include "plString.h" +#include "plFileSystem.h" // Define this for use of Streams with Logging (commonly used w/ a packet sniffer) diff --git a/Sources/Plasma/CoreLib/plFileSystem.cpp b/Sources/Plasma/CoreLib/plFileSystem.cpp new file mode 100644 index 00000000..071a32fc --- /dev/null +++ b/Sources/Plasma/CoreLib/plFileSystem.cpp @@ -0,0 +1,367 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#include "plFileSystem.h" + +#if HS_BUILD_FOR_WIN32 +# include "hsWindows.h" +# include +#else +# include +# include +# include +# include +# include +#endif +#include +#include "plProduct.h" + +/* NOTE For this file: Windows uses UTF-16 filenames, and does not support + * the use of UTF-8 in their ANSI API. In order to ensure proper unicode + * support, we convert the UTF-8 format stored in plString to UTF-16 before + * passing them along to Windows. + */ + +plString plFileName::GetFileName() const +{ + int end = fName.FindLast('/'); + if (end < 0) + end = fName.FindLast('\\'); + if (end < 0) + return fName; + + return fName.Substr(end + 1); +} + +plString plFileName::GetFileExt() const +{ + int dot = fName.FindLast('.'); + + // Be sure not to get a dot in the directory! + int end = fName.FindLast('/'); + if (end < 0) + end = fName.FindLast('\\'); + + if (dot > end) + return fName.Substr(dot + 1); + + return plString::Null; +} + +plString plFileName::GetFileNameNoExt() const +{ + int dot = fName.FindLast('.'); + + int end = fName.FindLast('/'); + if (end < 0) + end = fName.FindLast('\\'); + + // Be sure not to get a dot in the directory! + if (dot > end) + return fName.Substr(end + 1, dot - end - 1); + return fName.Substr(end + 1); +} + +plFileName plFileName::StripFileName() const +{ + int end = fName.FindLast('/'); + if (end < 0) + end = fName.FindLast('\\'); + if (end < 0) + return ""; + + return fName.Left(end); +} + +plFileName plFileName::StripFileExt() const +{ + int dot = fName.FindLast('.'); + + // Be sure not to get a dot in the directory! + int end = fName.FindLast('/'); + if (end < 0) + end = fName.FindLast('\\'); + + if (dot > end) + return fName.Left(dot); + + return *this; +} + +plFileName plFileName::Normalize(char slash) const +{ + plStringBuffer norm; + char *norm_p = norm.CreateWritableBuffer(fName.GetSize()); + for (const char *p = fName.c_str(); *p; ++p) { + if (*p == '/' || *p == '\\') + *norm_p++ = slash; + else + *norm_p++ = *p; + } + *norm_p = 0; + return plString(norm); +} + +plFileName plFileName::AbsolutePath() const +{ + if (!IsValid()) + return *this; + + plFileName path = Normalize(); + +#if HS_BUILD_FOR_WIN32 + plStringBuffer wideName = path.fName.ToWchar(); + wchar_t path_sm[MAX_PATH]; + uint32_t path_length = GetFullPathNameW(wideName, MAX_PATH, path_sm, nullptr); + if (path_length >= MAX_PATH) { + // Buffer not big enough + wchar_t *path_lg = new wchar_t[path_length]; + GetFullPathNameW(wideName, path_length, path_lg, nullptr); + path = plString::FromWchar(path_lg); + delete [] path_lg; + } else { + path = plString::FromWchar(path_sm); + } +#else + char *path_a = realpath(path.c_str(), nullptr); + hsAssert(path_a, "Failure to get absolute path (unsupported libc?)"); + path = path_a; + free(path_a); +#endif + + return path; +} + +plFileName plFileName::Join(const plFileName &base, const plFileName &path) +{ + if (!base.IsValid()) + return path; + if (!path.IsValid()) + return base; + + char last = base.fName.CharAt(base.GetSize() - 1); + char first = path.fName.CharAt(0); + if (last != '/' && last != '\\') { + if (first != '/' && first != '\\') { + return plString::Format("%s" PATH_SEPARATOR_STR "%s", + base.fName.c_str(), path.fName.c_str()); + } + return base.fName + path.fName; + } else if (first != '/' && first != '\\') { + return base.fName + path.fName; + } + // Both have a slash, but we only need one + return base.fName + path.fName.Substr(1); +} + + +/* plFileInfo */ +plFileInfo::plFileInfo(const plFileName &filename) + : fFileSize(-1), fCreateTime(), fModifyTime(), fFlags() +{ + if (!filename.IsValid()) + return; + +#if HS_BUILD_FOR_WIN32 + struct __stat64 info; + if (!_wstat64(filename.AsString().ToWchar(), &info) == 0) + return; +#else + struct stat info; + if (!stat(filename.AsString().c_str(), &info) == 0) + return; +#endif + + fFlags |= kEntryExists; + fFileSize = info.st_size; + fCreateTime = info.st_ctime; + fModifyTime = info.st_mtime; + if (info.st_mode & S_IFDIR) + fFlags |= kIsDirectory; + if (info.st_mode & S_IFREG) + fFlags |= kIsNormalFile; +} + + +/* plFileSystem */ +plFileName plFileSystem::GetCWD() +{ + plFileName cwd; + +#if HS_BUILD_FOR_WIN32 + wchar_t cwd_sm[MAX_PATH]; + uint32_t cwd_length = GetCurrentDirectoryW(MAX_PATH, cwd_sm); + if (cwd_length >= MAX_PATH) { + // Buffer not big enough + wchar_t *cwd_lg = new wchar_t[cwd_length]; + GetCurrentDirectoryW(cwd_length, cwd_lg); + cwd = plString::FromWchar(cwd_lg); + delete [] cwd_lg; + } else { + cwd = plString::FromWchar(cwd_sm); + } +#else + char *cwd_a = getcwd(nullptr, 0); + hsAssert(cwd_a, "Failure to get working directory (unsupported libc?)"); + cwd = cwd_a; + free(cwd_a); +#endif + + return cwd; +} + +FILE *plFileSystem::Open(const plFileName &filename, const char *mode) +{ +#if HS_BUILD_FOR_WIN32 + wchar_t wmode[8]; + size_t mlen = strlen(mode); + hsAssert(mlen < arrsize(wmode), "Mode string too long"); + + // Quick and dirty, because mode should only ever be ANSI chars + for (size_t i = 0; i < mlen; ++i) { + hsAssert(!(mode[i] & 0x80), "I SAID mode should ONLY ever be ANSI chars!"); + wmode[i] = static_cast(mode[i]); + } + wmode[mlen] = 0; + + return _wfopen(filename.AsString().ToWchar(), wmode); +#else + return fopen(filename.AsString().c_str(), mode); +#endif +} + +bool plFileSystem::Unlink(const plFileName &filename) +{ +#if HS_BUILD_FOR_WIN32 + return _wunlink(filename.AsString().ToWchar()) == 0; +#else + return unlink(filename.AsString().c_str()) == 0; +#endif +} + +bool plFileSystem::Move(const plFileName &from, const plFileName &to) +{ +#if HS_BUILD_FOR_WIN32 + return MoveFileW(from.AsString().ToWchar(), to.AsString().ToWchar()); +#else + if (!Copy(from, to)) + return false; + return Unlink(from); +#endif +} + +bool plFileSystem::Copy(const plFileName &from, const plFileName &to) +{ +#if HS_BUILD_FOR_WIN32 + return CopyFileW(from.AsString().ToWchar(), to.AsString().ToWchar(), FALSE); +#else + typedef std::unique_ptr> _FileRef; + + _FileRef ffrom(Open(from, "rb"), fclose); + _FileRef fto(Open(to, "wb"), fclose); + if (!ffrom.get() || !fto.get()) + return false; + + size_t count; + uint8_t buffer[4096]; + while (!feof(ffrom.get())) { + count = fread(buffer, sizeof(uint8_t), arrsize(buffer), ffrom.get()); + if (ferror(ffrom.get())) + return false; + fwrite(data, sizeof(uint8_t), count, fto.get()); + } + + return true; +#endif +} + +bool plFileSystem::CreateDir(const plFileName &dir, bool checkParents) +{ + if (checkParents) { + plFileName parent = dir.StripFileName(); + if (parent.IsValid() && !plFileInfo(parent).Exists() && !CreateDir(parent, true)) + return false; + } + + if (plFileInfo(dir).Exists()) + return true; + +#if HS_BUILD_FOR_WIN32 + return CreateDirectoryW(dir.AsString().ToWchar(), nullptr); +#else + return (mkdir(dir.AsString().c_str(), 0755) == 0); +#endif +} + +plFileName plFileSystem::GetUserDataPath() +{ + static plFileName _userData; + + if (!_userData.IsValid()) { +#if HS_BUILD_FOR_WIN32 + wchar_t path[MAX_PATH]; + if (!SHGetSpecialFolderPathW(NULL, path, CSIDL_LOCAL_APPDATA, TRUE)) + return ""; + + _userData = plFileName::Join(plString::FromWchar(path), plProduct::LongName()); +#else + _userData = plFileName::Join(getenv("HOME"), "." + plProduct::LongName()); +#endif + plFileSystem::CreateDir(_userData); + } + + return _userData; +} + +plFileName plFileSystem::GetInitPath() +{ + static plFileName _initPath = plFileName::Join(GetUserDataPath(), "Init"); + plFileSystem::CreateDir(_initPath); + return _initPath; +} + +plFileName plFileSystem::GetLogPath() +{ + static plFileName _logPath = plFileName::Join(GetUserDataPath(), "Log"); + plFileSystem::CreateDir(_logPath); + return _logPath; +} diff --git a/Sources/Plasma/CoreLib/plFileSystem.h b/Sources/Plasma/CoreLib/plFileSystem.h new file mode 100644 index 00000000..2654bb0d --- /dev/null +++ b/Sources/Plasma/CoreLib/plFileSystem.h @@ -0,0 +1,284 @@ +/*==LICENSE==* + +CyanWorlds.com Engine - MMOG client, server and tools +Copyright (C) 2011 Cyan Worlds, Inc. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Additional permissions under GNU GPL version 3 section 7 + +If you modify this Program, or any covered work, by linking or +combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, +NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent +JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK +(or a modified version of those libraries), +containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, +PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG +JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the +licensors of this Program grant you additional +permission to convey the resulting work. Corresponding Source for a +non-source form of such a combination shall include the source code for +the parts of OpenSSL and IJG JPEG Library used as well as that of the covered +work. + +You can contact Cyan Worlds, Inc. by email legal@cyan.com + or by snail mail at: + Cyan Worlds, Inc. + 14617 N Newport Hwy + Mead, WA 99021 + +*==LICENSE==*/ + +#ifndef plFileSystem_Defined +#define plFileSystem_Defined + +#include "plString.h" +#include + +#if HS_BUILD_FOR_WIN32 +# define PATH_SEPARATOR '\\' +# define PATH_SEPARATOR_STR "\\" +#else +# define PATH_SEPARATOR '/' +# define PATH_SEPARATOR_STR "/" +#endif + +/** Represents a filename or path, including utilities for manipulating, + * splitting, and joining path components. + * \sa plFileInfo + */ +class plFileName +{ +public: + /** Construct an empty filename. */ + plFileName() { } + + /** Construct a filename from the UTF-8 character data in \a cstr. */ + plFileName(const char *cstr) : fName(cstr) { } + + /** Construct a filename from the plString argument \a copy. */ + plFileName(const plString ©) : fName(copy) { } + + /** Copy constructor. */ + plFileName(const plFileName ©) : fName(copy.fName) { } + + /** Assignment operator. Same as plFileName(const char *). */ + plFileName &operator=(const char *cstr) + { + fName.operator=(cstr); + return *this; + } + + /** Assignment operator. Same as plFileName(const plString &). */ + plFileName &operator=(const plString ©) + { + fName.operator=(copy); + return *this; + } + + /** Assignment operator. Same as plFileName(const plFileName &). */ + plFileName &operator=(const plFileName ©) + { + fName.operator=(copy.fName); + return *this; + } + + /** Comparison operator. */ + bool operator==(const char *other) const { return fName.operator==(other); } + + /** Comparison operator. */ + bool operator==(const plFileName &other) const { return fName.operator==(other.fName); } + + /** Inverse of operator==(const char *other) const. */ + bool operator!=(const char *other) const { return fName.operator!=(other); } + + /** Inverse of operator==(const plFileName &other) const. */ + bool operator!=(const plFileName &other) const { return fName.operator!=(other.fName); } + + /** Operator overload for use in containers which depend on \c std::less. */ + bool operator<(const plFileName &other) const { return fName.Compare(other.fName) < 0; } + + /** Functor which compares two filenames case-insensitively for sorting. */ + struct less_i + { + bool operator()(const plFileName &_L, const plFileName &_R) const + { return _L.fName.Compare(_R.fName, plString::kCaseInsensitive) < 0; } + }; + + /** Return whether this filename is valid (not empty). */ + bool IsValid() const { return !fName.IsEmpty(); } + + /** Return the length of the filename string (UTF-8). */ + size_t GetSize() const { return fName.GetSize(); } + + /** Convert the filename to a string. This does not resolve relative + * paths or normalize slashes, it just returns the stored name string. + */ + const plString &AsString() const { return fName; } + + /** Return the name portion of the path (including extension). + * For example: + *
plFileName("C:\\Path\\Filename.ext") => "Filename.ext"
+ */ + plString GetFileName() const; + + /** Return the file extension from the filename. + * For example: + *
plFileName("C:\\Path\\Filename.ext") => "ext"
+ */ + plString GetFileExt() const; + + /** Return the name portion of the path, excluding its extension. + * For example: + *
plFileName("C:\\Path\\Filename.ext") => "Filename"
+ */ + plString GetFileNameNoExt() const; + + /** Return the path with the filename portion stripped off. + * For example: + *
plFileName("C:\\Path\\Filename.ext") => "C:\\Path"
+ */ + plFileName StripFileName() const; + + /** Return the filename with the extension stripped off. + * For example: + *
plFileName("C:\\Path\\Filename.ext") => "C:\\Path\\Filename"
+ */ + plFileName StripFileExt() const; + + /** Normalize slashes to a particular format. By default, we use the + * OS's native slash format. + * For example: + *
plFileName("C:\\Path/Filename.ext").Normalize('\\') => "C:\\Path\\Filename.ext"
+ */ + plFileName Normalize(char slash = PATH_SEPARATOR) const; + + /** Expand relative filenames and ./.. pieces to an absolute path. */ + plFileName AbsolutePath() const; + + /** Join two path components together with the correct path separator. + * For example: + *
plFileName::Join("C:\\Path", "Filename.ext") => "C:\\Path\\Filename.ext"
+ */ + static plFileName Join(const plFileName &base, const plFileName &path); + + /** Join three path components together with the correct path separator. + * \todo Make this more efficient. + */ + static plFileName Join(const plFileName &base, const plFileName &path, + const plFileName& path2) + { return Join(Join(base, path), path2); } + + /** Join four path components together with the correct path separator. + * \todo Make this more efficient. + */ + static plFileName Join(const plFileName &base, const plFileName &path, + const plFileName& path2, const plFileName &path3) + { return Join(Join(Join(base, path), path2), path3); } + +private: + plString fName; +}; + + +/** Structure to get information about a file by name. + * \sa plFileName + */ +class plFileInfo +{ +public: + /** Construct an invalid plFileInfo which points to no file. */ + plFileInfo() + : fFileSize(-1), fCreateTime(), fModifyTime(), fFlags() { } + + /** Construct a plFileInfo and fill it with info about the specified + * file, if it exists. + */ + explicit plFileInfo(const plFileName &filename); + + /** Retrieve the filename associated with this info structure. */ + const plFileName &FileName() const { return fName; } + + /** Return whether the plFileInfo has been initialized. */ + bool IsValid() const { return fName.IsValid(); } + + /** Determine whether the file exists on the filesystem. */ + bool Exists() const { return (fFlags & kEntryExists); } + + /** Returns the size of the file on the disk, in bytes. */ + int64_t FileSize() const { return fFileSize; } + + /** Returns the creation time of the file. */ + uint64_t CreateTime() const { return fCreateTime; } + + /** Returns the last modification time of the file. */ + uint64_t ModifyTime() const { return fModifyTime; } + + /** Returns \p true if this file is a directory. */ + bool IsDirectory() const { return (fFlags & kIsDirectory); } + + /** Returns \p true if this file is a regular file. */ + bool IsFile() const { return (fFlags & kIsNormalFile); } + +private: + plFileName fName; + int64_t fFileSize; + uint64_t fCreateTime, fModifyTime; + + enum { + kEntryExists = (1<<0), + kIsDirectory = (1<<1), + kIsNormalFile = (1<<2), + }; + uint32_t fFlags; +}; + + +namespace plFileSystem +{ + /** Get the current working directory of the application. */ + plFileName GetCWD(); + + /** Open a file using the correct platform fopen API. */ + FILE *Open(const plFileName &filename, const char *mode); + + /** Delete a file from the filesystem. */ + bool Unlink(const plFileName &filename); + + /** Move or rename a file. */ + bool Move(const plFileName &from, const plFileName &to); + + /** Copy a file to a new location. */ + bool Copy(const plFileName &from, const plFileName &to); + + /** Create a directory. If \a checkParents is \p true, this will also + * check the whole path and create any parent directories as needed. + */ + bool CreateDir(const plFileName &dir, bool checkParents = false); + + /** Get the User's data directory. If it doesn't exist, this will + * create it. + */ + plFileName GetUserDataPath(); + + /** Get the Init script direcotory. If it doesn't exist, this will + * create it. */ + plFileName GetInitPath(); + + /** Get the Log output directory. If it doesn't exist, this will + * create it. */ + plFileName GetLogPath(); +} + +#endif // plFileSystem_Defined diff --git a/Sources/Plasma/CoreLib/plString.cpp b/Sources/Plasma/CoreLib/plString.cpp index 5f390933..5b0be23b 100644 --- a/Sources/Plasma/CoreLib/plString.cpp +++ b/Sources/Plasma/CoreLib/plString.cpp @@ -877,110 +877,3 @@ size_t ustrlen(const UniChar *ustr, size_t max) ; return length; } - - -/* plFileName */ -static_assert(sizeof(plFileName) == sizeof(plString), - "plFileName should be a thin wrapper around plString"); - -plString plFileName::GetFileName() const -{ - int end = fName.FindLast('/'); - if (end < 0) - end = fName.FindLast('\\'); - if (end < 0) - return fName; - - return fName.Substr(end + 1); -} - -plString plFileName::GetFileExt() const -{ - int dot = fName.FindLast('.'); - - // Be sure not to get a dot in the directory! - int end = fName.FindLast('/'); - if (end < 0) - end = fName.FindLast('\\'); - - if (dot > end) - return fName.Substr(dot + 1); - - return plString::Null; -} - -plString plFileName::GetFileNameNoExt() const -{ - int dot = fName.FindLast('.'); - - int end = fName.FindLast('/'); - if (end < 0) - end = fName.FindLast('\\'); - - // Be sure not to get a dot in the directory! - if (dot > end) - return fName.Substr(end + 1, dot - end - 1); - return fName.Substr(end + 1); -} - -plFileName plFileName::StripFileName() const -{ - int end = fName.FindLast('/'); - if (end < 0) - end = fName.FindLast('\\'); - if (end < 0) - return *this; - - return fName.Left(end); -} - -plFileName plFileName::StripFileExt() const -{ - int dot = fName.FindLast('.'); - - // Be sure not to get a dot in the directory! - int end = fName.FindLast('/'); - if (end < 0) - end = fName.FindLast('\\'); - - if (dot > end) - return fName.Left(dot); - - return *this; -} - -plFileName plFileName::Normalize(char slash) const -{ - plStringBuffer norm; - char *norm_p = norm.CreateWritableBuffer(fName.GetSize()); - for (const char *p = fName.c_str(); *p; ++p) { - if (*p == '/' || *p == '\\') - *norm_p++ = slash; - else - *norm_p++ = *p; - } - *norm_p = 0; - return plString(norm); -} - -plFileName plFileName::Join(const plFileName &base, const plFileName &path) -{ - if (!base.IsValid()) - return path; - if (!path.IsValid()) - return base; - - char last = base.fName.CharAt(base.GetSize() - 1); - char first = path.fName.CharAt(0); - if (last != '/' && last != '\\') { - if (first != '/' && first != '\\') { - return plString::Format("%s" PATH_SEPARATOR_STR "%s", - base.fName.c_str(), path.fName.c_str()); - } - return base.fName + path.fName; - } else if (first != '/' && first != '\\') { - return base.fName + path.fName; - } - // Both have a slash, but we only need one - return base.fName + path.fName.Substr(1); -} diff --git a/Sources/Plasma/CoreLib/plString.h b/Sources/Plasma/CoreLib/plString.h index 410315cd..38ac1a51 100644 --- a/Sources/Plasma/CoreLib/plString.h +++ b/Sources/Plasma/CoreLib/plString.h @@ -223,7 +223,7 @@ public: * \note This constructor expects the input to be UTF-8 encoded. For * conversion from ISO-8859-1 8-bit data, use FromIso8859_1(). */ - plString(const char *cstr) { IConvertFromUtf8(cstr, kSizeAuto); } + plString(const char *cstr, size_t size = kSizeAuto) { IConvertFromUtf8(cstr, size); } /** Copy constructor. */ plString(const plString ©) : fUtf8Buffer(copy.fUtf8Buffer) { } @@ -539,13 +539,6 @@ public: static plString Fill(size_t count, char c); public: - /** Functor which compares two strings case-sensitively for sorting. */ - struct less - { - bool operator()(const plString &_L, const plString &_R) const - { return _L.Compare(_R, kCaseSensitive) < 0; } - }; - /** Functor which compares two strings case-insensitively for sorting. */ struct less_i { @@ -553,13 +546,6 @@ public: { return _L.Compare(_R, kCaseInsensitive) < 0; } }; - /** Functor which compares two strings case-sensitively for equality. */ - struct equal - { - bool operator()(const plString &_L, const plString &_R) const - { return _L.Compare(_R, kCaseSensitive) == 0; } - }; - /** Functor which compares two strings case-insensitively for equality. */ struct equal_i { @@ -660,124 +646,4 @@ private: /** \p strlen implementation for UniChar based C-style string buffers. */ size_t ustrlen(const UniChar *ustr, size_t max = plString::kSizeAuto); - -#if HS_BUILD_FOR_WIN32 -# define PATH_SEPARATOR '\\' -# define PATH_SEPARATOR_STR "\\" -#else -# define PATH_SEPARATOR '/' -# define PATH_SEPARATOR_STR "/" -#endif - -/** Subclass of plString with specific methods to help deal with common - * filename manipulation tasks. - */ -class plFileName -{ -public: - /** Construct an empty filename. */ - plFileName() { } - - /** Construct a filename from the UTF-8 character data in \a cstr. */ - plFileName(const char *cstr) : fName(cstr) { } - - /** Construct a filename from the plString argument \a copy. */ - plFileName(const plString ©) : fName(copy) { } - - /** Copy constructor. */ - plFileName(const plFileName ©) : fName(copy.fName) { } - - /** Assignment operator. Same as plFileName(const char *). */ - plFileName &operator=(const char *cstr) - { - fName.operator=(cstr); - return *this; - } - - /** Assignment operator. Same as plFileName(const plString &). */ - plFileName &operator=(const plString ©) - { - fName.operator=(copy); - return *this; - } - - /** Assignment operator. Same as plFileName(const plFileName &). */ - plFileName &operator=(const plFileName ©) - { - fName.operator=(copy.fName); - return *this; - } - - /** Return whether this filename is valid (not empty). */ - bool IsValid() const { return !fName.IsEmpty(); } - - /** Return the length of the filename string (UTF-8). */ - size_t GetSize() const { return fName.GetSize(); } - - /** Convert the filename to a string. This does not resolve relative - * paths or normalize slashes, it just returns the stored name string. - */ - const plString &AsString() const { return fName; } - - /** Return the name portion of the path (including extension). - * For example: - *
plFileName("C:\\Path\\Filename.ext") => "Filename.ext"
- */ - plString GetFileName() const; - - /** Return the file extension from the filename. - * For example: - *
plFileName("C:\\Path\\Filename.ext") => "ext"
- */ - plString GetFileExt() const; - - /** Return the name portion of the path, excluding its extension. - * For example: - *
plFileName("C:\\Path\\Filename.ext") => "Filename"
- */ - plString GetFileNameNoExt() const; - - /** Return the path with the filename portion stripped off. - * For example: - *
plFileName("C:\\Path\\Filename.ext") => "C:\\Path"
- */ - plFileName StripFileName() const; - - /** Return the filename with the extension stripped off. - * For example: - *
plFileName("C:\\Path\\Filename.ext") => "C:\\Path\\Filename"
- */ - plFileName StripFileExt() const; - - /** Normalize slashes to a particular format. By default, we use the - * OS's native slash format. - * For example: - *
plFileName("C:\\Path/Filename.ext").Normalize("\\") => "C:\\Path\\Filename.ext"
- */ - plFileName Normalize(char slash = PATH_SEPARATOR) const; - - /** Join two path components together with the correct path separator. - * For example: - *
plFileName::Join("C:\\Path", "Filename.ext") => "C:\\Path\\Filename.ext"
- */ - static plFileName Join(const plFileName &base, const plFileName &path); - - /** Join three path components together with the correct path separator. - * \todo Make this more efficient. - */ - static plFileName Join(const plFileName &base, const plFileName &path, - const plFileName& path2) - { return Join(Join(base, path), path2); } - - /** Join four path components together with the correct path separator. - * \todo Make this more efficient. - */ - static plFileName Join(const plFileName &base, const plFileName &path, - const plFileName& path2, const plFileName &path3) - { return Join(Join(Join(base, path), path2), path3); } - -private: - plString fName; -}; - #endif //plString_Defined