framework2

Форк
0
2079 строк · 66.8 Кб
1
#include "ofFileUtils.h"
2
#include "ofLog.h"
3
#include "ofUtils.h"
4

5
#ifndef TARGET_WIN32
6
	#include <pwd.h>
7
	#include <sys/stat.h>
8
	#include <unistd.h>
9
#endif
10

11
#ifdef TARGET_OSX
12
	#include <mach-o/dyld.h>       /* _NSGetExecutablePath */
13
	#include <limits.h>        /* PATH_MAX */
14
#endif
15

16
// FIXME: better explicit declaration
17
using std::string;
18
using std::vector;
19
using std::fstream;
20
using std::istream;
21
using std::ostream;
22
using std::ios;
23

24
namespace{
25
	bool enableDataPath = true;
26

27
	//--------------------------------------------------
28
//	MARK: - near future
29
//	of::filesystem::path defaultDataPath(){
30
	std::string defaultDataPath(){
31
	#if defined TARGET_OSX
32
		try{
33
			return of::filesystem::canonical(ofFilePath::getCurrentExeDir() / of::filesystem::path("../../../data/")).string();
34
		}catch(...){
35
			return (ofFilePath::getCurrentExeDir() / of::filesystem::path("../../../data/")).string();
36
		}
37
	#elif defined TARGET_ANDROID
38
		return string("sdcard/");
39
	#else
40
		try{
41
            return of::filesystem::canonical(ofFilePath::join(ofFilePath::getCurrentExeDir(),  "data/")).make_preferred().string();
42
        }catch(...){
43
			return (ofFilePath::getCurrentExeDir() / of::filesystem::path("data/")).string();
44
		}
45
	#endif
46
	}
47

48
	//--------------------------------------------------
49
	of::filesystem::path & defaultWorkingDirectory(){
50
		static auto * defaultWorkingDirectory = new of::filesystem::path(ofFilePath::getCurrentExeDir());
51
		return * defaultWorkingDirectory;
52
	}
53

54
	//--------------------------------------------------
55
	of::filesystem::path & dataPathRoot(){
56
		static auto * dataPathRoot = new of::filesystem::path(defaultDataPath());
57
		return *dataPathRoot;
58
	}
59
}
60

61
namespace of{
62
	namespace priv{
63
		void initfileutils(){
64
			defaultWorkingDirectory() = of::filesystem::absolute(of::filesystem::current_path());
65
		}
66
	}
67
}
68

69

70
//------------------------------------------------------------------------------------------------------------
71
//------------------------------------------------------------------------------------------------------------
72
// -- ofBuffer
73
//------------------------------------------------------------------------------------------------------------
74
//------------------------------------------------------------------------------------------------------------
75

76
//--------------------------------------------------
77
ofBuffer::ofBuffer()
78
:currentLine(end(),end()){
79
}
80

81
//--------------------------------------------------
82
ofBuffer::ofBuffer(const char * buffer, std::size_t size)
83
:buffer(buffer,buffer+size)
84
,currentLine(end(),end()){
85
}
86

87
//--------------------------------------------------
88
ofBuffer::ofBuffer(istream & stream, std::size_t ioBlockSize)
89
:currentLine(end(),end()){
90
	set(stream, ioBlockSize);
91
}
92

93
//--------------------------------------------------
94
bool ofBuffer::set(istream & stream, std::size_t ioBlockSize){
95
	if(stream.bad()){
96
		clear();
97
		return false;
98
	}else{
99
		buffer.clear();
100
	}
101

102
	vector<char> aux_buffer(ioBlockSize);
103
	while(stream.good()){
104
		stream.read(&aux_buffer[0], ioBlockSize);
105
		append(aux_buffer.data(), stream.gcount());
106
	}
107
	return true;
108
}
109

110
//--------------------------------------------------
111
void ofBuffer::setall(char mem){
112
	buffer.assign(buffer.size(), mem);
113
}
114

115
//--------------------------------------------------
116
bool ofBuffer::writeTo(ostream & stream) const {
117
	if(stream.bad()){
118
		return false;
119
	}
120
	stream.write(buffer.data(), buffer.size());
121
	return stream.good();
122
}
123

124
//--------------------------------------------------
125
void ofBuffer::set(const char * buffer, std::size_t size){
126
	this->buffer.assign(buffer, buffer+size);
127
}
128

129
//--------------------------------------------------
130
void ofBuffer::set(const std::string & text){
131
	set(text.c_str(), text.size());
132
}
133

134
//--------------------------------------------------
135
void ofBuffer::append(const std::string& buffer){
136
	append(buffer.c_str(), buffer.size());
137
}
138

139
//--------------------------------------------------
140
void ofBuffer::append(const char * buffer, std::size_t size){
141
	this->buffer.insert(this->buffer.end(), buffer, buffer + size);
142
}
143

144
//--------------------------------------------------
145
void ofBuffer::reserve(std::size_t size){
146
	buffer.reserve(size);
147
}
148

149
//--------------------------------------------------
150
void ofBuffer::clear(){
151
	buffer.clear();
152
}
153

154
//--------------------------------------------------
155
void ofBuffer::allocate(std::size_t size){
156
	resize(size);
157
}
158

159
//--------------------------------------------------
160
void ofBuffer::resize(std::size_t size){
161
	buffer.resize(size);
162
}
163

164

165
//--------------------------------------------------
166
char * ofBuffer::getData(){
167
	return buffer.data();
168
}
169

170
//--------------------------------------------------
171
const char * ofBuffer::getData() const{
172
	return buffer.data();
173
}
174

175
//--------------------------------------------------
176
char * ofBuffer::getBinaryBuffer(){
177
	return getData();
178
}
179

180
//--------------------------------------------------
181
const char * ofBuffer::getBinaryBuffer() const {
182
	return getData();
183
}
184

185
//--------------------------------------------------
186
string ofBuffer::getText() const {
187
	if(buffer.empty()){
188
		return "";
189
	}
190
	return std::string(buffer.begin(), buffer.end());
191
}
192

193
//--------------------------------------------------
194
ofBuffer::operator std::string() const {
195
	return getText();
196
}
197

198
//--------------------------------------------------
199
ofBuffer & ofBuffer::operator=(const std::string & text){
200
	set(text);
201
	return *this;
202
}
203

204
//--------------------------------------------------
205
std::size_t ofBuffer::size() const {
206
	return buffer.size();
207
}
208

209
//--------------------------------------------------
210
string ofBuffer::getNextLine(){
211
	if(currentLine.empty()){
212
		currentLine = getLines().begin();
213
	}else{
214
		++currentLine;
215
	}
216
	return currentLine.asString();
217
}
218

219
//--------------------------------------------------
220
string ofBuffer::getFirstLine(){
221
	currentLine = getLines().begin();
222
	return currentLine.asString();
223
}
224

225
//--------------------------------------------------
226
bool ofBuffer::isLastLine(){
227
	return currentLine == getLines().end();
228
}
229

230
//--------------------------------------------------
231
void ofBuffer::resetLineReader(){
232
	currentLine = getLines().begin();
233
}
234

235
//--------------------------------------------------
236
vector<char>::iterator ofBuffer::begin(){
237
	return buffer.begin();
238
}
239

240
//--------------------------------------------------
241
vector<char>::iterator ofBuffer::end(){
242
	return buffer.end();
243
}
244

245
//--------------------------------------------------
246
vector<char>::const_iterator ofBuffer::begin() const{
247
	return buffer.begin();
248
}
249

250
//--------------------------------------------------
251
vector<char>::const_iterator ofBuffer::end() const{
252
	return buffer.end();
253
}
254

255
//--------------------------------------------------
256
vector<char>::reverse_iterator ofBuffer::rbegin(){
257
	return buffer.rbegin();
258
}
259

260
//--------------------------------------------------
261
vector<char>::reverse_iterator ofBuffer::rend(){
262
	return buffer.rend();
263
}
264

265
//--------------------------------------------------
266
vector<char>::const_reverse_iterator ofBuffer::rbegin() const{
267
	return buffer.rbegin();
268
}
269

270
//--------------------------------------------------
271
vector<char>::const_reverse_iterator ofBuffer::rend() const{
272
	return buffer.rend();
273
}
274

275
//--------------------------------------------------
276
ofBuffer::Line::Line(vector<char>::iterator _begin, vector<char>::iterator _end)
277
	:_current(_begin)
278
	,_begin(_begin)
279
	,_end(_end){
280

281
	if(_begin == _end){
282
		line =  "";
283
		return;
284
	}
285

286
	_current = std::find(_begin, _end, '\n');
287
	if(_current - 1 >= _begin && *(_current - 1) == '\r'){
288
		line = string(_begin, _current - 1);
289
	}else{
290
		line = string(_begin, _current);
291
	}
292
	if(_current != _end){
293
		_current+=1;
294
	}
295
}
296

297
//--------------------------------------------------
298
const std::string & ofBuffer::Line::operator*() const{
299
	return line;
300
}
301

302
//--------------------------------------------------
303
const std::string * ofBuffer::Line::operator->() const{
304
	return &line;
305
}
306

307
//--------------------------------------------------
308
const std::string & ofBuffer::Line::asString() const{
309
	return line;
310
}
311

312
//--------------------------------------------------
313
ofBuffer::Line & ofBuffer::Line::operator++(){
314
	*this = Line(_current,_end);
315
	return *this;
316
}
317

