cb00acc8d82ad52f50bc23b2b28977cadf265adf
[libdcp.git] / asdcplib / src / KM_fileio.h
1 /*
2 Copyright (c) 2004-2009, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8 1. Redistributions of source code must retain the above copyright
9    notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11    notice, this list of conditions and the following disclaimer in the
12    documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14    derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27   /*! \file    KM_fileio.h
28     \version $Id: KM_fileio.h,v 1.17 2009/06/22 05:49:02 jhurst Exp $
29     \brief   portable file i/o
30   */
31
32 #ifndef _KM_FILEIO_H_
33 #define _KM_FILEIO_H_
34
35 #include <KM_util.h>
36 #include <string>
37 #include <boost/filesystem.hpp>
38 #include <openssl/md5.h>
39
40 #ifdef KM_WIN32
41 # include <io.h>
42 #else
43 # include <dirent.h>
44 # include <unistd.h>
45 # include <time.h>
46 # include <sys/types.h>
47 #include <regex.h>
48 #endif
49
50 #include <sys/stat.h>
51
52
53
54 namespace Kumu
55 {
56   class DirScanner
57   {
58   public:
59           DirScanner();
60           Result_t Open(const char *);
61           Result_t GetNext(char *);
62           Result_t Close();
63   private:
64           boost::filesystem::directory_iterator _iterator;
65   };
66
67 #ifdef KM_WIN32
68   typedef __int64  fsize_t;
69   typedef __int64  fpos_t;
70   typedef HANDLE FileHandle;
71
72   enum SeekPos_t {
73     SP_BEGIN = FILE_BEGIN,
74     SP_POS   = FILE_CURRENT,
75     SP_END   = FILE_END
76   };
77 #else
78   typedef off_t    fsize_t;
79   typedef off_t    fpos_t;
80   typedef int      FileHandle;
81   const FileHandle INVALID_HANDLE_VALUE = -1L;
82
83   enum SeekPos_t {
84     SP_BEGIN = SEEK_SET,
85     SP_POS   = SEEK_CUR,
86     SP_END   = SEEK_END
87   };
88 #endif  
89         
90   //
91 #ifndef KM_SMALL_FILES_OK
92   template <bool sizecheck>    void compile_time_size_checker();
93   template <> inline void compile_time_size_checker<false>() {}
94   //
95   // READ THIS if your compiler is complaining about a previously declared implementation of
96   // compile_time_size_checker(). For example, GCC 4.0.1 looks like this:
97   //
98   // error: 'void Kumu::compile_time_size_checker() [with bool sizecheck = false]' previously declared here
99   //
100   // This is happening because the equality being tested below is false. The reason for this 
101   // will depend on your OS, but on Linux it is probably because you have not used -D_FILE_OFFSET_BITS=64
102   // Adding this magic macro to your CFLAGS will get you going again. If you are on a system that
103   // does not support 64-bit files, you can disable this check by using -DKM_SMALL_FILES_OK. You
104   // will then of course be limited to file sizes < 4GB.
105   //
106   template <> inline void compile_time_size_checker<sizeof(Kumu::fsize_t)==sizeof(ui64_t)>() {}
107 #endif
108   //
109
110   const ui32_t Kilobyte = 1024;
111   const ui32_t Megabyte = Kilobyte * Kilobyte;
112   const ui32_t Gigabyte = Megabyte * Kilobyte;
113
114   const ui32_t MaxFilePath = Kilobyte;
115
116
117   //------------------------------------------------------------------------------------------
118   // Path Manglers
119   //------------------------------------------------------------------------------------------
120
121   // types
122   typedef std::list<std::string> PathCompList_t; // a list of path components
123   typedef std::list<std::string> PathList_t; // a list of paths
124
125   // tests
126   bool        PathExists(const std::string& Path); // true if the path exists in the filesystem
127   bool        PathIsFile(const std::string& Path); // true if the path exists in the filesystem and is a file
128   bool        PathIsDirectory(const std::string& Path); // true if the path exists in the filesystem and is a directory
129   fsize_t     FileSize(const std::string& Path); // returns the size of a regular file, 0 for a directory or device
130   bool        PathsAreEquivalent(const std::string& lhs, const std::string& rhs); // true if paths point to the same filesystem entry
131
132   // Returns free space and total space available for the given path
133   Result_t    FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space);
134
135   // split and reassemble paths as lists of path components
136   PathCompList_t& PathToComponents(const std::string& Path, PathCompList_t& CList, char separator = '/'); // removes '//'
137   std::string ComponentsToPath(const PathCompList_t& CList, char separator = '/');
138   std::string ComponentsToAbsolutePath(const PathCompList_t& CList, char separator = '/'); // add separator to the front
139   bool        PathHasComponents(const std::string& Path, char separator = '/'); // true if paths starts with separator
140
141   bool        PathIsAbsolute(const std::string& Path, char separator = '/'); // true if path begins with separator
142   std::string PathMakeAbsolute(const std::string& Path, char separator = '/'); // compute position of relative path using getcwd()
143   std::string PathMakeLocal(const std::string& Path, const std::string& Parent); // remove Parent from front of Path, if it exists
144   std::string PathMakeCanonical(const std::string& Path, char separator = '/'); // remove '.' and '..'
145
146   // common operations
147   std::string PathBasename(const std::string& Path, char separator = '/'); // returns right-most path element (list back())
148   std::string PathDirname(const std::string& Path, char separator = '/'); // returns everything but the right-most element
149   std::string PathGetExtension(const std::string& Path); // returns everything in the right-most element following the right-most '.'
150   std::string PathSetExtension(const std::string& Path, const std::string& Extension); // empty extension removes '.' as well
151
152   std::string PathJoin(const std::string& Path1, const std::string& Path2, char separator = '/');
153   std::string PathJoin(const std::string& Path1, const std::string& Path2, const std::string& Path3, char separator = '/');
154   std::string PathJoin(const std::string& Path1, const std::string& Path2,
155                        const std::string& Path3, const std::string& Path4, char separator = '/');
156
157
158   //------------------------------------------------------------------------------------------
159   // Path Search
160   //------------------------------------------------------------------------------------------
161
162   // An interface for a path matching function, used by FindInPath() and FindInPaths() below
163   //
164   class IPathMatch
165   {
166   public:
167     virtual ~IPathMatch() {}
168     virtual bool Match(const std::string& s) const = 0;
169   };
170
171   // matches any pathname
172  class PathMatchAny : public IPathMatch
173   {
174   public:
175     virtual ~PathMatchAny() {}
176     inline bool Match(const std::string&) const { return true; }
177   };
178
179 #ifndef KM_WIN32
180   // matches pathnames using a regular expression
181  class PathMatchRegex : public IPathMatch
182   {
183     regex_t m_regex;
184     PathMatchRegex();
185     const PathMatchRegex& operator=(const PathMatchRegex&);
186
187   public:
188     PathMatchRegex(const std::string& Pattern);
189     PathMatchRegex(const PathMatchRegex&);
190     virtual ~PathMatchRegex();
191     bool Match(const std::string& s) const;
192   };
193
194   // matches pathnames using a Bourne shell glob expression
195  class PathMatchGlob : public IPathMatch
196   {
197     regex_t m_regex;
198     PathMatchGlob();
199     const PathMatchGlob& operator=(const PathMatchGlob&);
200
201   public:
202     PathMatchGlob(const std::string& Pattern);
203     PathMatchGlob(const PathMatchGlob&);
204     virtual ~PathMatchGlob();
205     bool Match(const std::string& s) const;
206   };
207 #endif /* !KM_WIN32 */
208
209   // Search all paths in SearchPaths for filenames matching Pattern (no directories are returned).
210   // Put results in FoundPaths. Returns after first find if one_shot is true.
211   PathList_t& FindInPath(const IPathMatch& Pattern, const std::string& SearchDir,
212                          PathList_t& FoundPaths, bool one_shot = false, char separator = '/');
213
214   PathList_t& FindInPaths(const IPathMatch& Pattern, const PathList_t& SearchPaths,
215                           PathList_t& FoundPaths, bool one_shot = false, char separator = '/');
216
217   //------------------------------------------------------------------------------------------
218   // Directory Manipulation
219   //------------------------------------------------------------------------------------------
220
221   // Create a directory, creates intermediate directories as necessary
222   Result_t CreateDirectoriesInPath(const std::string& Path);
223
224   // Delete a file (fails if the path points to a directory)
225   Result_t DeleteFile(const std::string& filename);
226
227   // Recursively remove a file or directory
228   Result_t DeletePath(const std::string& pathname);
229
230   //------------------------------------------------------------------------------------------
231   // File I/O Wrappers
232   //------------------------------------------------------------------------------------------
233
234   // Instant IO for strings
235   //
236   // Reads an entire file into a string.
237   Result_t ReadFileIntoString(const char* filename, std::string& outString, ui32_t max_size = 8 * Megabyte);
238
239   // Writes a string to a file, overwrites the existing file if present.
240   Result_t WriteStringIntoFile(const char* filename, const std::string& inString);
241
242   // Instant IO for archivable objects
243   //
244   // Unarchives a file into an object
245   Result_t ReadFileIntoObject(const std::string& Filename, IArchive& Object, ui32_t max_size = 8 * Kumu::Megabyte);
246
247   // Archives an object into a file
248   Result_t WriteObjectIntoFile(const IArchive& Object, const std::string& Filename);
249
250   // Instant IO for memory buffers
251   //
252   // Unarchives a file into a buffer
253   Result_t ReadFileIntoBuffer(const std::string& Filename, Kumu::ByteString& Buffer,
254                               ui32_t max_size = 8 * Kumu::Megabyte);
255
256   // Archives a buffer into a file
257   Result_t WriteBufferIntoFile(const Kumu::ByteString& Buffer, const std::string& Filename);
258
259
260   //------------------------------------------------------------------------------------------
261   // File I/O
262   //------------------------------------------------------------------------------------------
263
264   //
265   class FileReader
266     {
267       KM_NO_COPY_CONSTRUCT(FileReader);
268
269     protected:
270       std::string m_Filename;
271       FileHandle  m_Handle;
272
273     public:
274       FileReader() : m_Handle(INVALID_HANDLE_VALUE) {}
275       virtual ~FileReader() { Close(); }
276
277       Result_t OpenRead(const char*) const;                          // open the file for reading
278       Result_t Close() const;                                        // close the file
279       fsize_t  Size() const;                                         // returns the file's current size
280       Result_t Seek(Kumu::fpos_t = 0, SeekPos_t = SP_BEGIN) const;   // move the file pointer
281       Result_t Tell(Kumu::fpos_t* pos) const;                        // report the file pointer's location
282       Result_t Read(byte_t*, ui32_t, ui32_t* = 0) const;             // read a buffer of data
283
284       inline Kumu::fpos_t Tell() const                               // report the file pointer's location
285         {
286           Kumu::fpos_t tmp_pos;
287           Tell(&tmp_pos);
288           return tmp_pos;
289         }
290
291       inline bool IsOpen() {                                         // returns true if the file is open
292         return (m_Handle != INVALID_HANDLE_VALUE);
293       }
294     };
295
296   //
297   class FileWriter : public FileReader
298     {
299       class h__iovec;
300       mem_ptr<h__iovec>  m_IOVec;
301       KM_NO_COPY_CONSTRUCT(FileWriter);
302       bool m_Hashing;
303       MD5_CTX m_MD5Context;
304
305     public:
306       FileWriter();
307       virtual ~FileWriter();
308
309       Result_t OpenWrite(const char*);                               // open a new file, overwrites existing
310       Result_t OpenModify(const char*);                              // open a file for read/write
311
312       // this part of the interface takes advantage of the iovec structure on
313       // platforms that support it. For each call to Writev(const byte_t*, ui32_t, ui32_t*),
314       // the given buffer is added to an internal iovec struct. All items on the list
315       // are written to disk by a call to Writev();
316       Result_t Writev(const byte_t*, ui32_t);                       // queue buffer for "gather" write
317       Result_t Writev(ui32_t* = 0);                                 // write all queued buffers
318
319       // if you call this while there are unwritten items on the iovec list,
320       // the iovec list will be written to disk before the given buffer,as though
321       // you had called Writev() first.
322       Result_t Write(const byte_t*, ui32_t, ui32_t* = 0);            // write buffer to disk
323
324       void StartHashing();
325       void MaybeHash(void const *, int);
326       std::string StopHashing();
327    };
328
329   Result_t CreateDirectoriesInPath(const std::string& Path);
330   Result_t FreeSpaceForPath(const std::string& path, Kumu::fsize_t& free_space, Kumu::fsize_t& total_space);
331   Result_t DeleteFile(const std::string& filename);
332   Result_t DeletePath(const std::string& pathname);
333
334 } // namespace Kumu
335
336
337 #endif // _KM_FILEIO_H_
338
339
340 //
341 // end KM_fileio.h
342 //