Add fshelpers and temp

This commit is contained in:
2025-11-24 01:00:01 -06:00
parent ae6ae23075
commit f74f66a77d
19 changed files with 920 additions and 54 deletions

View File

@@ -49,6 +49,8 @@ src/Filesystem/MemoryFilesystem.cpp
src/Filesystem/SubdirFilesystem.cpp
src/Filesystem/NullFilesystem.cpp
src/Filesystem/MountableFilesystem.cpp
src/Filesystem/FSHelpers.cpp
src/Filesystem/TempFS.cpp
src/Crypto/ClientTLSStream.cpp
src/Crypto/MbedHelpers.cpp
src/Args.cpp
@@ -379,3 +381,4 @@ set(CPACK_PACKAGE_VERSION_MINOR "${TessesFramework_VERSION_MINOR}")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libmbedtls-dev (>= 2.28.8)")
include(CPack)
add_subdirectory(pkgconfig)

View File

@@ -1 +1,2 @@
export DEB_VERSION=1.0.0
export BUILD=$(($BUILD_NO-163))
export DEB_VERSION=1.0.0-$BUILD

View File

@@ -16,23 +16,23 @@ namespace Tesses::Framework::Date
int minute=0;
int second=0;
bool isLocal=false;
int64_t ToEpochNoConvert();
int64_t ToEpochNoConvert() const;
void FromEpochNoConvert(int64_t gmt);
public:
DateTime();
DateTime(int year, int month, int day, int hour, int minute, int seconds, bool isLocal=true);
DateTime(int64_t epoch);
int Year();
int Month();
int Day();
int Hour();
int Minute();
int Second();
int DayOfWeek();
bool IsLocal();
int64_t ToEpoch();
DateTime ToLocal();
DateTime ToUTC();
int Year() const;
int Month() const;
int Day() const;
int Hour() const;
int Minute() const;
int Second() const;
int DayOfWeek() const;
bool IsLocal() const;
int64_t ToEpoch() const;
DateTime ToLocal() const;
DateTime ToUTC() const;
void SetToLocal();
void SetToUTC();
void SetYear(int y);
@@ -52,15 +52,105 @@ namespace Tesses::Framework::Date
static DateTime Now();
static DateTime NowUTC();
std::string ToString();
std::string ToString(std::string fmt);
std::string ToString() const;
std::string ToString(std::string fmt) const;
std::string ToHttpDate();
std::string ToHttpDate() const;
static bool TryParseHttpDate(std::string txt, DateTime& dt);
operator std::string() const
{
return ToString();
}
operator int64_t() const
{
return ToEpoch();
}
};
class TimeSpan {
int64_t totalSeconds;
public:
TimeSpan();
TimeSpan(int64_t totalSeconds);
TimeSpan(int hours, int minutes, int seconds);
TimeSpan(int days,int hours, int minutes, int seconds);
void Set(int days, int hours, int minutes, int seconds);
void Set(int hours, int minutes, int seconds);
void SetDays(int d);
void SetHours(int h);
void SetMinutes(int m);
void SetSeconds(int s);
int Days() const;
int Hours() const;
int Minutes() const;
int Seconds() const;
int64_t TotalSeconds() const;
int64_t TotalMinutes() const;
int64_t TotalHours() const;
void SetTotalSeconds(int64_t totalSeconds);
void SetTotalMinutes(int64_t totalMinutes);
void SetTotalHours(int64_t totalHours);
void AddSeconds(int64_t seconds);
void AddMinutes(int64_t minutes);
void AddHours(int64_t hours);
void AddDays(int64_t days);
std::string ToString(bool slim=true) const;
static bool TryParse(std::string text, TimeSpan& span);
operator int64_t() const
{
return TotalSeconds();
}
operator std::string()
{
return ToString();
}
};
DateTime operator+(const DateTime& dt, const TimeSpan& ts)
{
DateTime dt2(dt.ToEpoch() + ts.TotalSeconds());
if(dt.IsLocal())
dt2.SetToLocal();
return dt2;
}
DateTime operator+(const TimeSpan& ts,const DateTime& dt)
{
DateTime dt2(dt.ToEpoch() + ts.TotalSeconds());
if(dt.IsLocal())
dt2.SetToLocal();
return dt2;
}
TimeSpan operator+(const TimeSpan& ts, const TimeSpan& ts2)
{
return (int64_t)ts + (int64_t)ts2;
}
DateTime operator-(const DateTime& dt, const TimeSpan& ts)
{
DateTime dt2(dt.ToEpoch() - ts.TotalSeconds());
if(dt.IsLocal())
dt2.SetToLocal();
return dt2;
}
TimeSpan operator-(const DateTime& dt, const DateTime& dt2)
{
return (int64_t)dt - (int64_t)dt2;
}
};

View File

