1 /* === S Y N F I G ========================================================= */
2 /*!	\file filesystem.h
3 **	\brief FileSystem
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	......... ... 2013 Ivan Mahonin
9 **
10 **	This package is free software; you can redistribute it and/or
11 **	modify it under the terms of the GNU General Public License as
12 **	published by the Free Software Foundation; either version 2 of
13 **	the License, or (at your option) any later version.
14 **
15 **	This package 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 GNU
18 **	General Public License for more details.
19 **	\endlegal
20 */
21 /* ========================================================================= */
22 
23 /* === S T A R T =========================================================== */
24 
25 #ifndef __SYNFIG_FILESYSTEM_H
26 #define __SYNFIG_FILESYSTEM_H
27 
28 /* === H E A D E R S ======================================================= */
29 
30 #include <cstdio>
31 
32 #include <istream>
33 #include <ostream>
34 #include <streambuf>
35 #include <vector>
36 
37 #include <ETL/handle>
38 
39 #include "string.h"
40 
41 /* === M A C R O S ========================================================= */
42 
43 /* === T Y P E D E F S ===================================================== */
44 
45 /* === C L A S S E S & S T R U C T S ======================================= */
46 
47 namespace synfig
48 {
49 
50 	class FileSystem : public etl::shared_object
51 	{
52 	public:
53 		typedef etl::handle<FileSystem> Handle;
54 		typedef std::vector<String> FileList;
55 
56 		class Stream : public etl::shared_object
57 		{
58 		public:
59 			typedef etl::handle<Stream> Handle;
60 
61 		protected:
62 			FileSystem::Handle file_system_;
63 			Stream(FileSystem::Handle file_system);
64 		public:
65 			virtual ~Stream();
file_system()66 			FileSystem::Handle file_system() const { return file_system_; }
67 		};
68 
69 		class ReadStream :
70 			public Stream,
71 			private std::streambuf,
72 			public std::istream
73 		{
74 		public:
75 			typedef etl::handle<ReadStream> Handle;
76 
77 		protected:
78 			char buffer_;
79 
80 			ReadStream(FileSystem::Handle file_system);
81 			virtual int underflow();
82 			virtual size_t internal_read(void *buffer, size_t size) = 0;
83 
84 		public:
read_block(void * buffer,size_t size)85 			size_t read_block(void *buffer, size_t size)
86 				{ return read((char*)buffer, size).gcount(); }
read_whole_block(void * buffer,size_t size)87 			bool read_whole_block(void *buffer, size_t size)
88 				{ return size == read_block(buffer, size); }
read_variable(T & v)89 			template<typename T> bool read_variable(T &v)
90 				{ return read_whole_block(&v, sizeof(T)); }
91 		};
92 
93 		class WriteStream :
94 			public Stream,
95 			private std::streambuf,
96 			public std::ostream
97 		{
98 		public:
99 			typedef etl::handle<WriteStream> Handle;
100 
101 		protected:
102 			WriteStream(FileSystem::Handle file_system);
103 	        virtual int overflow(int ch);
104 			virtual size_t internal_write(const void *buffer, size_t size) = 0;
105 
106 		public:
write_block(const void * buffer,size_t size)107 			bool write_block(const void *buffer, size_t size)
108 			{
109 				for(size_t i = 0; i < size; i++)
110 					if (!put(((const char*)buffer)[i]).good())
111 						return i;
112 				return size;
113 			}
write_whole_block(const void * buffer,size_t size)114 			bool write_whole_block(const void *buffer, size_t size)
115 				{ return size == write_block(buffer, size); }
write_whole_stream(std::streambuf & streambuf)116 			bool write_whole_stream(std::streambuf &streambuf)
117 				{ return (*this << &streambuf).good(); }
write_whole_stream(std::istream & stream)118 			bool write_whole_stream(std::istream &stream)
119 				{ return write_whole_stream(*stream.rdbuf()); }
write_whole_stream(ReadStream::Handle stream)120 			bool write_whole_stream(ReadStream::Handle stream)
121 				{ return !stream || write_whole_stream(*(std::istream*)&(*stream)); }
write_variable(const T & v)122 			template<typename T> bool write_variable(const T &v)
123 				{ return write_whole_block(&v, sizeof(T)); }
124 		};
125 
126 		class Identifier {
127 		public:
128 			FileSystem::Handle file_system;
129 			String filename;
Identifier()130 			Identifier() { }
Identifier(const FileSystem::Handle & file_system,const String & filename)131 			Identifier(const FileSystem::Handle &file_system, const String &filename):
132 				file_system(file_system), filename(filename) { }
133 
empty()134 			bool empty() const { return file_system; }
135 			operator bool () const { return !empty(); }
136 
137 			bool operator < (const Identifier &other) const
138 			{
139 				if (file_system.get() < other.file_system.get()) return true;
140 				if (other.file_system.get() < file_system.get()) return false;
141 				if (filename < other.filename) return true;
142 				if (other.filename < filename) return false;
143 				return false;
144 			}
145 			bool operator > (const Identifier &other) const
146 				{ return other < *this; }
147 			bool operator != (const Identifier &other) const
148 				{ return *this > other || other < *this; }
149 			bool operator == (const Identifier &other) const
150 				{ return !(*this != other); }
151 
152 			ReadStream::Handle get_read_stream() const;
153 			WriteStream::Handle get_write_stream() const;
154 		};
155 
156 		FileSystem();
157 		virtual ~FileSystem();
158 
159 		virtual bool is_file(const String &filename) = 0;
160 		virtual bool is_directory(const String &filename) = 0;
161 
162 		virtual bool directory_create(const String &dirname) = 0;
163 		virtual bool directory_scan(const String &dirname, FileList &out_files) = 0;
164 
165 		virtual bool file_remove(const String &filename) = 0;
166 		virtual bool file_rename(const String &from_filename, const String &to_filename);
167 		virtual ReadStream::Handle get_read_stream(const String &filename) = 0;
168 		virtual WriteStream::Handle get_write_stream(const String &filename) = 0;
169 		virtual String get_real_uri(const String &filename);
170 
is_exists(const String filename)171 		inline bool is_exists(const String filename) { return is_file(filename) || is_directory(filename); }
172 
173 		String get_real_filename(const String &filename);
get_identifier(const String & filename)174 		Identifier get_identifier(const String &filename) { return Identifier(this, filename); }
175 
176 		bool directory_create_recursive(const String &dirname);
177 		bool remove_recursive(const String &filename);
178 
179 		static bool copy(Handle from_file_system, const String &from_filename, Handle to_file_system, const String &to_filename);
180 		static bool copy_recursive(Handle from_file_system, const String &from_filename, Handle to_file_system, const String &to_filename);
181 
182 		static String fix_slashes(const String &filename);
183 
184 		///!@brief Read a stream line by line even '\r\n' ended
185 		static std::istream& safe_get_line(std::istream& is, String& t);
186 	};
187 
188 	//! Always empty filesystem (dummy)
189 	class FileSystemEmpty : public FileSystem
190 	{
191 	public:
192 		typedef etl::handle<FileSystemEmpty> Handle;
193 
194 		FileSystemEmpty();
195 		virtual ~FileSystemEmpty();
196 
is_file(const String &)197 		virtual bool is_file(const String & /*filename*/)
198 			{ return false; }
is_directory(const String & filename)199 		virtual bool is_directory(const String &filename)
200 			{ return fix_slashes(filename).empty(); }
201 
directory_create(const String & dirname)202 		virtual bool directory_create(const String &dirname)
203 			{ return is_directory(dirname); }
directory_scan(const String & dirname,FileList & out_files)204 		virtual bool directory_scan(const String &dirname, FileList &out_files)
205 			{ out_files.clear(); return is_directory(dirname); }
206 
file_remove(const String & filename)207 		virtual bool file_remove(const String &filename)
208 			{ return !is_directory(filename); }
file_rename(const String & from_filename,const String & to_filename)209 		virtual bool file_rename(const String &from_filename, const String &to_filename)
210 			{ return is_directory(from_filename) && is_directory(to_filename); }
get_read_stream(const String &)211 		virtual FileSystem::ReadStream::Handle get_read_stream(const String &/*filename*/)
212 			{ return ReadStream::Handle(); }
get_write_stream(const String &)213 		virtual FileSystem::WriteStream::Handle get_write_stream(const String &/*filename*/)
214 			{ return WriteStream::Handle(); }
215 	};
216 }
217 
218 /* === E N D =============================================================== */
219 
220 #endif
221