CXFilePath

From cxwiki

The CXFilePath class provides an platform-neutral file path representation. The file paths are encoded in UTF8 with forward slash ("/") separators. No other characters are reserved or prevented. CXFilePath objects are considered case sensitive, regardless of whether the underlying file system is or is not case sensitive. The underlying CXFilePathBase templated class allows selection of a string container. CXFilePath is implemented as CXFilePathBase<CXString>. As an alternative, the application can use CXFilePathBase<CXStringEdit> instead of CXFilePath if high-performance editing is required.
 
CXFilePath is intended to refer to paths in the local file system, and as such its behaviour may differ in subtle ways depending on the host platform. Specifically, the concept of a "file system root" differs between OSes, and the platforms may differ with respect to which characters or names are permissible. It is uncommon that the application would need to be aware of these differences.
 
The standard "/./" and "/../" constructs are supported for referring to the current directory and parent directory respectively.
 

Native Encodings

Where the host platform differs from these details, transformation between CXFilePath encoding and the native encoding occurs at the lowest possible level. The application should never need to deal with native encoding except where it is directly accessing native functions (bypassing the cxsource framework).
 

Win32

Windows filepaths are UTF-16 encoded, use backslash ("\") separators, have virtually unlimited length and support a wide range of characters. Unfortunately, the Windows shell imposes a lot of legacy restrictions on paths, such that a typical path is limited to 230 characters, allows a forward slash ("/") separator in most but not all cases, doesn't allow certain characters to appear at all, doesn't allow certain characters to appear at certain locations in the path, and treats certain filenames as special devices. Further complicating this scenario, many Win32 API functions accept shell paths.

The CXFilePath abstract-to-native mappings resolve this as follows:

  • If the filepath is longer than 230 characters, and represents a windows network path (ie. is prefixed with "//"), it is converted to a UNC path by stripping the two leading slashes and then prefixing "\\?\UNC\".
  • If the filepath is longer than 230 characters, and is an absolute path, it is converted to a UNC path by prefixing "\\?\UNC\"
  • Otherwise, the filepath is used as-is.

All forward slash character ("/") are converted to backslash characters ("\").

TBD: Absolute vs relative paths.
 
TBD.
C:\foo\bah.txt
C:\foo/bah.txt
\\machine\share\foo\bah.txt
\\?..
 

Posix

CXFilePath directly adopts posix filepath format and no significant transformations are required to convert between a posix file path and a CXFilePath. If the underlying APIs do not accept UTF-8 input, then a string codepage transformation may be required.
 
A leading slash indicates an absolute path, otherwise the path is considered relative. The slash character ("/") is the root element of any absolute filepath; other volumes are mounted as folders within the root filesystem.
 

Construction

Various constructors are available to allow a CXFilePath to be build from a C String, string classes, etc.

//
CXFilePath(void);

//
CXFilePath(const char* __nullable path);
CXFilePath(const CXString& path);
CXFilePath(const CXStringEdit& path);
template <class OP> inline CXFilePath(const CXFilePathBase<OP>& other);

 

Nullness

CXFilePath does not distinguish between null and empty states. An empty filepath cannot be used to reference a file (although it can be appended as a relative filepath, to no effect) and so it is typically treated as a sentinel for a null / invalid / unset value.

// Returns true if this CXFilePath object has a non-zero length.
operator bool(void) const;

// Returns true if this CXFilePath is empty.
bool operator !(void) const;

 

Path Operations

Various methods are available for working with path components.
// Returns the filename portion of this path.
CXString GetFilename(void) const;
  
// Removes and returns the leftmost path element (root).
CXString StripLeftElement(bool bShouldStripFilenameElement = true);

// Remove and return the rightmost path element (filename).
CXString StripRightElement(void);

// Returns the path minus its rightmost path element.
CXString GetParentPath(void) const;

// Returns true if this object represents an absolute path.
// TBD.
bool IsAbsolutePath(void) const;

// Returns true if this object represents the filesystem root.
// TBD.
bool IsRoot(void) const;

// Returns true if this object contains a file name but no path
// separators.
bool IsFilenameOnly(void) const;

// Appends the specified suffix to this filepath. This ensures
// that there is a single path separator at the end of this
// path, before the start of the child path.
void AddPath(CXStringArgument child);

// Appends the specified string suffix to this filepath. This
// does not add or remove any path separators.
void Add(const char* __nonnull child);

// Attempt to resolve any './' and '../' references, symlinks, etc.
// TBD.
bool Resolve(void);

 

String Manipulation

Read-only access to the underlying string payload is available.

// Returns a zero-terminated C String internal pointer to this
// object's payload. This remains valid until the CXFilePath
// object is deleted, or until its length is changed (implicitly
// or explicitly).
operator const char* __nonnull (void) const;

// Returns a CXStringArgument temporary which references this
// object's payload. This remains valid until the CXFilePath
// object is deleted, or until its length is changed (implicitly
// or explicitly).
operator CXStringArgument(void) const;

// Returns a reference to a character in this object's payload.
// The index is a byte offset, not a Glyph index. Valid indices
// are within the [0..Length()] range.
const char& operator[](int pos) const;

// Returns the number of bytes in this object's string payload.
size_t Length(void) const;

// (Cocoa or iOS only.) Returns an NSString* object which 
// contains this object's filepath as a string.
operator NSString* __nonnull (void) const;

// Returns this object's filepath as a CXString.
const CXString& AsString(void) const;

// Returns a zero-terminated C String internal pointer to this
// object's payload. This remains valid until the CXFilePath
// object is deleted, or until its length is changed (implicitly
// or explicitly).
const char* __nonnull c_str(void) const;

// Returns the first byte of this filepath. Returns zero
// if the filepath is empty.
char GetFirstChar(void) const;

 

Comparison

Bytewise comparison operators are available. A c++ sort operator is available. If case-insensitive operations are required, the CXStringUtils functions should be used.

// Byte-for-byte string equality test.
bool operator==(const CXFilePath& path) const;
bool operator==(const CXString& str) const;
bool operator==(const char* __nonnull str) const;

// Byte-for-byte string inequality test.
bool operator!=(const CXFilePath& path) const;
bool operator!=(const CXString& str) const;
bool operator!=(const char* __nonnull str) const;

// Sort operator.
bool operator<(const QUAL& other) const;

 

Helper Methods

Assorted helper methods for working with file paths.

// Convert the entire filepath to lowercase; useful for filename 
// matching on case-insensitive filesystems.
void ToLower(void);

// Given a proposed filename (NOT a filepath), this function 
// returns a filename which is considered valid and safe on the
// local platform. The returned filename is not guaranteed unique.
static CXString GetSafeFilename(const char* __nonnull filename);

// Given an absolute filepath as the first parameter, this returns
// the filepath verbatim. Given a relative filepath as the first
// parameter, the return value is a path concatenation of the
// second parameter and the first parameter.
static CXFilePath ResolvePathRelativeTo(const CXFilePath& relativeOrAbsolutePath, const CXFilePath& basePathForRelative);

// If the second parameter is a path prefix of the first parameter,
// the prefix is stripped and the remaining relative path is 
// returned. Otherwise, an empty filepath is returned.
static CXFilePath GetPathRelativeTo(const CXFilePath& absolutePath, CXFilePath basePathForRelative);

// This function returns whether the second parameter is a path
// prefix of the first parameter.
static bool IsPathRelativeTo(const CXFilePath& absolutePath, const CXFilePath& basePathForRelative);

// Returns a "file://" URI representing the same file as this object.
CXString AsFileURIString(void) const;

// Returns the path concatenation of this filepath and the specified
// child path.
CXFilePath GetAddPath(const char* __nonnull child);

 

Streamers

The CXFilePath object may be streamed to and from a binary stream.

// Writes this object's filepath to the specified binary stream.
template <CX_STREAMER_TMPL_DECL> CX_STREAMER_QUAL& operator << (CX_STREAMER_QUAL& stream, const CXFilePath& src);

// Reads a filepath from the specified binary stream and assigns
// it to this object. This should only be used only trusted streams,
// as the resultant filepath could in theory be gigabytes in size.
template <CX_STREAMER_TMPL_DECL> CX_STREAMER_QUAL& operator >> (CX_STREAMER_QUAL& stream, CXFilePath& dst);

 

Stringification

Stringification is used when converting arbitrary c++ types to a string, typically for logging or composing human-readable output text.

// Converts the specified filepath to a string.
void CXStringify(CXString& o_result, const CXFilePath& value);