Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
FileHandling.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5 Multimediale Systeme der Informationsverarbeitung
6 Institut fuer Informatik
7 Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 // must be first:
25 //#include "precompiled.h"
26 
27 #define _CRT_SECURE_NO_DEPRECATE
28 #include <stdio.h>
29 
30 #include "FileHandling.hh"
31 
32 #ifdef WIN32
33 # include <Base/Common/W32Compat.hh>
34 # include <direct.h>
35 # include <time.h>
36 # include <windows.h>
37 #else //WIN32
38 # include <unistd.h>
39 # include <sys/time.h>
40 # include <sys/types.h>
41 # include <dirent.h>
42 # include <dlfcn.h>
43 #endif //WIN32
44 # include <sys/stat.h>
45 #include <math.h>
46 
47 // STD
48 #include <iostream>
49 #include <fstream>
50 #include <iomanip> // for std::setw, std::setfill
51 
52 // BIAS
53 #include "Base/Debug/Error.hh"
54 
55 // for transform:
56 #include <algorithm>
57 #include <cctype>
58 
59 #ifdef WIN32
60 # include <direct.h> // _getcwd
61 #endif
62 
63 using namespace std;
64 using namespace BIAS;
65 
66 namespace BIAS
67 {
68 
69  int FileHandling::RemoveDir(const string &subdir)
70  {
71  string command;
72  int res=0;
73 #ifdef WIN32
74  command ="rmdir /S /Q "+subdir;
75 #else
76  command = "rm -rf "+subdir;
77 #endif
78  res = system(command.c_str());
79  if (res<0) {
80  perror(command.c_str());
81  return -1;
82  }
83  return 0;
84  }
85 
86  int FileHandling::CreateDir(const string &subdir)
87  {
88  string command;
89  int res=0;
90 #ifdef WIN32
91  command ="md "+subdir;
92 #else
93  command = "mkdir "+subdir;
94 #endif
95 
96  res = system(command.c_str());
97  if (res<0) {
98  perror(command.c_str());
99  return -1;
100  }
101  return 0;
102  }
103 
104  int FileHandling::CreateDirRecursive(const string &dir)
105  {
106  vector<string> parts;
107  FileHandling::SplitPath(dir, parts);
108  if (!parts.empty())
109  {
110  // create all subdirectory names
111  vector<string> subdirs(parts.size());
112 #ifdef WIN32
113  subdirs[0] = (FileHandling::IsAbsolute(dir) ? "" : ".\\") + parts[0];
114 #else
115  subdirs[0] = (FileHandling::IsAbsolute(dir) ? "/" : "./") + parts[0];
116 #endif
117  for (unsigned int i = 1; i < parts.size(); i++) {
118 #ifdef WIN32
119  subdirs[i] = subdirs[i-1] + "\\" + parts[i];
120 #else
121  subdirs[i] = subdirs[i-1] + "/" + parts[i];
122 #endif
123  }
124  // find last existing subdirectory
125  int last = (int)subdirs.size()-1;
126  while (!FileHandling::FileExists(subdirs[last]) && last >= 0) last--;
127  // create all subdirectories from last existing on
128  int res = 0;
129  for (int j = last+1; j < (int)subdirs.size() && res == 0; j++) {
130  res = FileHandling::CreateDir(subdirs[j]);
131  }
132  return res;
133  }
134  // nothing to do, return OK (application path is assumed to exist)
135  return 0;
136  }
137 
138  bool FileHandling::FileExists(const string &file)
139  {
140  struct stat statbuf;
141  int res = stat(file.c_str(), &statbuf);
142 
143  if (res < 0) return false;
144  else return true;
145  }
146 
147  int FileHandling::GetDirectoryContent(const string &Dir,
148  const string &prefix,
149  const string &suffix,
150  vector<string> &content,
151  const bool GetFullPath)
152  {
153  string filename;
154  int pl = (int)prefix.length();
155  int sl = (int)suffix.length();
156  content.clear();
157 
158 #ifdef WIN32
159  std::string tmp = Dir+"/*";
160 
161  TCHAR searchPath[MAX_PATH];
162  // a wildcard needs to be added to the end of the path, e.g. "C:\*"
163  lstrcpy(searchPath, tmp.c_str());
164  // PathAppend(searchPath, "*"); // defined in shell lightweight API (v4.71)
165 
166  WIN32_FIND_DATA ffd; // file information struct
167  HANDLE sh = FindFirstFile(searchPath, &ffd);
168  if(INVALID_HANDLE_VALUE == sh) return -1; // not a proper path i guess
169 
170  // enumerate all items; NOTE: FindFirstFile has already got info for an item
171  do {
172  //std::cout << "Name = " << ffd.cFileName << std::endl;
173  //std::cout << "Type = " << ( (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
174  // ? "dir\n" : "file\n" );
175  //std::cout << "Size = " << ffd.nFileSizeLow << std::endl;
176  filename = ffd.cFileName;
177  if (filename ==".." || filename==".") continue;
178 
179  int l = (int)filename.length();
180  if (pl ==0 || (l>=pl && filename.substr(0,pl) == prefix)) {
181  if (sl==0 || (l>=sl && filename.substr(l-sl,sl) ==suffix)) {
182  if (GetFullPath) content.push_back(Dir+"/"+filename);
183  else content.push_back(filename);
184  }
185  }
186 
187  } while (FindNextFile(sh, &ffd));
188 
189  FindClose(sh);
190 #else
191  DIR *dp;
192  struct dirent *ep;
193  dp = opendir (Dir.c_str());
194  if (dp == NULL) {
195  perror (Dir.c_str());
196  return -1;
197  }
198  while ( (ep = readdir (dp)) != NULL) {
199  filename = ep->d_name;
200  if (filename ==".." || filename==".") continue;
201  // cout <<Dir<<" filename: "<<filename<<endl;
202  int l = filename.length();
203  if (pl ==0 || (l >= pl && filename.substr(0,pl) == prefix)) {
204  // cout <<"Prefix matched"<<endl;
205  if (sl==0 || (l >= sl && filename.substr(l-sl,sl) ==suffix)) {
206  //cout <<"Suffix matched"<<endl;
207  if (GetFullPath) content.push_back(Dir+"/"+filename);
208  else content.push_back(filename);
209  }
210  }
211  }
212  (void) closedir (dp);
213 #endif
214  return 0;
215  }
216 
217  bool FileHandling::FileReadable(const std::string &filename)
218  {
219  ifstream ifs(filename.c_str());
220  // OK determines if file stream could be opened and is readable
221  bool ok = ifs.good();
222  ifs.close();
223  return ok;
224  }
225 
226  bool FileHandling::CopyFileTo(const std::string &oldFilename,
227  const std::string &newFilename)
228  {
229  bool res = false;
230  std::ifstream fin(oldFilename.c_str(), std::fstream::binary);
231  if (fin) {
232  std::ofstream fout(newFilename.c_str(), std::fstream::trunc | std::fstream::binary);
233  if (fout) {
234  fout << fin.rdbuf();
235  fout.close();
236  res = true;
237  }
238  fin.close();
239  }
240  return res;
241  }
242 
243  void FileHandling::SplitName(const std::string &fullname,
244  string &dir, string &base, string &suffix )
245  {
246  // find from right, regular expression: dir/subdir/base.ext
247 #ifdef WIN32
248  // separator for directory (both slashes are possible)
249  string::size_type tmp1 = fullname.rfind('\\');
250  string::size_type tmp2 = fullname.rfind('/');
251  string::size_type posL;
252  if (tmp1 == std::string::npos)
253  posL = tmp2;
254  else if (tmp2 == std::string::npos)
255  posL = tmp1;
256  else
257  posL = (tmp1>tmp2)?tmp1:tmp2;
258 #else
259  string::size_type posL = fullname.rfind('/'); // separator for directory
260 #endif
261  string::size_type posR = fullname.rfind('.'); // separator for suffix
262 
263  // which separators were found?
264  bool foundDir = (posL!=std::string::npos);
265  bool foundSuf = (posR!=std::string::npos);
266 
267  // bugfix: "." may appear as first character of directory names also,
268  // make sure that this is not the case here
269  if (foundSuf) {
270  if (posR > 0) {
271  if (fullname.at(posR-1) == '\\' || fullname.at(posR-1) == '/') {
272  foundSuf = false;
273  }
274  } else {
275  foundSuf = false;
276  }
277  }
278 
279  if (foundDir && foundSuf) {
280  // found path and suffix, base is inner part
281  dir = fullname.substr(0, posL+1 ); // start, length
282  base = fullname.substr(posL+1, (posR-posL-1) );
283  if (posL<posR)
284  suffix = fullname.substr(posR, (fullname.size()-posR) );
285  else
286  suffix = "";
287 
288  } else if (foundDir && !foundSuf) {
289  dir = fullname.substr(0, posL+1 ); // start, length
290  base = fullname.substr(posL+1, (fullname.size()-posL) );
291  suffix = ""; // no suffix found.
292 
293  } else if (!foundDir && foundSuf) {
294  dir = "";
295  base = fullname.substr(0, posR);
296  suffix = fullname.substr(posR, (fullname.size()-posR) );
297 
298  } else {
299  // given string is already a basename
300  // BIASWARN("Failed to split path, no delimiters found!");
301  dir="";
302  base=fullname;
303  suffix="";
304  }
305  }
306 
307  std::string FileHandling::Directory(const std::string &fullname)
308  {
309  string dir, base, suf;
310  FileHandling::SplitName(fullname, dir, base, suf);
311  return dir;
312  }
313 
314  std::string FileHandling::Basename(const std::string &fullname)
315  {
316  string dir, base, suf;
317  FileHandling::SplitName(fullname, dir, base, suf );
318  return base;
319  }
320 
321  std::string FileHandling::Suffix(const std::string &fullname)
322  {
323  string dir, base, suf;
324  FileHandling::SplitName(fullname, dir, base, suf );
325  return suf;
326  }
327 
328  std::string FileHandling::Extension(const std::string &fullname)
329  {
330  string suf = Suffix(fullname);
331  string ext = suf;
332 
333  // remove the dot to get extension from suffix
334  string::size_type pos = suf.rfind('.'); // separator
335  const bool found = (pos!=std::string::npos);
336 
337  // cut the dot if found, keep full extension otherwise
338  if (found)
339  ext = suf.substr(pos+1, (suf.size()-pos-1) );
340 
341  return ext;
342  }
343 
344  std::string FileHandling::Filename(const std::string &fullname)
345  {
346  string dir, base, suf;
347  FileHandling::SplitName(fullname, dir, base, suf);
348  return base+suf;
349  }
350 
351  std::string FileHandling::DirectoryAndBasename(const std::string &fullname)
352  {
353  string dir, base, suf;
354  FileHandling::SplitName(fullname, dir, base, suf);
355  string dir_and_base="";
356  if(dir.size()>0){
357  dir_and_base = dir;
358 #ifdef WIN32
359  dir_and_base += ('\\');
360 #else
361  dir_and_base += ('/');
362 #endif
363  }
364  dir_and_base += base;
365 
366  return dir_and_base;
367  }
368 
369  void FileHandling::SplitPath(const string &fullpath,
370  vector<string> &result)
371  {
372 #ifdef WIN32
373  const string delimiters = "\\/";
374 #else
375  const string delimiters = "/";
376 #endif
377  result.clear();
378  string str = fullpath;
379  string::size_type pos = str.find_first_of(delimiters);
380  while (pos != string::npos) {
381  if (pos > 0){
382  result.push_back(str.substr(0, pos));
383  }
384  str = str.substr(pos+1);
385  pos = str.find_first_of(delimiters);
386  }
387  if (str.length() > 0) {
388  result.push_back(str);
389  }
390  }
391 
392  void FileHandling::LogCommandLine(int argc, char** argv, std::ostream &os)
393  {
394  for (int i=0; i<argc; i++){
395  os<<argv[i]<<" "<<endl;
396  }
397  os<<endl;
398  os<<"argc="<<argc<<endl;
399  for (int i=0; i<argc; i++){
400  os<<"argv["<<i<<"]="<<argv[i]<<endl;
401  }
402  os<<flush;
403  }
404 
405  void FileHandling::LogCommandLine(int argc, char** argv,
406  const std::string &filename)
407  {
408  ofstream ofs;
409  ofs.open(filename.c_str()); //, ios::app);
410  if (!ofs.good()) {
411  BIASERR("Failed to open "<<filename<<" for LogCommandLine!")
412  LogCommandLine(argc, argv, std::cout);
413  } else {
414  LogCommandLine(argc, argv, ofs);
415  }
416  ofs.close();
417  }
418 
419  std::string FileHandling::LeadingZeroString(const int &n,
420  const unsigned int &digits )
421  {
422  return FileHandling::toString(n, digits);
423  }
424 
425  char FileHandling::ToLower_c(char c) {
426  return char(tolower(c));
427  }
428 
429  char FileHandling::ToUpper_c(char c) {
430  return char(toupper(c));
431  }
432 
433  std::string FileHandling::LowerCase(const std::string &input)
434  {
435  string s(input);
436  // convert each char to lower case
437  transform(s.begin(), s.end(), s.begin(), ToLower_c);
438  return s;
439  }
440 
441  std::string FileHandling::UpperCase(const std::string &input)
442  {
443  string s(input);
444  // convert each char to lower case
445  transform(s.begin(), s.end(), s.begin(), ToUpper_c);
446  return s;
447  }
448 
449  std::string FileHandling::CurrentDateTimeString()
450  {
451  time_t tim = time(NULL);
452  tm *now = localtime(&tim);
453  // printf("Date is %d/%02d/%02d\n", now->tm_year+1900,
454  // now->tm_mon+1, now->tm_mday);
455  // printf("Time is %02d:%02d\n", now->tm_hour, now->tm_min);
456 
457  stringstream sstime;
458  sstime << setw(4) << setfill('0') << now->tm_year+1900
459  << setw(2) << setfill('0') << now->tm_mon+1
460  << setw(2) << setfill('0') << now->tm_mday << "_"
461  << setw(2) << setfill('0') << now->tm_hour
462  << setw(2) << setfill('0') << now->tm_min
463  << setw(2) << setfill('0') << now->tm_sec;
464 
465  return sstime.str();
466  }
467 
468 
469  int FileHandling::ExtractNumberFromRight(const std::string &inStr,
470  int &number, int &posL, int &posR)
471  {
472  // parse numeric part of string from right
473  number=0;
474  posL=posR=0;
475 
476  bool done=false;
477  bool numericStarted=false;
478  //bool numericEnded=false; //unused
479  int exp10=0;
480  int current = (int)inStr.size()-1;
481  while (!done && current>=0)
482  {
483  const char c=inStr[current];
484  switch (c) {
485  case '0':
486  case '1':
487  case '2':
488  case '3':
489  case '4':
490  case '5':
491  case '6':
492  case '7':
493  case '8':
494  case '9':
495  { // numerical character: weight digit with current exponent
496  if (!numericStarted){
497  numericStarted=true;
498  posR=current;
499  }
500  const int act =atoi(&c);
501  const int addAct = int(act*pow(10.0, exp10 ));
502  number += addAct;
503  // next exponent
504  exp10++;
505  break;
506  }
507  default:
508  { // non-numerical character
509  if (numericStarted){
510  //bool numericEnded=true; //unused
511  posL=current+1;
512  done=true;
513  }
514  }
515  }; // switch
516  current--;
517  }// while
518 
519  // found at least one digit?
520  if (!numericStarted) {
521  //BIASWARN("could not extract digit from "<<inStr);
522  return -1;
523  }
524 
525  return 0;
526  }
527 
528  int FileHandling::FilenameSequence(const std::string & refFileName,
529  std::string & resultFilename,
530  const int & offsetFromRef,
531  const unsigned int & stepsize )
532  {
533  // extract directory and extension which are kept
534  string dir, base, suffix;
535  SplitName(refFileName, dir, base, suffix );
536 
537  // extract numeric part of base filename from right
538  int actIndex=0; //< act. index
539  int posL=0, posR=0; //< cutout positione
540  int result=ExtractNumberFromRight(base, actIndex, posL, posR );
541  if (result!=0){
542  BIASERR("could not extract digit from base="<<base)
543  return result; // err.
544  }
545 
546  // OK
547  const int numberOfDigits = posR-posL+1;
548  BIASASSERT(numberOfDigits>0);
549 
550  // compute new index based on old index
551  int newIndex = actIndex +offsetFromRef*stepsize;
552 
553  // construct new filename
554  string basePrefix = base.substr(0, posL); // start, length
555  string basePostfix = base.substr(posR+1, (base.size()-numberOfDigits));
556  resultFilename = dir + (basePrefix + FileHandling::LeadingZeroString(newIndex,numberOfDigits) + basePostfix)
557  + suffix;
558  return 0;
559  }
560 
561  int FileHandling::FilenameExpansion(const std::string &in, std::string & out)
562  {
563  out = in;
564  // replace tilde prefix?
565  if (in.size()>1){
566  if (in[0]=='~'){
567  // like tcsh/bash shell expansion
568  string tilde = getenv("HOME");
569  if (tilde=="")
570  {
571  // useful for WIN32: if no HOME is set use HOMEDRIVE+HOMEPATH instead
572  string homedrive = getenv("HOMEDRIVE");
573  string homepath = getenv("HOMEPATH");
574  //const string profile = getenv("USERPROFILE");
575  // replace \ by / to avoid excaped characters
576  const char backslash='\\';
577  const char fwdslash='/';
578  unsigned int n=0;
579  for (n=0; n<homedrive.size(); n++)
580  if (homedrive[n]==backslash)
581  homedrive[n]=fwdslash;
582  for (n=0; n<homepath.size(); n++)
583  if (homepath[n]==backslash)
584  homepath[n]=fwdslash;
585  //for (n=0; n<profile.size(); n++)
586  // if (profile[n]==backslash)
587  // profile[n]=fwdslash;
588 
589  tilde=homedrive+homepath;
590  }
591  if (out.size()>0) {
592  out.replace(0, 1, tilde); // do replacement
593  }
594  }
595  }
596  return 0;
597  }
598 
599  std::string FileHandling::GetCwd()
600  {
601  string s;
602 #if defined(WIN32)
603  { // scope of buf
604  // NULL triggers dynamic new/allocation by getcwd, works for long NTFS paths
605  char * buf = _getcwd( NULL, 0 );
606  if (buf==NULL){
607  BIASERR("_getcwd error");
608  perror( "_getcwd error");
609  BIASBREAK;
610  } else {
611  // copy to std string
612  s=buf;
613  }
614  free(buf);
615  }
616 #else
617  char currentdir[1024];
618  //getcwd(currentdir, 1024);
619  char *cwd = getcwd(currentdir, 1024);
620  if (!cwd){
621  BIASERR("error getcwd()")
622  perror("");
623  }
624  else s = cwd;
625 #endif
626  return s;
627  }
628 
629  int FileHandling::ChDir(const std::string &dir)
630  {
631 #ifdef WIN32
632  return _chdir(dir.c_str());
633 #else
634  return chdir(dir.c_str());
635 #endif
636  }
637 
638  std::string FileHandling::GetApplicationPath()
639  {
640  string s;
641 #if defined(WIN32)
642  TCHAR szPathName[_MAX_PATH];
643  ::GetModuleFileName(NULL, szPathName, _MAX_PATH);
644  s = szPathName;
645  BIASERR("Module: "<<s);
646 #else
647  BIASERR("not implemented")
648 #endif
649  return s;
650  }
651 
652 }
653 
654 bool FileHandling::IsAbsolute(const std::string &path)
655 {
656  if (!path.empty()) {
657 #ifdef WIN32
658  return (path.find(string(":\\")) != string::npos);
659 #else
660  return (path[0] == '/');
661 #endif
662  }
663  return false;
664 }