218 lines
5.8 KiB
C++
218 lines
5.8 KiB
C++
/*
|
|
* Copyright 2015 - 2024 gary@drinkingtea.net
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#include <ox/std/memops.hpp>
|
|
#include <ox/std/strops.hpp>
|
|
#include <ox/std/trace.hpp>
|
|
#include "pathiterator.hpp"
|
|
|
|
namespace ox {
|
|
|
|
PathIterator::PathIterator(const char *path, std::size_t maxSize, std::size_t iterator) {
|
|
m_path = path;
|
|
m_maxSize = maxSize;
|
|
m_iterator = iterator;
|
|
}
|
|
|
|
PathIterator::PathIterator(const char *path): PathIterator(path, ox::strlen(path)) {
|
|
}
|
|
|
|
PathIterator::PathIterator(CRStringView path): PathIterator(path.data(), path.bytes()) {
|
|
}
|
|
|
|
/**
|
|
* @return 0 if no error
|
|
*/
|
|
Error PathIterator::dirPath(char *out, std::size_t outSize) {
|
|
const auto idx = ox::lastIndexOf(m_path, '/', m_maxSize);
|
|
const auto size = static_cast<std::size_t>(idx + 1);
|
|
if (idx >= 0 && size < outSize) {
|
|
ox::memcpy(out, m_path, size);
|
|
out[size] = 0;
|
|
return OxError(0);
|
|
} else {
|
|
return OxError(1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return 0 if no error
|
|
*/
|
|
Error PathIterator::fileName(char *out, std::size_t outSize) {
|
|
auto idx = ox::lastIndexOf(m_path, '/', m_maxSize);
|
|
if (idx >= 0) {
|
|
idx++; // pass up the preceding /
|
|
std::size_t fileNameSize = static_cast<size_t>(ox::strlen(&m_path[idx]));
|
|
if (fileNameSize < outSize) {
|
|
ox::memcpy(out, &m_path[idx], fileNameSize);
|
|
out[fileNameSize] = 0;
|
|
return OxError(0);
|
|
} else {
|
|
return OxError(1);
|
|
}
|
|
} else {
|
|
return OxError(2);
|
|
}
|
|
}
|
|
|
|
// Gets the get item in the path
|
|
Error PathIterator::get(char *pathOut, std::size_t pathOutSize) {
|
|
std::size_t size = 0;
|
|
if (m_iterator >= m_maxSize) {
|
|
oxTracef("ox.fs.PathIterator.get", "m_iterator ({}) >= m_maxSize ({})", m_iterator, m_maxSize);
|
|
return OxError(1);
|
|
}
|
|
if (!ox::strlen(&m_path[m_iterator])) {
|
|
oxTrace("ox.fs.PathIterator.get", "!ox::strlen(&m_path[m_iterator])");
|
|
return OxError(1);
|
|
}
|
|
auto start = m_iterator;
|
|
if (m_path[start] == '/') {
|
|
start++;
|
|
}
|
|
// end is at the next /
|
|
const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
|
|
// correct end if it is invalid, which happens if there is no next /
|
|
if (!substr) {
|
|
substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
|
|
}
|
|
const auto end = static_cast<size_t>(substr - m_path);
|
|
size = end - start;
|
|
// cannot fit the output in the output parameter
|
|
if (size >= pathOutSize || size == 0) {
|
|
return OxError(1);
|
|
}
|
|
ox::memcpy(pathOut, &m_path[start], size);
|
|
// truncate trailing /
|
|
if (size && pathOut[size - 1] == '/') {
|
|
size--;
|
|
}
|
|
pathOut[size] = 0; // end with null terminator
|
|
return OxError(0);
|
|
}
|
|
|
|
// Gets the get item in the path
|
|
Error PathIterator::next(char *pathOut, std::size_t pathOutSize) {
|
|
std::size_t size = 0;
|
|
auto retval = OxError(1);
|
|
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
|
|
retval = OxError(0);
|
|
if (m_path[m_iterator] == '/') {
|
|
m_iterator++;
|
|
}
|
|
const auto start = m_iterator;
|
|
// end is at the next /
|
|
const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
|
|
// correct end if it is invalid, which happens if there is no next /
|
|
if (!substr) {
|
|
substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
|
|
}
|
|
const auto end = static_cast<size_t>(substr - m_path);
|
|
size = end - start;
|
|
// cannot fit the output in the output parameter
|
|
if (size >= pathOutSize) {
|
|
return OxError(1);
|
|
}
|
|
ox::memcpy(pathOut, &m_path[start], size);
|
|
}
|
|
// truncate trailing /
|
|
if (size && pathOut[size - 1] == '/') {
|
|
size--;
|
|
}
|
|
pathOut[size] = 0; // end with null terminator
|
|
m_iterator += size;
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
* @return 0 if no error
|
|
*/
|
|
Error PathIterator::get(IString<MaxFileNameLength> *fileName) {
|
|
return get(fileName->data(), fileName->cap());
|
|
}
|
|
|
|
/**
|
|
* @return 0 if no error
|
|
*/
|
|
Error PathIterator::next(IString<MaxFileNameLength> *fileName) {
|
|
return next(fileName->data(), fileName->cap());
|
|
}
|
|
|
|
Result<std::size_t> PathIterator::nextSize() const {
|
|
std::size_t size = 0;
|
|
auto retval = OxError(1);
|
|
auto it = m_iterator;
|
|
if (it < m_maxSize && ox::strlen(&m_path[it])) {
|
|
retval = OxError(0);
|
|
if (m_path[it] == '/') {
|
|
it++;
|
|
}
|
|
const auto start = it;
|
|
// end is at the next /
|
|
const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
|
|
// correct end if it is invalid, which happens if there is no next /
|
|
if (!substr) {
|
|
substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
|
|
}
|
|
const auto end = static_cast<std::size_t>(substr - m_path);
|
|
size = end - start;
|
|
}
|
|
it += size;
|
|
return {size, retval};
|
|
}
|
|
|
|
bool PathIterator::hasNext() const {
|
|
std::size_t size = 0;
|
|
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
|
|
std::size_t start = m_iterator;
|
|
if (m_path[start] == '/') {
|
|
start++;
|
|
}
|
|
// end is at the next /
|
|
const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
|
|
// correct end if it is invalid, which happens if there is no next /
|
|
if (!substr) {
|
|
substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
|
|
}
|
|
const auto end = static_cast<std::size_t>(substr - m_path);
|
|
size = end - start;
|
|
}
|
|
return size > 0;
|
|
}
|
|
|
|
bool PathIterator::valid() const {
|
|
return m_iterator < m_maxSize && m_path[m_iterator] != 0;
|
|
}
|
|
|
|
PathIterator PathIterator::next() const {
|
|
std::size_t size = 0;
|
|
auto iterator = m_iterator;
|
|
if (iterator < m_maxSize && ox::strlen(&m_path[iterator])) {
|
|
if (m_path[iterator] == '/') {
|
|
iterator++;
|
|
}
|
|
const auto start = iterator;
|
|
// end is at the next /
|
|
const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
|
|
// correct end if it is invalid, which happens if there is no next /
|
|
if (!substr) {
|
|
substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
|
|
}
|
|
const auto end = static_cast<std::size_t>(substr - m_path);
|
|
size = end - start;
|
|
}
|
|
iterator += size;
|
|
return {m_path, m_maxSize, iterator + 1};
|
|
}
|
|
|
|
const char *PathIterator::fullPath() const {
|
|
return m_path;
|
|
}
|
|
|
|
}
|