1 //---
2 //
3 // License: MIT
4 //
5 // Description: This class provides manipulation of filenames.
6 //
7 //---
8 // $Id$
9 
10 #include <ossim/ossimConfig.h>  /* to pick up platform defines */
11 
12 #include <ossim/base/ossimFilename.h>
13 #include <ossim/base/ossimFileInfoInterface.h>
14 #include <ossim/base/ossimCommon.h>
15 #include <ossim/base/ossimConstants.h>
16 #include <ossim/base/ossimDirectory.h>
17 #include <ossim/base/ossimDate.h>
18 #include <ossim/base/ossimEnvironmentUtility.h>
19 #include <ossim/base/ossimNotify.h>
20 #include <ossim/base/ossimRegExp.h>
21 #include <ossim/base/ossimStreamFactoryRegistry.h>
22 
23 
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cstring>
27 #include <cerrno>
28 #include <iostream>
29 #include <fstream>
30 using namespace std;
31 
32 #if defined(_WIN32)
33 #  include <io.h>
34 #  include <direct.h>
35 #  include <sys/utime.h>
36 #  include <windows.h>
37 #else
38 #  include <sys/types.h>
39 #  include <utime.h>
40 #  include <sys/stat.h>
41 #  include <unistd.h>
42 #  include <dirent.h>
43 #  include <fcntl.h>
44 #endif
45 
46 #include <sys/stat.h>
47 
48 #ifdef __BORLANDC__
49 #  include <dir.h>
50 #  include <direct.h>
51 #  include <stdlib.h>
52 #  include <io.h>
53 #endif
54 
55 #if defined(_WIN32)
56 const char ossimFilename::OSSIM_NATIVE_PATH_SEPARATOR = '\\';
57 #else
58 const char ossimFilename::OSSIM_NATIVE_PATH_SEPARATOR = '/';
59 #endif
60 
61 // Internal ossimFilename separator.
62 const char ossimFilename::OSSIM_FILENAME_PATH_SEPARATOR = '/';
63 
64 
65 /**
66  * This was taken from Wx widgets for performing touch and access date stamps.
67  */
68 #if defined(_WIN32)
69 typedef WIN32_FIND_DATA FIND_STRUCT;
70 typedef HANDLE FIND_DATA;
71 typedef DWORD FIND_ATTR;
72 
73 class ossimFileHandle
74 {
75 public:
76    enum OpenMode
77    {
78       Read,
79       Write
80    };
81 
ossimFileHandle(const ossimString & filename,OpenMode mode)82    ossimFileHandle(const ossimString& filename, OpenMode mode)
83    {
84       m_hFile = ::CreateFile(
85          filename.c_str(),              // name
86          mode == Read ? GENERIC_READ    // access mask
87          : GENERIC_WRITE,
88          FILE_SHARE_READ |              // sharing mode
89          FILE_SHARE_WRITE,              // (allow everything)
90          NULL,                          // no secutity attr
91          OPEN_EXISTING,                 // creation disposition
92          0,                             // no flags
93          NULL                           // no template file
94          );
95 
96       if ( m_hFile == INVALID_HANDLE_VALUE )
97       {
98 //             wxLogSysError(_("Failed to open '%s' for %s"),
99 //                           filename.c_str(),
100 //                           mode == Read ? _("reading") : _("writing"));
101       }
102    }
103 
~ossimFileHandle()104    ~ossimFileHandle()
105    {
106       if ( m_hFile != INVALID_HANDLE_VALUE )
107       {
108          if ( !::CloseHandle(m_hFile) )
109          {
110 //                 wxLogSysError(_("Failed to close file handle"));
111          }
112       }
113    }
114 
115    // return true only if the file could be opened successfully
isOk() const116    bool isOk() const { return m_hFile != INVALID_HANDLE_VALUE; }
117 
118    // get the handle
operator HANDLE() const119    operator HANDLE() const { return m_hFile; }
120 
121 private:
122    HANDLE m_hFile;
123 };
124 
convertOssimToFileTime(FILETIME * ft,const ossimDate & dt)125 static void convertOssimToFileTime(FILETIME *ft, const ossimDate& dt)
126 {
127    SYSTEMTIME st;
128    st.wDay = dt.getDay();
129    st.wMonth = (WORD)(dt.getMonth());
130    st.wYear = (WORD)dt.getYear();
131    st.wHour = dt.getHour();
132    st.wMinute = dt.getMin();
133    st.wSecond = dt.getSec();
134 //     st.wMilliseconds = dt.GetMillisecond();
135 
136    FILETIME ftLocal;
137    if ( !::SystemTimeToFileTime(&st, &ftLocal) )
138    {
139 //         wxLogLastError(_T("SystemTimeToFileTime"));
140    }
141 
142    if ( !::LocalFileTimeToFileTime(&ftLocal, ft) )
143    {
144 //         wxLogLastError(_T("LocalFileTimeToFileTime"));
145    }
146 }
147 
convertFileTimeToOssim(ossimLocalTm & dt,const FILETIME & ft)148 static void convertFileTimeToOssim(ossimLocalTm &dt, const FILETIME &ft)
149 {
150    FILETIME ftcopy = ft;
151    FILETIME ftLocal;
152    if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) )
153    {
154 //         wxLogLastError(_T("FileTimeToLocalFileTime"));
155    }
156 
157    SYSTEMTIME st;
158    if ( !::FileTimeToSystemTime(&ftLocal, &st) )
159    {
160 //         wxLogLastError(_T("FileTimeToSystemTime"));
161    }
162 
163    dt.setDay(st.wDay);
164    dt.setMonth(st.wMonth);
165    dt.setYear(st.wYear);
166    dt.setHour(st.wHour);
167    dt.setMin(st.wMinute);
168    dt.setSec(st.wSecond);
169 
170 //     dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear,
171 //             st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
172 }
173 
IsFindDataOk(FIND_DATA fd)174 static inline bool IsFindDataOk(FIND_DATA fd)
175 {
176    return fd != INVALID_HANDLE_VALUE;
177 }
178 
FindFirst(const ossimString & spec,FIND_STRUCT * finddata)179 static inline FIND_DATA FindFirst(const ossimString& spec,
180                                   FIND_STRUCT *finddata)
181 {
182    return ::FindFirstFile(spec.c_str(), finddata);
183 }
184 
ossimGetDirectoryTimes(const ossimString & dirname,FILETIME * ftAccess,FILETIME * ftCreate,FILETIME * ftMod)185 static bool ossimGetDirectoryTimes(const ossimString& dirname,
186                                    FILETIME *ftAccess,
187                                    FILETIME *ftCreate,
188                                    FILETIME *ftMod)
189 {
190 
191    FIND_STRUCT fs;
192    FIND_DATA fd = FindFirst(dirname, &fs);
193    if ( !IsFindDataOk(fd) )
194    {
195       return false;
196    }
197 
198    *ftAccess = fs.ftLastAccessTime;
199    *ftCreate = fs.ftCreationTime;
200    *ftMod = fs.ftLastWriteTime;
201 
202    FindClose(fd);
203 
204    return true;
205 }
206 #endif
207 
208 const ossimFilename ossimFilename::NIL=("");
209 
ossimFilename()210 ossimFilename::ossimFilename()
211    : ossimString()
212 {}
213 
ossimFilename(const ossimFilename & src)214 ossimFilename::ossimFilename(const ossimFilename& src)
215    : ossimString(src)
216 {
217 }
218 
ossimFilename(const ossimString & src)219 ossimFilename::ossimFilename(const ossimString& src)
220    : ossimString(src)
221 {
222    if ( m_str.size() )
223    {
224       converPathSeparator();
225       // convertToNative();
226    }
227 }
228 
ossimFilename(const std::string & src)229 ossimFilename::ossimFilename(const std::string& src)
230    : ossimString(src)
231 {
232    if ( m_str.size() )
233    {
234       converPathSeparator();
235       // convertToNative();
236    }
237 }
238 
ossimFilename(const char * src)239 ossimFilename::ossimFilename(const char* src)
240    : ossimString(src)
241 {
242    if ( m_str.size() )
243    {
244       converPathSeparator();
245       // convertToNative();
246    }
247 }
248 
operator =(const ossimFilename & f)249 const ossimFilename& ossimFilename::operator=(const ossimFilename& f)
250 {
251    if ( this != &f )
252    {
253       m_str = f.m_str;
254    }
255    return *this;
256 }
257 
ossimFilename(Iter s,Iter e)258 template <class Iter> ossimFilename::ossimFilename(Iter s, Iter e)
259    : ossimString(s, e)
260 {
261    if ( m_str.size() )
262    {
263       converPathSeparator();
264       // convertToNative();
265    }
266 }
267 
operator ==(const ossimFilename & rhs) const268 bool ossimFilename::operator == (const ossimFilename& rhs)const
269 {
270    return ossimString::operator==(rhs);
271 }
272 
operator ==(const ossimString & rhs) const273 bool ossimFilename::operator == (const ossimString& rhs)const
274 {
275    return ossimString::operator==(rhs);
276 }
277 
operator ==(const char * rhs) const278 bool ossimFilename::operator == (const char* rhs)const
279 {
280    return ossimString::operator ==(rhs);
281 }
282 
283 #if 0
284 void ossimFilename::convertBackToForwardSlashes()
285 {
286    std::string::iterator currentChar = this->begin();
287 
288    while(currentChar != this->end())
289    {
290       if(*currentChar == '\\')
291       {
292          *currentChar = '/';
293       }
294       ++currentChar;
295    }
296 }
297 
298 void ossimFilename::convertForwardToBackSlashes()
299 {
300    std::string::iterator currentChar = this->begin();
301 
302    while(currentChar != this->end())
303    {
304       if(*currentChar == '/')
305       {
306          *currentChar = '\\';
307       }
308       ++currentChar;
309    }
310    m_pathSeparator = '\\';
311 }
312 #endif
313 
setTimes(ossimLocalTm * accessTime,ossimLocalTm * modTime,ossimLocalTm * createTime) const314 bool ossimFilename::setTimes(ossimLocalTm* accessTime,
315                              ossimLocalTm* modTime,
316 #if defined(_WIN32)
317                              ossimLocalTm* createTime)const
318 #else
319                              ossimLocalTm* /* createTime */ )const
320 #endif
321 {
322 #if defined(_WIN32)
323    if(isDir())
324    {
325       // need to implement this later
326       return false;
327    }
328    else
329    {
330       ossimFileHandle fh(this->expand(), ossimFileHandle::Write);
331       if(fh.isOk())
332       {
333          FILETIME ftAccess, ftCreate, ftWrite;
334 
335          if ( createTime )
336          {
337             convertOssimToFileTime(&ftCreate, *createTime);
338          }
339          if ( accessTime )
340          {
341             convertOssimToFileTime(&ftAccess, *accessTime);
342          }
343          if ( modTime )
344          {
345             convertOssimToFileTime(&ftWrite, *modTime);
346          }
347          if ( ::SetFileTime(fh,
348                             createTime ? &ftCreate : NULL,
349                             accessTime ? &ftAccess : NULL,
350                             modTime ? &ftWrite : NULL) )
351          {
352             return true;
353          }
354       }
355    }
356 #else
357    if ( !accessTime && !modTime )
358    {
359       // can't modify the creation time anyhow, don't try
360       return true;
361    }
362    utimbuf utm;
363    utm.actime = accessTime ? accessTime->getTicks() : modTime->getTicks();
364    utm.modtime = modTime ? modTime->getTicks() : accessTime->getTicks();
365    if ( utime(expand().c_str(), &utm) == 0 )
366    {
367       return true;
368    }
369 
370 #endif
371 
372    return false;
373 }
374 
getTimes(ossimLocalTm * accessTime,ossimLocalTm * modTime,ossimLocalTm * createTime) const375 bool ossimFilename::getTimes(ossimLocalTm *accessTime,
376                              ossimLocalTm *modTime,
377                              ossimLocalTm *createTime) const
378 {
379    if(!expand().exists()) return false;
380 
381 #if defined(_WIN32)
382    // we must use different methods for the files and directories under
383    // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and
384    // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and
385    // not 9x
386    bool ok;
387    FILETIME ftAccess, ftCreate, ftWrite;
388    if ( isDir() )
389    {
390       ok = ossimGetDirectoryTimes(expand().c_str(),
391                                   &ftAccess, &ftCreate, &ftWrite);
392       ok = false;
393    }
394    else // file
395    {
396       ossimFileHandle fh(expand().c_str(), ossimFileHandle::Read);
397       if ( fh.isOk() )
398       {
399          ok = ::GetFileTime(fh,
400                             createTime ? &ftCreate : NULL,
401                             accessTime ? &ftAccess : NULL,
402                             modTime ? &ftWrite : NULL) != 0;
403       }
404       else
405       {
406          ok = false;
407       }
408    }
409 
410    if ( ok )
411    {
412       if ( createTime )
413       {
414          convertFileTimeToOssim(*createTime, ftCreate);
415       }
416       if ( accessTime )
417       {
418          convertFileTimeToOssim(*accessTime, ftAccess);
419       }
420       if ( modTime )
421       {
422          convertFileTimeToOssim(*modTime, ftWrite);
423       }
424 
425       return true;
426    }
427 #else
428    struct stat sbuf;
429    stat(c_str(), &sbuf);
430    if ( stat( expand().c_str(), &sbuf) == 0 )
431    {
432       if ( accessTime )
433       {
434          *accessTime = ossimLocalTm(sbuf.st_atime);
435       }
436       if ( modTime )
437       {
438          *modTime = ossimLocalTm(sbuf.st_mtime);
439       }
440       if ( createTime )
441       {
442          *createTime = ossimLocalTm(sbuf.st_ctime);
443       }
444       return true;
445    }
446 #endif // platforms
447 
448 
449    return false;
450 }
451 
452 // Time in seconds since last accessed.
lastAccessed() const453 ossim_int64 ossimFilename::lastAccessed() const
454 {
455    ossim_int64 result = -1;
456 
457    if( expand().exists() )
458    {
459       ossim_int64 currentTime = ossim::getTime();
460 
461 #if defined(_WIN32)
462       cerr << "ossimFilename::lastAccessed() not implemented for windows!" << endl;
463 #else
464       struct stat sbuf;
465       stat(c_str(), &sbuf);
466       if ( stat( expand().c_str(), &sbuf) == 0 )
467       {
468          time_t atime = sbuf.st_atime; // This cast to seconds(time_t).
469          result = currentTime - (ossim_int64)atime;
470       }
471 #endif // platforms
472    }
473 
474    return result;
475 }
476 
touch() const477 bool ossimFilename::touch()const
478 {
479 #if defined( _WIN32 )
480    ossimDate now;
481 
482    return setTimes(&now, &now, 0);
483 
484 #else
485    if ( utime(expand().c_str(), NULL) == 0 )
486    {
487       return true;
488    }
489 
490    return false;
491 #endif
492 }
493 
expand() const494 ossimFilename ossimFilename::expand() const
495 {
496    //---
497    // Note:  ossimEnvironmentUtility::getCurrentWorkingDir() is returning
498    // a blank string on windows with vs9.  This was resulting in seg faults
499    // in this method so added checks were added for size of returned result.
500    // (drb  20100113)
501    //---
502    ossimFilename result = "";
503    if ( size() )
504    {
505       result = *this;
506 
507       if ( needsExpansion() )
508       {
509 
510 //#if defined(_WIN32)
511 //         result.convertBackToForwardSlashes();
512 //#endif
513 
514          bool addCwd = false;
515 
516          if ( (size() > 1) && (*(begin()) == '~') && (*(begin()+1) == OSSIM_FILENAME_PATH_SEPARATOR) )
517          {
518             ossimFilename homeDir =
519                ossimEnvironmentUtility::instance()->getUserDir();
520 
521             ossimFilename s( (result.begin()+2) , result.end());
522             result = homeDir.dirCat(s);
523          }
524          else if( (size() > 1) &&
525                   (*(begin()) == '.') && (*(begin()+1) == OSSIM_FILENAME_PATH_SEPARATOR) )
526          {
527             // dot slash i.e. ./foo
528             addCwd = true;
529          }
530          else if ( (size() > 2)  && (*(begin()) == '.')
531                    && (*(begin()+1) == '.') && (*(begin()+2) == OSSIM_FILENAME_PATH_SEPARATOR) )
532          {
533             // ../foo
534             addCwd = true;
535          }
536          else if (result == ".")
537          {
538             result = ossimEnvironmentUtility::instance()->
539                getCurrentWorkingDir();
540          }
541 
542          if (addCwd)
543          {
544             ossimFilename cwd = ossimEnvironmentUtility::instance()->
545                getCurrentWorkingDir();
546             result = cwd.dirCat(result);
547          }
548          else if ( result.isRelative() )
549          {
550             if ( result.size() && ((*(result.begin())) != '$') )
551             {
552                ossimFilename cwd = ossimEnvironmentUtility::instance()->
553                   getCurrentWorkingDir();
554                result = cwd.dirCat(result);
555             }
556          }
557 
558          // Check result to see if we're finished.
559          if ( result.needsExpansion() )
560          {
561             // now expand any environment variable substitutions
562 
563             ossimFilename finalResult;
564             const char* tempPtr = result.c_str();
565             ossim_int32 startIdx = -1;
566             ossim_int32 resultSize = (ossim_uint32)result.size();
567             ossim_int32 scanIdx = 0;
568             while(scanIdx < resultSize)
569             {
570                // look for start of substitution pattern
571                if(tempPtr[scanIdx] == '$')
572                {
573                   if(tempPtr[scanIdx+1] == '(')
574                   {
575                      scanIdx += 2;
576                      startIdx = scanIdx;
577                   }
578                   else
579                   {
580                      //---
581                      // Infinite loop fix with below file on window:
582                      // "\\kiosk\x$\SourceImagery\foo.ntf" (drb 21 Nov. 2016)
583                      //---
584                      finalResult += tempPtr[scanIdx];
585                      ++scanIdx;
586                   }
587                }
588                // look for an end pattern and apply if we found a start pattern
589                else if(tempPtr[scanIdx] == ')')
590                {
591                   if(startIdx != -1)
592                   {
593                      ossimFilename value(
594                         ossimEnvironmentUtility::instance()->
595                         getEnvironmentVariable(ossimString(tempPtr+startIdx,
596                                                            tempPtr+scanIdx)));
597 #if defined(_WIN32) // do windows style replacment
598                      //                    value.convertBackToForwardSlashes();
599 #endif
600                      finalResult += value;
601                      // reset start idx indicator to not set so we are ready for next pattern
602                      //
603                      startIdx = -1;
604                   }
605                   else // if no start then tack on the )
606                   {
607                      finalResult += tempPtr[scanIdx];
608                   }
609                   ++scanIdx;
610                }
611                else if(startIdx == -1)
612                {
613                   finalResult += tempPtr[scanIdx];
614                   ++scanIdx;
615                }
616                else
617                {
618                   ++scanIdx;
619                }
620             }
621 #if defined(_WIN32)
622 
623 #else
624             finalResult.gsub("//", "/", true);
625 #endif
626             result = finalResult;
627 
628          } // matches:  if ( result.needsExpansion() )
629 
630 #if defined(_WIN32)
631          //        result.convertForwardToBackSlashes();
632 #endif
633 
634       } // matches: if ( needsExpansion() )
635 
636       //---
637       // If we had a size before "expand()" and now we don't something went
638       // wrong...
639       //---
640       if (!result.size())
641       {
642          result = *this;
643       }
644 
645    } // matches: if ( size() )
646 
647    return result;
648 }
649 
exists() const650 bool ossimFilename::exists() const
651 {
652    bool result = false;
653    if ( isUrl() == false )
654    {
655 #if defined(_WIN32)
656       result = (_access(c_str(), ossimFilename::OSSIM_EXIST) == 0);
657 #else
658       result = ((access(c_str(), ossimFilename::OSSIM_EXIST)) == 0);
659 #endif
660    }
661    else
662    {
663       result = ossim::StreamFactoryRegistry::instance()->exists( this->string() );
664    }
665    return result;
666 }
667 
isFile() const668 bool ossimFilename::isFile() const
669 {
670 #if defined(_WIN32)
671    struct _stat sbuf;
672    if ( _stat(c_str(), &sbuf ) == -1)
673       return false;
674    return (_S_IFMT & sbuf.st_mode ? true : false);
675 #else
676    struct stat sbuf;
677 
678    stat(c_str(), &sbuf);
679    return ((sbuf.st_mode & S_IFMT) == S_IFREG);
680 #endif
681 }
682 
isDir() const683 bool ossimFilename::isDir() const
684 {
685    if ( empty() )
686    {
687       return false;
688    }
689 
690    ossimFilename temp = c_str();
691    const char& lastChar = temp[temp.size()-1];
692    if ( lastChar == '/' || lastChar == '\\' )
693    {
694       temp = temp.beforePos(temp.size() - 1);
695    }
696 
697 #if defined(_WIN32)
698 
699    struct _stat sbuf;
700    if ( _stat(temp.c_str(), &sbuf ) == -1)
701       return false;
702    return (_S_IFDIR & sbuf.st_mode ? true : false);
703 #else
704    struct stat sbuf;
705    if (stat(temp.c_str(), &sbuf) == -1)
706       return false;
707    return (S_ISDIR(sbuf.st_mode));
708 #endif
709 }
710 
isReadable() const711 bool ossimFilename::isReadable() const
712 {
713 #if defined(_WIN32)
714 
715    struct _stat sbuf;
716    if ( _stat(c_str(), &sbuf ) == -1)
717       return false;
718    return (_S_IREAD & sbuf.st_mode ? true : false);
719 #else
720    return (access(c_str(), ossimFilename::OSSIM_READ) == 0);
721 #endif
722 }
723 
isUrl() const724 bool ossimFilename::isUrl() const
725 {
726    bool result = false;
727    if ( m_str.size() )
728    {
729       //---
730       // Must have at least room for a protocol and "://", e.g.
731       // "s3://my_bucket/data1/foo.tif
732       //---
733       std::size_t found = m_str.find( std::string("://") );
734       if ( ( found != std::string::npos ) && ( found > 1 ) )
735       {
736          result = true;
737       }
738    }
739    return result;
740 }
741 
isWriteable() const742 bool ossimFilename::isWriteable() const
743 {
744 #if defined(_WIN32)
745 
746    struct _stat sbuf;
747    if ( _stat(c_str(), &sbuf ) == -1)
748       return false;
749    return (_S_IWRITE & sbuf.st_mode ? true : false);
750 #else
751    return (access(c_str(), ossimFilename::OSSIM_WRITE) == 0);
752 #endif
753 }
754 
isExecutable() const755 bool ossimFilename::isExecutable() const
756 {
757 #if defined(_WIN32)
758 
759    struct _stat sbuf;
760    if ( _stat(c_str(), &sbuf ) == -1)
761       return false;
762    return (_S_IEXEC & sbuf.st_mode ? true : false);
763 #else
764    return (access(c_str(), ossimFilename::OSSIM_EXE) == 0);
765 #endif
766 }
767 
ext() const768 ossimString ossimFilename::ext() const
769 {
770    std::string::size_type pos = m_str.rfind('.');
771    if (pos == std::string::npos)
772    {
773       return ossimFilename::NIL;
774    }
775 
776    return ossimFilename(m_str.substr(pos+1));
777 }
778 
file() const779 ossimFilename ossimFilename::file() const
780 {
781    std::string::size_type pos = m_str.rfind(OSSIM_FILENAME_PATH_SEPARATOR);
782    if (pos == std::string::npos)
783       return *this;
784    else
785       return ossimFilename(m_str.substr(pos+1));
786 }
787 
path() const788 ossimFilename ossimFilename::path() const
789 {
790    // finds the last occurrence of the given string; in this case '/';
791    std::string::size_type pos = m_str.rfind(OSSIM_FILENAME_PATH_SEPARATOR);
792 
793    if (pos == 0)
794       return ossimFilename(ossimFilename(OSSIM_FILENAME_PATH_SEPARATOR));
795    if (pos == std::string::npos)
796    {
797       // We got to the end of the file and did not find a path separator.
798       return ossimFilename::NIL;
799    }
800 
801    return ossimFilename(m_str.substr(0, pos));
802 }
803 
drive() const804 ossimFilename ossimFilename::drive()const
805 {
806    ossimFilename result;
807    ossimRegExp regEx("^([a-z|A-Z])+:");
808    if(regEx.find( m_str.c_str() ) )
809    {
810       result = ossimFilename(ossimString(this->begin() + regEx.start(),
811                                          this->begin() + regEx.end()));
812    }
813    else
814    {
815       result = "";
816    }
817 
818    return result;
819 }
820 
fileNoExtension() const821 ossimFilename ossimFilename::fileNoExtension()const
822 {
823    std::string::size_type dot_pos   = m_str.rfind('.');
824    std::string::size_type slash_pos = m_str.rfind(OSSIM_FILENAME_PATH_SEPARATOR);
825 
826    if(dot_pos == std::string::npos)
827    {
828       if(slash_pos == std::string::npos)
829       {
830          return *this;
831       }
832       else
833       {
834          return ossimFilename(this->begin()+slash_pos+1,
835                               this->end());
836       }
837    }
838    else if(slash_pos == std::string::npos)
839    {
840       return ossimFilename(this->begin(), this->begin()+dot_pos);
841    }
842    else if(slash_pos < dot_pos)
843    {
844       return ossimFilename(this->begin()+slash_pos+1,
845                            this->begin() + dot_pos);
846    }
847 
848    return ossimFilename(this->begin()+slash_pos+1,
849                         this->end());
850 
851 }
noExtension() const852 ossimFilename ossimFilename::noExtension()const
853 {
854    ossimString drivePart;
855    ossimString pathPart;
856    ossimString filePart;
857    ossimString extPart;
858 
859    split(drivePart, pathPart, filePart, extPart);
860 
861    extPart.clear();
862 
863    ossimFilename result;
864 
865    result.merge(drivePart, pathPart, filePart, extPart);
866 
867    return result;
868 }
869 
setExtension(const ossimString & e)870 ossimFilename& ossimFilename::setExtension(const ossimString& e)
871 {
872    ossimString newExtPart = e;
873 
874    //---
875    // If e has a dot "." in the front of it strip it off...
876    //---
877    if ( (e.begin() != e.end()) && ((*(e.begin())) == '.') )
878    {
879       newExtPart = ossimString(e.begin() + 1, e.end());
880    }
881 
882    ossimString drivePart;
883    ossimString pathPart;
884    ossimString filePart;
885    ossimString extPart;
886 
887    split(drivePart,
888          pathPart,
889          filePart,
890          extPart);
891 
892    merge(drivePart,
893          pathPart,
894          filePart,
895          newExtPart);
896 
897    return *this;
898 }
899 
setDrive(const ossimString & d)900 ossimFilename& ossimFilename::setDrive(const ossimString& d)
901 {
902    ossimString drivePart;
903    ossimString pathPart;
904    ossimString filePart;
905    ossimString extPart;
906 
907    split(drivePart,
908          pathPart,
909          filePart,
910          extPart);
911 
912    merge(d,
913          pathPart,
914          filePart,
915          extPart);
916 
917    return *this;
918 }
919 
setPath(const ossimString & p)920 ossimFilename& ossimFilename::setPath(const ossimString& p)
921 {
922    ossimString drivePart;
923    ossimString pathPart;
924    ossimString filePart;
925    ossimString extPart;
926 
927    split(drivePart,
928          pathPart,
929          filePart,
930          extPart);
931 
932    merge(drivePart,
933          p,
934          filePart,
935          extPart);
936 
937    return *this;
938 }
939 
setFile(const ossimString & f)940 ossimFilename& ossimFilename::setFile(const ossimString& f)
941 {
942    ossimString drivePart;
943    ossimString pathPart;
944    ossimString filePart;
945    ossimString extPart;
946 
947    split(drivePart,
948          pathPart,
949          filePart,
950          extPart);
951 
952    merge(drivePart,
953          pathPart,
954          f,
955          extPart);
956 
957    return *this;
958 }
959 
960 
split(ossimString & drivePart,ossimString & pathPart,ossimString & filePart,ossimString & extPart) const961 void ossimFilename::split(ossimString& drivePart,
962                           ossimString& pathPart,
963                           ossimString& filePart,
964                           ossimString& extPart)const
965 {
966    drivePart = drive();
967    pathPart  = path();
968    if(drivePart != "")
969    {
970       pathPart = pathPart.substitute(drivePart, "");
971    }
972    filePart  = fileNoExtension();
973    extPart   = ext();
974 }
975 
merge(const ossimString & drivePart,const ossimString & pathPart,const ossimString & filePart,const ossimString & extPart)976 void ossimFilename::merge(const ossimString& drivePart,
977                           const ossimString& pathPart,
978                           const ossimString& filePart,
979                           const ossimString& extPart)
980 {
981    ossimFilename result = drivePart;
982 
983    if(pathPart != "")
984    {
985       result = result.dirCat(ossimFilename(pathPart));
986    }
987 
988    if(filePart!="")
989    {
990       result = result.dirCat(ossimFilename(filePart));
991    }
992 
993    if(extPart != "")
994    {
995       result += ".";
996       result += extPart;
997    }
998 
999    *this = result;
1000 }
1001 
dirCat(const ossimFilename & file) const1002 ossimFilename ossimFilename::dirCat(const ossimFilename& file) const
1003 {
1004    // If this string is empty simply return the input file.
1005    if (empty()) return file;
1006    if (file.empty()) return *this;
1007 
1008    ossimFilename dir      = *this;
1009    ossimFilename tempFile = file;
1010 
1011    // Check the end and see if it already has a "/".
1012    string::const_iterator i = dir.end();
1013 
1014    --i; // decrement past the trailing null.
1015 
1016    if ( (*i) != OSSIM_FILENAME_PATH_SEPARATOR)
1017    {
1018       dir += ossimString(OSSIM_FILENAME_PATH_SEPARATOR);
1019    }
1020 
1021    // check for dot slash or just slash: ./foo or /foo
1022    std::string::iterator iter = tempFile.begin();
1023    if (iter != tempFile.end())
1024    {
1025       if ((*iter) == OSSIM_FILENAME_PATH_SEPARATOR)
1026       {
1027          ++iter; // skip slash
1028       }
1029       else if (tempFile.size() > 1)
1030       {
1031          if ( ((*iter) == '.') &&  ( *(iter + 1) == OSSIM_FILENAME_PATH_SEPARATOR) )
1032          {
1033             iter = iter + 2; // skip dot slash
1034          }
1035       }
1036    }
1037 
1038    dir += std::string(iter, tempFile.end());
1039 
1040    return dir;
1041 }
1042 
fileSize() const1043 ossim_int64 ossimFilename::fileSize() const
1044 {
1045    ossim_int64 size = 0;
1046 
1047    if ( isUrl() == false )
1048    {
1049       struct stat sbuf;
1050       if ( stat( this->c_str(), &sbuf ) == 0 )
1051       {
1052          size = (ossim_int64)sbuf.st_size;
1053       }
1054       else
1055       {
1056          ifstream in(c_str());
1057          if(in)
1058          {
1059             in.seekg(0, std::ios_base::end);
1060             size = (ossim_int64)in.tellg();
1061          }
1062       }
1063    }
1064    else
1065    {
1066       std::shared_ptr<ossim::istream> in = ossim::StreamFactoryRegistry::instance()->
1067          createIstream( this->string() );
1068       if ( in )
1069       {
1070          ossimFileInfoInterface* intf = dynamic_cast<ossimFileInfoInterface*>( in.get() );
1071          if ( intf )
1072          {
1073             size = intf->getFileSize();
1074          }
1075          else
1076          {
1077             in->seekg(0, std::ios_base::end);
1078             size = (ossim_int64)in->tellg();
1079          }
1080       }
1081    }
1082 
1083    return size;
1084 }
1085 
createDirectory(bool recurseFlag,int perm) const1086 bool ossimFilename::createDirectory( bool recurseFlag,
1087                                      int perm ) const
1088 {
1089    if(exists()) return true;
1090 
1091    if ( empty() ) return false;
1092 
1093    if(recurseFlag)
1094    {
1095       ossimString tempString = this->expand().c_str();
1096 
1097       vector<ossimString> result;
1098       tempString.split(result,OSSIM_FILENAME_PATH_SEPARATOR);
1099 
1100       if(result.size())
1101       {
1102          ossimString current = result[0];
1103 
1104 // Reconstruct UNC paths under Windows.
1105 #if defined(_WIN32)
1106          bool bGotUNC = false;
1107          if ( current.length() == 0 && tempString.length() > 2 )
1108          {
1109             const char* fstr = tempString.c_str();
1110             const char fstar0 = fstr[0];
1111             const char fstar1 = fstr[1];
1112             if ( fstar0=='\\' && fstar1=='\\' )
1113             {
1114                bGotUNC = true;
1115                current = OSSIM_FILENAME_PATH_SEPARATOR;
1116             }
1117          }
1118 #endif
1119 
1120          for(ossim_uint32 i = 1; i < result.size(); ++i)
1121          {
1122             current += (OSSIM_FILENAME_PATH_SEPARATOR+result[i]);
1123 
1124 #if defined(_WIN32)
1125             if ( bGotUNC == true && i==1 )
1126             {
1127                // The root of the UNC path is assumed to exist.
1128                continue;
1129             }
1130 #endif
1131 
1132             if(current != OSSIM_FILENAME_PATH_SEPARATOR)
1133             {
1134                if(!ossimFilename(current).exists())
1135                {
1136 #if defined(__BORLANDC__)
1137                   if ( _mkdir(current.c_str()) != 0 )
1138 #elif defined(_WIN32)
1139                   if ( _mkdir(current.c_str()) != 0 )
1140 #else
1141                   if ( mkdir(current.c_str(), perm) != 0 )
1142 #endif
1143                   {
1144                      return false;
1145                   }
1146                }
1147             }
1148          }
1149       }
1150    }
1151    else
1152    {
1153 #if defined (__BORLANDC__)
1154       if ( _mkdir(c_str()) != 0 )
1155 #elif defined(_WIN32)
1156       if ( _mkdir(c_str()) != 0 )
1157 #else
1158       if ( mkdir(c_str(), perm) != 0 )
1159 #endif
1160       {
1161          return false;
1162       }
1163       else
1164       {
1165          return true;
1166       }
1167    }
1168    return true;
1169 }
1170 
remove(const ossimFilename & pathname)1171 bool ossimFilename::remove(const ossimFilename& pathname)
1172 {
1173    bool result = true;
1174 
1175 #if defined(__VISUALC__)  || defined(__BORLANDC__) || defined(__WATCOMC__) || \
1176    defined(__GNUWIN32__) || defined(_MSC_VER)
1177 
1178    // Note: not sure if these work on all of the above flavors. drb - 14 Sep. 2011.
1179    if(pathname.isDir())
1180    {
1181       // Note this only removes empty directories.
1182       result = ( RemoveDirectory( pathname.c_str() ) != 0 );
1183    }
1184    else
1185    {
1186       result = ( DeleteFile( pathname.c_str() ) != 0 );
1187    }
1188 #else /* Unix flavor from unistd.h. */
1189    if(pathname.isDir())
1190    {
1191       result = ( rmdir( pathname.c_str() ) == 0 );
1192    }
1193    else
1194    {
1195       result = ( unlink( pathname.c_str() ) == 0 );
1196    }
1197 #endif
1198 
1199    return result;
1200 }
1201 
wildcardRemove(const ossimFilename & pathname)1202 bool ossimFilename::wildcardRemove(const ossimFilename& pathname)
1203 {
1204    std::vector<ossimFilename> fileListToRemove;
1205    ossimFilename tempPathname = pathname;
1206 
1207    if(!tempPathname.isDir())
1208    {
1209       ossimFilename file = tempPathname.file();
1210       ossimFilename path = tempPathname.path();
1211       if(path == "")
1212       {
1213          path = ".";
1214       }
1215       ossimDirectory dir;
1216       if(dir.open(path))
1217       {
1218          dir.findAllFilesThatMatch(fileListToRemove,
1219                                    file.c_str());
1220       }
1221       else
1222       {
1223       }
1224    }
1225    else
1226    {
1227       fileListToRemove.push_back(ossimFilename(pathname));
1228    }
1229    ossim_uint32 idx = 0;
1230    bool result = true;
1231    for(idx = 0; idx < fileListToRemove.size(); ++idx)
1232    {
1233 #if defined(__VISUALC__)  || defined(__BORLANDC__) || defined(__WATCOMC__) || \
1234    defined(__GNUWIN32__) || defined(_MSC_VER)
1235 
1236       if(remove(fileListToRemove[idx].c_str()) != 0)
1237       {
1238          result = false;
1239       }
1240 #else
1241       if (unlink(fileListToRemove[idx]) == -1)
1242       {
1243          result = false;
1244       }
1245 #endif /* HAVE_UNISTD_H */
1246    }
1247    return result;
1248 }
1249 
rename(const ossimFilename & destFile,bool overwriteDestinationFlag) const1250 bool ossimFilename::rename(const ossimFilename& destFile, bool overwriteDestinationFlag)const
1251 {
1252    bool result = true;
1253    if ( this->string() != destFile.string() )
1254    {
1255       if ( overwriteDestinationFlag && destFile.exists() )
1256       {
1257          destFile.remove();
1258       }
1259 
1260       if ( destFile.exists() == false )
1261       {
1262          // std::rename from cstdio returns 0 on success.
1263          if ( std::rename(this->c_str(), destFile.c_str()) != 0 )
1264          {
1265             result = false;
1266          }
1267       }
1268       else
1269       {
1270          ossimNotify(ossimNotifyLevel_WARN)
1271             << "ossimFilenam::rename WARNING:"
1272             << "\nDestination File Exists: " << destFile << std::endl;
1273          result = false;
1274       }
1275    }
1276    return result;
1277 }
1278 
remove() const1279 bool ossimFilename::remove()const
1280 {
1281    return ossimFilename::remove(*this);
1282 }
1283 
wildcardRemove() const1284 bool ossimFilename::wildcardRemove()const
1285 {
1286    return ossimFilename::wildcardRemove(*this);
1287 }
1288 
copyFileTo(const ossimFilename & outputFile) const1289 bool ossimFilename::copyFileTo(const ossimFilename& outputFile) const
1290 {
1291    bool result = false;
1292 
1293    std::ifstream is(this->c_str(), std::ios::in|std::ios::binary);
1294    if ( is.good() )
1295    {
1296       ossimFilename f = outputFile;
1297       if ( f.isDir() )
1298       {
1299          f = f.dirCat( this->file() );
1300       }
1301 
1302       if ( f != *this )
1303       {
1304          std::ofstream os( f.c_str(), std::ios::out|std::ios::binary );
1305          if ( os.good() )
1306          {
1307             // Copy the file:
1308             char c;
1309             while(is.get(c))
1310             {
1311                os.put(c);
1312             }
1313 
1314             if ( is.eof() &&  !os.fail())
1315             {
1316                result = true;
1317             }
1318             else
1319             {
1320                ossimNotify(ossimNotifyLevel_WARN)
1321                   << "WARNING: "
1322                   << "ossimFilename::copyFileTo WARNING:"
1323                   << "\nError detected writing from file "
1324                   << this->c_str() << " to file " << f.c_str() << std::endl;
1325             }
1326          }
1327          else
1328          {
1329             ossimNotify(ossimNotifyLevel_WARN)
1330                << "WARNING: "
1331                << "ossimFilename::copyFileTo WARNING:"
1332                << "\nCannot open: " << f.c_str() << std::endl;
1333          }
1334       } //  if ( f != *this )
1335       else
1336       {
1337          ossimNotify(ossimNotifyLevel_WARN)
1338             << "WARNING: "
1339             << "ossimFilename::copyFileTo WARNING:"
1340             << "\nFiles the same!" << std::endl;
1341       }
1342 
1343    } // if ( is.good() )
1344    else
1345    {
1346       ossimNotify(ossimNotifyLevel_WARN)
1347          << "WARNING: "
1348          << "ossimFilename::copyFileTo WARNING:"
1349          << "\nCannot open: " << this->c_str() << std::endl;
1350    }
1351 
1352    return result;
1353 }
1354 
1355 //---
1356 // We will only return false if we are absolutely sure absolutely sure we
1357 // are not relative. No pun intended:)
1358 //---
isRelative() const1359 bool ossimFilename::isRelative() const
1360 {
1361    bool result = true;
1362    if (size())
1363    {
1364       //---
1365       // Look for unix "/"...
1366       // ESH: Look for Windows "\" (with prepending escape character \)
1367       //---
1368       if ( (*(begin()) == '/') || (*(begin()) == '\\') )
1369       {
1370          result = false;
1371       }
1372       else
1373       {
1374          // Look for windows drive
1375          ossimRegExp regEx("^([a-z|A-Z])+:");
1376          if ( regEx.find(c_str()) == true)
1377          {
1378             result = false;
1379          }
1380       }
1381    }
1382    return result;
1383 }
1384 
needsExpansion() const1385 bool ossimFilename::needsExpansion() const
1386 {
1387    bool result = false;
1388    if ( m_str.size() )
1389    {
1390       // Do not expand URLs.
1391       if ( isUrl() == false )
1392       {
1393          result = isRelative();
1394          if (result == false)
1395          {
1396             // Check for '$'
1397             std::string::size_type pos = m_str.find('$', 0);
1398             {
1399                if (pos != std::string::npos)
1400                {
1401                   // found '$'
1402                   result = true;
1403                }
1404             }
1405 
1406          }
1407       }
1408    }
1409    return result;
1410 }
1411 
getPathSeparator() const1412 char ossimFilename::getPathSeparator() const
1413 {
1414    return OSSIM_FILENAME_PATH_SEPARATOR;
1415 }
1416 
appendTimestamp()1417 ossimFilename& ossimFilename::appendTimestamp()
1418 {
1419    const std::string format = "%Y%m%d-%H%Mh%Ss";
1420    std::string timestamp;
1421    ossim::getFormattedTime(format, true, timestamp);
1422 
1423    return append(timestamp);
1424 }
1425 
append(const ossimString & append_this)1426 ossimFilename& ossimFilename::append(const ossimString& append_this)
1427 {
1428    ossimString drivePart;
1429    ossimString pathPart;
1430    ossimString filePart;
1431    ossimString extPart;
1432 
1433    split(drivePart, pathPart, filePart, extPart);
1434    filePart += append_this;
1435    merge(drivePart, pathPart, filePart, extPart);
1436 
1437    return *this;
1438 }
1439 
converPathSeparator()1440 void ossimFilename::converPathSeparator()
1441 {
1442    if ( m_str.size() )
1443    {
1444       std::replace( m_str.begin(), m_str.end(), '\\', OSSIM_FILENAME_PATH_SEPARATOR );
1445    }
1446 }
1447 
native() const1448 std::string ossimFilename::native() const
1449 {
1450 #if defined(_WIN32)
1451    std::string s = m_str;
1452    std::replace( s.begin(), s.end(),OSSIM_FILENAME_PATH_SEPARATOR, OSSIM_NATIVE_PATH_SEPARATOR );
1453    return s;
1454 #else
1455    return m_str;
1456 #endif
1457 }
1458 
1459 #if 0
1460 void ossimFilename::convertToNative()
1461 {
1462 #if defined(_WIN32)
1463    if ( isUrl() == false )
1464    {
1465       convertForwardToBackSlashes();
1466    }
1467 #else
1468    convertBackToForwardSlashes();
1469 
1470 #endif
1471 }
1472 #endif
1473