cgv
Loading...
Searching...
No Matches
file.cxx
1#include "file.h"
2#include <cgv/utils/dir.h>
3#include <cgv/type/standard_types.h>
4#include <string.h>
5#include <vector>
6#ifdef _WIN32
7#include <io.h>
8#include <fcntl.h>
9#else
10#include <unistd.h>
11#include <sys/types.h>
12#include <sys/stat.h>
13#include <fcntl.h>
14#include <iostream>
15#include <glob.h>
16#endif
17
18#if (__cplusplus >= 201703L || _MSVC_LANG >= 201703L)
19#include <filesystem>
20#define USE_STD_FILESYSTEM
21#endif
22
23namespace cgv {
24 namespace utils {
25 namespace file {
26#if _MSC_VER > 1400
27#pragma warning (disable:4996)
28#endif
29
30void* open(const std::string& file_name, const std::string& mode, void* buf, int length)
31{
32 FILE *file = fopen(file_name.c_str(), mode.c_str());
33 if ( (file != 0) && (setvbuf((FILE*) file, (char*) buf, _IOFBF, length) == 0) )
34 return file;
35 else
36 return 0;
37}
38
39
40bool exists(const std::string& file_name)
41{
42#ifdef USE_STD_FILESYSTEM
43 return std::filesystem::exists(file_name);
44#else
45 void* handle = find_first(file_name);
46 bool ret = (bool)handle;
47 find_close(handle);
48 return ret;
49#endif
50}
51
52std::string find_recursive(const std::string& path, const std::string& file_name)
53{
54#ifdef USE_STD_FILESYSTEM
55 if (!cgv::utils::dir::exists(path))
56 return "";
57 if(cgv::utils::file::exists(path + '/' + file_name))
58 return path + '/' + file_name;
59
60 std::filesystem::path target_file_name = file_name;
61
62 for(const std::filesystem::directory_entry& dir_entry : std::filesystem::recursive_directory_iterator(path)) {
63 if(dir_entry.is_regular_file() && !dir_entry.is_symlink()) {
64 if(dir_entry.path().filename() == target_file_name) {
65 if(cgv::utils::file::exists(dir_entry.path().string())) {
66 return dir_entry.path().string();
67 }
68 }
69 }
70 }
71
72 return "";
73#else
74 if (cgv::utils::file::exists(path+'/'+file_name))
75 return path+'/'+file_name;
76 void* h = find_first(path+"/*");
77 while (h) {
78 if (find_directory(h) && find_name(h) != "." && find_name(h) != "..") {
79 std::string res = find_recursive(path+'/'+find_name(h), file_name);
80 if (!res.empty()) {
81 find_close(h);
82 return res;
83 }
84 }
85 h = find_next(h);
86 }
87 return "";
88#endif
89}
90
92std::string find_in_paths(const std::string& file_name, const std::string& path_list,
93 bool recursive, const std::string& sub_dir)
94{
95 // first check file name itself
96 if (cgv::utils::file::exists(file_name))
97 return file_name;
98
99 // then check in sub_dir
100 std::string sfn;
101 if (sub_dir.empty())
102 sfn = file_name;
103 else {
104 sfn = sub_dir+'/'+file_name;
105 if (cgv::utils::file::exists(sfn))
106 return sfn;
107 }
108
109 // iterate all entries in path list and check for file_name in sub_dir
110 size_t pos = 0;
111 do {
112 size_t end_pos = path_list.find_first_of(';', pos);
113 std::string fn;
114 if (end_pos == std::string::npos) {
115 fn = path_list.substr(pos)+'/'+sfn;
116 pos = path_list.length();
117 }
118 else {
119 fn = path_list.substr(pos,end_pos-pos)+'/'+sfn;
120 pos = end_pos+1;
121 }
122 if (cgv::utils::file::exists(fn))
123 return fn;
124 } while (pos < path_list.length());
125
126 // recursive iteration
127 pos = 0;
128 do {
129 size_t end_pos = path_list.find_first_of(';', pos);
130 std::string fn;
131 if (end_pos == std::string::npos) {
132 fn = path_list.substr(pos);
133 pos = path_list.length();
134 }
135 else {
136 fn = path_list.substr(pos, end_pos-pos);
137 pos = end_pos+1;
138 }
139 fn = find_recursive(fn, sfn);
140 if (!fn.empty())
141 return fn;
142 } while (pos < path_list.length());
143 return "";
144}
145
146bool remove(const std::string& file_name)
147{
148 return ::remove(file_name.c_str()) == 0;
149}
150
151bool rename(const std::string& before, const std::string& after)
152{
153 return ::rename(before.c_str(), after.c_str()) == 0;
154}
155
156bool copy(const std::string& from, const std::string& to)
157{
158 bool success = false;
159 FILE* fp = ::fopen(from.c_str(), "rb");
160 FILE* gp = ::fopen(to.c_str(), "wb");
161 if (fp && gp) {
162 success = true;
163 char buffer[4096];
164 while (!feof(fp)) {
165 size_t count = fread (buffer, sizeof(char), 4096, fp);
166 if (count != fwrite(buffer, sizeof(char), count, gp) ) {
167 success = false;
168 break;
169 }
170 }
171 }
172 if (fp) fclose(fp);
173 if (gp) fclose(gp);
174 return success;
175}
176
177Result cmp(const std::string& what, const std::string& with)
178{
179 Result result = file::EQUAL;
180 FILE* fp = ::fopen(what.c_str(), "rb");
181 FILE* gp = ::fopen(with.c_str(), "rb");
182 if (fp && gp) {
183 char bufferf[4096];
184 char bufferg[4096];
185 while (!feof(fp)) {
186 size_t countf = fread (bufferf, sizeof(char), 4096, fp);
187 size_t countg = fread (bufferg, sizeof(char), 4096, gp);
188 if ( (countf != countg) ||
189 (::memcmp(bufferf, bufferg, sizeof(char)*countf) != 0) ) {
190 result = file::DIFFERENT;
191 break;
192 }
193 }
194 }
195 else
196 result = file::FILE_ERROR;
197 if (fp) fclose(fp);
198 if (gp) fclose(gp);
199 return result;
200}
201
202size_t size(const std::string& file_name, bool ascii)
203{
204#ifdef USE_STD_FILESYSTEM
205 try {
206 return std::filesystem::file_size(file_name);
207 }
208 catch(...) {
209 return (size_t)-1;
210 }
211#else
212#ifdef _WIN32
213 if (ascii) {
214 void* handle = find_first(file_name);
215 size_t s = (size_t)-1;
216 if(handle)
217 s = find_size(handle);
218 find_close(handle);
219 return s;
220 }
221 else {
222 FILE* fp = fopen(file_name.c_str(), ascii ? "r" : "rb");
223 if (fp == 0)
224 return 0;
225 size_t s = 0;
226 if (fseek(fp, 0, SEEK_END) == 0) {
227 fpos_t pos;
228 fgetpos(fp, &pos);
229 s = size_t(pos);
230 }
231 fclose(fp);
232 return s;
233 }
234#else
235 int fh = ::open(file_name.c_str(), O_RDONLY);
236 if (fh == -1)
237 return -1;
238 struct stat fileinfo;
239 fstat(fh, &fileinfo);
240 close(fh);
241 return fileinfo.st_size;
242#endif
243#endif
244}
245
247bool read(const std::string& filename, char* ptr, size_t size, bool ascii, size_t file_offset)
248{
249 FILE* fp = ::fopen(filename.c_str(), ascii ? "r" : "rb");
250 if (file_offset != 0) {
251 if (
252#ifdef _WIN32
253 _fseeki64
254#else
255 fseeko64
256#endif
257 (fp, file_offset, SEEK_SET) != 0)
258 return false;
259 }
260 size_t n = ::fread(ptr, 1, size, fp);
261 fclose(fp);
262 return n == size;
263}
264
266bool read(const std::string& file_name, std::string& content, bool ascii)
267{
268 size_t l = size(file_name, ascii);
269 if (l == (size_t)-1) return false;
270/* char* buffer = new char[l];
271 FILE* fp = ::fopen(file_name.c_str(), ascii ? "r" : "rb");
272 unsigned int n = ::fread(buffer, 1, l, fp);
273 content.resize(n);
274 memcpy(&content[0],buffer,n);
275 delete [] buffer;
276 return true;*/
277 content.resize(l);
278 FILE* fp = ::fopen(file_name.c_str(), ascii ? "r" : "rb");
279 size_t n = ::fread(&content[0], 1, l, fp);
280 content.resize(n);
281 ::fclose(fp);
282 return true;
283}
284
285char* read(const std::string& file_name, bool ascii, size_t* size_ptr, size_t add_nr_bytes_to_buffer)
286{
287 size_t l = size(file_name);
288 if (l == (size_t)-1) return 0;
289 char* buffer = new char[l+ add_nr_bytes_to_buffer];
290 FILE* fp = ::fopen(file_name.c_str(), ascii ? "r" : "rb");
291 l = ::fread(buffer, 1, l, fp);
292 ::fclose(fp);
293 if (size_ptr) *size_ptr = l;
294 return buffer;
295}
296
297bool write(const std::string& filename, const std::string& content, bool ascii)
298{
299 return write(filename, content.c_str(), content.length(), ascii);
300}
301
302bool write(const std::string& file_name, const char* ptr, size_t size, bool ascii)
303{
304 bool res = false;
305 FILE* fp = ::fopen(file_name.c_str(), ascii ? "w" : "wb");
306 if (fp) {
307 res = ::fwrite(ptr, 1, size, fp) == size;
308 ::fclose(fp);
309 }
310 return res;
311}
312
313bool append(const std::string& file_name, const char* ptr, size_t size, bool ascii)
314{
315 bool res = false;
316 FILE* fp = ::fopen(file_name.c_str(), ascii ? "a" : "ab");
317 if (fp) {
318 res = ::fwrite(ptr, 1, size, fp) == size;
319 ::fclose(fp);
320 }
321 return res;
322}
323
324bool append(const std::string& file_name_1, const std::string& file_name_2, bool ascii)
325{
326 const size_t buffer_size = 10000000;
327 size_t N = cgv::utils::file::size(file_name_2, ascii);
328 std::vector<char> buffer(buffer_size, 0);
329 size_t off = 0;
330 while (off < N) {
331 size_t n = N - off;
332 if (n > buffer_size)
333 n = buffer_size;
334 if (!cgv::utils::file::read(file_name_2, &buffer.front(), n, ascii, off))
335 return false;
336 if (!cgv::utils::file::append(file_name_1, &buffer.front(), n, ascii))
337 return false;
338 off += n;
339 }
340 return true;
341}
342
343#ifdef _WIN32
344struct FileInfo
345{
346 _finddata_t fileinfo;
347 intptr_t handle;
348};
349#else
351{
352 glob_t* globResults;
353 int index;
354};
355#endif
356
358long long find_last_write_time(const void* handle)
359{
360 FileInfo *fi = (FileInfo*) handle;
361#ifdef _WIN32
362 return fi->fileinfo.time_write;
363#else
364 struct stat statBuffer;
365 int result =stat(find_name(fi).c_str(),&statBuffer);
366 if (result == 0)
367 {
368 return statBuffer.st_ctime;
369 }
370
371 return 0;
372#endif
373}
374
376long long get_last_write_time(const std::string& file_path)
377{
378 void* handle = find_first(file_path);
379 long long time = -1;
380 if(handle)
381 time = find_last_write_time(handle);
382 find_close(handle);
383 return time;
384}
385
387void* find_first(const std::string& filter)
388{
389 FileInfo *fi = new FileInfo;
390#ifdef _WIN32
391 fi->handle = _findfirst(filter.c_str(), &fi->fileinfo);
392 if (fi->handle == -1) {
393 delete fi;
394 return 0;
395 }
396 return fi;
397#else
398 fi->globResults=new glob_t();
399 fi->index=0;
400 if(glob(filter.c_str(),GLOB_NOSORT,NULL,(fi->globResults))!=0)
401 {
402 delete fi->globResults;
403 delete fi;
404 return 0;
405 }
406 //printf("filter: %s",filter.c_str());
407 //for(int i=0;i<fi->globResults->gl_pathc;i++) printf("file: %s\n",get_file_name(fi->globResults->gl_pathv[i]).c_str());
408 return fi;
409#endif
410}
411
413void* find_next(void* handle)
414{
415 FileInfo *fi = (FileInfo*) handle;
416#ifdef _WIN32
417 if (_findnext(fi->handle, &fi->fileinfo) == -1) {
418 find_close(handle);
419 return 0;
420 }
421 return fi;
422#else
423 fi->index+=1;
424 if(fi->globResults->gl_pathc > fi->index)
425 return fi;
426 delete fi->globResults;
427 delete fi;
428 return NULL;
429#endif
430}
431
433void find_close(void* handle) {
434 if(handle == 0)
435 return;
436 FileInfo* fi = (FileInfo*)handle;
437#ifdef _WIN32
438 _findclose(fi->handle);
439 delete fi;
440 handle = 0;
441#else
442 delete fi->globResults;
443 delete fi;
444#endif
445}
446
448std::string find_name(void* handle)
449{
450 FileInfo *fi = (FileInfo*) handle;
451#ifdef _WIN32
452 return std::string(fi->fileinfo.name);
453#else
454 if(fi->globResults->gl_pathc > fi->index)
455 return get_file_name(std::string(fi->globResults->gl_pathv[fi->index]));
456
457 return std::string("");
458#endif
459}
461bool find_read_only(const void* handle)
462{
463#ifdef _WIN32
464 FileInfo *fi = (FileInfo*) handle;
465 return fi->fileinfo.attrib & _A_RDONLY;
466#else
467 std::cerr << "Not Implemented" << std::endl;
468 return false;
469#endif
470}
471
473bool find_directory(const void* handle)
474{
475 FileInfo *fi = (FileInfo*) handle;
476#ifdef _WIN32
477 return (fi->fileinfo.attrib & _A_SUBDIR) != 0;
478#else
479 if(fi->globResults->gl_pathc > fi->index)
480 {
481 struct stat stat_buf;
482 stat(fi->globResults->gl_pathv[fi->index],&stat_buf);
483 return S_ISDIR(stat_buf.st_mode);
484 }
485 return false;
486#endif
487}
489bool find_system(const void* handle)
490{
491#ifdef _WIN32
492 FileInfo *fi = (FileInfo*) handle;
493 return (fi->fileinfo.attrib & _A_SYSTEM) != 0;
494#else
495 std::cerr << "Not Implemented" << std::endl;
496 return false;
497#endif
498}
500bool find_hidden(const void* handle)
501{
502#ifdef _WIN32
503 FileInfo *fi = (FileInfo*) handle;
504 return (fi->fileinfo.attrib & _A_HIDDEN) != 0;
505#else
506 std::cerr << "Not Implemented" << std::endl;
507 return false;
508#endif
509}
511bool find_archive(const void* handle)
512{
513#ifdef _WIN32
514 FileInfo *fi = (FileInfo*) handle;
515 return (fi->fileinfo.attrib & _A_ARCH) != 0;
516#else
517 std::cerr << "Not Implemented" << std::endl;
518 return false;
519#endif
520}
522bool find_normal(const void* handle)
523{
524 FileInfo *fi = (FileInfo*) handle;
525#ifdef _WIN32
526 return fi->fileinfo.attrib == _A_NORMAL;
527#else
528 if(fi->globResults->gl_pathc > fi->index)
529 {
530 struct stat stat_buf;
531 stat(fi->globResults->gl_pathv[fi->index],&stat_buf);
532 return S_ISREG(stat_buf.st_mode);
533 }
534 return false;
535#endif
536}
538size_t find_size(void* handle)
539{
540 FileInfo *fi = (FileInfo*) handle;
541#ifdef _WIN32
542 return fi->fileinfo.size;
543#else
544 if(fi->globResults->gl_pathc > fi->index)
545 {
546 struct stat stat_buf;
547 stat(fi->globResults->gl_pathv[fi->index],&stat_buf);
548 return stat_buf.st_size;
549 }
550 return 0;
551#endif
552}
553
555std::string get_extension(const std::string& file_path)
556{
557 size_t pos = file_path.find_last_of('.');
558 if (pos == std::string::npos)
559 return std::string();
560 return file_path.substr(pos+1);
561}
562
564std::string drop_extension(const std::string& file_path)
565{
566 // If there is no extension, the original path can be returned directly
567 // As paths can also contain dots (relative paths), we need to check the base name specifically, not the entire path
568 std::string base_name = get_file_name(file_path);
569 size_t pos = base_name.find_last_of('.');
570 if (pos == std::string::npos)
571 return file_path;
572
573 return file_path.substr(0,file_path.find_last_of('.'));
574}
575
577std::string get_file_name(const std::string& file_path)
578{
579 size_t pos[3] = {
580 file_path.find_last_of('/'),
581 file_path.find_last_of('\\'),
582 file_path.find_last_of(':')
583 };
584 size_t p = std::string::npos;
585 for (unsigned int i=0; i<3; ++i)
586 if (pos[i] != std::string::npos)
587 if (p == std::string::npos || pos[i] > p)
588 p = pos[i];
589 if (p == std::string::npos)
590 return file_path;
591 return file_path.substr(p+1);
592}
593
595std::string get_path(const std::string& file_path)
596{
597 size_t pos[3] = {
598 file_path.find_last_of('/'),
599 file_path.find_last_of('\\'),
600 file_path.find_last_of(':')
601 };
602 size_t p = std::string::npos;
603 for (unsigned int i=0; i<3; ++i)
604 if (pos[i] != std::string::npos)
605 if (p == std::string::npos || pos[i] > p)
606 p = pos[i];
607 if (p == std::string::npos)
608 return "";
609 return file_path.substr(0,p);
610}
611
612char to_lower(char c)
613{
614 if (c >= 'A' && c <= 'Z')
615 return (c-'A')+'a';
616 switch (c) {
617 case (char) 0xD6 : return (char) 0xF6; // Oe -> oe
618 case (char) 0xC4 : return (char) 0xE4; // Ae -> ae
619 case (char) 0xDC : return (char) 0xFC; // Ue -> ue
620 default: return c;
621 }
622}
623
624bool is_letter(char c)
625{
626 c = to_lower(c);
627 return c >= 'a' && c <= 'z';
628}
630bool is_relative_path(const std::string& file_path)
631{
632 if (file_path.size() == 0)
633 return true;
634 if (file_path[0] == '/')
635 return false;
636 if (file_path[0] == '\\')
637 return false;
638 if (file_path.size() == 1)
639 return true;
640 if (file_path[1] == ':' && is_letter(file_path[0]))
641 return false;
642 return true;
643}
644
646std::string clean_path(const std::string& file_path)
647{
648 std::string cleaned_path = file_path;
649 unsigned i;
650 for (i=0; i<cleaned_path.size(); ++i) {
651 char c = cleaned_path[i];
652 if (c == '\\')
653 c = '/';
654#ifdef _WIN32
655 else c = to_lower(c);
656#endif
657 cleaned_path[i] = c;
658 }
659 bool last_is_slash = false;
660 unsigned n = (unsigned int) cleaned_path.size();
661 unsigned m = n;
662 for (unsigned int i=0, j=0; i<n; ++i, ++j) {
663 if (j < i)
664 cleaned_path[j] = cleaned_path[i];
665 if (cleaned_path[i] == '/')
666 if (last_is_slash) {
667 --j;
668 --m;
669 }
670 else
671 last_is_slash = true;
672 else
673 last_is_slash = false;
674 }
675 if (cleaned_path[m-1] == '/')
676 --m;
677 return cleaned_path.substr(0,m);
678}
679
681std::string platform_path(const std::string& file_path)
682{
683 std::string cleaned_path = clean_path(file_path);
684 unsigned i;
685 for (i = 0; i < cleaned_path.size(); ++i) {
686 char c = cleaned_path[i];
687#ifdef _WIN32
688 if (c == '/')
689 c = '\\';
690#else
691 if (c == '\\')
692 c = '/';
693#endif
694 cleaned_path[i] = c;
695 }
696 return cleaned_path;
697}
698
700bool shorten_path(std::string& file_path, const std::string& prefix_path)
701{
702 std::string cleaned_prefix_path = clean_path(prefix_path);
703 std::string cleaned_file_path = clean_path(file_path);
704 if (cleaned_file_path.size() < cleaned_prefix_path.size()) {
705 file_path = cleaned_file_path;
706 return false;
707 }
708 if (cleaned_file_path.substr(0,cleaned_prefix_path.size()) != cleaned_prefix_path) {
709 file_path = cleaned_file_path;
710 return false;
711 }
712 if (cleaned_file_path.size() == cleaned_prefix_path.size()) {
713 file_path = "";
714 return true;
715 }
716 unsigned int o = (unsigned int) cleaned_prefix_path.size();
717 if (cleaned_file_path[o] == '/')
718 ++o;
719 file_path = cleaned_file_path.substr(o);
720 return true;
721}
722
723
724
725bool read_string_bin(std::string& s, FILE* fp)
726{
728 if (fread(&length, sizeof(cgv::type::uint16_type), 1, fp) != 1)
729 return false;
730 s.resize(length);
731 if (length == 0)
732 return true;
733 return fread(&s[0], sizeof(char), length, fp) == length;
734}
735
736bool write_string_bin(const std::string& s, FILE* fp)
737{
739 if (fwrite(&length, sizeof(cgv::type::uint16_type), 1, fp) != 1)
740 return false;
741 if (length == 0)
742 return true;
743 return fwrite(&s[0], sizeof(char), length, fp) == length;
744}
745
746
747 }
748 }
749}
complete implementation of method actions that only call one method when entering a node
Definition action.h:113
unsigned short uint16_type
this type provides an 16 bit unsigned integer type
the cgv namespace
Definition print.h:11