@@ -0,0 +1,33 @@
#pragma once
#include "TempFS.hpp"
#include "VFSFix.hpp"
namespace Tesses::Framework::Filesystem::Helpers
{
void ReadAllText(std::shared_ptr<VFS> vfs, VFSPath path, std::string& text);
void ReadAllLines(std::shared_ptr<VFS> vfs, VFSPath path, std::vector<std::string>& lines);
void ReadAllBytes(std::shared_ptr<VFS> vfs, VFSPath path, std::vector<uint8_t>& array);
std::string ReadAllText(std::shared_ptr<VFS> vfs, VFSPath path);
std::vector<std::string> ReadAllLines(std::shared_ptr<VFS> vfs, VFSPath path);
std::vector<uint8_t> ReadAllBytes(std::shared_ptr<VFS> vfs, VFSPath path);
void WriteAllText(std::shared_ptr<VFS> vfs, VFSPath path, const std::string& text);
void WriteAllLines(std::shared_ptr<VFS> vfs, VFSPath path, const std::vector<std::string>& parts);
void WriteAllBytes(std::shared_ptr<VFS> vfs, VFSPath path, const std::vector<uint8_t>& bytes);
void CopyStreamProgress(std::shared_ptr<Streams::Stream> src,std::shared_ptr<Streams::Stream> dest, std::function<void(int64_t offset, int64_t length)> progress);
void CopyFile(std::shared_ptr<VFS> vfsSrc, VFSPath pathSrc, std::shared_ptr<VFS> vfsDest, VFSPath pathDest, bool overwrite=true);
void CopyFile(std::shared_ptr<VFS> vfsSrc, VFSPath pathSrc, std::shared_ptr<VFS> vfsDest, VFSPath pathDest, std::function<void(int64_t offset, int64_t length)> progress, bool overwrite=true);
void CopyDirectory(std::shared_ptr<VFS> vfsSrc, VFSPath pathSrc, std::shared_ptr<VFS> vfsDest, VFSPath pathDest, bool overwrite=true);
void CopyDirectory(std::shared_ptr<VFS> vfsSrc, VFSPath pathSrc, std::shared_ptr<VFS> vfsDest, VFSPath pathDest, std::function<void(int64_t offset, int64_t length, VFSPath currentFile)> progress, bool overwrite=true);
inline std::shared_ptr<TempFS> CreateTempFS(bool deleteOnDestroy=true)
{
return std::make_shared<TempFS>(deleteOnDestroy);
}
inline std::shared_ptr<TempFS> CreateTempFS(std::shared_ptr<VFS> vfs,bool deleteOnDestroy=true)
{
return std::make_shared<TempFS>(vfs,deleteOnDestroy);
}
}

View File

@@ -0,0 +1,51 @@
#pragma once
#include "../Common.hpp"
#include "VFS.hpp"
#include "VFSFix.hpp"
namespace Tesses::Framework::Filesystem
{
void UniqueString(std::string& text);
class TempFS : public VFS
{
std::shared_ptr<VFS> vfs;
bool deleteOnDestroy;
std::shared_ptr<VFS> parent;
std::string tmp_str;
public:
std::string TempDirectoryName();
TempFS(bool deleteOnDestroy=true);
TempFS(std::shared_ptr<VFS> vfs,bool deleteOnDestroy=true);
std::shared_ptr<Tesses::Framework::Streams::Stream> OpenFile(VFSPath path, std::string mode);
void CreateDirectory(VFSPath path);
void DeleteDirectory(VFSPath path);
bool SpecialFileExists(VFSPath path);
bool FileExists(VFSPath path);
bool RegularFileExists(VFSPath path);
bool SymlinkExists(VFSPath path);
bool CharacterDeviceExists(VFSPath path);
bool BlockDeviceExists(VFSPath path);
bool SocketFileExists(VFSPath path);
bool FIFOFileExists(VFSPath path);
bool DirectoryExists(VFSPath path);
void DeleteFile(VFSPath path);
void CreateSymlink(VFSPath existingFile, VFSPath symlinkFile);
VFSPathEnumerator EnumeratePaths(VFSPath path);
void CreateHardlink(VFSPath existingFile, VFSPath newName);
void MoveFile(VFSPath src, VFSPath dest);
void MoveDirectory(VFSPath src, VFSPath dest);
void DeleteDirectoryRecurse(VFSPath path);
VFSPath ReadLink(VFSPath path);
std::string VFSPathToSystem(VFSPath path);
VFSPath SystemToVFSPath(std::string path);
void GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess);
void SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess);
bool StatVFS(VFSPath path, StatVFSData& vfsData);
void Chmod(VFSPath path, uint32_t mode);
void Close();
~TempFS();
};
}

View File

@@ -29,6 +29,8 @@ namespace Tesses::Framework::Filesystem
static std::vector<std::string> SplitPath(std::string path);
std::vector<std::string> path;
VFSPath();
VFSPath(const char* path) : VFSPath((std::string)path)
{}
VFSPath(std::vector<std::string> path);
VFSPath(std::string path);
VFSPath(VFSPath p, std::string subent);
@@ -36,22 +38,27 @@ namespace Tesses::Framework::Filesystem
VFSPath GetParent();
VFSPath CollapseRelativeParents();
std::string GetFileName();
bool HasExtension();
std::string GetExtension();
VFSPath GetParent() const;
VFSPath CollapseRelativeParents() const;
std::string GetFileName() const;
bool HasExtension() const;
std::string GetExtension() const;
void ChangeExtension(std::string ext);
void RemoveExtension();
std::string ToString();
std::string ToString() const;
operator std::string() const
{
return ToString();
}
static VFSPath GetAbsoluteCurrentDirectory();
static void SetAbsoluteCurrentDirectory(VFSPath path);
VFSPath MakeAbsolute();
VFSPath MakeAbsolute() const;
VFSPath MakeAbsolute(VFSPath curDir);
VFSPath MakeRelative();
VFSPath MakeRelative(VFSPath toMakeRelativeTo);
VFSPath MakeAbsolute(VFSPath curDir) const;
VFSPath MakeRelative() const;
VFSPath MakeRelative(VFSPath toMakeRelativeTo) const;
};
VFSPath operator/(VFSPath p, VFSPath p2);
VFSPath operator/(VFSPath p, std::string p2);

