1#include <cgv/base/register.h>
5#include <cgv/utils/dir.h>
6#include <cgv/utils/file.h>
7#include <cgv/utils/tokenizer.h>
16using namespace cgv::utils::file;
21std::string find_data_file_rec(
const std::string& path,
const std::string& file_name)
23 if (cgv::utils::file::exists(path+
'/'+file_name))
24 return path+
'/'+file_name;
25 void* h = find_first(path+
"*");
27 if (find_directory(h) && find_name(h) !=
"." && find_name(h) !=
"..") {
28 std::string fn = path+find_name(h)+
'/';
29 if (exists(fn+file_name))
31 fn = find_data_file_rec(fn, file_name);
40std::string find_data_file_1(
const std::string& base_path,
const std::string& sub_path,
const std::string& file_name,
bool recurse)
42 std::string base_path_prefix = base_path;
43 if (!base_path_prefix.empty() && base_path_prefix.back() !=
'/')
44 base_path_prefix +=
"/";
45 std::string dir_name = base_path_prefix+sub_path;
46 if (!dir_name.empty()) {
47 if (!dir::exists(dir_name))
49 if (dir_name.back() !=
'/')
52 if (exists(dir_name+file_name))
53 return dir_name+file_name;
56 return find_data_file_rec(dir_name, file_name);
59std::string
find_data_file(
const std::string& file_name,
const std::string& strategy,
const std::string& sub_directory,
const std::string& master_path)
61 for (
unsigned i=0; i<strategy.size(); ++i) {
62 switch (strategy[i]) {
66 std::map<std::string, resource_file_info>::const_iterator it =
ref_resource_file_map().find(file_name);
68 return std::string(
"res://")+file_name;
74 std::string fn = find_data_file_1(
"", sub_directory, file_name, strategy[i] ==
'C');
83 std::string fn = find_data_file_1(master_path, sub_directory, file_name, strategy[i] ==
'M');
92 for (
unsigned int i=0; i<path_list.size(); ++i) {
93 std::string fn = find_data_file_1(path_list[i], sub_directory, file_name, strategy[i] ==
'D');
103 if (!parent_stack.empty()) {
104 std::string fn = find_data_file_1(parent_stack.back(), sub_directory, file_name, strategy[i] ==
'P');
114 for (
size_t i=parent_stack.size(); i>0; --i) {
115 std::string fn = find_data_file_1(parent_stack[i-1], sub_directory, file_name, strategy[i] ==
'A');
123 return std::string();
128 std::cout << text << std::endl;
133 std::cerr << text << std::endl;
136int std_query(
const std::string& text,
const std::string& answers,
int default_answer)
138 std::vector<std::string> answer_strings;
139 std::vector<int> answer_values;
141 std::vector<cgv::utils::token> tokens;
143 std::cout << text <<
"\n select answer from {" << answers <<
"} with 0..." << tokens.size() - 1 <<
":>";
150std::string
std_ask_dir(
const std::string& text,
const std::string& path)
152 std::cout << text <<
"\n:>";
160 const std::string& url,
const std::string& cache_strategy,
const std::string& producer,
161 const std::string& sub_directory,
const std::string& master_path,
user_feedback uf)
165 if (!file_path.empty())
170 while (i < cache_strategy.size() && file_path.empty()) {
171 switch (cache_strategy[i++]) {
173 case 'C': file_path =
".";
break;
175 case 'M':
if (cgv::utils::dir::exists(master_path))
176 file_path = master_path;
181 for (
unsigned int i = 0; i < path_list.size(); ++i)
182 if (cgv::utils::dir::exists(path_list[i])) {
183 file_path = path_list[i];
191 if (!parent_stack.empty()) {
192 if (cgv::utils::dir::exists(parent_stack.back()))
193 file_path = parent_stack.back();
200 for (
size_t i = parent_stack.size(); i > 0; --i) {
201 if (cgv::utils::dir::exists(parent_stack[i])) {
202 file_path = parent_stack[i];
210 if (file_path.empty()) {
213 if (uf.
query(producer +
" wants to download <" + file_name +
"> but has no path to store it. Do you want to specify a path to store the download?",
218 file_path = uf.
ask_dir(std::string(
"specify path to store ") + producer +
" downloads", master_path);
219 if (file_path.empty())
223 if (!sub_directory.empty()) {
224 if (file_path.back() !=
'/' && file_path.back() !=
'\\')
226 file_path += sub_directory;
227 if (!cgv::utils::dir::exists(file_path)) {
230 if (uf.
query(producer +
" wants to create directory <" + file_path +
"> to store downloads. Do you allow this?",
233 if (!cgv::utils::dir::mkdir(file_path)) {
235 uf.
message(std::string(
"could not create subdirectory <") + sub_directory +
"> in cache path");
241 if (file_path.back() !=
'/' && file_path.back() !=
'\\')
243 file_path += file_name;
245 std::string cmd =
"curl --output \"";
246 cmd += file_path +
"\" " + url;
250 int result = system(cmd.c_str());
251 if (result == -1 || !cgv::utils::file::exists(file_path)) {
254 if (uf.
query(std::string(
"download of <") + file_name +
"> failed. Please check internet connectivity! Try again?",
263std::string clean_data_path(
const std::string& data_path)
265 if (data_path.size() == 0)
267 unsigned int p = (
unsigned int) data_path.size()-1;
268 if (data_path[p] ==
'/' || data_path[p] ==
'\\')
269 return clean_data_path(data_path.substr(0,p));
276 static std::vector<std::string> data_path_list;
277 static bool initialized =
false;
279 char* cgv_data = getenv(
"CGV_DATA");
281 std::string cgv_data_str(cgv_data);
282 std::vector<token> data_path_tokens;
284 for (
unsigned int i=0; i<data_path_tokens.size(); ++i) {
285 std::string data_path =
to_string(data_path_tokens[i]);
286 data_path_list.push_back(clean_data_path(data_path));
291 return data_path_list;
298 if (cgv::utils::dir::exists(path_or_file_name))
300 else if (cgv::utils::file::exists(path_or_file_name))
302 else if (cgv::utils::file::get_extension(path_or_file_name).empty())
323 static std::vector<std::string> parent_file_stack;
324 return parent_file_stack;
327bool find_and_extend_system_path(std::string& file_name)
329 std::string system_paths(std::getenv(
"PATH"));
330 std::vector<cgv::utils::token> path_tokens;
339 for (
unsigned int i = 0; i<path_tokens.size(); ++i) {
340 std::string system_path =
to_string(path_tokens[i]);
341 if (cgv::utils::file::exists(system_path +
"/" + file_name)) {
342 file_name = system_path +
"/" + file_name;
352 if (file_name.substr(0,6) !=
"res://")
353 return fopen(file_name.c_str(), mode);
354 std::map<std::string, resource_file_info>::const_iterator i =
ref_resource_file_map().find(file_name.substr(6));
357 std::string source_file = i->second.source_file;
358 if (source_file.empty())
364 if (!find_and_extend_system_path(source_file)) {
365 std::cerr <<
"ERROR: could not find " << source_file <<
" to import " << i->second.file_data << std::endl;
370 unsigned int off = i->second.file_offset;
371 if (off == (
unsigned int)-1) {
372 off =
find_file_offset(source_file, i->second.file_data, i->second.file_length);
373 if (off == (
unsigned int)-1) {
374 std::cerr <<
"ERROR: could not find offset of " << i->second.file_data <<
" to import from " << source_file << std::endl;
378 FILE* fp = fopen(source_file.c_str(), mode);
380 std::cerr <<
"ERROR: could not open " << source_file <<
" to import " << i->second.file_data << std::endl;
383 fseek(fp, off, SEEK_SET);
388bool read_data_file(
const std::string& file_name, std::string& content,
bool ascii)
390 if (file_name.substr(0, 6) ==
"str://") {
391 std::map<std::string, resource_file_info>::const_iterator it =
ref_resource_file_map().find(file_name.substr(6));
394 content = it->second.file_data;
397 if (file_name.substr(0, 6) !=
"res://")
398 return file::read(file_name, content, ascii);
404 if (!fread(&content[0], 1, n, fp)) {
415 if (file_name.substr(0,6) !=
"res://")
416 return (
unsigned int) file::size(file_name.c_str());
424 char* file_data = read(file_name,
false, &file_size);
425 if (!file_data || file_size < data_size)
427 unsigned int n = (
unsigned int) (file_size-data_size);
428 char* fdata = file_data;
429 for (
unsigned int off = 0; off < n; ++off, ++fdata) {
431 for (
unsigned int i = 0; i < data_size; ++i) {
432 if (
data[i] != fdata[i]) {
the tokenizer allows to split text into tokens in a convenient way.
tokenizer & set_ws(const std::string &ws)
set the list of white spaces, that separate tokens and are skipped
the base namespace holds the base hierarchy, support for plugin registration and signals
std::string std_ask_dir(const std::string &text, const std::string &path)
std::cout and std::cin based implementation of the ask_dir function for third argument to the user_fe...
std::string & ref_prog_path_prefix()
return a refence to the path prefix of the started executable, this can be prepended for example to d...
std::string find_or_download_data_file(const std::string &file_name, const std::string &find_strategy, const std::string &url, const std::string &cache_strategy, const std::string &producer, const std::string &sub_directory, const std::string &master_path, user_feedback uf)
same as find_data_file() but in case file is not found, it is downloaded from the provided url and st...
void stderr_message(const std::string &text)
std::cerr based implementation of the message function for first argument to the user_feedback constr...
int std_query(const std::string &text, const std::string &answers, int default_answer)
std::cout and std::cin based implementation of the query function for second argument to the user_fee...
unsigned int find_file_offset(const std::string &file_name, const char *data, unsigned int data_size)
find the offset of the given data block in the given file
void pop_file_parent()
pop the latestly pushed parent path from the parent path stack.
void push_file_parent(const std::string &path_or_file_name)
extract a valid path from the given argument and push it onto the stack of parent paths....
std::vector< std::string > & ref_parent_file_stack()
return a reference to the data path list, which is constructed from the environment variable CGV_DATA
bool read_data_file(const std::string &file_name, std::string &content, bool ascii)
read ascii file into a string
std::vector< std::string > & ref_data_path_list()
return a reference to the data path list, which is constructed from the environment variable CGV_DATA
FILE * open_data_file(const std::string &file_name, const char *mode)
open a file with fopen supporting resource files, that have the prefix "res://"
std::map< std::string, resource_file_info > & ref_resource_file_map()
return a reference to a mapping of resource file names to resource file infos
std::string find_data_file(const std::string &file_name, const std::string &strategy, const std::string &sub_directory, const std::string &master_path)
Find a file with the given strategy and return the file name extended by the necessary path.
std::string & ref_prog_name()
return a refence to the name of the started executable
unsigned int data_file_size(const std::string &file_name)
return the file size of a given file with support for resource files, that have the prefix "res://"
void stdout_message(const std::string &text)
std::cout based implementation of the message function for first argument to the user_feedback constr...
namespace for data management components
namespace that holds tools that dont fit any other namespace
std::string to_string(const std::string &v, unsigned int w, unsigned int p, bool)
specialization of conversion from string to strings
void bite_all(tokenizer &t, std::vector< token > &result)
bite all tokens into a token vector
this header is dependency free
function pointers implementing user feedback functionality of find_or_download_data_file() function
void(* message)(const std::string &text)
pointer to function that shows a text message to user
int(* query)(const std::string &text, const std::string &answers, int default_answer)
pointer to function that shows a text query and asks for an answer
std::string(* ask_dir)(const std::string &text, const std::string &path)
pointer to function that opens a directory save dialog