Mercurial > foo_out_sdl
diff foosdk/sdk/foobar2000/SDK/fsItem.cpp @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/SDK/fsItem.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,429 @@ +#include "foobar2000-sdk-pch.h" + + +t_filestats2 fsItemBase::getStatsOpportunist() { + return filestats2_invalid; +} + +void fsItemBase::remove(abort_callback& aborter) { + getFS()->remove(this->canonicalPath()->c_str(), aborter); +} + +fb2k::stringRef fsItemBase::shortName() { + return nameWithExt(); +} + +file::ptr fsItemFile::openRead(abort_callback& aborter) { + return open(filesystem::open_mode_read, aborter); +} +file::ptr fsItemFile::openWriteExisting(abort_callback& aborter) { + return open(filesystem::open_mode_write_existing, aborter); +} +file::ptr fsItemFile::openWriteNew(abort_callback& aborter) { + return open(filesystem::open_mode_write_new, aborter); +} + +void fsItemFolder::removeRecur(abort_callback& aborter) { + auto list = this->listContents(listMode::filesAndFolders | listMode::hidden | listMode::suppressStats, aborter); + for (auto i : list->typed< fsItemBase >()) { + fsItemFolderPtr f; + if (f &= i) f->removeRecur(aborter); + else i->remove(aborter); + } + + this->remove(aborter); +} + +void fsItemFile::copyToOther(fsItemFilePtr other, abort_callback& aborter) { + aborter.check(); + + auto fSource = this->openRead(aborter); + auto fTarget = other->openWriteNew(aborter); + file::g_transfer_file(fSource, fTarget, aborter); + + // fTarget->commit(aborter); + + // we cannot transfer other properties, this should be overridden for such +} + +fsItemPtr fsItemBase::copyTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) { + aborter.check(); + { + fsItemFilePtr f; + if (f &= this) { + auto target = folder->createFile(desiredName, createMode, aborter); + f->copyToOther(target, aborter); + return std::move(target); + } + } + { + fsItemFolderPtr f; + if (f &= this) { + auto target = folder->createFolder(desiredName, createMode, aborter); + auto contents = f->listContents(listMode::filesAndFolders | listMode::hidden | listMode::suppressStats, aborter); + for (auto item : contents->typed<fsItemBase>()) { + item->copyTo(target, createMode, aborter); + } + return std::move(target); + } + } + PFC_ASSERT(!"Should not get here, bad fsItemBase object"); + return nullptr; +} + +fsItemPtr fsItemBase::copyTo(fsItemFolderPtr folder, unsigned createMode, abort_callback& aborter) { + auto temp = this->nameWithExt(); + return this->copyTo(folder, temp->c_str(), createMode, aborter); +} + +fsItemPtr fsItemBase::moveTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) { + auto ret = this->copyTo(folder, desiredName, createMode, aborter); + fsItemFolder::ptr asFolder; + if (asFolder &= this) { + asFolder->removeRecur(aborter); + } else { + this->remove(aborter); + } + return ret; +} + +fsItemPtr fsItemBase::moveTo(fsItemFolderPtr folder, unsigned createMode, abort_callback& aborter) { + auto fn = this->nameWithExt(); + return this->moveTo(folder, fn->c_str(), createMode, aborter); +} +fb2k::memBlockRef fsItemFile::readWhole(size_t sizeSanity, abort_callback& aborter) { + auto file = this->openRead(aborter); + auto size64 = file->get_size_ex(aborter); + if (size64 > sizeSanity) throw exception_io_data(); + auto size = (size_t)size64; + pfc::mem_block block; + block.resize(size); + file->read_object(block.ptr(), size, aborter); + return fb2k::memBlock::blockWithData(std::move(block)); +} + +namespace { + static void uniqueFn(pfc::string8& fn, unsigned add) { + if (add > 0) { + pfc::string8 fnOnly = pfc::remove_ext_v2(fn); + pfc::string8 ext = pfc::extract_ext_v2(fn); + fn = std::move(fnOnly); + fn << " (" << add << ")"; + if (ext.length() > 0) fn << "." << ext; + } + } + + using namespace fb2k; + class fsItemFileStd : public fsItemFile { + public: + fsItemFileStd(filesystem::ptr fs, stringRef canonicalPath, t_filestats2 const & opportunistStats) : m_fs(fs), m_path(canonicalPath), m_opportunistStats(opportunistStats) { + m_opportunistStats.set_folder(false); + m_opportunistStats.set_remote(fs->is_remote(canonicalPath->c_str())); + } + + filesystem::ptr getFS() override { return m_fs; } + + bool isRemote() override { return m_fs->is_remote(m_path->c_str()); } + + t_filestats2 getStats2(uint32_t s2flags, abort_callback& a) override { + auto s = m_fs->get_stats2_(m_path->c_str(), s2flags, a); + PFC_ASSERT((s2flags & stats2_fileOrFolder) == 0 || !s.is_folder()); + return s; + } + + fb2k::stringRef canonicalPath() override { return m_path; } + + fb2k::stringRef nameWithExt() override { + pfc::string8 temp; + m_fs->extract_filename_ext(m_path->c_str(), temp); + return makeString(temp); + } + fb2k::stringRef shortName() override { + pfc::string8 temp; + if (m_fs->get_display_name_short_(m_path->c_str(), temp)) return makeString(temp); + return nameWithExt(); + } + t_filestats2 getStatsOpportunist() override { + return m_opportunistStats; + } + file::ptr open(uint32_t openMode, abort_callback& aborter) override { + file::ptr ret; + m_fs->open(ret, m_path->c_str(), openMode, aborter); + return ret; + } + fb2k::memBlockRef readWhole(size_t sizeSanity, abort_callback& aborter) override { + // Prefer fs->readWholeFile over fsItemFile methods as the fs object might implement it + return m_fs->readWholeFile(m_path->c_str(), sizeSanity, aborter); + } + fsItemPtr moveTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) override { + for (unsigned add = 0; ; ++add) { + pfc::string8 fn(desiredName); uniqueFn(fn, add); + pfc::string8 dst(folder->canonicalPath()->c_str()); + dst.end_with(m_fs->pathSeparator()); + dst += fn; + bool bDidExist = false; + try { + if (createMode == createMode::allowExisting) m_fs->move_overwrite(m_path->c_str(), dst, aborter); + else m_fs->move(m_path->c_str(), dst, aborter); + } catch (exception_io_already_exists const &) { + bDidExist = true; + } + + switch (createMode) { + case createMode::allowExisting: + break; // OK + case createMode::failIfExists: + if (bDidExist) throw exception_io_already_exists(); + break; // OK + case createMode::generateUniqueName: + if (bDidExist) { + continue; // the for loop + } + break; // OK + default: + PFC_ASSERT(!"Should not get here"); + break; + } + auto stats = m_opportunistStats; + stats.set_file(); + return m_fs->makeItemFileStd(dst, stats); + } + } + private: + const filesystem::ptr m_fs; + const stringRef m_path; + t_filestats2 m_opportunistStats; + }; + class fsItemFolderStd : public fsItemFolder { + public: + fsItemFolderStd(filesystem::ptr fs, stringRef canonicalPath, t_filestats2 const & opportunistStats) : m_fs(fs), m_path(canonicalPath), m_opportunistStats(opportunistStats) { + m_opportunistStats.set_folder(true); + m_opportunistStats.set_remote(fs->is_remote(canonicalPath->c_str())); + } + + filesystem::ptr getFS() override { return m_fs; } + + t_filestats2 getStatsOpportunist() override { + return m_opportunistStats; + } + + bool isRemote() override { return m_fs->is_remote(m_path->c_str()); } + + t_filestats2 getStats2(uint32_t s2flags, abort_callback& a) override { + auto s = m_fs->get_stats2_(m_path->c_str(), s2flags, a); + PFC_ASSERT((s2flags & stats2_fileOrFolder) == 0 || s.is_folder() ); + return s; + } + + fb2k::stringRef canonicalPath() override { return m_path; } + + fb2k::stringRef nameWithExt() override { + pfc::string8 temp; + m_fs->extract_filename_ext(m_path->c_str(), temp); + return makeString(temp); + } + fb2k::stringRef shortName() override { + pfc::string8 temp; + if (m_fs->get_display_name_short_(m_path->c_str(), temp)) return makeString(temp); + return nameWithExt(); + } + fb2k::arrayRef listContents(unsigned listMode, abort_callback& aborter) override { + auto out = arrayMutable::empty(); + filesystem::list_callback_t cb = [&] ( const char * p, t_filestats2 const & stats ) { + if (stats.is_folder()) { + if (listMode & listMode::folders) out->add(new service_impl_t< fsItemFolderStd >(m_fs, makeString(p), stats)); + } else { + if (listMode & listMode::files) out->add(new service_impl_t< fsItemFileStd >(m_fs, makeString(p), stats)); + } + }; + m_fs->list_directory_(m_path->c_str(), cb, listMode, aborter); + return out->copyConst(); + } + + fsItemFile::ptr findChildFile(const char* fileName, abort_callback& aborter) override { + auto sub = subPath(fileName); + auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder | foobar2000_io::stats2_remote, aborter); + if (!stats.is_folder()) { + return m_fs->makeItemFileStd(sub->c_str(), stats); + } + throw exception_io_not_found(); + } + fsItemFolder::ptr findChildFolder(const char* fileName, abort_callback& aborter) override { + auto sub = subPath(fileName); + auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder | foobar2000_io::stats2_remote, aborter); + if (stats.is_folder()) { + return m_fs->makeItemFolderStd(sub->c_str(), stats); + } + throw exception_io_not_found(); + } + fsItemBase::ptr findChild(const char* fileName, abort_callback& aborter) override { + auto sub = subPath(fileName); + auto stats = m_fs->get_stats2_(sub->c_str(), stats2_fileOrFolder | foobar2000_io::stats2_remote, aborter); + if ( stats.is_folder() ) { + return m_fs->makeItemFileStd(sub->c_str(), stats ); + } else { + return m_fs->makeItemFolderStd(sub->c_str(), stats ); + } + } + fsItemFile::ptr createFile(const char* fileName, unsigned createMode, abort_callback& aborter) override { + for (unsigned add = 0; ; ++add) { + pfc::string8 fn(fileName); uniqueFn(fn, add); + auto sub = subPath(fn); + + t_filestats2 stats; + + bool bDidExist = false; + try { + stats = m_fs->get_stats2_( sub->c_str(), stats2_all, aborter ); + bDidExist = stats.is_file(); + } catch(exception_io_not_found const &) {} + switch (createMode) { + case createMode::allowExisting: + break; // OK + case createMode::failIfExists: + if (bDidExist) throw exception_io_already_exists(); + break; // OK + case createMode::generateUniqueName: + if (bDidExist) { + continue; // the for loop + } + break; + default: + PFC_ASSERT(!"Should not get here"); + break; + } + if (!bDidExist) { + // actually create an empty file if it did not yet exist + // FIX ME this should be atomic with exists() check + file::ptr creator; + m_fs->open(creator, sub->c_str(), filesystem::open_mode_write_new, aborter); + stats = creator->get_stats2_( stats2_all, aborter ); + } + return m_fs->makeItemFileStd(sub->c_str(), stats); + } + } + fsItemFolder::ptr createFolder(const char* fileName, unsigned createMode, abort_callback& aborter) override { + for (unsigned add = 0; ; ++add) { + pfc::string8 fn(fileName); uniqueFn(fn, add); + auto sub = subPath(fn); + bool bDidExist = false; + try { + m_fs->create_directory(sub->c_str(), aborter); + } catch (exception_io_already_exists const &) { + bDidExist = true; + } + switch (createMode) { + case createMode::allowExisting: + break; // OK + case createMode::failIfExists: + if (bDidExist) throw exception_io_already_exists(); + break; + case createMode::generateUniqueName: + if (bDidExist) { + continue; // the for loop + } + break; + default: + PFC_ASSERT(!"Should not get here"); + break; + } + // Inherit opportunist stats + return m_fs->makeItemFolderStd(sub->c_str(), this->m_opportunistStats); + } + } + fsItemPtr moveTo(fsItemFolderPtr folder, const char* desiredName, unsigned createMode, abort_callback& aborter) override { + for (unsigned add = 0; ; ++add) { + pfc::string8 fn(desiredName); uniqueFn(fn, add); + pfc::string8 dst(folder->canonicalPath()->c_str()); + dst.end_with(m_fs->pathSeparator()); + dst += fn; + bool bDidExist = false; + try { + if (createMode == createMode::allowExisting) m_fs->move_overwrite(m_path->c_str(), dst, aborter); + else m_fs->move(m_path->c_str(), dst, aborter); + } catch (exception_io_already_exists const &) { + bDidExist = true; + } + + switch (createMode) { + case createMode::allowExisting: + break; // OK + case createMode::failIfExists: + if (bDidExist) throw exception_io_already_exists(); + break; // OK + case createMode::generateUniqueName: + if (bDidExist) { + continue; // the for loop + } + break; // OK + default: + PFC_ASSERT(!"Should not get here"); + break; + } + + return m_fs->makeItemFolderStd(dst, m_opportunistStats); + + } + } + private: + stringRef subPath(const char* name) { + pfc::string8 temp(m_path->c_str()); + temp.add_filename(name); + return makeString(temp); + } + const filesystem::ptr m_fs; + const stringRef m_path; + t_filestats2 m_opportunistStats; + }; +} + +fsItemFolder::ptr filesystem::makeItemFolderStd(const char* pathCanonical, t_filestats2 const& opportunistStats) { + return new service_impl_t<fsItemFolderStd>(this, makeString(pathCanonical), opportunistStats); +} + +fsItemFile::ptr filesystem::makeItemFileStd(const char* pathCanonical, t_filestats2 const & opportunistStats) { + return new service_impl_t<fsItemFileStd>(this, makeString(pathCanonical), opportunistStats); +} +fsItemBase::ptr filesystem::findItem_(const char* path, abort_callback& p_abort) { + filesystem_v3::ptr v3; + if (v3 &= this) { + return v3->findItem(path, p_abort); + } + auto stats = this->get_stats2_(path, stats2_fileOrFolder, p_abort); + if (stats.is_folder()) return this->makeItemFolderStd(path, stats); + else return this->makeItemFileStd(path, stats); + +} +fsItemFile::ptr filesystem::findItemFile_(const char* path, abort_callback& p_abort) { + filesystem_v3::ptr v3; + if (v3 &= this) return v3->findItemFile(path, p_abort); + + auto stats = this->get_stats2_(path, stats2_fileOrFolder, p_abort); + if (!stats.is_folder()) return this->makeItemFileStd(path, stats); + throw exception_io_not_found(); +} +fsItemFolder::ptr filesystem::findItemFolder_(const char* path, abort_callback& p_abort) { + filesystem_v3::ptr v3; + if (v3 &= this) return v3->findItemFolder(path, p_abort); + + auto stats = this->get_stats2_(path, stats2_fileOrFolder, p_abort); + if (stats.is_folder()) return this->makeItemFolderStd(path, stats); + throw exception_io_not_found(); +} + + +fsItemBase::ptr fsItemBase::fromPath(const char* path, abort_callback& aborter) { + return filesystem::get(path)->findItem_(path, aborter); +} + +fsItemFile::ptr fsItemFile::fromPath(const char* path, abort_callback& aborter) { + return filesystem::get(path)->findItemFile_(path, aborter); +} + +fsItemFolder::ptr fsItemFolder::fromPath(const char* path, abort_callback& aborter) { + return filesystem::get(path)->findItemFolder_(path, aborter); +} + +t_filestats fsItemBase::getStats(abort_callback& a) { + return getStats2(stats2_all, a).to_legacy(); +}