318
//--------------------------------------------------
319
ofBuffer::Line ofBuffer::Line::operator++(int) {
320
	Line tmp(*this);
321
	operator++();
322
	return tmp;
323
}
324

325
//--------------------------------------------------
326
bool ofBuffer::Line::operator!=(Line const& rhs) const{
327
	return rhs._begin != _begin || rhs._end != _end;
328
}
329

330
//--------------------------------------------------
331
bool ofBuffer::Line::operator==(Line const& rhs) const{
332
	return rhs._begin == _begin && rhs._end == _end;
333
}
334

335
bool ofBuffer::Line::empty() const{
336
	return _begin == _end;
337
}
338

339

340

341
//--------------------------------------------------
342
ofBuffer::RLine::RLine(vector<char>::reverse_iterator _rbegin, vector<char>::reverse_iterator _rend)
343
	:_current(_rbegin)
344
	,_rbegin(_rbegin)
345
	,_rend(_rend){
346

347
	if(_rbegin == _rend){
348
		line =  "";
349
		return;
350
	}
351
	_current = std::find(_rbegin+1, _rend, '\n');
352
	line = string(_current.base(), _rbegin.base() - 1);
353
	if(_current < _rend-1 && *(_current + 1) == '\r'){
354
		_current+=1;
355
	}
356
}
357

358
//--------------------------------------------------
359
const std::string & ofBuffer::RLine::operator*() const{
360
	return line;
361
}
362

363
//--------------------------------------------------
364
const std::string * ofBuffer::RLine::operator->() const{
365
	return &line;
366
}
367

368
//--------------------------------------------------
369
const std::string & ofBuffer::RLine::asString() const{
370
	return line;
371
}
372

373
//--------------------------------------------------
374
ofBuffer::RLine & ofBuffer::RLine::operator++(){
375
	*this = RLine(_current,_rend);
376
	return *this;
377
}
378

379
//--------------------------------------------------
380
ofBuffer::RLine ofBuffer::RLine::operator++(int) {
381
	RLine tmp(*this);
382
	operator++();
383
	return tmp;
384
}
385

386
//--------------------------------------------------
387
bool ofBuffer::RLine::operator!=(RLine const& rhs) const{
388
	return rhs._rbegin != _rbegin || rhs._rend != _rend;
389
}
390

391
//--------------------------------------------------
392
bool ofBuffer::RLine::operator==(RLine const& rhs) const{
393
	return rhs._rbegin == _rbegin && rhs._rend == _rend;
394
}
395

396
bool ofBuffer::RLine::empty() const{
397
	return _rbegin == _rend;
398
}
399

400
//--------------------------------------------------
401
ofBuffer::Lines::Lines(vector<char>::iterator begin, vector<char>::iterator end)
402
:_begin(begin)
403
,_end(end){}
404

405
//--------------------------------------------------
406
ofBuffer::Line ofBuffer::Lines::begin(){
407
	return Line(_begin,_end);
408
}
409

410
//--------------------------------------------------
411
ofBuffer::Line ofBuffer::Lines::end(){
412
	return Line(_end,_end);
413
}
414

415

416
//--------------------------------------------------
417
ofBuffer::RLines::RLines(vector<char>::reverse_iterator rbegin, vector<char>::reverse_iterator rend)
418
:_rbegin(rbegin)
419
,_rend(rend){}
420

421
//--------------------------------------------------
422
ofBuffer::RLine ofBuffer::RLines::begin(){
423
	return RLine(_rbegin,_rend);
424
}
425

426
//--------------------------------------------------
427
ofBuffer::RLine ofBuffer::RLines::end(){
428
	return RLine(_rend,_rend);
429
}
430

431
//--------------------------------------------------
432
ofBuffer::Lines ofBuffer::getLines(){
433
	return ofBuffer::Lines(begin(), end());
434
}
435

436
//--------------------------------------------------
437
ofBuffer::RLines ofBuffer::getReverseLines(){
438
	return ofBuffer::RLines(rbegin(), rend());
439
}
440

441
//--------------------------------------------------
442
ostream & operator<<(ostream & ostr, const ofBuffer & buf){
443
	buf.writeTo(ostr);
444
	return ostr;
445
}
446

447
//--------------------------------------------------
448
istream & operator>>(istream & istr, ofBuffer & buf){
449
	buf.set(istr);
450
	return istr;
451
}
452

453
//--------------------------------------------------
454
ofBuffer ofBufferFromFile(const of::filesystem::path & path, bool binary){
455
	ofFile f(path,ofFile::ReadOnly, binary);
456
	return ofBuffer(f);
457
}
458

459
//--------------------------------------------------
460
bool ofBufferToFile(const of::filesystem::path & path, const ofBuffer& buffer, bool binary){
461
	ofFile f(path, ofFile::WriteOnly, binary);
462
	return buffer.writeTo(f);
463
}
464

465
//------------------------------------------------------------------------------------------------------------
466
//------------------------------------------------------------------------------------------------------------
467
// -- ofFile
468
//------------------------------------------------------------------------------------------------------------
469
//------------------------------------------------------------------------------------------------------------
470

471
//------------------------------------------------------------------------------------------------------------
472
ofFile::ofFile()
473
:mode(Reference)
474
,binary(true){
475
}
476

477
ofFile::ofFile(const of::filesystem::path & path, Mode mode, bool binary)
478
:mode(mode)
479
,binary(true){
480
	open(path, mode, binary);
481
}
482

483
//-------------------------------------------------------------------------------------------------------------
484
ofFile::~ofFile(){
485
	//close();
486
}
487

488
//-------------------------------------------------------------------------------------------------------------
489
ofFile::ofFile(const ofFile & mom)
490
:basic_ios()
491
,fstream()
492
,mode(Reference)
493
,binary(true){
494
	copyFrom(mom);
495
}
496

497
//-------------------------------------------------------------------------------------------------------------
498
ofFile & ofFile::operator=(const ofFile & mom){
499
	copyFrom(mom);
500
	return *this;
501
}
502

503
//-------------------------------------------------------------------------------------------------------------
504
void ofFile::copyFrom(const ofFile & mom){
505
	if(&mom != this){
506
		Mode new_mode = mom.mode;
507
		if(new_mode != Reference && new_mode != ReadOnly){
508
			new_mode = ReadOnly;
509
			ofLogWarning("ofFile") << "copyFrom(): copying a writable file, opening new copy as read only";
510
		}
511
		open(mom.myFile.string(), new_mode, mom.binary);
512
	}
513
}
514

515
//------------------------------------------------------------------------------------------------------------
516
bool ofFile::openStream(Mode _mode, bool _binary){
517
	mode = _mode;
518
	binary = _binary;
519
	ios_base::openmode binary_mode = binary ? ios::binary : (ios_base::openmode)0;
520
	switch(_mode) {
521
		case WriteOnly:
522
		case ReadWrite:
523
		case Append:
524
			if(!ofDirectory(ofFilePath::getEnclosingDirectory(path())).exists()){
525
				ofFilePath::createEnclosingDirectory(path());
526
			}
527
			break;
528
		case Reference:
529
		case ReadOnly:
530
			break;
531
	}
532
	switch(_mode){
533
		case Reference:
534
			return true;
535
			break;
536

537
		case ReadOnly:
538
			if(exists() && isFile()){
539
				fstream::open(path().c_str(), ios::in | binary_mode);
540
			}
541
			break;
542

543
		case WriteOnly:
544
			fstream::open(path().c_str(), ios::out | binary_mode);
545
			break;
546

547
		case ReadWrite:
548
			fstream::open(path().c_str(), ios_base::in | ios_base::out | binary_mode);
549
			break;
550

551
		case Append:
552
			fstream::open(path().c_str(), ios::out | ios::app | binary_mode);
553
			break;
554
	}
555
	return fstream::good();
556
}
557

558
//------------------------------------------------------------------------------------------------------------
559
bool ofFile::open(const of::filesystem::path & _path, Mode _mode, bool binary){
560
	close();
561
	myFile = ofToDataPath(_path);
562
	return openStream(_mode, binary);
563
}
564

565
//------------------------------------------------------------------------------------------------------------
566
bool ofFile::openFromCWD(const of::filesystem::path & _path, Mode _mode, bool binary){
567
	close();
568
	myFile = _path;
569
	return openStream(_mode, binary);
570
}
571

572
//-------------------------------------------------------------------------------------------------------------
573
bool ofFile::changeMode(Mode _mode, bool binary){
574
	if(_mode != mode){
575
		auto _path = path();
576
		close();
577
		myFile = _path;
578
		return openStream(_mode, binary);
579
	}
580
	else{
581
		return true;
582
	}
583
}
584

585
//-------------------------------------------------------------------------------------------------------------
586
bool ofFile::isWriteMode(){
587
	return mode != ReadOnly;
588
}
589

590
//-------------------------------------------------------------------------------------------------------------
591
void ofFile::close(){
592
	myFile = of::filesystem::path();
593
	if(mode!=Reference) fstream::close();
594
}
595

596
//------------------------------------------------------------------------------------------------------------
597
bool ofFile::create(){
598
	return create(path());
599
}
600