View File

@@ -9,6 +9,7 @@ namespace Tesses::Framework::Platform::Environment
namespace SpecialFolders {
Tesses::Framework::Filesystem::VFSPath GetTemp();
Tesses::Framework::Filesystem::VFSPath GetHomeFolder();
Tesses::Framework::Filesystem::VFSPath GetDownloads();
Tesses::Framework::Filesystem::VFSPath GetMusic();

View File

@@ -29,6 +29,7 @@
#include "Filesystem/NullFilesystem.hpp"
#include "Filesystem/MountableFilesystem.hpp"
#include "Filesystem/MemoryFilesystem.hpp"
#include "Filesystem/FSHelpers.hpp"
#include "Crypto/ClientTLSStream.hpp"
#include "Crypto/MbedHelpers.hpp"
#include "Lazy.hpp"

View File

@@ -11,6 +11,7 @@ namespace Tesses::Framework::TextStreams
int32_t ReadChar();
std::string ReadLine();
bool ReadLine(std::string& str);
void ReadAllLines(std::vector<std::string>& lines);
std::string ReadToEnd();
void ReadToEnd(std::string& str);
void CopyTo(TextWriter& writer, size_t bufSz=1024);

21
pkgconfig/CMakeLists.txt Normal file
View File

@@ -0,0 +1,21 @@
set(PKGCONFIG_INCLUDEDIR "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}")
set(PKGCONFIG_LIBDIR "\${prefix}/${CMAKE_INSTALL_LIBDIR}")
set(PKGCONFIG_PROJECT_DESCRIPTION "A cross platform wrapper library")
set(PKGCONFIG_PROJECT_HOMEPAGE_URL "https://onedev.site.tesses.net/tesses-framework")
if(TESSESFRAMEWORK_ENABLE_MBED)
set(PKGCONFIG_DEPS "Requires: mbedtls")
else()
set(PKGCONFIG_DEPS "")
endif()
configure_file(tessesframework_static.pc.in tessesframework_static.pc @ONLY)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/tessesframework_static.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
configure_file(tessesframework.pc.in tessesframework.pc @ONLY)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/tessesframework.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

View File

@@ -0,0 +1,13 @@
prefix=@CMAKE_INSTALL_PREFIX@
includedir=@PKGCONFIG_INCLUDEDIR@
libdir=@PKGCONFIG_LIBDIR@
Name: @PROJECT_NAME@
Description: @PKGCONFIG_PROJECT_DESCRIPTION@
URL: @PKGCONFIG_PROJECT_HOMEPAGE_URL@
Version: @PROJECT_VERSION@
@PKGCONFIG_DEPS@
Cflags: -I"${includedir}"
Libs: -L"${libdir}" -ltessesframework_shared

View File

@@ -0,0 +1,13 @@
prefix=@CMAKE_INSTALL_PREFIX@
includedir=@PKGCONFIG_INCLUDEDIR@
libdir=@PKGCONFIG_LIBDIR@
Name: @PROJECT_NAME@
Description: @PKGCONFIG_PROJECT_DESCRIPTION@
URL: @PKGCONFIG_PROJECT_HOMEPAGE_URL@
Version: @PROJECT_VERSION@
@PKGCONFIG_DEPS@
Cflags: -I"${includedir}"
Libs: -L"${libdir}" -ltessesframework

View File

@@ -105,35 +105,35 @@ namespace Tesses::Framework::Date
this->second = seconds;
this->isLocal = isLocal;
}
int DateTime::Year()
int DateTime::Year() const
{
return this->year;
}
int DateTime::Month()
int DateTime::Month() const
{
return this->month;
}
int DateTime::Day()
int DateTime::Day() const
{
return this->day;
}
int DateTime::Hour()
int DateTime::Hour() const
{
return this->hour;
}
int DateTime::Minute()
int DateTime::Minute() const
{
return this->minute;
}
int DateTime::Second()
int DateTime::Second() const
{
return this->second;
}
bool DateTime::IsLocal()
bool DateTime::IsLocal() const
{
return this->isLocal;
}
int DateTime::DayOfWeek()
int DateTime::DayOfWeek() const
{
date::year_month_day ymd(date::year(year),date::month((uint32_t)month),date::day((uint32_t)day));
date::sys_days d = ymd;
@@ -214,7 +214,7 @@ namespace Tesses::Framework::Date
this->isLocal=true;
this->FromEpochNoConvert(local);
}
DateTime DateTime::ToLocal()
DateTime DateTime::ToLocal() const
{
DateTime dt = *this;
dt.SetToLocal();
@@ -294,13 +294,13 @@ namespace Tesses::Framework::Date
this->FromEpochNoConvert(local);
}
DateTime DateTime::ToUTC()
DateTime DateTime::ToUTC() const
{
DateTime dt = *this;
dt.SetToUTC();
return dt;
}
int64_t DateTime::ToEpoch()
int64_t DateTime::ToEpoch() const
{
if(this->isLocal)
{
@@ -309,7 +309,7 @@ namespace Tesses::Framework::Date
}
return this->ToEpochNoConvert();
}
int64_t DateTime::ToEpochNoConvert()
int64_t DateTime::ToEpochNoConvert() const
{
date::year y = (date::year)year;
date::month m = (date::month)month;
@@ -551,7 +551,7 @@ namespace Tesses::Framework::Date
dt.second = second;
return true;
}
std::string DateTime::ToHttpDate()
std::string DateTime::ToHttpDate() const
{
auto utc=this->ToUTC();
std::string weekday=weekday_short[utc.DayOfWeek()];
@@ -567,12 +567,12 @@ namespace Tesses::Framework::Date
return strm.str();
}
std::string DateTime::ToString()
std::string DateTime::ToString() const
{
return ToString("%Y/%m/%d %H:%M:%S");
}
std::string DateTime::ToString(std::string fmt)
std::string DateTime::ToString(std::string fmt) const
{
auto weekday = this->DayOfWeek();
@@ -732,4 +732,211 @@ namespace Tesses::Framework::Date
}
return text;
}
TimeSpan::TimeSpan()
{
this->totalSeconds = 0;
}
TimeSpan::TimeSpan(int64_t totalSeconds)
{
this->totalSeconds = totalSeconds;
}
TimeSpan::TimeSpan(int hours, int minutes, int seconds) : TimeSpan(0,hours,minutes,seconds)
{
}
TimeSpan::TimeSpan(int days,int hours, int minutes, int seconds)
{
this->totalSeconds = (int64_t)days * 86400;
this->totalSeconds += (int64_t)hours * 3600;
this->totalSeconds += (int64_t)minutes * 60;
this->totalSeconds += (int64_t)seconds;
}
void TimeSpan::Set(int days, int hours, int minutes, int seconds)
{
this->totalSeconds = (int64_t)days * 86400;
this->totalSeconds += (int64_t)hours * 3600;
this->totalSeconds += (int64_t)minutes * 60;
this->totalSeconds += (int64_t)seconds;
}
void TimeSpan::Set(int hours, int minutes, int seconds)
{
this->totalSeconds = (int64_t)hours * 3600;
this->totalSeconds += (int64_t)minutes * 60;
this->totalSeconds += (int64_t)seconds;
}
void TimeSpan::SetDays(int d)
{
Set(d,this->Hours(),this->Minutes(),this->Seconds());
}
void TimeSpan::SetHours(int h)
{
Set(this->Days(),h,this->Minutes(), this->Seconds());
}
void TimeSpan::SetMinutes(int m)
{
Set(this->Days(),this->Hours(),m,this->Seconds());
}
void TimeSpan::SetSeconds(int s)
{
Set(this->Days(),this->Hours(),this->Minutes(),s);
}
int TimeSpan::Days() const
{
return (int)(this->totalSeconds / 86400);
}
int TimeSpan::Hours() const
{
return (int)((this->totalSeconds / 3600) % 24);
}
int TimeSpan::Minutes() const
{
return (int)((this->totalSeconds / 60) % 60);
}
int TimeSpan::Seconds() const
{
return (int)(this->totalSeconds % 60);
}
int64_t TimeSpan::TotalSeconds() const
{
return this->totalSeconds;
}
int64_t TimeSpan::TotalMinutes() const
{
return this->totalSeconds / 60;
}
int64_t TimeSpan::TotalHours() const
{
return this->totalSeconds / 3600;
}
void TimeSpan::AddSeconds(int64_t seconds)
{
this->totalSeconds += seconds;
}
void TimeSpan::AddMinutes(int64_t minutes)
{
this->totalSeconds += minutes * 60;
}
void TimeSpan::AddHours(int64_t hours)
{
this->totalSeconds += hours * 3600;
}
void TimeSpan::AddDays(int64_t days)
{
this->totalSeconds += days * 86400;
}
void TimeSpan::SetTotalSeconds(int64_t totalSeconds)
{
this->totalSeconds = totalSeconds;
}
void TimeSpan::SetTotalMinutes(int64_t totalMinutes)
{
this->totalSeconds = totalMinutes * 60;
}
void TimeSpan::SetTotalHours(int64_t totalHours)
{
this->totalSeconds = totalHours * 3600;
}
std::string TimeSpan::ToString(bool slim) const
{
std::string str={};
if(this->totalSeconds < 0)
str += "-";
if(slim && this->totalSeconds > -36000 && this->totalSeconds < 36000)
{
//0:00
//00:00
//0:00:00
if(this->totalSeconds <= -3600 || this->totalSeconds >= 3600)
{
//hours must force multi digit minutes
str += std::to_string(this->Hours());
str += ":";
str += Http::HttpUtils::LeftPad(std::to_string(this->Minutes()),2,' ');
}
else
{
str += std::to_string(this->Minutes());
}
str += ":";
str += Http::HttpUtils::LeftPad(std::to_string(this->Seconds()),2,' ');
}
else
{
//00:00:00
//0.00:00:00
if(this->totalSeconds <= -86400 || this->totalSeconds >= 86400)
{
str += std::to_string(this->Days());
str += ".";
}
str += Http::HttpUtils::LeftPad(std::to_string(this->Hours()),2,' ');
str += ":";
str += Http::HttpUtils::LeftPad(std::to_string(this->Minutes()),2,' ');
str += ":";
str += Http::HttpUtils::LeftPad(std::to_string(this->Seconds()),2,' ');
}
return str;
}
bool TimeSpan::TryParse(std::string text, TimeSpan& span)
{
if(text.empty()) return false;
bool negative = text[0] == '-';
int64_t totalSeconds = 0;
try{
std::string colonPart = text.substr(negative ? 1 : 0);
auto res = Http::HttpUtils::SplitString(colonPart,":");
if(res.size() < 2 || res.size() > 3) return false;
std::string hour = res[0];
size_t index=hour.find('.');
if(index != std::string::npos)
{
totalSeconds += std::stoll(hour.substr(0,index)) * 86400;
hour = hour.substr(index+1);
}
if(res.size() == 2)
{
//mm:ss
totalSeconds += std::stoll(hour) * 60;
totalSeconds += std::stoll(res[1]);
}
else if(res.size() == 3)
{
totalSeconds += std::stoll(hour) * 3600;
totalSeconds += std::stoll(res[1]) * 60;
totalSeconds += std::stoll(res[2]);
}
else return false;
}catch(...) {return false;}
if(negative) totalSeconds = -totalSeconds;
span.SetTotalSeconds(totalSeconds);
return true;
}
}

