* Copyright 2004-2007, Ingo Weinhold, bonefish@users.sf.net.
* Distributed under the terms of the MIT License.
*/
#include "KPath.h"
#include <stdlib.h>
#include "fssh_string.h"
#include "vfs.h"
#define TRACE(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;
if (fBuffer && fBufferSize != bufferSize) {
free(fBuffer);
fBuffer = NULL;
fBufferSize = 0;
}
fPathLength = 0;
fLocked = false;
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) {
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 {
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;
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;
if (leafIndex != 0 || fBuffer[leafIndex - 1]) {
fBuffer[leafIndex] = '\0';
fPathLength = leafIndex;
_ChopTrailingSlashes();
}
if (newLeaf)
return Append(newLeaf);
return FSSH_B_OK;
}
fssh_status_t
KPath::Append(const char *component, bool isComponent)
{
if (!fBuffer)
return FSSH_B_NO_INIT;
if (!component)
return FSSH_B_BAD_VALUE;
if (fPathLength == 0)
return SetPath(component);
fssh_size_t componentLength = fssh_strlen(component);
if (componentLength < 1)
return FSSH_B_OK;
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;
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';
}
}