601
//------------------------------------------------------------------------------------------------------------
602
bool ofFile::create(const of::filesystem::path & path){
603
	bool success = false;
604

605
	auto oldmode = this->mode;
606
	auto oldpath = this->path();
607
	success = open(path,ofFile::WriteOnly,binary);
608
	close();
609

610
	if( !oldpath.empty() ){
611
		open(oldpath,oldmode,binary);
612
	}
613

614
	return success;
615
}
616

617
//------------------------------------------------------------------------------------------------------------
618
ofBuffer ofFile::readToBuffer(){
619
	if(myFile.string().empty() || !of::filesystem::exists(myFile)){
620
		return ofBuffer();
621
	}
622

623
	return ofBuffer(*this);
624
}
625

626
//------------------------------------------------------------------------------------------------------------
627
bool ofFile::writeFromBuffer(const ofBuffer & buffer){
628
	if(myFile.string().empty()){
629
		return false;
630
	}
631
	if(!isWriteMode()){
632
		ofLogError("ofFile") << "writeFromBuffer(): trying to write to read only file \"" << myFile.string() << "\"";
633
	}
634
	return buffer.writeTo(*this);
635
}
636

637
//------------------------------------------------------------------------------------------------------------
638
std::filebuf *ofFile::getFileBuffer() const {
639
	return rdbuf();
640
}
641

642
//------------------------------------------------------------------------------------------------------------
643
bool ofFile::exists() const {
644
	if(path().empty()){
645
		return false;
646
	}
647
	return of::filesystem::exists(myFile);
648
}
649

650
//------------------------------------------------------------------------------------------------------------
651
//	MARK: - near future
652
//of::filesystem::path ofFile::path() const {
653
//return myFile;
654
std::string ofFile::path() const {
655
	return myFile.string();
656
}
657

658
//------------------------------------------------------------------------------------------------------------
659
string ofFile::getExtension() const {
660
	auto dotext = myFile.extension().string();
661
	// FIXME: probably not needed;
662
	if(!dotext.empty() && dotext.front()=='.'){
663
		return std::string(dotext.begin()+1,dotext.end());
664
	}else{
665
		return dotext;
666
	}
667
}
668

669
//------------------------------------------------------------------------------------------------------------
670
string ofFile::getFileName() const {
671
	return myFile.filename().string();
672
}
673

674
//------------------------------------------------------------------------------------------------------------
675
string ofFile::getBaseName() const {
676
	return myFile.stem().string();
677
}
678

679
//------------------------------------------------------------------------------------------------------------
680
//	MARK: - near future
681
//of::filesystem::path ofFile::getEnclosingDirectory() const {
682
std::string ofFile::getEnclosingDirectory() const {
683
	return ofFilePath::getEnclosingDirectory(path());
684
}
685

686
//------------------------------------------------------------------------------------------------------------
687
//	MARK: - near future
688
//of::filesystem::path ofFile::getAbsolutePath() const {
689
std::string ofFile::getAbsolutePath() const {
690
	return ofFilePath::getAbsolutePath(path());
691
}
692

693
//------------------------------------------------------------------------------------------------------------
694
bool ofFile::canRead() const {
695
	
696
#ifdef TARGET_WIN32
697
	DWORD attr = GetFileAttributes(myFile.native().c_str());
698
	if (attr == INVALID_FILE_ATTRIBUTES)
699
	{
700
		return false;
701
	}
702
	return true;
703
#else
704
	struct stat info;
705
	stat(path().c_str(), &info);  // Error check omitted
706
	auto perm = of::filesystem::status(myFile).permissions();
707
#if OF_USING_STD_FS
708
	if(geteuid() == info.st_uid){
709
		return (perm & of::filesystem::perms::owner_read) != of::filesystem::perms::none;
710
	}else if (getegid() == info.st_gid){
711
		return (perm & of::filesystem::perms::group_read) != of::filesystem::perms::none;
712
	}else{
713
		return (perm & of::filesystem::perms::others_read) != of::filesystem::perms::none;
714
	}
715
#else
716
	if(geteuid() == info.st_uid){
717
		return perm & of::filesystem::perms::owner_read;
718
	}else if (getegid() == info.st_gid){
719
		return perm & of::filesystem::perms::group_read;
720
	}else{
721
		return perm & of::filesystem::perms::others_read;
722
	}
723
#endif
724
#endif
725
}
726

727
//------------------------------------------------------------------------------------------------------------
728
bool ofFile::canWrite() const {
729
#ifdef TARGET_WIN32
730
	DWORD attr = GetFileAttributes(myFile.native().c_str());
731
	if (attr == INVALID_FILE_ATTRIBUTES){
732
		return false;
733
	}else{
734
		return (attr & FILE_ATTRIBUTE_READONLY) == 0;
735
	}
736
#else
737
	struct stat info;
738
	stat(path().c_str(), &info);  // Error check omitted
739
	auto perm = of::filesystem::status(myFile).permissions();
740
#if OF_USING_STD_FS
741
	if(geteuid() == info.st_uid){
742
		return (perm & of::filesystem::perms::owner_write) != of::filesystem::perms::none;
743
	}else if (getegid() == info.st_gid){
744
		return (perm & of::filesystem::perms::group_write) != of::filesystem::perms::none;
745
	}else{
746
		return (perm & of::filesystem::perms::others_write) != of::filesystem::perms::none;
747
	}
748
#else
749
	if(geteuid() == info.st_uid){
750
		return perm & of::filesystem::owner_write;
751
	}else if (getegid() == info.st_gid){
752
		return perm & of::filesystem::group_write;
753
	}else{
754
		return perm & of::filesystem::others_write;
755
	}
756
#endif
757
#endif
758
}
759

760
//------------------------------------------------------------------------------------------------------------
761
bool ofFile::canExecute() const {
762
#ifdef TARGET_WIN32
763
	return getExtension() == "exe";
764
#else
765
	struct stat info;
766
	stat(path().c_str(), &info);  // Error check omitted
767
	auto perm = of::filesystem::status(myFile).permissions();
768
#if OF_USING_STD_FS
769
	if(geteuid() == info.st_uid){
770
		return (perm & of::filesystem::perms::owner_exec) != of::filesystem::perms::none;
771
	}else if (getegid() == info.st_gid){
772
		return (perm & of::filesystem::perms::group_exec) != of::filesystem::perms::none;
773
	}else{
774
		return (perm & of::filesystem::perms::others_exec) != of::filesystem::perms::none;
775
	}
776
#else
777
	if(geteuid() == info.st_uid){
778
		return perm & of::filesystem::owner_exe;
779
	}else if (getegid() == info.st_gid){
780
		return perm & of::filesystem::group_exe;
781
	}else{
782
		return perm & of::filesystem::others_exe;
783
	}
784
#endif
785
#endif
786
}
787
//------------------------------------------------------------------------------------------------------------
788
bool ofFile::isFile() const {
789
	return of::filesystem::is_regular_file(myFile);
790
}
791

792
//------------------------------------------------------------------------------------------------------------
793
bool ofFile::isLink() const {
794
	return of::filesystem::is_symlink(myFile);
795
}
796

797
//------------------------------------------------------------------------------------------------------------
798
bool ofFile::isDirectory() const {
799
	return of::filesystem::is_directory(myFile);
800
}
801

802
//------------------------------------------------------------------------------------------------------------
803
bool ofFile::isDevice() const {
804
#ifdef TARGET_WIN32
805
	return false;
806
#else
807
#if OF_USING_STD_FS
808
	return of::filesystem::is_block_file(of::filesystem::status(myFile));
809
#else
810
	return of::filesystem::status(myFile).type() == of::filesystem::block_file;
811
#endif
812
#endif
813
}
814

815
//------------------------------------------------------------------------------------------------------------
816
bool ofFile::isHidden() const {
817
#ifdef TARGET_WIN32
818
	return false;
819
#else
820
	return myFile.filename() != "." && myFile.filename() != ".." && myFile.filename().string()[0] == '.';
821
#endif
822
}
823

824
//------------------------------------------------------------------------------------------------------------
825
void ofFile::setWriteable(bool flag){
826
	try{
827
#if !OF_USING_STD_FS || (OF_USING_STD_FS && OF_USE_EXPERIMENTAL_FS)
828
		if(flag){
829
			of::filesystem::permissions(myFile,of::filesystem::perms::owner_write | of::filesystem::perms::add_perms);
830
		}else{
831
			of::filesystem::permissions(myFile,of::filesystem::perms::owner_write | of::filesystem::perms::remove_perms);
832
		}
833
#else
834
		if(flag){
835
			of::filesystem::permissions(myFile,
836
										 of::filesystem::perms::owner_write,
837
										 of::filesystem::perm_options::add);
838
		}else{
839
			of::filesystem::permissions(myFile,
840
										 of::filesystem::perms::owner_write,
841
										 of::filesystem::perm_options::remove);
842
		}
843
#endif
844
	}catch(std::exception & e){
845
		ofLogError() << "Couldn't set write permission on " << myFile << ": " << e.what();
846
	}
847
}
848

849
//------------------------------------------------------------------------------------------------------------
850
// deprecated
851
void ofFile::setReadOnly(bool flag){
852
	setWriteable(!flag);
853
}
854