View File

@@ -0,0 +1,184 @@
#include "TessesFramework/Filesystem/FSHelpers.hpp"
#include "TessesFramework/TextStreams/StreamReader.hpp"
#include "TessesFramework/TextStreams/StreamWriter.hpp"
namespace Tesses::Framework::Filesystem::Helpers
{
void ReadAllText(std::shared_ptr<VFS> vfs, VFSPath path, std::string& text)
{
auto file = vfs->OpenFile(path,"rb");
if(file->CanRead())
{
TextStreams::StreamReader reader(file);
reader.ReadToEnd(text);
}
}
void ReadAllLines(std::shared_ptr<VFS> vfs, VFSPath path, std::vector<std::string>& lines)
{
auto file = vfs->OpenFile(path,"rb");
if(file->CanRead())
{
TextStreams::StreamReader reader(file);
reader.ReadAllLines(lines);
}
}
void ReadAllBytes(std::shared_ptr<VFS> vfs, VFSPath path, std::vector<uint8_t>& array)
{
auto file = vfs->OpenFile(path,"rb");
if(file->CanRead())
{
if(file->CanSeek())
{
size_t length = (size_t)file->GetLength();
array.resize(length);
file->ReadBlock(array.data(), array.size());
}
else
{
size_t totalSize = 0;
size_t read = 0;
do {
array.resize(totalSize+1024);
read = file->ReadBlock(array.data()+totalSize,1024);
totalSize += read;
} while(read != 0);
array.resize(totalSize);
}
}
}
std::string ReadAllText(std::shared_ptr<VFS> vfs, VFSPath path)
{
std::string text;
ReadAllText(vfs,path,text);
return text;
}
std::vector<std::string> ReadAllLines(std::shared_ptr<VFS> vfs, VFSPath path)
{
std::vector<std::string> lines;
ReadAllLines(vfs,path,lines);
return lines;
}
std::vector<uint8_t> ReadAllBytes(std::shared_ptr<VFS> vfs, VFSPath path)
{
std::vector<uint8_t> bytes;
ReadAllBytes(vfs,path,bytes);
return bytes;
}
void WriteAllText(std::shared_ptr<VFS> vfs, VFSPath path, const std::string& text)
{
auto file = vfs->OpenFile(path,"wb");
if(file->CanWrite())
{
TextStreams::StreamWriter writer(file);
writer.Write(text);
}
}
void WriteAllLines(std::shared_ptr<VFS> vfs, VFSPath path, const std::vector<std::string>& parts)
{
auto file = vfs->OpenFile(path,"wb");
if(file->CanWrite())
{
TextStreams::StreamWriter writer(file);
for(auto& line : parts)
{
writer.WriteLine(line);
}
}
}
void WriteAllBytes(std::shared_ptr<VFS> vfs, VFSPath path, const std::vector<uint8_t>& bytes)
{
auto file = vfs->OpenFile(path,"wb");
if(file->CanWrite())
{
file->WriteBlock(bytes.data(),bytes.size());
}
}
void CopyFile(std::shared_ptr<VFS> vfsSrc, VFSPath pathSrc, std::shared_ptr<VFS> vfsDest, VFSPath pathDest, bool overwrite)
{
if(!overwrite && vfsDest->FileExists(pathDest)) return;
if(!vfsSrc->FileExists(pathSrc)) return;
auto src=vfsSrc->OpenFile(pathSrc,"wb");
auto dest = vfsDest->OpenFile(pathDest,"wb");
if(src->CanRead() && dest->CanWrite())
src->CopyTo(dest);
}
void CopyStreamProgress(std::shared_ptr<Streams::Stream> src,std::shared_ptr<Streams::Stream> dest, std::function<void(int64_t offset, int64_t length)> progress)
{
int64_t length=0;
try {
length = src->GetLength();
} catch(...) {
length=0;
}
if(length == 0) length = (int64_t)1<<62; // a big number so its always 0% if the stream does not have a length
int64_t offset = 0;
size_t read = 0;
std::vector<uint8_t> data(4096);
do {
read = src->ReadBlock(data.data(),data.size());
dest->WriteBlock(data.data(),read);
offset += (int64_t)read;
if(read != 0)
progress(offset,length);
} while(read != 0);
if(offset > 0)
progress(offset,offset);
}
void CopyFile(std::shared_ptr<VFS> vfsSrc, VFSPath pathSrc, std::shared_ptr<VFS> vfsDest, VFSPath pathDest, std::function<void(int64_t offset, int64_t length)> progress, bool overwrite)
{
if(!overwrite && vfsDest->FileExists(pathDest)) return;
if(!vfsSrc->FileExists(pathSrc)) return;
auto src=vfsSrc->OpenFile(pathSrc,"wb");
auto dest = vfsDest->OpenFile(pathDest,"wb");
if(src->CanRead() && dest->CanWrite())
CopyStreamProgress(src,dest,progress);
}
void CopyDirectory(std::shared_ptr<VFS> vfsSrc, VFSPath pathSrc, std::shared_ptr<VFS> vfsDest, VFSPath pathDest,bool overwrite)
{
if(vfsSrc->DirectoryExists(pathSrc))
{
vfsDest->CreateDirectory(pathDest);
for(auto& srcPath : vfsSrc->EnumeratePaths(pathSrc))
{
if(vfsSrc->DirectoryExists(srcPath))
{
CopyDirectory(vfsSrc,srcPath,vfsDest,pathDest / srcPath.GetFileName());
}
if(vfsSrc->FileExists(srcPath))
{
CopyFile(vfsSrc,srcPath,vfsDest,pathDest / srcPath.GetFileName(),overwrite);
}
}
}
}
void CopyDirectory(std::shared_ptr<VFS> vfsSrc, VFSPath pathSrc, std::shared_ptr<VFS> vfsDest, VFSPath pathDest, std::function<void(int64_t offset, int64_t length, VFSPath currentFile)> progress, bool overwrite)
{
if(vfsSrc->DirectoryExists(pathSrc))
{
vfsDest->CreateDirectory(pathDest);
for(auto& srcPath : vfsSrc->EnumeratePaths(pathSrc))
{
if(vfsSrc->DirectoryExists(srcPath))
{
CopyDirectory(vfsSrc,srcPath,vfsDest,pathDest / srcPath.GetFileName(),progress,overwrite);
}
if(vfsSrc->FileExists(srcPath))
{
CopyFile(vfsSrc,srcPath,vfsDest,pathDest / srcPath.GetFileName(),[progress,srcPath](int64_t offset, int64_t length)->void {
progress(offset,length,srcPath);
},overwrite);
}
}
}
}
}

