1 /* === S Y N F I G ========================================================= */
2 /*! \file filesystem.cpp
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 /* === H E A D E R S ======================================================= */
24
25 #ifdef USING_PCH
26 # include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #include <glibmm.h>
33
34 #include <ETL/stringf>
35
36 #include "filesystem.h"
37
38 #endif
39
40 /* === U S I N G =========================================================== */
41
42 using namespace std;
43 using namespace etl;
44 using namespace synfig;
45
46 /* === M A C R O S ========================================================= */
47
48 /* === G L O B A L S ======================================================= */
49
50 /* === P R O C E D U R E S ================================================= */
51
52 /* === M E T H O D S ======================================================= */
53
54 // FileSystemEmpty
55
FileSystemEmpty()56 FileSystemEmpty::FileSystemEmpty() { }
~FileSystemEmpty()57 FileSystemEmpty::~FileSystemEmpty() { }
58
59 // Stream
60
Stream(FileSystem::Handle file_system)61 FileSystem::Stream::Stream(FileSystem::Handle file_system):
62 file_system_(file_system) { }
63
~Stream()64 FileSystem::Stream::~Stream()
65 { }
66
67 // ReadStream
68
ReadStream(FileSystem::Handle file_system)69 FileSystem::ReadStream::ReadStream(FileSystem::Handle file_system):
70 Stream(file_system),
71 std::istream((std::streambuf*)this)
72 {
73 setg(&buffer_ + 1, &buffer_ + 1, &buffer_ + 1);
74 }
75
underflow()76 int FileSystem::ReadStream::underflow()
77 {
78 if (gptr() < egptr()) return std::streambuf::traits_type::to_int_type(*gptr());
79 if (sizeof(buffer_) != internal_read(&buffer_, sizeof(buffer_))) return EOF;
80 setg(&buffer_, &buffer_, &buffer_ + 1);
81 return std::streambuf::traits_type::to_int_type(*gptr());
82 }
83
84 // WriteStream
85
WriteStream(FileSystem::Handle file_system)86 FileSystem::WriteStream::WriteStream(FileSystem::Handle file_system):
87 Stream(file_system),
88 std::ostream((std::streambuf*)this)
89 { }
90
91 int
overflow(int character)92 FileSystem::WriteStream::overflow(int character)
93 {
94 char c = std::streambuf::traits_type::to_char_type(character);
95 return character != EOF && sizeof(c) == internal_write(&c, sizeof(c)) ? character : EOF;
96 }
97
98 // Identifier
99
get_read_stream() const100 FileSystem::ReadStream::Handle FileSystem::Identifier::get_read_stream() const
101 { return file_system ? file_system->get_read_stream(filename) : ReadStream::Handle(); }
get_write_stream() const102 FileSystem::WriteStream::Handle FileSystem::Identifier::get_write_stream() const
103 { return file_system ? file_system->get_write_stream(filename) : WriteStream::Handle(); }
104
105
106 // FileSystem
107
FileSystem()108 FileSystem::FileSystem() { }
109
~FileSystem()110 FileSystem::~FileSystem() { }
111
file_rename(const String & from_filename,const String & to_filename)112 bool FileSystem::file_rename(const String &from_filename, const String &to_filename)
113 {
114 if (fix_slashes(from_filename) == fix_slashes(to_filename))
115 return true;
116 ReadStream::Handle read_stream = get_read_stream(from_filename);
117 if (!read_stream) return false;
118 WriteStream::Handle write_stream = get_write_stream(to_filename);
119 if (!write_stream) return false;
120 return write_stream->write_whole_stream(read_stream)
121 && file_remove(from_filename);
122 }
123
directory_create_recursive(const String & dirname)124 bool FileSystem::directory_create_recursive(const String &dirname) {
125 return is_directory(dirname)
126 || (directory_create_recursive(etl::dirname(dirname)) && directory_create(dirname));
127 }
128
remove_recursive(const String & filename)129 bool FileSystem::remove_recursive(const String &filename)
130 {
131 assert(!filename.empty());
132
133 if (filename.empty())
134 return false;
135 if (is_file(filename))
136 return file_remove(filename);
137 if (is_directory(filename))
138 {
139 FileList files;
140 directory_scan(filename, files);
141 bool success = true;
142 for(FileList::const_iterator i = files.begin(); i != files.end(); ++i)
143 if (!remove_recursive(filename + ETL_DIRECTORY_SEPARATOR + *i))
144 success = false;
145 return success;
146 }
147 return true;
148 }
149
copy(Handle from_file_system,const String & from_filename,Handle to_file_system,const String & to_filename)150 bool FileSystem::copy(Handle from_file_system, const String &from_filename, Handle to_file_system, const String &to_filename)
151 {
152 if (from_file_system.empty() || to_file_system.empty()) return false;
153 ReadStream::Handle read_stream = from_file_system->get_read_stream(from_filename);
154 if (read_stream.empty()) return false;
155 WriteStream::Handle write_stream = to_file_system->get_write_stream(to_filename);
156 if (write_stream.empty()) return false;
157 return write_stream->write_whole_stream(read_stream);
158 }
159
copy_recursive(Handle from_file_system,const String & from_filename,Handle to_file_system,const String & to_filename)160 bool FileSystem::copy_recursive(Handle from_file_system, const String &from_filename, Handle to_file_system, const String &to_filename)
161 {
162 if (!from_file_system || !to_file_system) return false;
163 if (from_file_system->is_file(from_filename))
164 return copy(from_file_system, from_filename, to_file_system, to_filename);
165 if (from_file_system->is_directory(from_filename))
166 {
167 if (!to_file_system->directory_create(to_filename))
168 return false;
169 FileList files;
170 bool success = from_file_system->directory_scan(from_filename, files);
171 for(FileList::const_iterator i = files.begin(); i != files.end(); ++i)
172 if (!copy_recursive(
173 from_file_system,
174 from_filename + ETL_DIRECTORY_SEPARATOR + *i,
175 to_file_system,
176 to_filename + ETL_DIRECTORY_SEPARATOR + *i ))
177 success = false;
178 return success;
179 }
180 return false;
181 }
182
fix_slashes(const String & filename)183 String FileSystem::fix_slashes(const String &filename)
184 {
185 String fixed = etl::cleanup_path(filename);
186 if (fixed == ".") fixed = "";
187 for(size_t i = 0; i < filename.size(); ++i)
188 if (fixed[i] == '\\') fixed[i] = '/';
189 return fixed;
190 }
191
192 std::istream&
safe_get_line(std::istream & is,String & t)193 FileSystem::safe_get_line(std::istream& is, String& t)
194 {
195 t.clear();
196 //code from http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf
197
198 // The characters in the stream are read one-by-one using a std::streambuf.
199 // That is faster than reading them one-by-one using the std::istream.
200 // Code that uses streambuf this way must be guarded by a sentry object.
201 // The sentry object performs various tasks,
202 // such as thread synchronization and updating the stream state.
203
204 std::istream::sentry se(is, true);
205 std::streambuf* sb = is.rdbuf();
206
207 for(;;) {
208 int c = sb->sbumpc();
209 switch (c) {
210 case '\n':
211 return is;
212 case '\r':
213 if(sb->sgetc() == '\n')
214 sb->sbumpc();
215 return is;
216 case EOF:
217 // Also handle the case when the last line has no line ending
218 if(t.empty())
219 is.setstate(std::ios::eofbit);
220 return is;
221 default:
222 t += (char)c;
223 }
224 }
225
226 return is;
227 }
228
get_real_uri(const String &)229 String FileSystem::get_real_uri(const String & /* filename */)
230 { return String(); }
231
get_real_filename(const String & filename)232 String FileSystem::get_real_filename(const String &filename) {
233 return Glib::filename_from_uri(get_real_uri(filename));
234 }
235
236
237 /* === E N T R Y P O I N T ================================================= */
238
239
240