855
//------------------------------------------------------------------------------------------------------------
856
void ofFile::setReadable(bool flag){
857
	try{
858
#if !OF_USING_STD_FS || (OF_USING_STD_FS && OF_USE_EXPERIMENTAL_FS)
859
		if(flag){
860
			of::filesystem::permissions(myFile,of::filesystem::perms::owner_read | of::filesystem::perms::add_perms);
861
		}else{
862
			of::filesystem::permissions(myFile,of::filesystem::perms::owner_read | of::filesystem::perms::remove_perms);
863
		}
864
#else
865
		if(flag){
866
			of::filesystem::permissions(myFile,
867
										 of::filesystem::perms::owner_read,
868
										 of::filesystem::perm_options::add);
869
		}else{
870
			of::filesystem::permissions(myFile,
871
										 of::filesystem::perms::owner_read,
872
										 of::filesystem::perm_options::remove);
873
		}
874
#endif
875
	}catch(std::exception & e){
876
		ofLogError() << "Couldn't set read permission on " << myFile << ": " << e.what();
877
	}
878
}
879

880
//------------------------------------------------------------------------------------------------------------
881
void ofFile::setExecutable(bool flag){
882
	try{
883
#if OF_USING_STD_FS
884
#   if OF_USE_EXPERIMENTAL_FS
885
		if(flag){
886
			of::filesystem::permissions(myFile, of::filesystem::perms::owner_exec | of::filesystem::perms::add_perms);
887
		} else{
888
			of::filesystem::permissions(myFile, of::filesystem::perms::owner_exec | of::filesystem::perms::remove_perms);
889
		}
890
#   else
891
		if(flag){
892
			of::filesystem::permissions(myFile,
893
										 of::filesystem::perms::owner_exec,
894
										 of::filesystem::perm_options::add);
895
		} else{
896
			of::filesystem::permissions(myFile,
897
										 of::filesystem::perms::owner_exec,
898
										 of::filesystem::perm_options::remove);
899
		}
900
#   endif
901
#else
902
		if(flag){
903
			of::filesystem::permissions(myFile, of::filesystem::perms::owner_exe | of::filesystem::perms::add_perms);
904
		} else{
905
			of::filesystem::permissions(myFile, of::filesystem::perms::owner_exe | of::filesystem::perms::remove_perms);
906
		}
907
#endif
908
	}catch(std::exception & e){
909
		ofLogError() << "Couldn't set executable permission on " << myFile << ": " << e.what();
910
	}
911
}
912

913
//------------------------------------------------------------------------------------------------------------
914
bool ofFile::copyTo(const of::filesystem::path& _path, bool bRelativeToData, bool overwrite) const{
915
	auto path = _path;
916

917
	if(path.empty()){
918
		ofLogError("ofFile") << "copyTo(): destination path " << _path << " is empty";
919
		return false;
920
	}
921
	if(isDirectory()){
922
		ofDirectory tmp;
923
		//don't want to add ofToDataPath to myFile path as it was already done in ofFile::open
924
		tmp.openFromCWD(myFile);
925
		return tmp.copyTo(path,bRelativeToData,overwrite);
926
	}
927
	if(!exists()){
928
		ofLogError("ofFile") << "copyTo(): source file " << this->path() << " does not exist";
929
		return false;
930
	}
931

932
	//bRelativeToData is handled here for the destination path - so we pass false to static functions below
933
	if(bRelativeToData){
934
		path = ofToDataPath(path);
935
	}
936

937
	if(ofFile::doesFileExist(path, false)){
938
		if(isFile()){
939
			ofFile tmp;
940
			tmp.openFromCWD(path,ofFile::Reference);
941
			if(tmp.isDirectory()){
942
				path = path / getFileName();
943
			}
944
		}
945
		if(ofFile::doesFileExist(path, false)){
946
			if(overwrite){
947
				ofFile::removeFile(path, false);
948
			}else{
949
				ofLogWarning("ofFile") << "copyTo(): destination file \"" << path << "\" already exists, set bool overwrite to true if you want to overwrite it";
950
			}
951
		}
952
	}
953

954
	try{
955
		ofDirectory destDir;
956
		auto p = ofFilePath::getEnclosingDirectory(path,false);
957
		destDir.openFromCWD(p);
958
		if(!destDir.exists()){
959
			ofFilePath::createEnclosingDirectory(path, false);
960
		}
961
		of::filesystem::copy_file(myFile,path);
962
	}catch(std::exception & except){
963
		ofLogError("ofFile") <<  "copyTo(): unable to copy \"" << path << "\": " << except.what();
964
		return false;
965
	}
966

967
	return true;
968
}
969

970
//------------------------------------------------------------------------------------------------------------
971
bool ofFile::moveTo(const of::filesystem::path& _path, bool bRelativeToData, bool overwrite){
972
	auto path = _path;
973

974
	if(path.empty()){
975
		ofLogError("ofFile") << "moveTo(): destination path is empty";
976
		return false;
977
	}
978
	if(!exists()){
979
		ofLogError("ofFile") << "moveTo(): source file does not exist";
980
		return false;
981
	}
982

983
	if(bRelativeToData){
984
		path = ofToDataPath(path);
985
	}
986
	if(ofFile::doesFileExist(path, false)){
987

988
		if(isFile()){
989
			ofFile tmp;
990
			tmp.openFromCWD(path,ofFile::Reference);
991
			if(tmp.isDirectory()){
992
				path = path / getFileName();
993
			}
994
		}
995
		if(ofFile::doesFileExist(path, false)){
996
			if(overwrite){
997
				ofFile::removeFile(path, false);
998
			}else{
999
				ofLogWarning("ofFile") << "copyTo(): destination file \"" << path << "\" already exists, set bool overwrite to true if you want to overwrite it";
1000
			}
1001
		}
1002
	}
1003

1004
	try{
1005
		auto mode = this->mode;
1006
		if(mode != ofFile::Reference){
1007
			changeMode(ofFile::Reference, binary);
1008
		}
1009
		ofDirectory destDir;
1010
		destDir.openFromCWD(ofFilePath::getEnclosingDirectory(path,false));
1011
		if(!destDir.exists()){
1012
			ofFilePath::createEnclosingDirectory(path,false);
1013
		}
1014
		of::filesystem::rename(myFile,path);
1015
		myFile = path;
1016
		if(mode != ofFile::Reference){
1017
			changeMode(mode, binary);
1018
		}
1019
	}
1020
	catch(std::exception & except){
1021
		ofLogError("ofFile") << "moveTo(): unable to move \"" << path << "\": " << except.what();
1022
		return false;
1023
	}
1024

1025
	return true;
1026
}
1027

1028
//------------------------------------------------------------------------------------------------------------
1029
bool ofFile::renameTo(const of::filesystem::path& path, bool bRelativeToData, bool overwrite){
1030
	return moveTo(path,bRelativeToData,overwrite);
1031
}
1032

1033
//------------------------------------------------------------------------------------------------------------
1034
bool ofFile::remove(bool recursive){
1035
	if(myFile.string().empty()){
1036
		ofLogError("ofFile") << "remove(): file path is empty";
1037
		return false;
1038
	}
1039
	if(!exists()){
1040
		ofLogError("ofFile") << "remove(): file does not exist";
1041
		return false;
1042
	}
1043

1044
	try{
1045
		if(mode!=Reference){
1046
			open(path(),Reference,binary);
1047
		}
1048
		if(recursive){
1049
			of::filesystem::remove_all(myFile);
1050
		}else{
1051
			of::filesystem::remove(myFile);
1052
		}
1053
	}catch(std::exception & except){
1054
		ofLogError("ofFile") << "remove(): unable to remove \"" << myFile << "\": " << except.what();
1055
		return false;
1056
	}
1057

1058
	return true;
1059
}
1060

1061
//------------------------------------------------------------------------------------------------------------
1062
uint64_t ofFile::getSize() const {
1063
	try{
1064
		return of::filesystem::file_size(myFile);
1065
	}catch(std::exception & except){
1066
		ofLogError("ofFile") << "getSize(): unable to get size of \"" << myFile << "\": " << except.what();
1067
		return 0;
1068
	}
1069
}
1070

1071
//------------------------------------------------------------------------------------------------------------
1072
bool ofFile::operator==(const ofFile & file) const {
1073
	return getAbsolutePath() == file.getAbsolutePath();
1074
}
1075

1076
//------------------------------------------------------------------------------------------------------------
1077
bool ofFile::operator!=(const ofFile & file) const {
1078
	return getAbsolutePath() != file.getAbsolutePath();
1079
}
1080

1081
//------------------------------------------------------------------------------------------------------------
1082
bool ofFile::operator<(const ofFile & file) const {
1083
	return getAbsolutePath() < file.getAbsolutePath();
1084
}
1085

1086
//------------------------------------------------------------------------------------------------------------
1087
bool ofFile::operator<=(const ofFile & file) const {
1088
	return getAbsolutePath() <= file.getAbsolutePath();
1089
}
1090

1091
//------------------------------------------------------------------------------------------------------------
1092
bool ofFile::operator>(const ofFile & file) const {
1093
	return getAbsolutePath() > file.getAbsolutePath();
1094
}
1095

1096
//------------------------------------------------------------------------------------------------------------
1097
bool ofFile::operator>=(const ofFile & file) const {
1098
	return getAbsolutePath() >= file.getAbsolutePath();
1099
}
1100

1101
//------------------------------------------------------------------------------------------------------------
1102
// ofFile Static Methods
1103
//------------------------------------------------------------------------------------------------------------
1104

