Files
geant4/source/analysis/g4tools/include/tools/file
T
2016-12-09 12:35:28 +01:00

605 lines
14 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_file
#define tools_file
#include "gzip"
#include "forit"
#include "words" //is_hippo
#include "path" //suffix
#include "S_STRING"
#include <cstdlib>
#include <cstring>
#ifdef TOOLS_MEM
#include "mem"
#endif
namespace tools {
namespace file {
inline bool exists(const std::string& a_string) {
FILE* file = ::fopen(a_string.c_str(),"rb");
if(!file) return false;
::fclose(file);
return true;
}
inline bool write(const std::string& a_file,const std::string& a_string) {
// a_string could contain \n separated lines.
FILE* file = ::fopen(a_file.c_str(),"wb");
if(!file) return false;
if(::fprintf(file,"%s",a_string.c_str())<0) {
::fclose(file);
return false;
}
::fclose(file);
return true;
}
inline bool write(const std::string& a_file,const std::vector<std::string>& a_text){
FILE* file = ::fopen(a_file.c_str(),"wb");
if(!file) return false;
tools_vforcit(std::string,a_text,it) {
if(::fprintf(file,"%s\n",(*it).c_str())<0) {
::fclose(file);
return false;
}
}
::fclose(file);
return true;
}
inline bool read_buff(FILE* a_file,char* a_buff,unsigned int a_lbuf,size_t& a_length) {
a_length = ::fread(a_buff,1,a_lbuf,a_file);
return true;
}
inline bool read_cstring(FILE* a_file,char* a_buff,unsigned int a_lbuf,size_t& a_length) {
if(::fgets(a_buff,a_lbuf,a_file)==NULL) {
a_length = 0;
return false; //EOF
}
size_t l = ::strlen(a_buff);
// On Windows, editors when saving binary files,
// put \r\n at place of \n ; we then look for \r\n.
if( (l>=2) && (a_buff[l-2]=='\r') && (a_buff[l-1]=='\n') ) {
a_buff[l-2] = '\0';
l -= 2;
} else if( (l>=1) && (a_buff[l-1]=='\n') ) {
a_buff[l-1] = '\0';
l -= 1;
}
a_length = l;
return true;
}
inline bool read(const std::string& a_file,std::vector<std::string>& a_text){
a_text.clear();
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) return false;
unsigned int BUFSIZE = 65536;
char* buffer = new char[BUFSIZE+1];
if(!buffer) {::fclose(file);return false;}
while(true) {
size_t l;
if(!read_cstring(file,buffer,BUFSIZE,l)) break; // EOF.
a_text.push_back(buffer);
}
delete [] buffer;
::fclose(file);
return true;
}
inline bool read_num(const std::string& a_file,std::vector<std::string>::size_type a_num,std::vector<std::string>& a_text,const std::string& a_cmt = ""){
a_text.clear();
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) return false;
unsigned int BUFSIZE = 65536;
char* buffer = new char[BUFSIZE+1];
if(!buffer) {::fclose(file);return false;}
while(true) {
size_t l;
if(!read_cstring(file,buffer,BUFSIZE,l)) break; // EOF.
if(a_cmt.size()&&(!strncmp(a_cmt.c_str(),buffer,a_cmt.size()))) continue;
if(a_text.size()<a_num) {
a_text.push_back(buffer);
} else {
break;
}
}
delete [] buffer;
::fclose(file);
return true;
}
inline bool read_bytes(const std::string& a_file,char*& a_buffer,long& a_length){
// Returned buffer should be deleted with delete [].
FILE* file = ::fopen(a_file.c_str(),"rb");
if(!file) {
a_buffer = 0;
a_length = 0L;
return false;
}
// Get file size :
::fseek(file,0L,SEEK_END);
long filesize = ::ftell(file);
if(!filesize) {
::fclose(file);
a_buffer = new char[1];
#ifdef TOOLS_MEM
mem::increment(s_new().c_str());
#endif
a_length = 0L;
return true; //empty file.
}
// Add one byte to be able to add \n if file contain lines.
a_buffer = new char[filesize+1];
if(!a_buffer) {
::fclose(file);
a_buffer = 0;
a_length = 0L;
return false;
}
#ifdef TOOLS_MEM
mem::increment(s_new().c_str());
#endif
::rewind(file);
size_t nitem = ::fread(a_buffer,(size_t)filesize,(size_t)1,file);
if(nitem!=1){
::fclose(file);
delete [] a_buffer;
#ifdef TOOLS_MEM
mem::decrement(s_new().c_str());
#endif
a_buffer = 0;
a_length = 0L;
return false;
}
::fclose(file);
a_buffer[filesize] = 0;
a_length = filesize;
return true;
}
inline bool write_bytes(const std::string& a_file,const char* a_buffer,size_t a_length){
FILE* file = ::fopen(a_file.c_str(),"wb");
if(!file) return false;
if(!a_length) {
::fclose(file);
return true;
}
size_t nitem = ::fwrite((char*)a_buffer,a_length,(size_t)1,file);
::fclose(file);
return (nitem!=1?false:true);
}
inline bool num_csv_doubles(const std::string& a_string,char& a_sep,unsigned int& a_number){
if(a_string.empty()) {a_sep=0;a_number=0;return true;} //it is ok.
//guess sep :
char sep = 0;
{const char* buffer = a_string.c_str();
//::printf("debug : |%s|\n",buffer);
const char* pos = buffer;
const char* mx = buffer+a_string.size();
char* end;
{double d = ::strtod(pos,&end);(void)d;}
//::printf("debug : d first %g\n",d);
if(end==pos) {a_sep=0;a_number=0;return false;} //not starting with a number.
if(end==mx) {a_sep=0;a_number=1;return true;} //is ok, one number only.
sep = *end;}
//::printf("debug : %d\n",sep);
unsigned int number = 0;
const char* buffer = a_string.c_str();
//::printf("debug : |%s|\n",buffer);
const char* pos = buffer;
const char* mx = buffer+a_string.size();
while(true) {
char* end;
{double d = ::strtod(pos,&end);(void)d;}
if(end==pos) {
if(end>=mx) break;
a_sep = sep;
a_number = number;
return false; //since a number expected.
}
//::printf("debug : d %g\n",d);
number++;
if(*end!=sep) {
if(end>=mx) break;
a_sep = sep;
a_number = number;
return false; //since a sep is expected.
}
pos = end+1;
if(pos>mx) break;
}
a_sep = sep;
a_number = number;
return true;
}
// NOTE : take care of the open in exlib/app/tntnet/main_cpp which can't work by using suffix.
inline bool is_hippo(const std::string& a_file,bool& a_is){
//if((suffix(a_file)=="hiptxt")||(suffix(a_file)=="tnt")) {
// a_is = true;
// return true;
//}
// An hippo file as :
// one line for title.
// one line with n labels separated by \t
// data lines with n numbers separated by a char sep (not necessary \t) (at least one data line expected).
std::vector<std::string> txt;
if(!file::read_num(a_file,3,txt)) {a_is=false;return false;}
if(txt.size()<3) {a_is=false;return true;}
char csep;
unsigned int number;
if(!num_csv_doubles(txt[2],csep,number)) {a_is=false;return true;}
std::vector<std::string> words;
tools::words(txt[1],"\t",false,words);
if(words.size()!=number) {a_is=false;return true;}
bool all_doubles = true;
tools_vforcit(std::string,words,it) {
const char* pos = (*it).c_str();
char* end;
double d = ::strtod(pos,&end);(void)d;
if(end==pos) {all_doubles=false;break;}
}
a_is = all_doubles?false:true; //all_double=false then we assume the second line is labels of columns.
return true;
}
// NOTE : the below is_csv() does not take into account a column with strings.
inline bool is_csv(const std::vector<std::string>& a_txt,bool& a_is){
//a_sep = 0;
a_is = false;
if(a_txt.empty()) return true;
//guess sep from first data line :
char sep = 0;
{const char* buffer = a_txt[0].c_str();
//::printf("debug : |%s|\n",buffer);
const char* pos = buffer;
char* end;
{double d = ::strtod(pos,&end);(void)d;}
//::printf("debug : d first %g\n",d);
if(end==pos) return true; //not starting with a number.
//end==mx is ok, one column only.
sep = *end;}
//::printf("debug : %d\n",sep);
unsigned int first_coln = 0;
tools_vforcit(std::string,a_txt,it) {
const char* buffer = (*it).c_str();
//::printf("debug : |%s|\n",buffer);
const char* pos = buffer;
const char* mx = buffer+(*it).size();
unsigned int coln = 0;
while(true) {
char* end;
{double d = ::strtod(pos,&end);(void)d;}
if(end==pos) break;
//::printf("debug : d %g\n",d);
if(*end!=sep) return true;
coln++;
pos = end+1;
if(pos>mx) break;
}
//::printf("debug : coln %d\n",coln);
if(it==a_txt.begin()) {
first_coln = coln;
} else {
if(coln!=first_coln) return true;
}
}
//a_sep = sep;
a_is = true;
return true;
}
inline bool is_csv(const std::string& a_file,bool& a_is){
// look at suffix. Some file can't be guessed.
if(suffix(a_file)=="csv") {a_is = true;return true;}
//try to guess :
std::vector<std::string> txt;
if(!file::read_num(a_file,3,txt,"#")) {a_is=false;return false;}
return is_csv(txt,a_is);
}
inline bool is_lua(const std::string& a_file,bool& a_is){
// look at suffix. Some file can't be guessed.
if(suffix(a_file)=="lua") {a_is = true;return true;}
//try to guess ?
a_is = false;
return true;
}
inline bool is_py(const std::string& a_file,bool& a_is){
// look at suffix. Some file can't be guessed.
if(suffix(a_file)=="py") {a_is = true;return true;}
//try to guess ?
a_is = false;
return true;
}
}}
#include "fileis"
namespace tools {
namespace file {
inline bool mime_type(const std::string& a_file,std::string& a_mime){
////////////////
// binaries :
////////////////
{bool is;
if(is_jpeg(a_file,is)&&is) {
a_mime = "image/jpeg";
return true;
}}
{bool is;
if(is_png(a_file,is)&&is) {
a_mime = "image/png";
return true;
}}
{bool is;
if(is_ico(a_file,is)&&is) {
a_mime = "image/vnd.microsoft.icon";
return true;
}}
{bool is;
if(is_fits(a_file,is)&&is) {
a_mime = "image/fits";
return true;
}}
{bool is;
if(is_gzip(a_file,is)&&is) {
a_mime = "application/gzip";
return true;
}}
{bool is;
if(is_zip(a_file,is)&&is) {
a_mime = "application/zip";
return true;
}}
{bool is;
if(is_root(a_file,is)&&is) {
a_mime = "application/octet-stream";
return true;
}}
////////////////
// text :
////////////////
{bool is;
if(is_aida(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_exsg(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_scenarios(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_slides(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_gdml(a_file,is)&&is) {
a_mime = "text/xml";
return true;
}}
{bool is;
if(is_ps(a_file,is)&&is) {
a_mime = "application/postscript";
return true;
}}
{bool is;
if(is_fog(a_file,is)&&is) {
a_mime = "text/plain";
return true;
}}
{bool is;
if(is_csv(a_file,is)&&is) {
a_mime = "text/csv";
return true;
}}
{bool is;
if(is_hippo(a_file,is)&&is) {
a_mime = "text/plain";
return true;
}}
{bool is;
if(is_dot(a_file,is)&&is) {
a_mime = "text/plain";
return true;
}}
{bool is;
if(is_iv(a_file,is)&&is) {
a_mime = "application/octet-stream";
return true;
}}
a_mime = "application/octet-stream";
return false;
}
/*
inline bool copy(const std::string& a_from,const std::string& a_to){
if(a_to==a_from) return true; //done
std::vector<std::string> text;
if(!file::read(a_from,text)) return false;
return file::write(a_to,text);
}
*/
inline bool found(const std::string& a_file,const std::string& a_what,std::vector<std::string>& a_found){
a_found.clear();
std::vector<std::string> text;
if(!file::read(a_file,text)) return false;
tools_vforcit(std::string,text,it) {
if((*it).find(a_what)!=std::string::npos) {
a_found.push_back(*it);
}
}
return true;
}
inline bool std_remove(const std::string& a_file) {
if(a_file.empty()) return true;
return (::remove(a_file.c_str()) ==0 ? true : false);
}
inline bool std_remove(std::vector<std::string>& a_files) {
bool status = true;
tools_vforit(std::string,a_files,it) {
if(!std_remove(*it)) status = false;
}
a_files.clear();
return status;
}
inline bool std_rename(const std::string& a_from,const std::string& a_to) {
//NOTE : a_from must not be a path !
// Darwin is ok with a path but not Linux !
// For example :
// ::rename("/tmp/tmp01"."x");
// return -1 on Linux.
// To do the upper then someone must use move.
// But there is no move in the standard lib C !
return (::rename(a_from.c_str(),a_to.c_str()) == 0 ? true : false);
}
inline bool copy_bytes(const std::string& a_from,const std::string& a_to) {
if(a_to==a_from) return true;
char* buffer;
long length;
if(!read_bytes(a_from,buffer,length)) return false;
bool status = write_bytes(a_to,buffer,(size_t)length);
delete [] buffer;
#ifdef TOOLS_MEM
mem::decrement(s_new().c_str());
#endif
return status;
}
/*
class holder {
public:
TOOLS_SCLASS(tools::file::holder)
public:
holder(const std::string& a_path):m_path(a_path){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
virtual ~holder() {
std_remove(m_path);
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
public:
holder(const holder& a_from):m_path(a_from.m_path){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
holder& operator=(const holder& a_from){
m_path = a_from.m_path;
return *this;
}
protected:
std::string m_path;
};
*/
}}
#include "file_reader"
namespace tools {
class FILE_reader : public virtual file::reader {
public: //file_reader
virtual bool open(const std::string& a_file) {
if(m_FILE) return false;
m_FILE = ::fopen(a_file.c_str(),"rb");
if(!m_FILE) return false;
return true;
}
virtual void close() {
if(!m_FILE) return;
::fclose(m_FILE);
m_FILE = 0;
}
virtual bool is_open() const {return m_FILE?true:false;}
virtual bool read(char* a_buff,unsigned int a_lbuf,size_t& a_length) {
a_length = ::fread(a_buff,1,a_lbuf,m_FILE);
return true;
}
virtual bool get_line(char* a_buff,unsigned int a_lbuf) {
return ::fgets(a_buff,a_lbuf,m_FILE)==NULL?false:true;
}
virtual bool eof() const {
#if defined(_MSC_VER) && _MSC_VER <= 1400
return feof(m_FILE)?true:false;
#else
return ::feof(m_FILE)?true:false;
#endif
}
public:
FILE_reader():m_FILE(0){}
virtual ~FILE_reader() {if(m_FILE) ::fclose(m_FILE);}
protected:
FILE_reader(const FILE_reader& a_from)
:file::reader(a_from)
,m_FILE(0)
{}
FILE_reader& operator=(const FILE_reader&){return *this;}
protected:
FILE* m_FILE;
};
}
#include "file_format" //backcomp
#include "fsize" //backcomp
#endif