/* * Copyright 2004-2007, Ingo Weinhold, bonefish@users.sf.net. * Distributed under the terms of the MIT License. */ /** A simple class wrapping a path. Has a fixed-sized buffer. */ #include "KPath.h" #include #include "fssh_string.h" #include "vfs.h" // debugging #define TRACE(x) ; //#define TRACE(x) dprintf x KPath::KPath(fssh_size_t bufferSize) : fBuffer(NULL), fBufferSize(0), fPathLength(0), fLocked(false) { SetTo(NULL, bufferSize); } KPath::KPath(const char* path, bool normalize, fssh_size_t bufferSize) : fBuffer(NULL), fBufferSize(0), fPathLength(0), fLocked(false) { SetTo(path, normalize, bufferSize); } KPath::KPath(const KPath& other) : fBuffer(NULL), fBufferSize(0), fPathLength(0), fLocked(false) { *this = other; } KPath::~KPath() { free(fBuffer); } fssh_status_t KPath::SetTo(const char* path, bool normalize, fssh_size_t bufferSize) { if (bufferSize == 0) bufferSize = FSSH_B_PATH_NAME_LENGTH; // free the previous buffer, if the buffer size differs if (fBuffer && fBufferSize != bufferSize) { free(fBuffer); fBuffer = NULL; fBufferSize = 0; } fPathLength = 0; fLocked = false; // allocate buffer if (!fBuffer) fBuffer = (char*)malloc(bufferSize); if (!fBuffer) return FSSH_B_NO_MEMORY; if (fBuffer) { fBufferSize = bufferSize; fBuffer[0] = '\0'; } return SetPath(path, normalize); } fssh_status_t KPath::InitCheck() const { return fBuffer ? FSSH_B_OK : FSSH_B_NO_MEMORY; } fssh_status_t KPath::SetPath(const char *path, bool normalize) { if (!fBuffer) return FSSH_B_NO_INIT; if (path) { if (normalize) { // normalize path fssh_status_t error = vfs_normalize_path(path, fBuffer, fBufferSize, true); if (error != FSSH_B_OK) { SetPath(NULL); return error; } fPathLength = fssh_strlen(fBuffer); } else { // don't normalize path fssh_size_t length = fssh_strlen(path); if (length >= fBufferSize) return FSSH_B_BUFFER_OVERFLOW; fssh_memcpy(fBuffer, path, length + 1); fPathLength = length; _ChopTrailingSlashes(); } } else { fBuffer[0] = '\0'; fPathLength = 0; } return FSSH_B_OK; } const char* KPath::Path() const { return fBuffer; } char * KPath::LockBuffer() { if (!fBuffer || fLocked) return NULL; fLocked = true; return fBuffer; } void KPath::UnlockBuffer() { if (!fLocked) { TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n")); return; } fLocked = false; fPathLength = fssh_strnlen(fBuffer, fBufferSize); if (fPathLength == fBufferSize) { TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n")); fPathLength--; fBuffer[fPathLength] = '\0'; } _ChopTrailingSlashes(); } const char * KPath::Leaf() const { if (!fBuffer) return NULL; // only "/" has trailing slashes -- then we have to return the complete // buffer, as we have to do in case there are no slashes at all if (fPathLength != 1 || fBuffer[0] != '/') { for (int32_t i = fPathLength - 1; i >= 0; i--) { if (fBuffer[i] == '/') return fBuffer + i + 1; } } return fBuffer; } fssh_status_t KPath::ReplaceLeaf(const char *newLeaf) { const char *leaf = Leaf(); if (!leaf) return FSSH_B_NO_INIT; int32_t leafIndex = leaf - fBuffer; // chop off the current leaf (don't replace "/", though) if (leafIndex != 0 || fBuffer[leafIndex - 1]) { fBuffer[leafIndex] = '\0'; fPathLength = leafIndex; _ChopTrailingSlashes(); } // if a leaf was given, append it if (newLeaf) return Append(newLeaf); return FSSH_B_OK; } fssh_status_t KPath::Append(const char *component, bool isComponent) { // check initialization and parameter if (!fBuffer) return FSSH_B_NO_INIT; if (!component) return FSSH_B_BAD_VALUE; if (fPathLength == 0) return SetPath(component); // get component length fssh_size_t componentLength = fssh_strlen(component); if (componentLength < 1) return FSSH_B_OK; // if our current path is empty, we just copy the supplied one // compute the result path len bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/' && component[0] != '/'; fssh_size_t resultPathLength = fPathLength + componentLength + (insertSlash ? 1 : 0); if (resultPathLength >= fBufferSize) return FSSH_B_BUFFER_OVERFLOW; // compose the result path if (insertSlash) fBuffer[fPathLength++] = '/'; fssh_memcpy(fBuffer + fPathLength, component, componentLength + 1); fPathLength = resultPathLength; return FSSH_B_OK; } KPath& KPath::operator=(const KPath& other) { SetTo(other.fBuffer, other.fBufferSize); return *this; } KPath& KPath::operator=(const char* path) { SetTo(path); return *this; } bool KPath::operator==(const KPath& other) const { if (!fBuffer) return !other.fBuffer; return (other.fBuffer && fPathLength == other.fPathLength && fssh_strcmp(fBuffer, other.fBuffer) == 0); } bool KPath::operator==(const char* path) const { if (!fBuffer) return (!path); return path && !fssh_strcmp(fBuffer, path); } bool KPath::operator!=(const KPath& other) const { return !(*this == other); } bool KPath::operator!=(const char* path) const { return !(*this == path); } void KPath::_ChopTrailingSlashes() { if (fBuffer) { while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/') fBuffer[--fPathLength] = '\0'; } }