framework2
2079 строк · 66.8 Кб
1#include "ofFileUtils.h"2#include "ofLog.h"3#include "ofUtils.h"4
5#ifndef TARGET_WIN326#include <pwd.h>7#include <sys/stat.h>8#include <unistd.h>9#endif10
11#ifdef TARGET_OSX12#include <mach-o/dyld.h> /* _NSGetExecutablePath */13#include <limits.h> /* PATH_MAX */14#endif15
16// FIXME: better explicit declaration
17using std::string;18using std::vector;19using std::fstream;20using std::istream;21using std::ostream;22using std::ios;23
24namespace{25bool enableDataPath = true;26
27//--------------------------------------------------28// MARK: - near future
29// of::filesystem::path defaultDataPath(){
30std::string defaultDataPath(){31#if defined TARGET_OSX32try{33return of::filesystem::canonical(ofFilePath::getCurrentExeDir() / of::filesystem::path("../../../data/")).string();34}catch(...){35return (ofFilePath::getCurrentExeDir() / of::filesystem::path("../../../data/")).string();36}37#elif defined TARGET_ANDROID38return string("sdcard/");39#else40try{41return of::filesystem::canonical(ofFilePath::join(ofFilePath::getCurrentExeDir(), "data/")).make_preferred().string();42}catch(...){43return (ofFilePath::getCurrentExeDir() / of::filesystem::path("data/")).string();44}45#endif46}47
48//--------------------------------------------------49of::filesystem::path & defaultWorkingDirectory(){50static auto * defaultWorkingDirectory = new of::filesystem::path(ofFilePath::getCurrentExeDir());51return * defaultWorkingDirectory;52}53
54//--------------------------------------------------55of::filesystem::path & dataPathRoot(){56static auto * dataPathRoot = new of::filesystem::path(defaultDataPath());57return *dataPathRoot;58}59}
60
61namespace of{62namespace priv{63void initfileutils(){64defaultWorkingDirectory() = of::filesystem::absolute(of::filesystem::current_path());65}66}67}
68
69
70//------------------------------------------------------------------------------------------------------------
71//------------------------------------------------------------------------------------------------------------
72// -- ofBuffer
73//------------------------------------------------------------------------------------------------------------
74//------------------------------------------------------------------------------------------------------------
75
76//--------------------------------------------------
77ofBuffer::ofBuffer()78:currentLine(end(),end()){79}
80
81//--------------------------------------------------
82ofBuffer::ofBuffer(const char * buffer, std::size_t size)83:buffer(buffer,buffer+size)84,currentLine(end(),end()){85}
86
87//--------------------------------------------------
88ofBuffer::ofBuffer(istream & stream, std::size_t ioBlockSize)89:currentLine(end(),end()){90set(stream, ioBlockSize);91}
92
93//--------------------------------------------------
94bool ofBuffer::set(istream & stream, std::size_t ioBlockSize){95if(stream.bad()){96clear();97return false;98}else{99buffer.clear();100}101
102vector<char> aux_buffer(ioBlockSize);103while(stream.good()){104stream.read(&aux_buffer[0], ioBlockSize);105append(aux_buffer.data(), stream.gcount());106}107return true;108}
109
110//--------------------------------------------------
111void ofBuffer::setall(char mem){112buffer.assign(buffer.size(), mem);113}
114
115//--------------------------------------------------
116bool ofBuffer::writeTo(ostream & stream) const {117if(stream.bad()){118return false;119}120stream.write(buffer.data(), buffer.size());121return stream.good();122}
123
124//--------------------------------------------------
125void ofBuffer::set(const char * buffer, std::size_t size){126this->buffer.assign(buffer, buffer+size);127}
128
129//--------------------------------------------------
130void ofBuffer::set(const std::string & text){131set(text.c_str(), text.size());132}
133
134//--------------------------------------------------
135void ofBuffer::append(const std::string& buffer){136append(buffer.c_str(), buffer.size());137}
138
139//--------------------------------------------------
140void ofBuffer::append(const char * buffer, std::size_t size){141this->buffer.insert(this->buffer.end(), buffer, buffer + size);142}
143
144//--------------------------------------------------
145void ofBuffer::reserve(std::size_t size){146buffer.reserve(size);147}
148
149//--------------------------------------------------
150void ofBuffer::clear(){151buffer.clear();152}
153
154//--------------------------------------------------
155void ofBuffer::allocate(std::size_t size){156resize(size);157}
158
159//--------------------------------------------------
160void ofBuffer::resize(std::size_t size){161buffer.resize(size);162}
163
164
165//--------------------------------------------------
166char * ofBuffer::getData(){167return buffer.data();168}
169
170//--------------------------------------------------
171const char * ofBuffer::getData() const{172return buffer.data();173}
174
175//--------------------------------------------------
176char * ofBuffer::getBinaryBuffer(){177return getData();178}
179
180//--------------------------------------------------
181const char * ofBuffer::getBinaryBuffer() const {182return getData();183}
184
185//--------------------------------------------------
186string ofBuffer::getText() const {187if(buffer.empty()){188return "";189}190return std::string(buffer.begin(), buffer.end());191}
192
193//--------------------------------------------------
194ofBuffer::operator std::string() const {195return getText();196}
197
198//--------------------------------------------------
199ofBuffer & ofBuffer::operator=(const std::string & text){200set(text);201return *this;202}
203
204//--------------------------------------------------
205std::size_t ofBuffer::size() const {206return buffer.size();207}
208
209//--------------------------------------------------
210string ofBuffer::getNextLine(){211if(currentLine.empty()){212currentLine = getLines().begin();213}else{214++currentLine;215}216return currentLine.asString();217}
218
219//--------------------------------------------------
220string ofBuffer::getFirstLine(){221currentLine = getLines().begin();222return currentLine.asString();223}
224
225//--------------------------------------------------
226bool ofBuffer::isLastLine(){227return currentLine == getLines().end();228}
229
230//--------------------------------------------------
231void ofBuffer::resetLineReader(){232currentLine = getLines().begin();233}
234
235//--------------------------------------------------
236vector<char>::iterator ofBuffer::begin(){237return buffer.begin();238}
239
240//--------------------------------------------------
241vector<char>::iterator ofBuffer::end(){242return buffer.end();243}
244
245//--------------------------------------------------
246vector<char>::const_iterator ofBuffer::begin() const{247return buffer.begin();248}
249
250//--------------------------------------------------
251vector<char>::const_iterator ofBuffer::end() const{252return buffer.end();253}
254
255//--------------------------------------------------
256vector<char>::reverse_iterator ofBuffer::rbegin(){257return buffer.rbegin();258}
259
260//--------------------------------------------------
261vector<char>::reverse_iterator ofBuffer::rend(){262return buffer.rend();263}
264
265//--------------------------------------------------
266vector<char>::const_reverse_iterator ofBuffer::rbegin() const{267return buffer.rbegin();268}
269
270//--------------------------------------------------
271vector<char>::const_reverse_iterator ofBuffer::rend() const{272return buffer.rend();273}
274
275//--------------------------------------------------
276ofBuffer::Line::Line(vector<char>::iterator _begin, vector<char>::iterator _end)277:_current(_begin)278,_begin(_begin)279,_end(_end){280
281if(_begin == _end){282line = "";283return;284}285
286_current = std::find(_begin, _end, '\n');287if(_current - 1 >= _begin && *(_current - 1) == '\r'){288line = string(_begin, _current - 1);289}else{290line = string(_begin, _current);291}292if(_current != _end){293_current+=1;294}295}
296
297//--------------------------------------------------
298const std::string & ofBuffer::Line::operator*() const{299return line;300}
301
302//--------------------------------------------------
303const std::string * ofBuffer::Line::operator->() const{304return &line;305}
306
307//--------------------------------------------------
308const std::string & ofBuffer::Line::asString() const{309return line;310}
311
312//--------------------------------------------------
313ofBuffer::Line & ofBuffer::Line::operator++(){314*this = Line(_current,_end);315return *this;316}
317
318//--------------------------------------------------
319ofBuffer::Line ofBuffer::Line::operator++(int) {320Line tmp(*this);321operator++();322return tmp;323}
324
325//--------------------------------------------------
326bool ofBuffer::Line::operator!=(Line const& rhs) const{327return rhs._begin != _begin || rhs._end != _end;328}
329
330//--------------------------------------------------
331bool ofBuffer::Line::operator==(Line const& rhs) const{332return rhs._begin == _begin && rhs._end == _end;333}
334
335bool ofBuffer::Line::empty() const{336return _begin == _end;337}
338
339
340
341//--------------------------------------------------
342ofBuffer::RLine::RLine(vector<char>::reverse_iterator _rbegin, vector<char>::reverse_iterator _rend)343:_current(_rbegin)344,_rbegin(_rbegin)345,_rend(_rend){346
347if(_rbegin == _rend){348line = "";349return;350}351_current = std::find(_rbegin+1, _rend, '\n');352line = string(_current.base(), _rbegin.base() - 1);353if(_current < _rend-1 && *(_current + 1) == '\r'){354_current+=1;355}356}
357
358//--------------------------------------------------
359const std::string & ofBuffer::RLine::operator*() const{360return line;361}
362
363//--------------------------------------------------
364const std::string * ofBuffer::RLine::operator->() const{365return &line;366}
367
368//--------------------------------------------------
369const std::string & ofBuffer::RLine::asString() const{370return line;371}
372
373//--------------------------------------------------
374ofBuffer::RLine & ofBuffer::RLine::operator++(){375*this = RLine(_current,_rend);376return *this;377}
378
379//--------------------------------------------------
380ofBuffer::RLine ofBuffer::RLine::operator++(int) {381RLine tmp(*this);382operator++();383return tmp;384}
385
386//--------------------------------------------------
387bool ofBuffer::RLine::operator!=(RLine const& rhs) const{388return rhs._rbegin != _rbegin || rhs._rend != _rend;389}
390
391//--------------------------------------------------
392bool ofBuffer::RLine::operator==(RLine const& rhs) const{393return rhs._rbegin == _rbegin && rhs._rend == _rend;394}
395
396bool ofBuffer::RLine::empty() const{397return _rbegin == _rend;398}
399
400//--------------------------------------------------
401ofBuffer::Lines::Lines(vector<char>::iterator begin, vector<char>::iterator end)402:_begin(begin)403,_end(end){}404
405//--------------------------------------------------
406ofBuffer::Line ofBuffer::Lines::begin(){407return Line(_begin,_end);408}
409
410//--------------------------------------------------
411ofBuffer::Line ofBuffer::Lines::end(){412return Line(_end,_end);413}
414
415
416//--------------------------------------------------
417ofBuffer::RLines::RLines(vector<char>::reverse_iterator rbegin, vector<char>::reverse_iterator rend)418:_rbegin(rbegin)419,_rend(rend){}420
421//--------------------------------------------------
422ofBuffer::RLine ofBuffer::RLines::begin(){423return RLine(_rbegin,_rend);424}
425
426//--------------------------------------------------
427ofBuffer::RLine ofBuffer::RLines::end(){428return RLine(_rend,_rend);429}
430
431//--------------------------------------------------
432ofBuffer::Lines ofBuffer::getLines(){433return ofBuffer::Lines(begin(), end());434}
435
436//--------------------------------------------------
437ofBuffer::RLines ofBuffer::getReverseLines(){438return ofBuffer::RLines(rbegin(), rend());439}
440
441//--------------------------------------------------
442ostream & operator<<(ostream & ostr, const ofBuffer & buf){443buf.writeTo(ostr);444return ostr;445}
446
447//--------------------------------------------------
448istream & operator>>(istream & istr, ofBuffer & buf){449buf.set(istr);450return istr;451}
452
453//--------------------------------------------------
454ofBuffer ofBufferFromFile(const of::filesystem::path & path, bool binary){455ofFile f(path,ofFile::ReadOnly, binary);456return ofBuffer(f);457}
458
459//--------------------------------------------------
460bool ofBufferToFile(const of::filesystem::path & path, const ofBuffer& buffer, bool binary){461ofFile f(path, ofFile::WriteOnly, binary);462return buffer.writeTo(f);463}
464
465//------------------------------------------------------------------------------------------------------------
466//------------------------------------------------------------------------------------------------------------
467// -- ofFile
468//------------------------------------------------------------------------------------------------------------
469//------------------------------------------------------------------------------------------------------------
470
471//------------------------------------------------------------------------------------------------------------
472ofFile::ofFile()473:mode(Reference)474,binary(true){475}
476
477ofFile::ofFile(const of::filesystem::path & path, Mode mode, bool binary)478:mode(mode)479,binary(true){480open(path, mode, binary);481}
482
483//-------------------------------------------------------------------------------------------------------------
484ofFile::~ofFile(){485//close();486}
487
488//-------------------------------------------------------------------------------------------------------------
489ofFile::ofFile(const ofFile & mom)490:basic_ios()491,fstream()492,mode(Reference)493,binary(true){494copyFrom(mom);495}
496
497//-------------------------------------------------------------------------------------------------------------
498ofFile & ofFile::operator=(const ofFile & mom){499copyFrom(mom);500return *this;501}
502
503//-------------------------------------------------------------------------------------------------------------
504void ofFile::copyFrom(const ofFile & mom){505if(&mom != this){506Mode new_mode = mom.mode;507if(new_mode != Reference && new_mode != ReadOnly){508new_mode = ReadOnly;509ofLogWarning("ofFile") << "copyFrom(): copying a writable file, opening new copy as read only";510}511open(mom.myFile.string(), new_mode, mom.binary);512}513}
514
515//------------------------------------------------------------------------------------------------------------
516bool ofFile::openStream(Mode _mode, bool _binary){517mode = _mode;518binary = _binary;519ios_base::openmode binary_mode = binary ? ios::binary : (ios_base::openmode)0;520switch(_mode) {521case WriteOnly:522case ReadWrite:523case Append:524if(!ofDirectory(ofFilePath::getEnclosingDirectory(path())).exists()){525ofFilePath::createEnclosingDirectory(path());526}527break;528case Reference:529case ReadOnly:530break;531}532switch(_mode){533case Reference:534return true;535break;536
537case ReadOnly:538if(exists() && isFile()){539fstream::open(path().c_str(), ios::in | binary_mode);540}541break;542
543case WriteOnly:544fstream::open(path().c_str(), ios::out | binary_mode);545break;546
547case ReadWrite:548fstream::open(path().c_str(), ios_base::in | ios_base::out | binary_mode);549break;550
551case Append:552fstream::open(path().c_str(), ios::out | ios::app | binary_mode);553break;554}555return fstream::good();556}
557
558//------------------------------------------------------------------------------------------------------------
559bool ofFile::open(const of::filesystem::path & _path, Mode _mode, bool binary){560close();561myFile = ofToDataPath(_path);562return openStream(_mode, binary);563}
564
565//------------------------------------------------------------------------------------------------------------
566bool ofFile::openFromCWD(const of::filesystem::path & _path, Mode _mode, bool binary){567close();568myFile = _path;569return openStream(_mode, binary);570}
571
572//-------------------------------------------------------------------------------------------------------------
573bool ofFile::changeMode(Mode _mode, bool binary){574if(_mode != mode){575auto _path = path();576close();577myFile = _path;578return openStream(_mode, binary);579}580else{581return true;582}583}
584
585//-------------------------------------------------------------------------------------------------------------
586bool ofFile::isWriteMode(){587return mode != ReadOnly;588}
589
590//-------------------------------------------------------------------------------------------------------------
591void ofFile::close(){592myFile = of::filesystem::path();593if(mode!=Reference) fstream::close();594}
595
596//------------------------------------------------------------------------------------------------------------
597bool ofFile::create(){598return create(path());599}
600
601//------------------------------------------------------------------------------------------------------------
602bool ofFile::create(const of::filesystem::path & path){603bool success = false;604
605auto oldmode = this->mode;606auto oldpath = this->path();607success = open(path,ofFile::WriteOnly,binary);608close();609
610if( !oldpath.empty() ){611open(oldpath,oldmode,binary);612}613
614return success;615}
616
617//------------------------------------------------------------------------------------------------------------
618ofBuffer ofFile::readToBuffer(){619if(myFile.string().empty() || !of::filesystem::exists(myFile)){620return ofBuffer();621}622
623return ofBuffer(*this);624}
625
626//------------------------------------------------------------------------------------------------------------
627bool ofFile::writeFromBuffer(const ofBuffer & buffer){628if(myFile.string().empty()){629return false;630}631if(!isWriteMode()){632ofLogError("ofFile") << "writeFromBuffer(): trying to write to read only file \"" << myFile.string() << "\"";633}634return buffer.writeTo(*this);635}
636
637//------------------------------------------------------------------------------------------------------------
638std::filebuf *ofFile::getFileBuffer() const {639return rdbuf();640}
641
642//------------------------------------------------------------------------------------------------------------
643bool ofFile::exists() const {644if(path().empty()){645return false;646}647return of::filesystem::exists(myFile);648}
649
650//------------------------------------------------------------------------------------------------------------
651// MARK: - near future
652//of::filesystem::path ofFile::path() const {
653//return myFile;
654std::string ofFile::path() const {655return myFile.string();656}
657
658//------------------------------------------------------------------------------------------------------------
659string ofFile::getExtension() const {660auto dotext = myFile.extension().string();661// FIXME: probably not needed;662if(!dotext.empty() && dotext.front()=='.'){663return std::string(dotext.begin()+1,dotext.end());664}else{665return dotext;666}667}
668
669//------------------------------------------------------------------------------------------------------------
670string ofFile::getFileName() const {671return myFile.filename().string();672}
673
674//------------------------------------------------------------------------------------------------------------
675string ofFile::getBaseName() const {676return myFile.stem().string();677}
678
679//------------------------------------------------------------------------------------------------------------
680// MARK: - near future
681//of::filesystem::path ofFile::getEnclosingDirectory() const {
682std::string ofFile::getEnclosingDirectory() const {683return ofFilePath::getEnclosingDirectory(path());684}
685
686//------------------------------------------------------------------------------------------------------------
687// MARK: - near future
688//of::filesystem::path ofFile::getAbsolutePath() const {
689std::string ofFile::getAbsolutePath() const {690return ofFilePath::getAbsolutePath(path());691}
692
693//------------------------------------------------------------------------------------------------------------
694bool ofFile::canRead() const {695
696#ifdef TARGET_WIN32697DWORD attr = GetFileAttributes(myFile.native().c_str());698if (attr == INVALID_FILE_ATTRIBUTES)699{700return false;701}702return true;703#else704struct stat info;705stat(path().c_str(), &info); // Error check omitted706auto perm = of::filesystem::status(myFile).permissions();707#if OF_USING_STD_FS708if(geteuid() == info.st_uid){709return (perm & of::filesystem::perms::owner_read) != of::filesystem::perms::none;710}else if (getegid() == info.st_gid){711return (perm & of::filesystem::perms::group_read) != of::filesystem::perms::none;712}else{713return (perm & of::filesystem::perms::others_read) != of::filesystem::perms::none;714}715#else716if(geteuid() == info.st_uid){717return perm & of::filesystem::perms::owner_read;718}else if (getegid() == info.st_gid){719return perm & of::filesystem::perms::group_read;720}else{721return perm & of::filesystem::perms::others_read;722}723#endif724#endif725}
726
727//------------------------------------------------------------------------------------------------------------
728bool ofFile::canWrite() const {729#ifdef TARGET_WIN32730DWORD attr = GetFileAttributes(myFile.native().c_str());731if (attr == INVALID_FILE_ATTRIBUTES){732return false;733}else{734return (attr & FILE_ATTRIBUTE_READONLY) == 0;735}736#else737struct stat info;738stat(path().c_str(), &info); // Error check omitted739auto perm = of::filesystem::status(myFile).permissions();740#if OF_USING_STD_FS741if(geteuid() == info.st_uid){742return (perm & of::filesystem::perms::owner_write) != of::filesystem::perms::none;743}else if (getegid() == info.st_gid){744return (perm & of::filesystem::perms::group_write) != of::filesystem::perms::none;745}else{746return (perm & of::filesystem::perms::others_write) != of::filesystem::perms::none;747}748#else749if(geteuid() == info.st_uid){750return perm & of::filesystem::owner_write;751}else if (getegid() == info.st_gid){752return perm & of::filesystem::group_write;753}else{754return perm & of::filesystem::others_write;755}756#endif757#endif758}
759
760//------------------------------------------------------------------------------------------------------------
761bool ofFile::canExecute() const {762#ifdef TARGET_WIN32763return getExtension() == "exe";764#else765struct stat info;766stat(path().c_str(), &info); // Error check omitted767auto perm = of::filesystem::status(myFile).permissions();768#if OF_USING_STD_FS769if(geteuid() == info.st_uid){770return (perm & of::filesystem::perms::owner_exec) != of::filesystem::perms::none;771}else if (getegid() == info.st_gid){772return (perm & of::filesystem::perms::group_exec) != of::filesystem::perms::none;773}else{774return (perm & of::filesystem::perms::others_exec) != of::filesystem::perms::none;775}776#else777if(geteuid() == info.st_uid){778return perm & of::filesystem::owner_exe;779}else if (getegid() == info.st_gid){780return perm & of::filesystem::group_exe;781}else{782return perm & of::filesystem::others_exe;783}784#endif785#endif786}
787//------------------------------------------------------------------------------------------------------------
788bool ofFile::isFile() const {789return of::filesystem::is_regular_file(myFile);790}
791
792//------------------------------------------------------------------------------------------------------------
793bool ofFile::isLink() const {794return of::filesystem::is_symlink(myFile);795}
796
797//------------------------------------------------------------------------------------------------------------
798bool ofFile::isDirectory() const {799return of::filesystem::is_directory(myFile);800}
801
802//------------------------------------------------------------------------------------------------------------
803bool ofFile::isDevice() const {804#ifdef TARGET_WIN32805return false;806#else807#if OF_USING_STD_FS808return of::filesystem::is_block_file(of::filesystem::status(myFile));809#else810return of::filesystem::status(myFile).type() == of::filesystem::block_file;811#endif812#endif813}
814
815//------------------------------------------------------------------------------------------------------------
816bool ofFile::isHidden() const {817#ifdef TARGET_WIN32818return false;819#else820return myFile.filename() != "." && myFile.filename() != ".." && myFile.filename().string()[0] == '.';821#endif822}
823
824//------------------------------------------------------------------------------------------------------------
825void ofFile::setWriteable(bool flag){826try{827#if !OF_USING_STD_FS || (OF_USING_STD_FS && OF_USE_EXPERIMENTAL_FS)828if(flag){829of::filesystem::permissions(myFile,of::filesystem::perms::owner_write | of::filesystem::perms::add_perms);830}else{831of::filesystem::permissions(myFile,of::filesystem::perms::owner_write | of::filesystem::perms::remove_perms);832}833#else834if(flag){835of::filesystem::permissions(myFile,836of::filesystem::perms::owner_write,837of::filesystem::perm_options::add);838}else{839of::filesystem::permissions(myFile,840of::filesystem::perms::owner_write,841of::filesystem::perm_options::remove);842}843#endif844}catch(std::exception & e){845ofLogError() << "Couldn't set write permission on " << myFile << ": " << e.what();846}847}
848
849//------------------------------------------------------------------------------------------------------------
850// deprecated
851void ofFile::setReadOnly(bool flag){852setWriteable(!flag);853}
854
855//------------------------------------------------------------------------------------------------------------
856void ofFile::setReadable(bool flag){857try{858#if !OF_USING_STD_FS || (OF_USING_STD_FS && OF_USE_EXPERIMENTAL_FS)859if(flag){860of::filesystem::permissions(myFile,of::filesystem::perms::owner_read | of::filesystem::perms::add_perms);861}else{862of::filesystem::permissions(myFile,of::filesystem::perms::owner_read | of::filesystem::perms::remove_perms);863}864#else865if(flag){866of::filesystem::permissions(myFile,867of::filesystem::perms::owner_read,868of::filesystem::perm_options::add);869}else{870of::filesystem::permissions(myFile,871of::filesystem::perms::owner_read,872of::filesystem::perm_options::remove);873}874#endif875}catch(std::exception & e){876ofLogError() << "Couldn't set read permission on " << myFile << ": " << e.what();877}878}
879
880//------------------------------------------------------------------------------------------------------------
881void ofFile::setExecutable(bool flag){882try{883#if OF_USING_STD_FS884# if OF_USE_EXPERIMENTAL_FS885if(flag){886of::filesystem::permissions(myFile, of::filesystem::perms::owner_exec | of::filesystem::perms::add_perms);887} else{888of::filesystem::permissions(myFile, of::filesystem::perms::owner_exec | of::filesystem::perms::remove_perms);889}890# else891if(flag){892of::filesystem::permissions(myFile,893of::filesystem::perms::owner_exec,894of::filesystem::perm_options::add);895} else{896of::filesystem::permissions(myFile,897of::filesystem::perms::owner_exec,898of::filesystem::perm_options::remove);899}900# endif901#else902if(flag){903of::filesystem::permissions(myFile, of::filesystem::perms::owner_exe | of::filesystem::perms::add_perms);904} else{905of::filesystem::permissions(myFile, of::filesystem::perms::owner_exe | of::filesystem::perms::remove_perms);906}907#endif908}catch(std::exception & e){909ofLogError() << "Couldn't set executable permission on " << myFile << ": " << e.what();910}911}
912
913//------------------------------------------------------------------------------------------------------------
914bool ofFile::copyTo(const of::filesystem::path& _path, bool bRelativeToData, bool overwrite) const{915auto path = _path;916
917if(path.empty()){918ofLogError("ofFile") << "copyTo(): destination path " << _path << " is empty";919return false;920}921if(isDirectory()){922ofDirectory tmp;923//don't want to add ofToDataPath to myFile path as it was already done in ofFile::open924tmp.openFromCWD(myFile);925return tmp.copyTo(path,bRelativeToData,overwrite);926}927if(!exists()){928ofLogError("ofFile") << "copyTo(): source file " << this->path() << " does not exist";929return false;930}931
932//bRelativeToData is handled here for the destination path - so we pass false to static functions below933if(bRelativeToData){934path = ofToDataPath(path);935}936
937if(ofFile::doesFileExist(path, false)){938if(isFile()){939ofFile tmp;940tmp.openFromCWD(path,ofFile::Reference);941if(tmp.isDirectory()){942path = path / getFileName();943}944}945if(ofFile::doesFileExist(path, false)){946if(overwrite){947ofFile::removeFile(path, false);948}else{949ofLogWarning("ofFile") << "copyTo(): destination file \"" << path << "\" already exists, set bool overwrite to true if you want to overwrite it";950}951}952}953
954try{955ofDirectory destDir;956auto p = ofFilePath::getEnclosingDirectory(path,false);957destDir.openFromCWD(p);958if(!destDir.exists()){959ofFilePath::createEnclosingDirectory(path, false);960}961of::filesystem::copy_file(myFile,path);962}catch(std::exception & except){963ofLogError("ofFile") << "copyTo(): unable to copy \"" << path << "\": " << except.what();964return false;965}966
967return true;968}
969
970//------------------------------------------------------------------------------------------------------------
971bool ofFile::moveTo(const of::filesystem::path& _path, bool bRelativeToData, bool overwrite){972auto path = _path;973
974if(path.empty()){975ofLogError("ofFile") << "moveTo(): destination path is empty";976return false;977}978if(!exists()){979ofLogError("ofFile") << "moveTo(): source file does not exist";980return false;981}982
983if(bRelativeToData){984path = ofToDataPath(path);985}986if(ofFile::doesFileExist(path, false)){987
988if(isFile()){989ofFile tmp;990tmp.openFromCWD(path,ofFile::Reference);991if(tmp.isDirectory()){992path = path / getFileName();993}994}995if(ofFile::doesFileExist(path, false)){996if(overwrite){997ofFile::removeFile(path, false);998}else{999ofLogWarning("ofFile") << "copyTo(): destination file \"" << path << "\" already exists, set bool overwrite to true if you want to overwrite it";1000}1001}1002}1003
1004try{1005auto mode = this->mode;1006if(mode != ofFile::Reference){1007changeMode(ofFile::Reference, binary);1008}1009ofDirectory destDir;1010destDir.openFromCWD(ofFilePath::getEnclosingDirectory(path,false));1011if(!destDir.exists()){1012ofFilePath::createEnclosingDirectory(path,false);1013}1014of::filesystem::rename(myFile,path);1015myFile = path;1016if(mode != ofFile::Reference){1017changeMode(mode, binary);1018}1019}1020catch(std::exception & except){1021ofLogError("ofFile") << "moveTo(): unable to move \"" << path << "\": " << except.what();1022return false;1023}1024
1025return true;1026}
1027
1028//------------------------------------------------------------------------------------------------------------
1029bool ofFile::renameTo(const of::filesystem::path& path, bool bRelativeToData, bool overwrite){1030return moveTo(path,bRelativeToData,overwrite);1031}
1032
1033//------------------------------------------------------------------------------------------------------------
1034bool ofFile::remove(bool recursive){1035if(myFile.string().empty()){1036ofLogError("ofFile") << "remove(): file path is empty";1037return false;1038}1039if(!exists()){1040ofLogError("ofFile") << "remove(): file does not exist";1041return false;1042}1043
1044try{1045if(mode!=Reference){1046open(path(),Reference,binary);1047}1048if(recursive){1049of::filesystem::remove_all(myFile);1050}else{1051of::filesystem::remove(myFile);1052}1053}catch(std::exception & except){1054ofLogError("ofFile") << "remove(): unable to remove \"" << myFile << "\": " << except.what();1055return false;1056}1057
1058return true;1059}
1060
1061//------------------------------------------------------------------------------------------------------------
1062uint64_t ofFile::getSize() const {1063try{1064return of::filesystem::file_size(myFile);1065}catch(std::exception & except){1066ofLogError("ofFile") << "getSize(): unable to get size of \"" << myFile << "\": " << except.what();1067return 0;1068}1069}
1070
1071//------------------------------------------------------------------------------------------------------------
1072bool ofFile::operator==(const ofFile & file) const {1073return getAbsolutePath() == file.getAbsolutePath();1074}
1075
1076//------------------------------------------------------------------------------------------------------------
1077bool ofFile::operator!=(const ofFile & file) const {1078return getAbsolutePath() != file.getAbsolutePath();1079}
1080
1081//------------------------------------------------------------------------------------------------------------
1082bool ofFile::operator<(const ofFile & file) const {1083return getAbsolutePath() < file.getAbsolutePath();1084}
1085
1086//------------------------------------------------------------------------------------------------------------
1087bool ofFile::operator<=(const ofFile & file) const {1088return getAbsolutePath() <= file.getAbsolutePath();1089}
1090
1091//------------------------------------------------------------------------------------------------------------
1092bool ofFile::operator>(const ofFile & file) const {1093return getAbsolutePath() > file.getAbsolutePath();1094}
1095
1096//------------------------------------------------------------------------------------------------------------
1097bool ofFile::operator>=(const ofFile & file) const {1098return getAbsolutePath() >= file.getAbsolutePath();1099}
1100
1101//------------------------------------------------------------------------------------------------------------
1102// ofFile Static Methods
1103//------------------------------------------------------------------------------------------------------------
1104
1105bool ofFile::copyFromTo(const of::filesystem::path& pathSrc, const of::filesystem::path& pathDst, bool bRelativeToData, bool overwrite){1106ofFile tmp;1107if( bRelativeToData ){1108tmp.open(pathSrc,ofFile::Reference);1109}else{1110tmp.openFromCWD(pathSrc,ofFile::Reference);1111}1112return tmp.copyTo(pathDst,bRelativeToData,overwrite);1113}
1114
1115//be careful with slashes here - appending a slash when moving a folder will causes mad headaches
1116//------------------------------------------------------------------------------------------------------------
1117bool ofFile::moveFromTo(const of::filesystem::path& pathSrc, const of::filesystem::path& pathDst, bool bRelativeToData, bool overwrite){1118ofFile tmp;1119if( bRelativeToData ){1120tmp.open(pathSrc,ofFile::Reference);1121}else{1122tmp.openFromCWD(pathSrc,ofFile::Reference);1123}1124return tmp.moveTo(pathDst, bRelativeToData, overwrite);1125}
1126
1127//------------------------------------------------------------------------------------------------------------
1128bool ofFile::doesFileExist(const of::filesystem::path& _fPath, bool bRelativeToData){1129ofFile tmp;1130if(bRelativeToData){1131tmp.open(_fPath,ofFile::Reference);1132}else{1133tmp.openFromCWD(_fPath,ofFile::Reference);1134}1135return !_fPath.empty() && tmp.exists();1136}
1137
1138//------------------------------------------------------------------------------------------------------------
1139bool ofFile::removeFile(const of::filesystem::path& _path, bool bRelativeToData){1140ofFile tmp;1141if(bRelativeToData){1142tmp.open(_path,ofFile::Reference);1143}else{1144tmp.openFromCWD(_path,ofFile::Reference);1145}1146return tmp.remove();1147}
1148
1149
1150//------------------------------------------------------------------------------------------------------------
1151//------------------------------------------------------------------------------------------------------------
1152// -- ofDirectory
1153//------------------------------------------------------------------------------------------------------------
1154//------------------------------------------------------------------------------------------------------------
1155
1156//------------------------------------------------------------------------------------------------------------
1157ofDirectory::ofDirectory(){1158showHidden = false;1159}
1160
1161//------------------------------------------------------------------------------------------------------------
1162ofDirectory::ofDirectory(const of::filesystem::path & path){1163showHidden = false;1164open(path);1165}
1166
1167//------------------------------------------------------------------------------------------------------------
1168void ofDirectory::open(const of::filesystem::path & path){1169originalDirectory = ofFilePath::getPathForDirectory(path.string());1170files.clear();1171myDir = of::filesystem::path(ofToDataPath(originalDirectory));1172}
1173
1174//------------------------------------------------------------------------------------------------------------
1175void ofDirectory::openFromCWD(const of::filesystem::path & path){1176originalDirectory = ofFilePath::getPathForDirectory(path.string());1177files.clear();1178myDir = of::filesystem::path(originalDirectory);1179}
1180
1181//------------------------------------------------------------------------------------------------------------
1182void ofDirectory::close(){1183myDir = of::filesystem::path();1184}
1185
1186//------------------------------------------------------------------------------------------------------------
1187bool ofDirectory::create(bool recursive){1188
1189if(!myDir.string().empty()){1190try{1191if(recursive){1192of::filesystem::create_directories(myDir);1193}else{1194of::filesystem::create_directory(myDir);1195}1196}1197catch(std::exception & except){1198ofLogError("ofDirectory") << "create(): " << except.what();1199return false;1200}1201}1202
1203return true;1204}
1205
1206//------------------------------------------------------------------------------------------------------------
1207bool ofDirectory::exists() const {1208return (myDir == "" || of::filesystem::exists(myDir));1209}
1210
1211//------------------------------------------------------------------------------------------------------------
1212// MARK: - near future
1213//of::filesystem::path ofDirectory::path() const {
1214// return myDir;
1215std::string ofDirectory::path() const {1216return myDir.string();1217}
1218
1219//------------------------------------------------------------------------------------------------------------
1220// MARK: - near future
1221//of::filesystem::path ofDirectory::getAbsolutePath() const {
1222// try{
1223// return of::filesystem::canonical(of::filesystem::absolute(myDir));
1224// }catch(...){
1225// return of::filesystem::absolute(myDir);
1226// }
1227//}
1228std::string ofDirectory::getAbsolutePath() const {1229try{1230return of::filesystem::canonical(of::filesystem::absolute(myDir)).string();1231}catch(...){1232return of::filesystem::absolute(myDir).string();1233}1234}
1235
1236//------------------------------------------------------------------------------------------------------------
1237bool ofDirectory::canRead() const {1238return ofFile(myDir,ofFile::Reference).canRead();1239}
1240
1241//------------------------------------------------------------------------------------------------------------
1242bool ofDirectory::canWrite() const {1243return ofFile(myDir,ofFile::Reference).canWrite();1244}
1245
1246//------------------------------------------------------------------------------------------------------------
1247bool ofDirectory::canExecute() const {1248return ofFile(myDir,ofFile::Reference).canExecute();1249}
1250
1251//------------------------------------------------------------------------------------------------------------
1252bool ofDirectory::isHidden() const {1253return ofFile(myDir,ofFile::Reference).isHidden();1254}
1255
1256//------------------------------------------------------------------------------------------------------------
1257void ofDirectory::setWriteable(bool flag){1258return ofFile(myDir,ofFile::Reference).setWriteable(flag);1259}
1260
1261//------------------------------------------------------------------------------------------------------------
1262// deprecated
1263void ofDirectory::setReadOnly(bool flag){1264setWriteable(!flag);1265}
1266
1267//------------------------------------------------------------------------------------------------------------
1268void ofDirectory::setReadable(bool flag){1269return ofFile(myDir,ofFile::Reference).setReadable(flag);1270}
1271
1272//------------------------------------------------------------------------------------------------------------
1273void ofDirectory::setExecutable(bool flag){1274return ofFile(myDir,ofFile::Reference).setExecutable(flag);1275}
1276
1277//------------------------------------------------------------------------------------------------------------
1278void ofDirectory::setShowHidden(bool showHidden){1279this->showHidden = showHidden;1280}
1281
1282//------------------------------------------------------------------------------------------------------------
1283bool ofDirectory::isDirectory() const {1284return of::filesystem::is_directory(myDir);1285}
1286
1287//------------------------------------------------------------------------------------------------------------
1288bool ofDirectory::copyTo(const of::filesystem::path& _path, bool bRelativeToData, bool overwrite){1289auto path = _path;1290
1291if(myDir.string().empty()){1292ofLogError("ofDirectory") << "copyTo(): source path is empty";1293return false;1294}1295if(!of::filesystem::exists(myDir)){1296ofLogError("ofDirectory") << "copyTo(): source directory does not exist";1297return false;1298}1299if(!of::filesystem::is_directory(myDir)){1300ofLogError("ofDirectory") << "copyTo(): source path is not a directory";1301return false;1302}1303
1304if(bRelativeToData){1305path = ofToDataPath(path, bRelativeToData);1306}1307
1308if(ofDirectory::doesDirectoryExist(path, false)){1309if(overwrite){1310ofDirectory::removeDirectory(path, true, false);1311}else{1312ofLogWarning("ofDirectory") << "copyTo(): dest \"" << path << "\" already exists, set bool overwrite to true to overwrite it";1313return false;1314}1315}1316
1317//our path is bRelativeToData handled from above - so can't open via the constructor approach1318ofDirectory dir;1319dir.openFromCWD(path);1320dir.create(true);1321
1322// Iterate through the source directory1323for(of::filesystem::directory_iterator file(myDir); file != of::filesystem::directory_iterator(); ++file){1324auto currentPath = of::filesystem::absolute(file->path());1325auto dst = of::filesystem::path(path) / currentPath.filename();1326if(of::filesystem::is_directory(currentPath)){1327ofDirectory current(currentPath);1328// Found directory: Recursion1329if(!current.copyTo(dst,false,overwrite)){1330return false;1331}1332}else{1333ofFile tmp;1334tmp.openFromCWD(file->path(),ofFile::Reference);1335tmp.copyTo(dst.string(),false,overwrite);1336}1337}1338
1339return true;1340}
1341
1342//------------------------------------------------------------------------------------------------------------
1343bool ofDirectory::moveTo(const of::filesystem::path& path, bool bRelativeToData, bool overwrite){1344if(copyTo(path,bRelativeToData,overwrite)){1345return remove(true);1346}1347
1348return false;1349}
1350
1351//------------------------------------------------------------------------------------------------------------
1352bool ofDirectory::renameTo(const of::filesystem::path& path, bool bRelativeToData, bool overwrite){1353return moveTo(path, bRelativeToData, overwrite);1354}
1355
1356//------------------------------------------------------------------------------------------------------------
1357bool ofDirectory::remove(bool recursive){1358if(path().empty() || !of::filesystem::exists(myDir)){1359return false;1360}1361
1362try{1363if(recursive){1364of::filesystem::remove_all(of::filesystem::canonical(myDir));1365}else{1366of::filesystem::remove(of::filesystem::canonical(myDir));1367}1368}catch(std::exception & except){1369ofLogError("ofDirectory") << "remove(): unable to remove file/directory: " << except.what();1370return false;1371}1372
1373return true;1374}
1375
1376//------------------------------------------------------------------------------------------------------------
1377void ofDirectory::allowExt(const std::string& extension){1378if(extension == "*"){1379ofLogWarning("ofDirectory") << "allowExt(): wildcard extension * is deprecated";1380}1381extensions.push_back(ofToLower(extension));1382}
1383
1384//------------------------------------------------------------------------------------------------------------
1385std::size_t ofDirectory::listDir(const of::filesystem::path & directory){1386open(directory);1387return listDir();1388}
1389
1390//------------------------------------------------------------------------------------------------------------
1391std::size_t ofDirectory::listDir(){1392files.clear();1393if(path().empty()){1394ofLogError("ofDirectory") << "listDir(): directory path is empty";1395return 0;1396}1397if(!of::filesystem::exists(myDir)){1398ofLogError("ofDirectory") << "listDir:() source directory does not exist: \"" << myDir << "\"";1399return 0;1400}1401
1402of::filesystem::directory_iterator end_iter;1403if ( of::filesystem::exists(myDir) && of::filesystem::is_directory(myDir)){1404for( of::filesystem::directory_iterator dir_iter(myDir) ; dir_iter != end_iter ; ++dir_iter){1405files.emplace_back(dir_iter->path().string(), ofFile::Reference);1406}1407}else{1408ofLogError("ofDirectory") << "listDir:() source directory does not exist: \"" << myDir << "\"";1409return 0;1410}1411
1412if(!showHidden){1413ofRemove(files, [](ofFile & file){1414return file.isHidden();1415});1416}1417
1418
1419if(!extensions.empty() && !ofContains(extensions, (string)"*")){1420ofRemove(files, [&](ofFile & file){1421return std::find(extensions.begin(), extensions.end(), ofToLower(file.getExtension())) == extensions.end();1422});1423}1424
1425if(ofGetLogLevel() == OF_LOG_VERBOSE){1426for(int i = 0; i < (int)size(); i++){1427ofLogVerbose() << "\t" << getName(i);1428}1429ofLogVerbose() << "listed " << size() << " files in \"" << originalDirectory << "\"";1430}1431
1432return size();1433}
1434
1435//------------------------------------------------------------------------------------------------------------
1436string ofDirectory::getOriginalDirectory() const {1437return originalDirectory;1438}
1439
1440//------------------------------------------------------------------------------------------------------------
1441string ofDirectory::getName(std::size_t position) const{1442return files.at(position).getFileName();1443}
1444
1445//------------------------------------------------------------------------------------------------------------
1446string ofDirectory::getPath(std::size_t position) const{1447return originalDirectory + getName(position);1448}
1449
1450//------------------------------------------------------------------------------------------------------------
1451ofFile ofDirectory::getFile(std::size_t position, ofFile::Mode mode, bool binary) const {1452ofFile file = files[position];1453file.changeMode(mode, binary);1454return file;1455}
1456
1457ofFile ofDirectory::operator[](std::size_t position) const {1458return getFile(position);1459}
1460
1461//------------------------------------------------------------------------------------------------------------
1462const vector<ofFile> & ofDirectory::getFiles() const{1463if(files.empty() && !myDir.empty()){1464const_cast<ofDirectory*>(this)->listDir();1465}1466return files;1467}
1468
1469//------------------------------------------------------------------------------------------------------------
1470bool ofDirectory::getShowHidden() const{1471return showHidden;1472}
1473
1474//------------------------------------------------------------------------------------------------------------
1475void ofDirectory::reset(){1476close();1477}
1478
1479//------------------------------------------------------------------------------------------------------------
1480static bool natural(const ofFile& a, const ofFile& b) {1481string aname = a.getBaseName(), bname = b.getBaseName();1482int aint = ofToInt(aname), bint = ofToInt(bname);1483if(ofToString(aint) == aname && ofToString(bint) == bname) {1484return aint < bint;1485} else {1486return a < b;1487}1488}
1489
1490
1491//------------------------------------------------------------------------------------------------------------
1492struct StringSort{1493of::filesystem::path path;1494string basename;1495int nameInt;1496string stringInt;1497};1498
1499//------------------------------------------------------------------------------------------------------------
1500static bool naturalStr(const StringSort& a, const StringSort& b) {1501if(a.stringInt == a.basename && b.stringInt == b.basename) {1502return a.nameInt < b.nameInt;1503} else {1504return a.path < b.path;1505}1506}
1507
1508//------------------------------------------------------------------------------------------------------------
1509static bool byDate(const ofFile& a, const ofFile& b) {1510auto ta = of::filesystem::last_write_time(a);1511auto tb = of::filesystem::last_write_time(b);1512return ta < tb;1513}
1514
1515//------------------------------------------------------------------------------------------------------------
1516void ofDirectory::sortByDate() {1517if (files.empty() && !myDir.empty()) {1518listDir();1519}1520ofSort(files, byDate);1521}
1522
1523//------------------------------------------------------------------------------------------------------------
1524void ofDirectory::sort(const SortMode & mode){1525if(files.empty() && !myDir.empty()){1526listDir();1527}1528
1529if( mode == ofDirectory::SORT_NATURAL ){1530vector <StringSort> sort;1531sort.reserve(files.size());1532
1533for( auto & f : files ){1534StringSort ss;1535ss.path = f.path();1536ss.basename = f.getBaseName();1537ss.nameInt = ofToInt(ss.basename);1538ss.stringInt = ofToString(ss.nameInt);1539sort.push_back(ss);1540}1541
1542ofSort(sort, naturalStr);1543files.clear();1544files.reserve(sort.size());1545for( auto & s : sort ){1546files.emplace_back( s.path , ofFile::Reference);1547}1548}1549else if(mode == ofDirectory::SORT_FAST){1550std::vector <string> sort;1551sort.reserve(files.size());1552
1553for( auto & f : files ){1554string ss = f.getFileName();1555sort.push_back(ss);1556}1557
1558std::sort(sort.begin(), sort.end());1559files.clear();1560files.reserve(sort.size());1561for( auto & s : sort ){1562files.emplace_back( myDir / of::filesystem::path(s), ofFile::Reference);1563}1564}else if(mode == ofDirectory::SORT_BY_DATE){1565sortByDate();1566}1567}
1568
1569//------------------------------------------------------------------------------------------------------------
1570ofDirectory ofDirectory::getSorted(){1571ofDirectory sorted(*this);1572sorted.listDir();1573sorted.sort();1574return sorted;1575}
1576
1577//------------------------------------------------------------------------------------------------------------
1578std::size_t ofDirectory::size() const{1579return files.size();1580}
1581
1582//------------------------------------------------------------------------------------------------------------
1583int ofDirectory::numFiles(){1584return static_cast<int>(size());1585}
1586
1587//------------------------------------------------------------------------------------------------------------
1588// ofDirectory Static Methods
1589//------------------------------------------------------------------------------------------------------------
1590
1591//------------------------------------------------------------------------------------------------------------
1592bool ofDirectory::removeDirectory(const of::filesystem::path& _path, bool deleteIfNotEmpty, bool bRelativeToData){1593auto path = _path;1594
1595ofFile dirToRemove;1596if(bRelativeToData){1597dirToRemove.open(path,ofFile::Reference);1598}else{1599dirToRemove.openFromCWD(path,ofFile::Reference);1600}1601
1602return dirToRemove.remove(deleteIfNotEmpty);1603}
1604
1605//------------------------------------------------------------------------------------------------------------
1606bool ofDirectory::createDirectory(const of::filesystem::path& _dirPath, bool bRelativeToData, bool recursive){1607auto dirPath = _dirPath;1608
1609if(bRelativeToData){1610dirPath = ofToDataPath(dirPath);1611}1612
1613// on OSX,of::filesystem::create_directories seems to return false *if* the path has folders that already exist1614// and true if it doesn't1615// so to avoid unnecessary warnings on OSX, we check if it exists here:1616
1617bool bDoesExistAlready = ofDirectory::doesDirectoryExist(dirPath,false);1618
1619if (!bDoesExistAlready){1620
1621bool success = false;1622try{1623if(!recursive){1624success = of::filesystem::create_directory(dirPath);1625}else{1626success = of::filesystem::create_directories(dirPath);1627}1628} catch(std::exception & except){1629ofLogError("ofDirectory") << "createDirectory(): couldn't create directory \"" << dirPath << "\": " << except.what();1630return false;1631}1632return success;1633}1634
1635// no need to create it - it already exists.1636return true;1637}
1638
1639//------------------------------------------------------------------------------------------------------------
1640bool ofDirectory::doesDirectoryExist(const of::filesystem::path& _dirPath, bool bRelativeToData){1641auto dirPath = _dirPath;1642try {1643if (bRelativeToData) {1644dirPath = ofToDataPath(dirPath);1645}1646return of::filesystem::exists(dirPath) && of::filesystem::is_directory(dirPath);1647}1648catch (std::exception & except) {1649ofLogError("ofDirectory") << "doesDirectoryExist(): couldn't find directory \"" << dirPath << "\": " << except.what() << std::endl;1650return false;1651}1652}
1653
1654//------------------------------------------------------------------------------------------------------------
1655bool ofDirectory::isDirectoryEmpty(const of::filesystem::path& _dirPath, bool bRelativeToData){1656auto dirPath = _dirPath;1657if(bRelativeToData){1658dirPath = ofToDataPath(dirPath);1659}1660
1661if(!dirPath.empty() && of::filesystem::exists(dirPath) && of::filesystem::is_directory(dirPath)){1662return of::filesystem::directory_iterator(dirPath) == of::filesystem::directory_iterator();1663}1664return false;1665}
1666
1667//------------------------------------------------------------------------------------------------------------
1668bool ofDirectory::operator==(const ofDirectory & dir) const{1669return getAbsolutePath() == dir.getAbsolutePath();1670}
1671
1672//------------------------------------------------------------------------------------------------------------
1673bool ofDirectory::operator!=(const ofDirectory & dir) const{1674return getAbsolutePath() != dir.getAbsolutePath();1675}
1676
1677//------------------------------------------------------------------------------------------------------------
1678bool ofDirectory::operator<(const ofDirectory & dir) const{1679return getAbsolutePath() < dir.getAbsolutePath();1680}
1681
1682//------------------------------------------------------------------------------------------------------------
1683bool ofDirectory::operator<=(const ofDirectory & dir) const{1684return getAbsolutePath() <= dir.getAbsolutePath();1685}
1686
1687//------------------------------------------------------------------------------------------------------------
1688bool ofDirectory::operator>(const ofDirectory & dir) const{1689return getAbsolutePath() > dir.getAbsolutePath();1690}
1691
1692//------------------------------------------------------------------------------------------------------------
1693bool ofDirectory::operator>=(const ofDirectory & dir) const{1694return getAbsolutePath() >= dir.getAbsolutePath();1695}
1696
1697//------------------------------------------------------------------------------------------------------------
1698vector<ofFile>::const_iterator ofDirectory::begin() const{1699return getFiles().begin();1700}
1701
1702//------------------------------------------------------------------------------------------------------------
1703vector<ofFile>::const_iterator ofDirectory::end() const{1704return files.end();1705}
1706
1707//------------------------------------------------------------------------------------------------------------
1708vector<ofFile>::const_reverse_iterator ofDirectory::rbegin() const{1709return getFiles().rbegin();1710}
1711
1712//------------------------------------------------------------------------------------------------------------
1713vector<ofFile>::const_reverse_iterator ofDirectory::rend() const{1714return files.rend();1715}
1716
1717
1718//------------------------------------------------------------------------------------------------------------
1719//------------------------------------------------------------------------------------------------------------
1720// -- ofFilePath
1721//------------------------------------------------------------------------------------------------------------
1722//------------------------------------------------------------------------------------------------------------
1723
1724
1725//------------------------------------------------------------------------------------------------------------
1726string ofFilePath::addLeadingSlash(const of::filesystem::path& _path){1727auto path = _path.string();1728auto sep = of::filesystem::path("/").make_preferred();1729if(!path.empty()){1730if(ofToString(path[0]) != sep.string()){1731path = (sep / path).string();1732}1733}1734return path;1735}
1736
1737//------------------------------------------------------------------------------------------------------------
1738// MARK: - near future
1739//of::filesystem::path ofFilePath::addTrailingSlash(const of::filesystem::path & _path){
1740std::string ofFilePath::addTrailingSlash(const of::filesystem::path & _path){1741#if OF_USING_STD_FS && !OF_USE_EXPERIMENTAL_FS1742if(_path.string().empty()) return "";1743// FIXME: Remove .string() here and following1744// return (of::filesystem::path(_path).make_preferred() / "");1745return (of::filesystem::path(_path).make_preferred() / "").string();1746#else1747auto path = of::filesystem::path(_path).make_preferred();1748auto sep = of::filesystem::path("/").make_preferred();1749if(!path.empty()){1750if(ofToString(path.string().back()) != sep.string()){1751path = (path / sep);1752}1753}1754// return path;
1755return path.string();1756#endif1757}
1758
1759
1760//------------------------------------------------------------------------------------------------------------
1761string ofFilePath::getFileExt(const of::filesystem::path& filename){1762return ofFile(filename,ofFile::Reference).getExtension();1763}
1764
1765//------------------------------------------------------------------------------------------------------------
1766// FIXME: remove const and copy
1767// MARK: - near future
1768// of::filesystem::path ofFilePath::removeExt(const of::filesystem::path& _filename){
1769std::string ofFilePath::removeExt(const of::filesystem::path& _filename){1770auto filename = _filename;1771// return filename.replace_extension();
1772return filename.replace_extension().string();1773}
1774
1775//------------------------------------------------------------------------------------------------------------
1776string ofFilePath::getPathForDirectory(const of::filesystem::path& path){1777// if a trailing slash is missing from a path, this will clean it up1778// if it's a windows-style "\" path it will add a "\"1779// if it's a unix-style "/" path it will add a "/"1780
1781// FIXME: Remove .string() here and following1782// FIXME: this seems over complicated and not useful anymore, using filesystem1783
1784#if OF_USING_STD_FS && !OF_USE_EXPERIMENTAL_FS1785if(path.string().empty()) return "";1786return (path / "").string();1787#else1788auto sep = of::filesystem::path("/").make_preferred();1789if(!path.empty() && ofToString(path.string().back())!=sep.string()){1790return (path / sep).string();1791}else{1792return path.string();1793}1794#endif1795}
1796
1797//------------------------------------------------------------------------------------------------------------
1798// FIXME: convert to of::filesystem::path
1799string ofFilePath::removeTrailingSlash(const of::filesystem::path& _path){1800auto path = _path.string();1801if(path.length() > 0 && (path[path.length() - 1] == '/' || path[path.length() - 1] == '\\')){1802path = path.substr(0, path.length() - 1);1803}1804return path;1805}
1806
1807
1808//------------------------------------------------------------------------------------------------------------
1809// FIXME: is this still useful? if yes convert to of::filesystem::path
1810string ofFilePath::getFileName(const of::filesystem::path& _filePath, bool bRelativeToData){1811auto filePath = _filePath;1812
1813if(bRelativeToData){1814filePath = ofToDataPath(filePath);1815}1816
1817// FIXME: this is probably over complicated1818return of::filesystem::path(filePath).filename().string();1819}
1820
1821//------------------------------------------------------------------------------------------------------------
1822string ofFilePath::getBaseName(const of::filesystem::path& filePath){1823// FIXME: is this still useful?1824return ofFile(filePath,ofFile::Reference).getBaseName();1825}
1826
1827//------------------------------------------------------------------------------------------------------------
1828// MARK: - near future
1829//of::filesystem::path ofFilePath::getEnclosingDirectory(const of::filesystem::path & _filePath, bool bRelativeToData){
1830std::string ofFilePath::getEnclosingDirectory(const of::filesystem::path & _filePath, bool bRelativeToData){1831auto fp = _filePath;1832if(bRelativeToData){1833fp = ofToDataPath(fp);1834}1835return addTrailingSlash(fp.parent_path());1836}
1837
1838//------------------------------------------------------------------------------------------------------------
1839bool ofFilePath::createEnclosingDirectory(const of::filesystem::path& filePath, bool bRelativeToData, bool bRecursive) {1840return ofDirectory::createDirectory(ofFilePath::getEnclosingDirectory(filePath,bRelativeToData), bRelativeToData, bRecursive);1841}
1842
1843//------------------------------------------------------------------------------------------------------------
1844// FIXME: - near future
1845//of::filesystem::path ofFilePath::getAbsolutePath(const of::filesystem::path& path, bool bRelativeToData){
1846std::string ofFilePath::getAbsolutePath(const of::filesystem::path& path, bool bRelativeToData){1847if(bRelativeToData){1848return ofToDataPath(path, true);1849}else{1850try{1851// return of::filesystem::canonical(of::filesystem::absolute(path));
1852return of::filesystem::canonical(of::filesystem::absolute(path)).string();1853}catch(...){1854// return of::filesystem::absolute(path);
1855return of::filesystem::absolute(path).string();1856}1857}1858}
1859
1860//------------------------------------------------------------------------------------------------------------
1861bool ofFilePath::isAbsolute(const of::filesystem::path& path){1862return of::filesystem::path(path).is_absolute();1863}
1864
1865//------------------------------------------------------------------------------------------------------------
1866string ofFilePath::getCurrentWorkingDirectory(){1867return of::filesystem::current_path().string();1868}
1869
1870//------------------------------------------------------------------------------------------------------------
1871// MARK: - near future
1872//of::filesystem::path ofFilePath::join(const of::filesystem::path& path1, const of::filesystem::path& path2){
1873// // FIXME: deprecate when possible. helper function more complex than actual solution
1874// return (path1 / path2);
1875//}
1876std::string ofFilePath::join(const of::filesystem::path& path1, const of::filesystem::path& path2){1877// FIXME: deprecate when possible. helper function more complex than actual solution1878return (path1 / path2).string();1879}
1880
1881//------------------------------------------------------------------------------------------------------------
1882string ofFilePath::getCurrentExePath(){1883#if defined(TARGET_LINUX) || defined(TARGET_ANDROID)1884char buff[FILENAME_MAX];1885ssize_t size = readlink("/proc/self/exe", buff, sizeof(buff) - 1);1886if (size == -1){1887ofLogError("ofFilePath") << "getCurrentExePath(): readlink failed with error " << errno;1888}1889else{1890buff[size] = '\0';1891return buff;1892}1893#elif defined(TARGET_OSX)1894char path[FILENAME_MAX];1895uint32_t size = sizeof(path);1896if(_NSGetExecutablePath(path, &size) != 0){1897ofLogError("ofFilePath") << "getCurrentExePath(): path buffer too small, need size " << size;1898}1899return path;1900#elif defined(TARGET_WIN32)1901vector<char> executablePath(MAX_PATH);1902DWORD result = ::GetModuleFileNameA(nullptr, &executablePath[0], static_cast<DWORD>(executablePath.size()));1903if(result == 0) {1904ofLogError("ofFilePath") << "getCurrentExePath(): couldn't get path, GetModuleFileNameA failed";1905}else{1906return string(executablePath.begin(), executablePath.begin() + result);1907}1908#endif1909return "";1910}
1911
1912//------------------------------------------------------------------------------------------------------------
1913// MARK: - near future
1914//of::filesystem::path ofFilePath::getCurrentExeDir(){
1915std::string ofFilePath::getCurrentExeDir(){1916return ofFilePath::getEnclosingDirectory(ofFilePath::getCurrentExePath(), false);1917}
1918
1919//------------------------------------------------------------------------------------------------------------
1920string ofFilePath::getUserHomeDir(){1921#ifdef TARGET_WIN321922// getenv will return any Environent Variable on Windows1923// USERPROFILE is the key on Windows 7 but it might be HOME1924// in other flavours of windows...need to check XP and NT...1925return ofGetEnv("USERPROFILE");1926#elif !defined(TARGET_EMSCRIPTEN)1927struct passwd * pw = getpwuid(getuid());1928return pw->pw_dir;1929#else1930return "";1931#endif1932}
1933
1934// MARK: - near future
1935//of::filesystem::path ofFilePath::makeRelative(const of::filesystem::path & from, const of::filesystem::path & to){
1936std::string ofFilePath::makeRelative(const of::filesystem::path & from, const of::filesystem::path & to){1937auto pathFrom = of::filesystem::absolute( from );1938auto pathTo = of::filesystem::absolute( to );1939of::filesystem::path ret;1940of::filesystem::path::const_iterator itrFrom( pathFrom.begin() ), itrTo( pathTo.begin() );1941// Find common base1942for( of::filesystem::path::const_iterator toEnd( pathTo.end() ), fromEnd( pathFrom.end() ) ; itrFrom != fromEnd && itrTo != toEnd && *itrFrom == *itrTo; ++itrFrom, ++itrTo );1943// Navigate backwards in directory to reach previously found base1944for( of::filesystem::path::const_iterator fromEnd( pathFrom.end() ); itrFrom != fromEnd; ++itrFrom ){1945if( (*itrFrom) != "." ){1946ret /= "..";1947}1948}1949// Now navigate down the directory branch1950for( ; itrTo != pathTo.end() ; ++itrTo ){1951if( itrTo->string() != "."){1952ret /= *itrTo;1953}1954}1955
1956// return ret;
1957return ret.string();1958}
1959
1960//--------------------------------------------------
1961void ofEnableDataPath(){1962enableDataPath = true;1963}
1964
1965//--------------------------------------------------
1966void ofDisableDataPath(){1967enableDataPath = false;1968}
1969
1970//--------------------------------------------------
1971bool ofRestoreWorkingDirectoryToDefault(){1972try{1973of::filesystem::current_path(defaultWorkingDirectory());1974return true;1975}catch(...){1976return false;1977}1978}
1979
1980//--------------------------------------------------
1981void ofSetDataPathRoot(const of::filesystem::path& newRoot){1982dataPathRoot() = newRoot;1983}
1984
1985//--------------------------------------------------
1986// MARK: - near future
1987//of::filesystem::path ofToDataPath(const of::filesystem::path & path, bool makeAbsolute){
1988std::string ofToDataPath(const of::filesystem::path & path, bool makeAbsolute){1989if (makeAbsolute && path.is_absolute()) {1990// return path;
1991return path.string();1992}1993
1994if (!enableDataPath) {1995// return path;
1996return path.string();1997}1998
1999bool hasTrailingSlash = !path.empty() && path.generic_string().back()=='/';2000
2001// if our Current Working Directory has changed (e.g. file open dialog)2002#ifdef TARGET_WIN322003if (defaultWorkingDirectory() != of::filesystem::current_path()) {2004// change our cwd back to where it was on app load2005bool ret = ofRestoreWorkingDirectoryToDefault();2006if(!ret){2007ofLogWarning("ofUtils") << "ofToDataPath: error while trying to change back to default working directory " << defaultWorkingDirectory();2008}2009}2010#endif2011
2012// this could be performed here, or wherever we might think we accidentally change the cwd, e.g. after file dialogs on windows2013const auto & dataPath = dataPathRoot();2014of::filesystem::path inputPath(path);2015of::filesystem::path outputPath;2016
2017// if path is already absolute, just return it2018if (inputPath.is_absolute()) {2019try {2020auto outpath = of::filesystem::canonical(inputPath).make_preferred();2021if(of::filesystem::is_directory(outpath) && hasTrailingSlash){2022return ofFilePath::addTrailingSlash(outpath);2023}else{2024return outpath.string();2025// return outpath;2026}2027}2028catch (...) {2029return inputPath.string();2030// return inputPath;2031}2032}2033
2034// here we check whether path already refers to the data folder by looking for common elements2035// if the path begins with the full contents of dataPathRoot then the data path has already been added2036// we compare inputPath.toString() rather that the input var path to ensure common formatting against dataPath.toString()2037auto dirDataPath = dataPath;2038// also, we strip the trailing slash from dataPath since `path` may be input as a file formatted path even if it is a folder (i.e. missing trailing slash)2039dirDataPath = ofFilePath::addTrailingSlash(dataPath);2040
2041auto relativeDirDataPath = ofFilePath::makeRelative(of::filesystem::current_path(), dataPath);2042relativeDirDataPath = ofFilePath::addTrailingSlash(relativeDirDataPath);2043
2044// FIXME: this can be simplified without using string conversion2045// if (inputPath.string().find(dirDataPath.string()) != 0 && inputPath.string().find(relativeDirDataPath.string())!=0) {2046if (inputPath.string().find(dirDataPath.string()) != 0 && inputPath.string().find(relativeDirDataPath)!=0) {2047// inputPath doesn't contain data path already, so we build the output path as the inputPath relative to the dataPath2048if(makeAbsolute){2049outputPath = dirDataPath / inputPath;2050}else{2051outputPath = relativeDirDataPath / inputPath;2052}2053} else {2054// inputPath already contains data path, so no need to change2055outputPath = inputPath;2056}2057
2058// finally, if we do want an absolute path and we don't already have one2059if(makeAbsolute){2060// then we return the absolute form of the path2061try {2062auto outpath = of::filesystem::canonical(of::filesystem::absolute(outputPath)).make_preferred();2063if(of::filesystem::is_directory(outpath) && hasTrailingSlash){2064return ofFilePath::addTrailingSlash(outpath);2065}else{2066// return outpath;
2067return outpath.string();2068}2069}2070catch (std::exception &) {2071return of::filesystem::absolute(outputPath).string();2072// return of::filesystem::absolute(outputPath);2073}2074}else{2075// or output the relative path2076// return outputPath;
2077return outputPath.string();2078}2079}
2080