1105
bool ofFile::copyFromTo(const of::filesystem::path& pathSrc, const of::filesystem::path& pathDst, bool bRelativeToData,  bool overwrite){
1106
	ofFile tmp;
1107
	if( bRelativeToData ){
1108
		tmp.open(pathSrc,ofFile::Reference);
1109
	}else{
1110
		tmp.openFromCWD(pathSrc,ofFile::Reference);
1111
	}
1112
	return 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
//------------------------------------------------------------------------------------------------------------
1117
bool ofFile::moveFromTo(const of::filesystem::path& pathSrc, const of::filesystem::path& pathDst, bool bRelativeToData, bool overwrite){
1118
	ofFile tmp;
1119
	if( bRelativeToData ){
1120
		tmp.open(pathSrc,ofFile::Reference);
1121
	}else{
1122
		tmp.openFromCWD(pathSrc,ofFile::Reference);
1123
	}
1124
	return tmp.moveTo(pathDst, bRelativeToData, overwrite);
1125
}
1126

1127
//------------------------------------------------------------------------------------------------------------
1128
bool ofFile::doesFileExist(const of::filesystem::path& _fPath, bool bRelativeToData){
1129
	ofFile tmp;
1130
	if(bRelativeToData){
1131
		tmp.open(_fPath,ofFile::Reference);
1132
	}else{
1133
		tmp.openFromCWD(_fPath,ofFile::Reference);
1134
	}
1135
	return !_fPath.empty() && tmp.exists();
1136
}
1137

1138
//------------------------------------------------------------------------------------------------------------
1139
bool ofFile::removeFile(const of::filesystem::path& _path, bool bRelativeToData){
1140
	ofFile tmp;
1141
	if(bRelativeToData){
1142
		tmp.open(_path,ofFile::Reference);
1143
	}else{
1144
		tmp.openFromCWD(_path,ofFile::Reference);
1145
	}
1146
	return tmp.remove();
1147
}
1148

1149

1150
//------------------------------------------------------------------------------------------------------------
1151
//------------------------------------------------------------------------------------------------------------
1152
// -- ofDirectory
1153
//------------------------------------------------------------------------------------------------------------
1154
//------------------------------------------------------------------------------------------------------------
1155

1156
//------------------------------------------------------------------------------------------------------------
1157
ofDirectory::ofDirectory(){
1158
	showHidden = false;
1159
}
1160

1161
//------------------------------------------------------------------------------------------------------------
1162
ofDirectory::ofDirectory(const of::filesystem::path & path){
1163
	showHidden = false;
1164
	open(path);
1165
}
1166

1167
//------------------------------------------------------------------------------------------------------------
1168
void ofDirectory::open(const of::filesystem::path & path){
1169
	originalDirectory = ofFilePath::getPathForDirectory(path.string());
1170
	files.clear();
1171
	myDir = of::filesystem::path(ofToDataPath(originalDirectory));
1172
}
1173

1174
//------------------------------------------------------------------------------------------------------------
1175
void ofDirectory::openFromCWD(const of::filesystem::path & path){
1176
	originalDirectory = ofFilePath::getPathForDirectory(path.string());
1177
	files.clear();
1178
	myDir = of::filesystem::path(originalDirectory);
1179
}
1180

1181
//------------------------------------------------------------------------------------------------------------
1182
void ofDirectory::close(){
1183
	myDir = of::filesystem::path();
1184
}
1185

1186
//------------------------------------------------------------------------------------------------------------
1187
bool ofDirectory::create(bool recursive){
1188

1189
	if(!myDir.string().empty()){
1190
		try{
1191
			if(recursive){
1192
				of::filesystem::create_directories(myDir);
1193
			}else{
1194
				of::filesystem::create_directory(myDir);
1195
			}
1196
		}
1197
		catch(std::exception & except){
1198
			ofLogError("ofDirectory") << "create(): " << except.what();
1199
			return false;
1200
		}
1201
	}
1202

1203
	return true;
1204
}
1205

1206
//------------------------------------------------------------------------------------------------------------
1207
bool ofDirectory::exists() const {
1208
	return (myDir == "" || of::filesystem::exists(myDir));
1209
}
1210

1211
//------------------------------------------------------------------------------------------------------------
1212
//	MARK: - near future
1213
//of::filesystem::path ofDirectory::path() const {
1214
//	return myDir;
1215
std::string ofDirectory::path() const {
1216
	return 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
//}
1228
std::string ofDirectory::getAbsolutePath() const {
1229
	try{
1230
		return of::filesystem::canonical(of::filesystem::absolute(myDir)).string();
1231
	}catch(...){
1232
		return of::filesystem::absolute(myDir).string();
1233
	}
1234
}
1235

1236
//------------------------------------------------------------------------------------------------------------
1237
bool ofDirectory::canRead() const {
1238
	return ofFile(myDir,ofFile::Reference).canRead();
1239
}
1240

1241
//------------------------------------------------------------------------------------------------------------
1242
bool ofDirectory::canWrite() const {
1243
	return ofFile(myDir,ofFile::Reference).canWrite();
1244
}
1245

1246
//------------------------------------------------------------------------------------------------------------
1247
bool ofDirectory::canExecute() const {
1248
	return ofFile(myDir,ofFile::Reference).canExecute();
1249
}
1250

1251
//------------------------------------------------------------------------------------------------------------
1252
bool ofDirectory::isHidden() const {
1253
	return ofFile(myDir,ofFile::Reference).isHidden();
1254
}
1255

1256
//------------------------------------------------------------------------------------------------------------
1257
void ofDirectory::setWriteable(bool flag){
1258
	return ofFile(myDir,ofFile::Reference).setWriteable(flag);
1259
}
1260

1261
//------------------------------------------------------------------------------------------------------------
1262
// deprecated
1263
void ofDirectory::setReadOnly(bool flag){
1264
	setWriteable(!flag);
1265
}
1266

1267
//------------------------------------------------------------------------------------------------------------
1268
void ofDirectory::setReadable(bool flag){
1269
	return ofFile(myDir,ofFile::Reference).setReadable(flag);
1270
}
1271

1272
//------------------------------------------------------------------------------------------------------------
1273
void ofDirectory::setExecutable(bool flag){
1274
	return ofFile(myDir,ofFile::Reference).setExecutable(flag);
1275
}
1276

1277
//------------------------------------------------------------------------------------------------------------
1278
void ofDirectory::setShowHidden(bool showHidden){
1279
	this->showHidden = showHidden;
1280
}
1281

1282
//------------------------------------------------------------------------------------------------------------
1283
bool ofDirectory::isDirectory() const {
1284
	return of::filesystem::is_directory(myDir);
1285
}
1286

1287
//------------------------------------------------------------------------------------------------------------
1288
bool ofDirectory::copyTo(const of::filesystem::path& _path, bool bRelativeToData, bool overwrite){
1289
	auto path = _path;
1290

1291
	if(myDir.string().empty()){
1292
		ofLogError("ofDirectory") << "copyTo(): source path is empty";
1293
		return false;
1294
	}
1295
	if(!of::filesystem::exists(myDir)){
1296
		ofLogError("ofDirectory") << "copyTo(): source directory does not exist";
1297
		return false;
1298
	}
1299
	if(!of::filesystem::is_directory(myDir)){
1300
		ofLogError("ofDirectory") << "copyTo(): source path is not a directory";
1301
		return false;
1302
	}
1303

1304
	if(bRelativeToData){
1305
		path = ofToDataPath(path, bRelativeToData);
1306
	}
1307

1308
	if(ofDirectory::doesDirectoryExist(path, false)){
1309
		if(overwrite){
1310
			ofDirectory::removeDirectory(path, true, false);
1311
		}else{
1312
			ofLogWarning("ofDirectory") << "copyTo(): dest \"" << path << "\" already exists, set bool overwrite to true to overwrite it";
1313
			return false;
1314
		}
1315
	}
1316

1317
	//our path is bRelativeToData handled from above - so can't open via the constructor approach
1318
	ofDirectory dir;
1319
	dir.openFromCWD(path);
1320
	dir.create(true);
1321

1322
	// Iterate through the source directory
1323
	for(of::filesystem::directory_iterator file(myDir); file != of::filesystem::directory_iterator(); ++file){
1324
		auto currentPath = of::filesystem::absolute(file->path());
1325
		auto dst = of::filesystem::path(path) / currentPath.filename();
1326
		if(of::filesystem::is_directory(currentPath)){
1327
			ofDirectory current(currentPath);
1328
			// Found directory: Recursion
1329
			if(!current.copyTo(dst,false,overwrite)){
1330
				return false;
1331
			}
1332
		}else{
1333
			ofFile tmp;
1334
			tmp.openFromCWD(file->path(),ofFile::Reference);
1335
			tmp.copyTo(dst.string(),false,overwrite);
1336
		}
1337
	}
1338

1339
	return true;
1340
}
1341

1342
//------------------------------------------------------------------------------------------------------------
1343
bool ofDirectory::moveTo(const of::filesystem::path& path, bool bRelativeToData, bool overwrite){
1344
	if(copyTo(path,bRelativeToData,overwrite)){
1345
		return remove(true);
1346
	}
1347

1348
	return false;
1349
}
1350

1351
//------------------------------------------------------------------------------------------------------------
1352
bool ofDirectory::renameTo(const of::filesystem::path& path, bool bRelativeToData, bool overwrite){
1353
	return moveTo(path, bRelativeToData, overwrite);
1354
}
1355

1356
//------------------------------------------------------------------------------------------------------------
1357
bool ofDirectory::remove(bool recursive){
1358
	if(path().empty() || !of::filesystem::exists(myDir)){
1359
		return false;
1360
	}
1361

1362
	try{
1363
		if(recursive){
1364
			of::filesystem::remove_all(of::filesystem::canonical(myDir));
1365
		}else{
1366
			of::filesystem::remove(of::filesystem::canonical(myDir));
1367
		}
1368
	}catch(std::exception & except){
1369
		ofLogError("ofDirectory") << "remove(): unable to remove file/directory: " << except.what();
1370
		return false;
1371
	}
1372

1373
	return true;
1374
}
1375

1376
//------------------------------------------------------------------------------------------------------------
1377
void ofDirectory::allowExt(const std::string& extension){
1378
	if(extension == "*"){
1379
		ofLogWarning("ofDirectory") << "allowExt(): wildcard extension * is deprecated";
1380
	}
1381
	extensions.push_back(ofToLower(extension));
1382
}
1383

1384
//------------------------------------------------------------------------------------------------------------
1385
std::size_t ofDirectory::listDir(const of::filesystem::path & directory){
1386
	open(directory);
1387
	return listDir();
1388
}
1389

1390
//------------------------------------------------------------------------------------------------------------
1391
std::size_t ofDirectory::listDir(){
1392
	files.clear();
1393
	if(path().empty()){
1394
		ofLogError("ofDirectory") << "listDir(): directory path is empty";
1395
		return 0;
1396
	}
1397
	if(!of::filesystem::exists(myDir)){
1398
		ofLogError("ofDirectory") << "listDir:() source directory does not exist: \"" << myDir << "\"";
1399
		return 0;
1400
	}
1401

1402
	of::filesystem::directory_iterator end_iter;
1403
	if ( of::filesystem::exists(myDir) && of::filesystem::is_directory(myDir)){
1404
		for( of::filesystem::directory_iterator dir_iter(myDir) ; dir_iter != end_iter ; ++dir_iter){
1405
			files.emplace_back(dir_iter->path().string(), ofFile::Reference);
1406
		}
1407
	}else{
1408
		ofLogError("ofDirectory") << "listDir:() source directory does not exist: \"" << myDir << "\"";
1409
		return 0;
1410
	}
1411

1412
	if(!showHidden){
1413
		ofRemove(files, [](ofFile & file){
1414
			return file.isHidden();
1415
		});
1416
	}
1417

1418

1419
	if(!extensions.empty() && !ofContains(extensions, (string)"*")){
1420
		ofRemove(files, [&](ofFile & file){
1421
			return std::find(extensions.begin(), extensions.end(), ofToLower(file.getExtension())) == extensions.end();
1422
		});
1423
	}
1424

1425
	if(ofGetLogLevel() == OF_LOG_VERBOSE){
1426
		for(int i = 0; i < (int)size(); i++){
1427
			ofLogVerbose() << "\t" << getName(i);
1428
		}
1429
		ofLogVerbose() << "listed " << size() << " files in \"" << originalDirectory << "\"";
1430
	}
1431

1432
	return size();
1433
}
1434

1435
//------------------------------------------------------------------------------------------------------------
1436
string ofDirectory::getOriginalDirectory() const {
1437
	return originalDirectory;
1438
}
1439

1440
//------------------------------------------------------------------------------------------------------------
1441
string ofDirectory::getName(std::size_t position) const{
1442
	return files.at(position).getFileName();
1443
}
1444

1445
//------------------------------------------------------------------------------------------------------------
1446
string ofDirectory::getPath(std::size_t position) const{
1447
	return originalDirectory + getName(position);
1448
}
1449

1450
//------------------------------------------------------------------------------------------------------------
1451
ofFile ofDirectory::getFile(std::size_t position, ofFile::Mode mode, bool binary) const {
1452
	ofFile file = files[position];
1453
	file.changeMode(mode, binary);
1454
	return file;
1455
}
1456

1457
ofFile ofDirectory::operator[](std::size_t position) const {
1458
	return getFile(position);
1459
}
1460

1461
//------------------------------------------------------------------------------------------------------------
1462
const vector<ofFile> & ofDirectory::getFiles() const{
1463
	if(files.empty() && !myDir.empty()){
1464
		const_cast<ofDirectory*>(this)->listDir();
1465
	}
1466
	return files;
1467
}
1468

1469
//------------------------------------------------------------------------------------------------------------
1470
bool ofDirectory::getShowHidden() const{
1471
	return showHidden;
1472
}
1473

1474
//------------------------------------------------------------------------------------------------------------
1475
void ofDirectory::reset(){
1476
	close();
1477
}
1478

1479
//------------------------------------------------------------------------------------------------------------
1480
static bool natural(const ofFile& a, const ofFile& b) {
1481
	string aname = a.getBaseName(), bname = b.getBaseName();
1482
	int aint = ofToInt(aname), bint = ofToInt(bname);
1483
	if(ofToString(aint) == aname && ofToString(bint) == bname) {
1484
		return aint < bint;
1485
	} else {
1486
		return a < b;
1487
	}
1488
}
1489

1490

1491
//------------------------------------------------------------------------------------------------------------
1492
struct StringSort{
1493
    of::filesystem::path path;
1494
    string basename;
1495
    int nameInt;
1496
    string stringInt;
1497
};
1498

1499
//------------------------------------------------------------------------------------------------------------
1500
static bool naturalStr(const StringSort& a, const StringSort& b) {
1501
    if(a.stringInt == a.basename && b.stringInt == b.basename) {
1502
        return a.nameInt < b.nameInt;
1503
    } else {
1504
        return a.path < b.path;
1505
    }
1506
}
1507

1508
//------------------------------------------------------------------------------------------------------------
1509
static bool byDate(const ofFile& a, const ofFile& b) {
1510
	auto ta = of::filesystem::last_write_time(a);
1511
	auto tb = of::filesystem::last_write_time(b);
1512
	return ta < tb;
1513
}
1514

1515
//------------------------------------------------------------------------------------------------------------
1516
void ofDirectory::sortByDate() {
1517
	if (files.empty() && !myDir.empty()) {
1518
		listDir();
1519
	}
1520
	ofSort(files, byDate);
1521
}
1522

1523
//------------------------------------------------------------------------------------------------------------
1524
void ofDirectory::sort(const SortMode & mode){
1525
	if(files.empty() && !myDir.empty()){
1526
		listDir();
1527
	}
1528

1529
    if( mode == ofDirectory::SORT_NATURAL ){
1530
        vector <StringSort> sort;
1531
        sort.reserve(files.size());
1532

1533
        for( auto & f : files ){
1534
            StringSort ss;
1535
            ss.path = f.path();
1536
            ss.basename = f.getBaseName();
1537
            ss.nameInt = ofToInt(ss.basename);
1538
            ss.stringInt = ofToString(ss.nameInt);
1539
            sort.push_back(ss);
1540
        }
1541
        
1542
        ofSort(sort, naturalStr);
1543
        files.clear();
1544
        files.reserve(sort.size());
1545
        for( auto & s : sort ){
1546
            files.emplace_back( s.path , ofFile::Reference);
1547
        }
1548
    }
1549
    else if(mode == ofDirectory::SORT_FAST){
1550
        std::vector <string> sort;
1551
        sort.reserve(files.size());
1552
        
1553
        for( auto & f : files ){
1554
            string ss = f.getFileName();
1555
            sort.push_back(ss);
1556
        }
1557

1558
        std::sort(sort.begin(), sort.end());
1559
        files.clear();
1560
        files.reserve(sort.size());
1561
        for( auto & s : sort ){
1562
            files.emplace_back( myDir / of::filesystem::path(s), ofFile::Reference);
1563
        }
1564
    }else if(mode == ofDirectory::SORT_BY_DATE){
1565
        sortByDate();
1566
    }
1567
}
1568

1569
//------------------------------------------------------------------------------------------------------------
1570
ofDirectory ofDirectory::getSorted(){
1571
	ofDirectory sorted(*this);
1572
	sorted.listDir();
1573
	sorted.sort();
1574
	return sorted;
1575
}
1576

1577
//------------------------------------------------------------------------------------------------------------
1578
std::size_t ofDirectory::size() const{
1579
	return files.size();
1580
}
1581

1582
//------------------------------------------------------------------------------------------------------------
1583
int ofDirectory::numFiles(){
1584
	return static_cast<int>(size());
1585
}
1586

1587
//------------------------------------------------------------------------------------------------------------
1588
// ofDirectory Static Methods
1589
//------------------------------------------------------------------------------------------------------------
1590

1591
//------------------------------------------------------------------------------------------------------------
1592
bool ofDirectory::removeDirectory(const of::filesystem::path& _path, bool deleteIfNotEmpty, bool bRelativeToData){
1593
	auto path = _path;
1594

1595
	ofFile dirToRemove;
1596
	if(bRelativeToData){
1597
		dirToRemove.open(path,ofFile::Reference);
1598
	}else{
1599
		dirToRemove.openFromCWD(path,ofFile::Reference);
1600
	}
1601

1602
	return dirToRemove.remove(deleteIfNotEmpty);
1603
}
1604

1605
//------------------------------------------------------------------------------------------------------------
1606
bool ofDirectory::createDirectory(const of::filesystem::path& _dirPath, bool bRelativeToData, bool recursive){
1607
	auto dirPath = _dirPath;
1608

1609
	if(bRelativeToData){
1610
		dirPath = ofToDataPath(dirPath);
1611
	}
1612

1613
	// on OSX,of::filesystem::create_directories seems to return false *if* the path has folders that already exist
1614
	// and true if it doesn't
1615
	// so to avoid unnecessary warnings on OSX, we check if it exists here:
1616

1617
	bool bDoesExistAlready = ofDirectory::doesDirectoryExist(dirPath,false);
1618

1619
	if (!bDoesExistAlready){
1620

1621
		bool success = false;
1622
		try{
1623
			if(!recursive){
1624
				success = of::filesystem::create_directory(dirPath);
1625
			}else{
1626
				success = of::filesystem::create_directories(dirPath);
1627
			}
1628
		} catch(std::exception & except){
1629
			ofLogError("ofDirectory") << "createDirectory(): couldn't create directory \"" << dirPath << "\": " << except.what();
1630
			return false;
1631
		}
1632
		return success;
1633
	}
1634

1635
	// no need to create it - it already exists.
1636
	return true;
1637
}
1638

1639
//------------------------------------------------------------------------------------------------------------
1640
bool ofDirectory::doesDirectoryExist(const of::filesystem::path& _dirPath, bool bRelativeToData){
1641
	auto dirPath = _dirPath;
1642
	try {
1643
		if (bRelativeToData) {
1644
			dirPath = ofToDataPath(dirPath);
1645
		}
1646
		return of::filesystem::exists(dirPath) && of::filesystem::is_directory(dirPath);
1647
	}
1648
	catch (std::exception & except) {
1649
		ofLogError("ofDirectory") << "doesDirectoryExist(): couldn't find directory \"" << dirPath << "\": " << except.what() << std::endl;
1650
		return false;
1651
	}
1652
}
1653

1654
//------------------------------------------------------------------------------------------------------------
1655
bool ofDirectory::isDirectoryEmpty(const of::filesystem::path& _dirPath, bool bRelativeToData){
1656
	auto dirPath = _dirPath;
1657
	if(bRelativeToData){
1658
		dirPath = ofToDataPath(dirPath);
1659
	}
1660

1661
	if(!dirPath.empty() && of::filesystem::exists(dirPath) && of::filesystem::is_directory(dirPath)){
1662
		return of::filesystem::directory_iterator(dirPath) == of::filesystem::directory_iterator();
1663
	}
1664
	return false;
1665
}
1666

1667
//------------------------------------------------------------------------------------------------------------
1668
bool ofDirectory::operator==(const ofDirectory & dir) const{
1669
	return getAbsolutePath() == dir.getAbsolutePath();
1670
}
1671

1672
//------------------------------------------------------------------------------------------------------------
1673
bool ofDirectory::operator!=(const ofDirectory & dir) const{
1674
	return getAbsolutePath() != dir.getAbsolutePath();
1675
}
1676

1677
//------------------------------------------------------------------------------------------------------------
1678
bool ofDirectory::operator<(const ofDirectory & dir) const{
1679
	return getAbsolutePath() < dir.getAbsolutePath();
1680
}
1681

1682
//------------------------------------------------------------------------------------------------------------
1683
bool ofDirectory::operator<=(const ofDirectory & dir) const{
1684
	return getAbsolutePath() <= dir.getAbsolutePath();
1685
}
1686

1687
//------------------------------------------------------------------------------------------------------------
1688
bool ofDirectory::operator>(const ofDirectory & dir) const{
1689
	return getAbsolutePath() > dir.getAbsolutePath();
1690
}
1691

1692
//------------------------------------------------------------------------------------------------------------
1693
bool ofDirectory::operator>=(const ofDirectory & dir) const{
1694
	return getAbsolutePath() >= dir.getAbsolutePath();
1695
}
1696

1697
//------------------------------------------------------------------------------------------------------------
1698
vector<ofFile>::const_iterator ofDirectory::begin() const{
1699
	return getFiles().begin();
1700
}
1701

1702
//------------------------------------------------------------------------------------------------------------
1703
vector<ofFile>::const_iterator ofDirectory::end() const{
1704
	return files.end();
1705
}
1706

1707
//------------------------------------------------------------------------------------------------------------
1708
vector<ofFile>::const_reverse_iterator ofDirectory::rbegin() const{
1709
	return getFiles().rbegin();
1710
}
1711

1712
//------------------------------------------------------------------------------------------------------------
1713
vector<ofFile>::const_reverse_iterator ofDirectory::rend() const{
1714
	return files.rend();
1715
}
1716

1717

1718
//------------------------------------------------------------------------------------------------------------
1719
//------------------------------------------------------------------------------------------------------------
1720
// -- ofFilePath
1721
//------------------------------------------------------------------------------------------------------------
1722
//------------------------------------------------------------------------------------------------------------
1723

1724

1725
//------------------------------------------------------------------------------------------------------------
1726
string ofFilePath::addLeadingSlash(const of::filesystem::path& _path){
1727
	auto path = _path.string();
1728
	auto sep = of::filesystem::path("/").make_preferred();
1729
	if(!path.empty()){
1730
		if(ofToString(path[0]) != sep.string()){
1731
			path = (sep / path).string();
1732
		}
1733
	}
1734
	return path;
1735
}
1736

1737
//------------------------------------------------------------------------------------------------------------
1738
//	MARK: - near future
1739
//of::filesystem::path ofFilePath::addTrailingSlash(const of::filesystem::path & _path){
1740
std::string ofFilePath::addTrailingSlash(const of::filesystem::path & _path){
1741
#if OF_USING_STD_FS && !OF_USE_EXPERIMENTAL_FS
1742
	if(_path.string().empty()) return "";
1743
	// FIXME: Remove .string() here and following
1744
	// return (of::filesystem::path(_path).make_preferred() / "");
1745
	return (of::filesystem::path(_path).make_preferred() / "").string();
1746
#else
1747
	auto path = of::filesystem::path(_path).make_preferred();
1748
	auto sep = of::filesystem::path("/").make_preferred();
1749
	if(!path.empty()){
1750
		if(ofToString(path.string().back()) != sep.string()){
1751
			path = (path / sep);
1752
		}
1753
	}
1754
//	return path;
1755
	return path.string();
1756
#endif
1757
}
1758

1759

1760
//------------------------------------------------------------------------------------------------------------
1761
string ofFilePath::getFileExt(const of::filesystem::path& filename){
1762
	return 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){
1769
std::string ofFilePath::removeExt(const of::filesystem::path& _filename){
1770
	auto filename = _filename;
1771
//	return filename.replace_extension();
1772
	return filename.replace_extension().string();
1773
}
1774

1775
//------------------------------------------------------------------------------------------------------------
1776
string ofFilePath::getPathForDirectory(const of::filesystem::path& path){
1777
	// if a trailing slash is missing from a path, this will clean it up
1778
	// 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 following
1782
	// FIXME: this seems over complicated and not useful anymore, using filesystem
1783

1784
#if OF_USING_STD_FS && !OF_USE_EXPERIMENTAL_FS
1785
	if(path.string().empty()) return "";
1786
	return (path / "").string();
1787
#else
1788
	auto sep = of::filesystem::path("/").make_preferred();
1789
	if(!path.empty() && ofToString(path.string().back())!=sep.string()){
1790
		return (path / sep).string();
1791
	}else{
1792
		return path.string();
1793
	}
1794
#endif
1795
}
1796

1797
//------------------------------------------------------------------------------------------------------------
1798
// FIXME: convert to of::filesystem::path
1799
string ofFilePath::removeTrailingSlash(const of::filesystem::path& _path){
1800
	auto path = _path.string();
1801
	if(path.length() > 0 && (path[path.length() - 1] == '/' || path[path.length() - 1] == '\\')){
1802
		path = path.substr(0, path.length() - 1);
1803
	}
1804
	return path;
1805
}
1806

1807

1808
//------------------------------------------------------------------------------------------------------------
1809
// FIXME: is this still useful? if yes convert to of::filesystem::path
1810
string ofFilePath::getFileName(const of::filesystem::path& _filePath, bool bRelativeToData){
1811
	auto filePath = _filePath;
1812

1813
	if(bRelativeToData){
1814
		filePath = ofToDataPath(filePath);
1815
	}
1816

1817
	// FIXME: this is probably over complicated
1818
	return of::filesystem::path(filePath).filename().string();
1819
}
1820

1821
//------------------------------------------------------------------------------------------------------------
1822
string ofFilePath::getBaseName(const of::filesystem::path& filePath){
1823
	// FIXME: is this still useful?
1824
	return 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){
1830
std::string ofFilePath::getEnclosingDirectory(const of::filesystem::path & _filePath, bool bRelativeToData){
1831
	auto fp = _filePath;
1832
	if(bRelativeToData){
1833
		fp = ofToDataPath(fp);
1834
	}
1835
	return addTrailingSlash(fp.parent_path());
1836
}
1837

1838
//------------------------------------------------------------------------------------------------------------
1839
bool ofFilePath::createEnclosingDirectory(const of::filesystem::path& filePath, bool bRelativeToData, bool bRecursive) {
1840
	return 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){
1846
std::string ofFilePath::getAbsolutePath(const of::filesystem::path& path, bool bRelativeToData){
1847
	if(bRelativeToData){
1848
		return ofToDataPath(path, true);
1849
	}else{
1850
		try{
1851
//			return of::filesystem::canonical(of::filesystem::absolute(path));
1852
			return of::filesystem::canonical(of::filesystem::absolute(path)).string();
1853
		}catch(...){
1854
//			return of::filesystem::absolute(path);
1855
			return of::filesystem::absolute(path).string();
1856
		}
1857
	}
1858
}
1859

1860
//------------------------------------------------------------------------------------------------------------
1861
bool ofFilePath::isAbsolute(const of::filesystem::path& path){
1862
	return of::filesystem::path(path).is_absolute();
1863
}
1864

1865
//------------------------------------------------------------------------------------------------------------
1866
string ofFilePath::getCurrentWorkingDirectory(){
1867
	return 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
//}
1876
std::string ofFilePath::join(const of::filesystem::path& path1, const of::filesystem::path& path2){
1877
	// FIXME: deprecate when possible. helper function more complex than actual solution
1878
	return (path1 / path2).string();
1879
}
1880

1881
//------------------------------------------------------------------------------------------------------------
1882
string ofFilePath::getCurrentExePath(){
1883
	#if defined(TARGET_LINUX) || defined(TARGET_ANDROID)
1884
		char buff[FILENAME_MAX];
1885
		ssize_t size = readlink("/proc/self/exe", buff, sizeof(buff) - 1);
1886
		if (size == -1){
1887
			ofLogError("ofFilePath") << "getCurrentExePath(): readlink failed with error " << errno;
1888
		}
1889
		else{
1890
			buff[size] = '\0';
1891
			return buff;
1892
		}
1893
	#elif defined(TARGET_OSX)
1894
		char path[FILENAME_MAX];
1895
		uint32_t size = sizeof(path);
1896
		if(_NSGetExecutablePath(path, &size) != 0){
1897
			ofLogError("ofFilePath") << "getCurrentExePath(): path buffer too small, need size " <<  size;
1898
		}
1899
		return path;
1900
	#elif defined(TARGET_WIN32)
1901
		vector<char> executablePath(MAX_PATH);
1902
		DWORD result = ::GetModuleFileNameA(nullptr, &executablePath[0], static_cast<DWORD>(executablePath.size()));
1903
		if(result == 0) {
1904
			ofLogError("ofFilePath") << "getCurrentExePath(): couldn't get path, GetModuleFileNameA failed";
1905
		}else{
1906
			return string(executablePath.begin(), executablePath.begin() + result);
1907
		}
1908
	#endif
1909
	return "";
1910
}
1911

1912
//------------------------------------------------------------------------------------------------------------
1913
// MARK: - near future
1914
//of::filesystem::path ofFilePath::getCurrentExeDir(){
1915
std::string ofFilePath::getCurrentExeDir(){
1916
	return ofFilePath::getEnclosingDirectory(ofFilePath::getCurrentExePath(), false);
1917
}
1918

1919
//------------------------------------------------------------------------------------------------------------
1920
string ofFilePath::getUserHomeDir(){
1921
	#ifdef TARGET_WIN32
1922
		// getenv will return any Environent Variable on Windows
1923
		// USERPROFILE is the key on Windows 7 but it might be HOME
1924
		// in other flavours of windows...need to check XP and NT...
1925
		return ofGetEnv("USERPROFILE");
1926
	#elif !defined(TARGET_EMSCRIPTEN)
1927
		struct passwd * pw = getpwuid(getuid());
1928
		return pw->pw_dir;
1929
	#else
1930
		return "";
1931
	#endif
1932
}
1933

1934
// MARK: - near future
1935
//of::filesystem::path ofFilePath::makeRelative(const of::filesystem::path & from, const of::filesystem::path & to){
1936
std::string ofFilePath::makeRelative(const of::filesystem::path & from, const of::filesystem::path & to){
1937
	auto pathFrom = of::filesystem::absolute( from );
1938
	auto pathTo = of::filesystem::absolute( to );
1939
	of::filesystem::path ret;
1940
	of::filesystem::path::const_iterator itrFrom( pathFrom.begin() ), itrTo( pathTo.begin() );
1941
	// Find common base
1942
	for( 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 base
1944
	for( of::filesystem::path::const_iterator fromEnd( pathFrom.end() ); itrFrom != fromEnd; ++itrFrom ){
1945
		if( (*itrFrom) != "." ){
1946
			ret /= "..";
1947
		}
1948
	}
1949
	// Now navigate down the directory branch
1950
	for( ; itrTo != pathTo.end() ; ++itrTo ){
1951
		if( itrTo->string() != "."){
1952
			ret /= *itrTo;
1953
		}
1954
	}
1955

1956
//	return ret;
1957
	return ret.string();
1958
}
1959

1960
//--------------------------------------------------
1961
void ofEnableDataPath(){
1962
	enableDataPath = true;
1963
}
1964

1965
//--------------------------------------------------
1966
void ofDisableDataPath(){
1967
	enableDataPath = false;
1968
}
1969

1970
//--------------------------------------------------
1971
bool ofRestoreWorkingDirectoryToDefault(){
1972
	try{
1973
		of::filesystem::current_path(defaultWorkingDirectory());
1974
		return true;
1975
	}catch(...){
1976
		return false;
1977
	}
1978
}
1979

1980
//--------------------------------------------------
1981
void ofSetDataPathRoot(const of::filesystem::path& newRoot){
1982
	dataPathRoot() = newRoot;
1983
}
1984

1985
//--------------------------------------------------
1986
// MARK: - near future
1987
//of::filesystem::path ofToDataPath(const of::filesystem::path & path, bool makeAbsolute){
1988
std::string ofToDataPath(const of::filesystem::path & path, bool makeAbsolute){
1989
	if (makeAbsolute && path.is_absolute()) {
1990
//		return path;
1991
		return path.string();
1992
	}
1993

1994
	if (!enableDataPath) {
1995
//		return path;
1996
		return path.string();
1997
	}
1998

1999
	bool hasTrailingSlash = !path.empty() && path.generic_string().back()=='/';
2000

2001
	// if our Current Working Directory has changed (e.g. file open dialog)
2002
#ifdef TARGET_WIN32
2003
	if (defaultWorkingDirectory() != of::filesystem::current_path()) {
2004
		// change our cwd back to where it was on app load
2005
		bool ret = ofRestoreWorkingDirectoryToDefault();
2006
		if(!ret){
2007
			ofLogWarning("ofUtils") << "ofToDataPath: error while trying to change back to default working directory " << defaultWorkingDirectory();
2008
		}
2009
	}
2010
#endif
2011

2012
	// this could be performed here, or wherever we might think we accidentally change the cwd, e.g. after file dialogs on windows
2013
	const auto & dataPath = dataPathRoot();
2014
	of::filesystem::path inputPath(path);
2015
	of::filesystem::path outputPath;
2016

2017
	// if path is already absolute, just return it
2018
	if (inputPath.is_absolute()) {
2019
		try {
2020
			auto outpath = of::filesystem::canonical(inputPath).make_preferred();
2021
			if(of::filesystem::is_directory(outpath) && hasTrailingSlash){
2022
				return ofFilePath::addTrailingSlash(outpath);
2023
			}else{
2024
				return outpath.string();
2025
				// return outpath;
2026
			}
2027
		}
2028
		catch (...) {
2029
			return inputPath.string();
2030
			// return inputPath;
2031
		}
2032
	}
2033

2034
	// here we check whether path already refers to the data folder by looking for common elements
2035
	// if the path begins with the full contents of dataPathRoot then the data path has already been added
2036
	// we compare inputPath.toString() rather that the input var path to ensure common formatting against dataPath.toString()
2037
	auto 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)
2039
	dirDataPath = ofFilePath::addTrailingSlash(dataPath);
2040

2041
	auto relativeDirDataPath = ofFilePath::makeRelative(of::filesystem::current_path(), dataPath);
2042
	relativeDirDataPath = ofFilePath::addTrailingSlash(relativeDirDataPath);
2043

2044
	// FIXME: this can be simplified without using string conversion
2045
	// if (inputPath.string().find(dirDataPath.string()) != 0 && inputPath.string().find(relativeDirDataPath.string())!=0) {
2046
	if (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 dataPath
2048
		if(makeAbsolute){
2049
			outputPath = dirDataPath / inputPath;
2050
		}else{
2051
			outputPath = relativeDirDataPath / inputPath;
2052
		}
2053
	} else {
2054
		// inputPath already contains data path, so no need to change
2055
		outputPath = inputPath;
2056
	}
2057

2058
	// finally, if we do want an absolute path and we don't already have one
2059
	if(makeAbsolute){
2060
		// then we return the absolute form of the path
2061
		try {
2062
			auto outpath = of::filesystem::canonical(of::filesystem::absolute(outputPath)).make_preferred();
2063
			if(of::filesystem::is_directory(outpath) && hasTrailingSlash){
2064
				return ofFilePath::addTrailingSlash(outpath);
2065
			}else{
2066
//				return outpath;
2067
				return outpath.string();
2068
			}
2069
		}
2070
		catch (std::exception &) {
2071
		   return of::filesystem::absolute(outputPath).string();
2072
			// return of::filesystem::absolute(outputPath);
2073
		}
2074
	}else{
2075
		// or output the relative path
2076
//		return outputPath;
2077
		return outputPath.string();
2078
	}
2079
}
2080

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.