205
src/Filesystem/TempFS.cpp Normal file
View File

@@ -0,0 +1,205 @@
#include "TessesFramework/Threading/Mutex.hpp"
#include "TessesFramework/Filesystem/TempFS.hpp"
#include "TessesFramework/Filesystem/LocalFS.hpp"
#include "TessesFramework/Filesystem/SubdirFilesystem.hpp"
#include "TessesFramework/Platform/Environment.hpp"
namespace Tesses::Framework::Filesystem {
Tesses::Framework::Threading::Mutex umtx;
int64_t uidx=0;
void UniqueString(std::string& text)
{
umtx.Lock();
text += std::to_string((int64_t)time(NULL));
text += "_";
text += std::to_string(uidx);
uidx++;
umtx.Unlock();
}
TempFS::TempFS(bool deleteOnDestroy) : TempFS(std::make_shared<SubdirFilesystem>(LocalFS, Platform::Environment::SpecialFolders::GetTemp()), deleteOnDestroy)
{
}
TempFS::TempFS(std::shared_ptr<VFS> vfs,bool deleteOnDestroy)
{
this->parent = vfs;
this->deleteOnDestroy=deleteOnDestroy;
this->tmp_str = "tf_tmp_";
UniqueString(this->tmp_str);
VFSPath p;
p.relative = false;
p.path.push_back(this->tmp_str);
this->parent->CreateDirectory(p);
this->vfs = std::make_shared<SubdirFilesystem>(this->parent,p);
}
std::string TempFS::TempDirectoryName()
{
return this->tmp_str;
}
std::shared_ptr<Tesses::Framework::Streams::Stream> TempFS::OpenFile(VFSPath path, std::string mode)
{
if(this->vfs == nullptr) return nullptr;
return this->vfs->OpenFile(path,mode);
}
void TempFS::CreateDirectory(VFSPath path)
{
if(this->vfs == nullptr) return;
this->vfs->CreateDirectory(path);
}
void TempFS::DeleteDirectory(VFSPath path)
{
if(this->vfs == nullptr) return;
this->vfs->DeleteDirectory(path);
}
bool TempFS::SpecialFileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->SpecialFileExists(path);
}
bool TempFS::FileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->FileExists(path);
}
bool TempFS::RegularFileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->RegularFileExists(path);
}
bool TempFS::SymlinkExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->SymlinkExists(path);
}
bool TempFS::CharacterDeviceExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->CharacterDeviceExists(path);
}
bool TempFS::BlockDeviceExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->BlockDeviceExists(path);
}
bool TempFS::SocketFileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->SocketFileExists(path);
}
bool TempFS::FIFOFileExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->FIFOFileExists(path);
}
bool TempFS::DirectoryExists(VFSPath path)
{
if(this->vfs == nullptr) return false;
return this->vfs->DirectoryExists(path);
}
void TempFS::DeleteFile(VFSPath path)
{
if(this->vfs == nullptr) return;
this->vfs->DeleteFile(path);
}
void TempFS::CreateSymlink(VFSPath existingFile, VFSPath symlinkFile)
{
if(this->vfs == nullptr) return;
this->vfs->CreateSymlink(existingFile, symlinkFile);
}
VFSPathEnumerator TempFS::EnumeratePaths(VFSPath path)
{
if(this->vfs == nullptr) return VFSPathEnumerator();
return this->vfs->EnumeratePaths(path);
}
void TempFS::CreateHardlink(VFSPath existingFile, VFSPath newName)
{
if(this->vfs == nullptr) return;
this->vfs->CreateHardlink(existingFile,newName);
}
void TempFS::MoveFile(VFSPath src, VFSPath dest)
{
if(this->vfs == nullptr) return;
this->vfs->MoveFile(src,dest);
}
void TempFS::MoveDirectory(VFSPath src, VFSPath dest)
{
if(this->vfs == nullptr) return;
this->vfs->MoveDirectory(src,dest);
}
void TempFS::DeleteDirectoryRecurse(VFSPath path)
{
if(this->vfs == nullptr) return;
this->vfs->DeleteDirectoryRecurse(path);
}
VFSPath TempFS::ReadLink(VFSPath path)
{
if(this->vfs == nullptr) return VFSPath();
return this->vfs->ReadLink(path);
}
std::string TempFS::VFSPathToSystem(VFSPath path)
{
if(this->vfs == nullptr) return "";
return this->vfs->VFSPathToSystem(path);
}
VFSPath TempFS::SystemToVFSPath(std::string path)
{
if(this->vfs == nullptr) return VFSPath();
return this->vfs->SystemToVFSPath(path);
}
void TempFS::GetDate(VFSPath path, Date::DateTime& lastWrite, Date::DateTime& lastAccess)
{
if(this->vfs == nullptr) return;
this->vfs->GetDate(path,lastWrite,lastAccess);
}
void TempFS::SetDate(VFSPath path, Date::DateTime lastWrite, Date::DateTime lastAccess)
{
if(this->vfs == nullptr) return;
this->vfs->SetDate(path,lastWrite,lastAccess);
}
bool TempFS::StatVFS(VFSPath path, StatVFSData& vfsData)
{
if(this->vfs == nullptr) return false;
return this->vfs->StatVFS(path, vfsData);
}
void TempFS::Chmod(VFSPath path, uint32_t mode)
{
if(this->vfs == nullptr) return;
this->vfs->Chmod(path,mode);
}
void TempFS::Close()
{
VFSPath p;
p.relative = false;
p.path.push_back(this->tmp_str);
this->vfs = nullptr;
if(this->deleteOnDestroy && this->parent->DirectoryExists(p))
this->parent->DeleteDirectoryRecurse(p);
}
TempFS::~TempFS()
{
Close();
}
}

