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