View File

@@ -202,21 +202,21 @@ namespace Tesses::Framework::Filesystem
std::filesystem::path mpath=res;
std::filesystem::current_path(mpath);
}
VFSPath VFSPath::MakeAbsolute()
VFSPath VFSPath::MakeAbsolute() const
{
return MakeAbsolute(GetAbsoluteCurrentDirectory());
}
VFSPath VFSPath::MakeAbsolute(VFSPath curDir)
VFSPath VFSPath::MakeAbsolute(VFSPath curDir) const
{
if (!this->relative) return *this;
VFSPath p2 = curDir / *this;
return p2.CollapseRelativeParents();
}
VFSPath VFSPath::MakeRelative()
VFSPath VFSPath::MakeRelative() const
{
return MakeRelative(GetAbsoluteCurrentDirectory());
}
VFSPath VFSPath::MakeRelative(VFSPath toMakeRelativeTo)
VFSPath VFSPath::MakeRelative(VFSPath toMakeRelativeTo) const
{
if(this->relative) return *this;
@@ -250,7 +250,7 @@ namespace Tesses::Framework::Filesystem
p2.relative = true;
return p2;
}
VFSPath VFSPath::CollapseRelativeParents()
VFSPath VFSPath::CollapseRelativeParents() const
{
std::vector<std::string> parts;
@@ -330,7 +330,7 @@ namespace Tesses::Framework::Filesystem
this->path = p;
}
bool VFSPath::HasExtension()
bool VFSPath::HasExtension() const
{
if(this->path.empty()) return false;
auto& str = this->path.back();
@@ -338,7 +338,7 @@ namespace Tesses::Framework::Filesystem
if(index == std::string::npos) return false;
return true;
}
std::string VFSPath::GetExtension()
std::string VFSPath::GetExtension() const
{
if(this->path.empty()) return {};
auto& str = this->path.back();
@@ -395,7 +395,7 @@ namespace Tesses::Framework::Filesystem
{
}
VFSPath VFSPath::GetParent()
VFSPath VFSPath::GetParent() const
{
std::vector<std::string> paths;
if(this->path.empty()) return VFSPath();
@@ -407,13 +407,13 @@ namespace Tesses::Framework::Filesystem
return res;
}
std::string VFSPath::GetFileName()
std::string VFSPath::GetFileName() const
{
if(this->path.empty()) return "";
return this->path.back();
}
std::string VFSPath::ToString()
std::string VFSPath::ToString() const
{
if(this->path.empty() && !this->relative) return "/";
if(!this->relative && this->path.size() == 1 && !this->path[0].empty() && this->path[0].back() == ':') return this->path[0] + "/";

View File

@@ -25,13 +25,18 @@ namespace Tesses::Framework::Platform::Environment
namespace SpecialFolders
{
VFSPath GetTemp()
{
return std::filesystem::temp_directory_path().string();
}
VFSPath GetHomeFolder()
{
#if defined(TESSESFRAMEWORK_ENABLE_PLATFORMFOLDERS) && !defined(SAGO_DISABLE)
return sago::getHomeDir();
#elif defined(__EMSCRIPTEN__)
return (std::string)"/home/web_user";
#elif defined(__ANDROID__)
return (std::string)"/sdcard/TF_User";
#else
return (std::string)"/TF_User";
#endif
@@ -40,6 +45,8 @@ namespace Tesses::Framework::Platform::Environment
{
#if defined(TESSESFRAMEWORK_ENABLE_PLATFORMFOLDERS) && !defined(SAGO_DISABLE)
return sago::getDownloadFolder();
#elif defined(__ANDROID__)
return (std::string)"/sdcard/Download";
#else
return GetHomeFolder() / "Downloads";
#endif
@@ -48,6 +55,8 @@ namespace Tesses::Framework::Platform::Environment
{
#if defined(TESSESFRAMEWORK_ENABLE_PLATFORMFOLDERS) && !defined(SAGO_DISABLE)
return sago::getMusicFolder();
#elif defined(__ANDROID__)
return (std::string)"/sdcard/Music";
#else
return GetHomeFolder() / "Music";
#endif
@@ -56,6 +65,8 @@ namespace Tesses::Framework::Platform::Environment
{
#if defined(TESSESFRAMEWORK_ENABLE_PLATFORMFOLDERS) && !defined(SAGO_DISABLE)
return sago::getPicturesFolder();
#elif defined(__ANDROID__)
return (std::string)"/sdcard/Pictures";
#else
return GetHomeFolder() / "Pictures";
#endif
@@ -64,6 +75,8 @@ namespace Tesses::Framework::Platform::Environment
{
#if defined(TESSESFRAMEWORK_ENABLE_PLATFORMFOLDERS) && !defined(SAGO_DISABLE)
return sago::getVideoFolder();
#elif defined(__ANDROID__)
return (std::string)"/sdcard/Movies";
#else
return GetHomeFolder() / "Videos";
#endif
@@ -72,6 +85,8 @@ namespace Tesses::Framework::Platform::Environment
{
#if defined(TESSESFRAMEWORK_ENABLE_PLATFORMFOLDERS) && !defined(SAGO_DISABLE)
return sago::getDocumentsFolder();
#elif defined(__ANDROID__)
return (std::string)"/sdcard/Documents";
#else
return GetHomeFolder() / "Documents";
#endif
@@ -237,6 +252,9 @@ namespace Tesses::Framework::Platform::Environment
}
std::string GetPlatform()
{
#if defined(__ANDROID__)
return "Android";
#endif
#if defined(__SWITCH__)
return "Nintendo Switch";
#endif

View File

@@ -37,7 +37,7 @@ I modified it to return home directory and conditionally compile for systems tha
#ifndef SAGO_PLATFORM_FOLDERS_H
#define SAGO_PLATFORM_FOLDERS_H
#if defined(GEKKO) || defined(__SWITCH__) || defined(__EMSCRIPTEN__) || defined(__PS2__)
#if defined(GEKKO) || defined(__SWITCH__) || defined(__EMSCRIPTEN__) || defined(__PS2__) || defined(__ANDROID__)
#define SAGO_DISABLE
#endif

View File

@@ -33,6 +33,23 @@ namespace Tesses::Framework::TextStreams
} while(r != -1);
return ret;
}
void TextReader::ReadAllLines(std::vector<std::string>& lines)
{
int32_t r = -1;
std::string builder;
do {
r = ReadChar();
if(r == -1) break;
if(r == '\r') continue;
if(r == '\n') {
lines.push_back(builder);
builder.clear();
continue;
}
builder += (char)r;
} while(r != -1);
}
std::string TextReader::ReadToEnd()
{