|
|
a61c48 |
/* === S Y N F I G ========================================================= */
|
|
|
a61c48 |
/*! \file filesystemtemporary.cpp
|
|
|
a61c48 |
** \brief FileSystemTemporary Implementation
|
|
|
a61c48 |
**
|
|
|
a61c48 |
** $Id$
|
|
|
a61c48 |
**
|
|
|
a61c48 |
** \legal
|
|
|
a61c48 |
** ......... ... 2016 Ivan Mahonin
|
|
|
a61c48 |
**
|
|
|
a61c48 |
** This package is free software; you can redistribute it and/or
|
|
|
a61c48 |
** modify it under the terms of the GNU General Public License as
|
|
|
a61c48 |
** published by the Free Software Foundation; either version 2 of
|
|
|
a61c48 |
** the License, or (at your option) any later version.
|
|
|
a61c48 |
**
|
|
|
a61c48 |
** This package is distributed in the hope that it will be useful,
|
|
|
a61c48 |
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
a61c48 |
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
a61c48 |
** General Public License for more details.
|
|
|
a61c48 |
** \endlegal
|
|
|
a61c48 |
*/
|
|
|
a61c48 |
/* ========================================================================= */
|
|
|
a61c48 |
|
|
|
a61c48 |
/* === H E A D E R S ======================================================= */
|
|
|
a61c48 |
|
|
|
a61c48 |
#ifdef USING_PCH
|
|
|
a61c48 |
# include "pch.h"
|
|
|
a61c48 |
#else
|
|
|
a61c48 |
#ifdef HAVE_CONFIG_H
|
|
|
a61c48 |
# include <config.h></config.h>
|
|
|
a61c48 |
#endif
|
|
|
a61c48 |
|
|
|
a61c48 |
#include <libxml++ libxml++.h=""></libxml++>
|
|
|
a61c48 |
|
|
|
a61c48 |
#include "general.h"
|
|
|
a61c48 |
#include "localization.h"
|
|
|
a61c48 |
|
|
|
a61c48 |
#include "filesystemtemporary.h"
|
|
|
a61c48 |
|
|
|
a61c48 |
#include "guid.h"
|
|
|
a61c48 |
#include "zstreambuf.h"
|
|
|
a61c48 |
|
|
|
a61c48 |
#endif
|
|
|
a61c48 |
|
|
|
a61c48 |
/* === U S I N G =========================================================== */
|
|
|
a61c48 |
|
|
|
a61c48 |
using namespace std;
|
|
|
a61c48 |
using namespace etl;
|
|
|
a61c48 |
using namespace synfig;
|
|
|
a61c48 |
|
|
|
a61c48 |
/* === M A C R O S ========================================================= */
|
|
|
a61c48 |
|
|
|
a61c48 |
/* === G L O B A L S ======================================================= */
|
|
|
a61c48 |
|
|
|
a61c48 |
/* === P R O C E D U R E S ================================================= */
|
|
|
a61c48 |
|
|
|
a61c48 |
/* === M E T H O D S ======================================================= */
|
|
|
a61c48 |
|
|
|
0dde72 |
FileSystemTemporary::FileSystemTemporary(const String &tag, const String &temporary_directory, const FileSystem::Handle &sub_file_system):
|
|
|
a61c48 |
file_system(FileSystemNative::instance()),
|
|
|
0dde72 |
tag(tag),
|
|
|
0dde72 |
temporary_directory(temporary_directory.empty() ? get_system_temporary_directory() : temporary_directory),
|
|
|
0dde72 |
temporary_filename_base(generate_temporary_filename_base(tag)),
|
|
|
e03d87 |
keep_files_when_destroyed(false),
|
|
|
a61c48 |
autosave(true)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
set_sub_file_system(sub_file_system);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
0dde72 |
FileSystemTemporary::~FileSystemTemporary()
|
|
|
0dde72 |
{
|
|
|
e03d87 |
if (!keep_files_when_destroyed) {
|
|
|
e03d87 |
discard_changes();
|
|
|
e03d87 |
}
|
|
|
0dde72 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
String
|
|
|
0dde72 |
FileSystemTemporary::get_system_temporary_directory()
|
|
|
a61c48 |
{
|
|
|
a61c48 |
const char *tmpdir;
|
|
|
a61c48 |
if ((tmpdir = getenv("TEMP")) == NULL)
|
|
|
a61c48 |
if ((tmpdir = getenv("TMP")) == NULL)
|
|
|
a61c48 |
if ((tmpdir = getenv("TMPDIR")) == NULL)
|
|
|
a61c48 |
tmpdir = "/tmp";
|
|
|
0dde72 |
return String(tmpdir);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
String
|
|
|
0dde72 |
FileSystemTemporary::generate_temporary_filename_base(const String &tag)
|
|
|
a61c48 |
{
|
|
|
0dde72 |
return "synfig_" + tag + "_" + GUID().get_string();
|
|
|
0dde72 |
}
|
|
|
0dde72 |
|
|
|
0dde72 |
bool
|
|
|
0dde72 |
FileSystemTemporary::scan_temporary_directory(const String &tag, FileList &out_files, const String &dirname)
|
|
|
0dde72 |
{
|
|
|
0dde72 |
String tmpdir = dirname.empty() ? get_system_temporary_directory() : dirname;
|
|
|
0dde72 |
|
|
|
0dde72 |
FileList files;
|
|
|
0dde72 |
if (!FileSystemNative::instance()->directory_scan(dirname, files))
|
|
|
0dde72 |
return false;
|
|
|
0dde72 |
|
|
|
0dde72 |
String prefix = "synfig_" + tag + "_";
|
|
|
0dde72 |
for(FileList::const_iterator i = files.begin(); i != files.end(); ++i)
|
|
|
0dde72 |
if (i->substr(0, prefix.size()) == prefix)
|
|
|
0dde72 |
if (FileSystemNative::instance()->is_file(tmpdir + ETL_DIRECTORY_SEPARATOR + *i))
|
|
|
0dde72 |
out_files.push_back(*i);
|
|
|
0dde72 |
return true;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
String
|
|
|
0dde72 |
FileSystemTemporary::generate_system_temporary_filename(const String &tag)
|
|
|
0dde72 |
{
|
|
|
0dde72 |
return get_system_temporary_directory() + ETL_DIRECTORY_SEPARATOR + generate_temporary_filename_base(tag);
|
|
|
0dde72 |
}
|
|
|
0dde72 |
|
|
|
0dde72 |
bool
|
|
|
0dde72 |
FileSystemTemporary::create_temporary_directory() const
|
|
|
a61c48 |
{
|
|
|
0dde72 |
return file_system->directory_create_recursive(get_temporary_directory());
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::is_file(const String &filename)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileMap::const_iterator i = files.find(fix_slashes(filename));
|
|
|
a61c48 |
if (i != files.end())
|
|
|
a61c48 |
return !i->second.is_removed && !i->second.is_directory;
|
|
|
2e482a |
return get_sub_file_system() && get_sub_file_system()->is_file(filename);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::is_directory(const String &filename)
|
|
|
a61c48 |
{
|
|
|
2e482a |
if (filename.empty()) return true;
|
|
|
a61c48 |
FileMap::const_iterator i = files.find(fix_slashes(filename));
|
|
|
a61c48 |
if (i != files.end())
|
|
|
a61c48 |
return !i->second.is_removed && i->second.is_directory;
|
|
|
2e482a |
return get_sub_file_system() && get_sub_file_system()->is_directory(filename);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::directory_create(const String &dirname)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (is_file(dirname)) return false;
|
|
|
a61c48 |
if (is_directory(dirname)) return true;
|
|
|
a61c48 |
|
|
|
a61c48 |
FileInfo info;
|
|
|
a61c48 |
info.name = fix_slashes(dirname);
|
|
|
a61c48 |
info.is_directory = true;
|
|
|
a61c48 |
files[info.name] = info;
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
return true;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::directory_scan(const String &dirname, FileList &out_files)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
out_files.clear();
|
|
|
a61c48 |
if (!is_directory(dirname)) return false;
|
|
|
a61c48 |
|
|
|
a61c48 |
String clean_dirname = fix_slashes(dirname);
|
|
|
a61c48 |
std::set<string> files_set;</string>
|
|
|
a61c48 |
|
|
|
a61c48 |
if (get_sub_file_system())
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileList list;
|
|
|
a61c48 |
if (!get_sub_file_system()->directory_scan(clean_dirname, list))
|
|
|
a61c48 |
return false;
|
|
|
a61c48 |
for(FileList::const_iterator i = list.begin(); i != list.end(); ++i)
|
|
|
a61c48 |
files_set.insert(*i);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
for(FileMap::iterator i = files.begin(); i != files.end(); i++)
|
|
|
a61c48 |
if (etl::dirname(i->second.name) == clean_dirname)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (i->second.is_removed)
|
|
|
a61c48 |
files_set.erase(etl::basename(i->second.name));
|
|
|
a61c48 |
else
|
|
|
a61c48 |
files_set.insert(etl::basename(i->second.name));
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
0a453e |
for(std::set<string>::const_iterator i = files_set.begin(); i != files_set.end(); ++i)</string>
|
|
|
a61c48 |
out_files.push_back(*i);
|
|
|
a61c48 |
return true;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::file_remove(const String &filename)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
// remove directory
|
|
|
a61c48 |
if (is_directory(filename))
|
|
|
a61c48 |
{
|
|
|
a61c48 |
// directory should be empty
|
|
|
a61c48 |
// NB: This code can check temporary files only,
|
|
|
a61c48 |
// but directory may contain other not tracked real files.
|
|
|
a61c48 |
String prefix = fix_slashes(filename + "/");
|
|
|
a61c48 |
for(FileMap::iterator i = files.begin(); i != files.end(); i++)
|
|
|
a61c48 |
if ( !i->second.is_removed
|
|
|
a61c48 |
&& i->second.name.substr(0, prefix.size()) == prefix )
|
|
|
a61c48 |
return false;
|
|
|
a61c48 |
|
|
|
a61c48 |
FileMap::iterator i = files.find(fix_slashes(filename));
|
|
|
a61c48 |
if (i == files.end())
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileInfo &info = files[fix_slashes(filename)];
|
|
|
a61c48 |
info.name = fix_slashes(filename);
|
|
|
a61c48 |
info.is_directory = true;
|
|
|
a61c48 |
info.is_removed = true;
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
else
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileInfo &info = i->second;
|
|
|
a61c48 |
info.is_removed = true;
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
else
|
|
|
a61c48 |
// remove file
|
|
|
a61c48 |
if (is_file(filename))
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileMap::iterator i = files.find(fix_slashes(filename));
|
|
|
a61c48 |
if (i == files.end())
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileInfo &info = files[fix_slashes(filename)];
|
|
|
a61c48 |
info.name = fix_slashes(filename);
|
|
|
a61c48 |
info.is_directory = false;
|
|
|
a61c48 |
info.is_removed = true;
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
else
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileInfo &info = i->second;
|
|
|
a61c48 |
info.is_removed = true;
|
|
|
a61c48 |
if (!info.tmp_filename.empty())
|
|
|
a61c48 |
{
|
|
|
a61c48 |
file_system->file_remove(info.tmp_filename);
|
|
|
a61c48 |
info.tmp_filename.clear();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
return true;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
FileSystem::ReadStream::Handle
|
|
|
a61c48 |
FileSystemTemporary::get_read_stream(const String &filename)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileMap::const_iterator i = files.find(fix_slashes(filename));
|
|
|
a61c48 |
if (i != files.end())
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (!i->second.is_removed && !i->second.is_directory && !i->second.tmp_filename.empty())
|
|
|
a61c48 |
return file_system->get_read_stream(i->second.tmp_filename);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
else
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (get_sub_file_system())
|
|
|
a61c48 |
return get_sub_file_system()->get_read_stream(filename);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
return FileSystem::ReadStream::Handle();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
FileSystem::WriteStream::Handle
|
|
|
a61c48 |
FileSystemTemporary::get_write_stream(const String &filename)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileSystem::WriteStream::Handle stream;
|
|
|
a61c48 |
|
|
|
a61c48 |
FileMap::iterator i = files.find(fix_slashes(filename));
|
|
|
a61c48 |
if (i == files.end())
|
|
|
a61c48 |
{
|
|
|
a61c48 |
// create new file
|
|
|
0dde72 |
create_temporary_directory();
|
|
|
a61c48 |
FileInfo new_info;
|
|
|
a61c48 |
new_info.name = fix_slashes(filename);
|
|
|
0dde72 |
new_info.tmp_filename = get_temporary_directory()
|
|
|
0dde72 |
+ ETL_DIRECTORY_SEPARATOR
|
|
|
0dde72 |
+ generate_temporary_filename_base(tag + ".file");
|
|
|
a61c48 |
stream = file_system->get_write_stream(new_info.tmp_filename);
|
|
|
a61c48 |
if (stream)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
files[new_info.name] = new_info;
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
else
|
|
|
a61c48 |
if (!i->second.is_directory || i->second.is_removed)
|
|
|
a61c48 |
{
|
|
|
0dde72 |
create_temporary_directory();
|
|
|
a61c48 |
String tmp_filename = i->second.tmp_filename.empty()
|
|
|
0dde72 |
? get_temporary_directory()
|
|
|
0dde72 |
+ ETL_DIRECTORY_SEPARATOR
|
|
|
0dde72 |
+ generate_temporary_filename_base(tag + ".file")
|
|
|
a61c48 |
: i->second.tmp_filename;
|
|
|
a61c48 |
stream = file_system->get_write_stream(tmp_filename);
|
|
|
a61c48 |
if (stream)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
i->second.tmp_filename = tmp_filename;
|
|
|
a61c48 |
i->second.is_directory = false;
|
|
|
a61c48 |
i->second.is_removed = false;
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
return stream;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
String
|
|
|
a61c48 |
FileSystemTemporary::get_real_uri(const String &filename)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileMap::const_iterator i = files.find(fix_slashes(filename));
|
|
|
a61c48 |
if (i != files.end())
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (!i->second.tmp_filename.empty())
|
|
|
a61c48 |
return file_system->get_real_uri(i->second.tmp_filename);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
else
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (get_sub_file_system())
|
|
|
a61c48 |
return get_sub_file_system()->get_real_uri(filename);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
return String();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::save_changes(
|
|
|
a61c48 |
const FileSystemNative::Handle &file_system,
|
|
|
a61c48 |
const FileSystem::Handle &target_file_system,
|
|
|
a61c48 |
FileMap &files,
|
|
|
a61c48 |
bool remove_files)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
assert(file_system);
|
|
|
a61c48 |
assert(target_file_system);
|
|
|
a61c48 |
|
|
|
a61c48 |
// remove files
|
|
|
a61c48 |
bool processed = true;
|
|
|
a61c48 |
while(processed)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
processed = false;
|
|
|
a61c48 |
for(FileMap::iterator i = files.begin(); i != files.end(); i++)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
bool to_remove = i->second.is_directory
|
|
|
a61c48 |
? target_file_system->is_file(i->second.name)
|
|
|
a61c48 |
: target_file_system->is_directory(i->second.name);
|
|
|
a61c48 |
to_remove = to_remove || i->second.is_removed;
|
|
|
a61c48 |
if (to_remove && target_file_system->file_remove(i->second.name))
|
|
|
a61c48 |
{
|
|
|
a61c48 |
processed = true;
|
|
|
2e482a |
if (i->second.is_removed) files.erase(i);
|
|
|
a61c48 |
break;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
// create directories
|
|
|
a61c48 |
processed = true;
|
|
|
a61c48 |
while(processed)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
processed = false;
|
|
|
a61c48 |
for(FileMap::iterator i = files.begin(); i != files.end(); i++)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (!i->second.is_removed
|
|
|
a61c48 |
&& i->second.is_directory
|
|
|
a61c48 |
&& target_file_system->directory_create(i->second.name))
|
|
|
a61c48 |
{
|
|
|
a61c48 |
processed = true;
|
|
|
a61c48 |
files.erase(i);
|
|
|
a61c48 |
break;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
// create files
|
|
|
a61c48 |
for(FileMap::iterator i = files.begin(); i != files.end();)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (!i->second.is_removed
|
|
|
a61c48 |
&& !i->second.is_directory
|
|
|
a61c48 |
&& !i->second.tmp_filename.empty()
|
|
|
a61c48 |
&& copy(file_system, i->second.tmp_filename, target_file_system, i->second.name))
|
|
|
a61c48 |
{
|
|
|
01d3e9 |
if (remove_files)
|
|
|
a61c48 |
file_system->file_remove(i->second.tmp_filename);
|
|
|
6bad43 |
|
|
|
a61c48 |
files.erase(i++);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
else i++;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
return files.empty();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::save_changes_copy(const FileSystem::Handle &sub_file_system) const
|
|
|
a61c48 |
{
|
|
|
a61c48 |
assert(sub_file_system);
|
|
|
a61c48 |
assert(sub_file_system != get_sub_file_system());
|
|
|
a61c48 |
FileMap files_copy = files;
|
|
|
a61c48 |
return save_changes(file_system, sub_file_system, files_copy, false);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::save_changes(const FileSystem::Handle &sub_file_system, bool as_copy)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (as_copy)
|
|
|
a61c48 |
return save_changes_copy(sub_file_system);
|
|
|
a61c48 |
set_sub_file_system(sub_file_system);
|
|
|
0a453e |
return save_changes();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::save_changes()
|
|
|
a61c48 |
{
|
|
|
a61c48 |
assert(get_sub_file_system());
|
|
|
a61c48 |
bool result = save_changes(this->file_system, get_sub_file_system(), files, true);
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
return result;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
void
|
|
|
a61c48 |
FileSystemTemporary::discard_changes()
|
|
|
a61c48 |
{
|
|
|
a61c48 |
// remove temporary files
|
|
|
a61c48 |
for(FileMap::iterator i = files.begin(); i != files.end(); i++)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (!i->second.is_removed
|
|
|
a61c48 |
&& !i->second.is_directory
|
|
|
a61c48 |
&& !i->second.tmp_filename.empty())
|
|
|
a61c48 |
{
|
|
|
a61c48 |
file_system->file_remove(i->second.tmp_filename);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
// update internal state
|
|
|
a61c48 |
files.clear();
|
|
|
a61c48 |
meta.clear();
|
|
|
a61c48 |
|
|
|
a61c48 |
// remove file with description
|
|
|
a61c48 |
assert(empty());
|
|
|
a61c48 |
save_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
void
|
|
|
0dde72 |
FileSystemTemporary::reset_temporary_filename_base(const String &tag, const String &temporary_directory)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
// remove previous file
|
|
|
a61c48 |
assert(empty());
|
|
|
a61c48 |
save_temporary();
|
|
|
0dde72 |
this->tag = tag;
|
|
|
0dde72 |
this->temporary_directory = temporary_directory;
|
|
|
0dde72 |
temporary_filename_base = generate_temporary_filename_base(this->tag);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
String
|
|
|
a61c48 |
FileSystemTemporary::get_meta(const String &key) const
|
|
|
a61c48 |
{
|
|
|
a61c48 |
map<string, string="">::const_iterator i = meta.find(key);</string,>
|
|
|
a61c48 |
return i == meta.end() ? String() : i->second;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
0a453e |
void
|
|
|
a61c48 |
FileSystemTemporary::set_meta(const String &key, const String &value)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
meta[key] = value;
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
void
|
|
|
a61c48 |
FileSystemTemporary::clear_meta()
|
|
|
a61c48 |
{
|
|
|
a61c48 |
meta.clear();
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
const std::map<string, string="">&</string,>
|
|
|
a61c48 |
FileSystemTemporary::get_metadata() const
|
|
|
a61c48 |
{ return meta; }
|
|
|
a61c48 |
|
|
|
a61c48 |
void
|
|
|
a61c48 |
FileSystemTemporary::set_metadata(const std::map<string, string=""> &data)</string,>
|
|
|
a61c48 |
{
|
|
|
a61c48 |
meta = data;
|
|
|
a61c48 |
autosave_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::autosave_temporary() const
|
|
|
a61c48 |
{
|
|
|
a61c48 |
return !autosave || save_temporary();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
a61c48 |
FileSystemTemporary::save_temporary() const
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if (empty())
|
|
|
a61c48 |
{
|
|
|
0dde72 |
file_system->file_remove(get_temporary_directory() + ETL_DIRECTORY_SEPARATOR + get_temporary_filename_base());
|
|
|
a61c48 |
return true;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
xmlpp::Document document;
|
|
|
a61c48 |
xmlpp::Element *root = document.create_root_node("temporary-file-system");
|
|
|
a61c48 |
|
|
|
a61c48 |
xmlpp::Element *meta_node = root->add_child("meta");
|
|
|
a61c48 |
for(map<string, string="">::const_iterator i = meta.begin(); i != meta.end(); i++)</string,>
|
|
|
a61c48 |
{
|
|
|
a61c48 |
xmlpp::Element *entry = meta_node->add_child("entry");
|
|
|
a61c48 |
entry->add_child("key")->set_child_text(i->first);
|
|
|
a61c48 |
entry->add_child("value")->set_child_text(i->second);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
xmlpp::Element *files_node = root->add_child("files");
|
|
|
a61c48 |
for(FileMap::const_iterator i = files.begin(); i != files.end(); i++)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
xmlpp::Element *entry = files_node->add_child("entry");
|
|
|
a61c48 |
entry->add_child("name")->set_child_text(i->second.name);
|
|
|
a61c48 |
entry->add_child("tmp-basename")->set_child_text(basename(i->second.tmp_filename));
|
|
|
a61c48 |
entry->add_child("is-directory")->set_child_text(i->second.is_directory ? "true" : "false");
|
|
|
a61c48 |
entry->add_child("is-removed")->set_child_text(i->second.is_removed ? "true" : "false");
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
0dde72 |
create_temporary_directory();
|
|
|
a61c48 |
FileSystem::WriteStream::Handle stream =
|
|
|
a61c48 |
file_system->get_write_stream(
|
|
|
a61c48 |
get_temporary_directory()
|
|
|
0dde72 |
+ ETL_DIRECTORY_SEPARATOR
|
|
|
a61c48 |
+ get_temporary_filename_base() );
|
|
|
a61c48 |
if (!stream) return false;
|
|
|
a61c48 |
|
|
|
a61c48 |
stream = new ZWriteStream(stream);
|
|
|
a61c48 |
try
|
|
|
a61c48 |
{
|
|
|
a61c48 |
document.write_to_stream_formatted(*stream, "UTF-8");
|
|
|
a61c48 |
}
|
|
|
a61c48 |
catch(...)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
synfig::error("FileSystemTemporary::save_temporary(): Caught unknown exception");
|
|
|
a61c48 |
return false;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
stream.reset();
|
|
|
a61c48 |
|
|
|
a61c48 |
return true;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
String
|
|
|
a61c48 |
FileSystemTemporary::get_xml_node_text(xmlpp::Node *node)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
String s;
|
|
|
a61c48 |
if (node != NULL)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
xmlpp::Element::NodeList list = node->get_children();
|
|
|
a61c48 |
for(xmlpp::Element::NodeList::iterator i = list.begin(); i != list.end(); i++)
|
|
|
a61c48 |
if (dynamic_cast<xmlpp::textnode*>(*i))</xmlpp::textnode*>
|
|
|
a61c48 |
s += dynamic_cast<xmlpp::textnode*>(*i)->get_content();</xmlpp::textnode*>
|
|
|
a61c48 |
}
|
|
|
a61c48 |
return s;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
bool
|
|
|
0dde72 |
FileSystemTemporary::open_temporary(const String &filename)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
assert(empty());
|
|
|
a61c48 |
discard_changes();
|
|
|
a61c48 |
|
|
|
0dde72 |
String tag;
|
|
|
0dde72 |
String temporary_directory = etl::dirname(filename);
|
|
|
0dde72 |
String temporary_filename_base = etl::basename(filename);
|
|
|
0dde72 |
|
|
|
0dde72 |
size_t tag_begin = temporary_filename_base.find_first_of("_");
|
|
|
0dde72 |
size_t tag_end = temporary_filename_base.find_last_of("_");
|
|
|
0dde72 |
if (tag_begin != String::npos && tag_end != String::npos && tag_end - tag_begin > 1)
|
|
|
0dde72 |
tag = temporary_filename_base.substr(tag_begin + 1, tag_end - tag_begin - 1);
|
|
|
0dde72 |
|
|
|
0dde72 |
FileSystem::ReadStream::Handle stream = file_system->get_read_stream(filename);
|
|
|
a61c48 |
if (!stream) return false;
|
|
|
a61c48 |
stream = new ZReadStream(stream);
|
|
|
a61c48 |
|
|
|
a61c48 |
xmlpp::DomParser parser;
|
|
|
a61c48 |
parser.parse_stream(*stream);
|
|
|
a61c48 |
stream.reset();
|
|
|
a61c48 |
if (!parser) return false;
|
|
|
a61c48 |
|
|
|
a61c48 |
xmlpp::Element *root = parser.get_document()->get_root_node();
|
|
|
a61c48 |
if (root->get_name() != "temporary-file-system") return false;
|
|
|
a61c48 |
|
|
|
a61c48 |
xmlpp::Element::NodeList list = root->get_children();
|
|
|
a61c48 |
for(xmlpp::Element::NodeList::iterator i = list.begin(); i != list.end(); i++)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if ((*i)->get_name() == "meta")
|
|
|
a61c48 |
{
|
|
|
a61c48 |
xmlpp::Element::NodeList meta_list = (*i)->get_children();
|
|
|
a61c48 |
for(xmlpp::Element::NodeList::iterator j = meta_list.begin(); j != meta_list.end(); j++)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if ((*j)->get_name() == "entry")
|
|
|
a61c48 |
{
|
|
|
a61c48 |
String key, value;
|
|
|
a61c48 |
xmlpp::Element::NodeList fields_list = (*j)->get_children();
|
|
|
a61c48 |
for(xmlpp::Element::NodeList::iterator k = fields_list.begin(); k != fields_list.end(); k++)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if ((*k)->get_name() == "key")
|
|
|
a61c48 |
key = get_xml_node_text(*k);
|
|
|
a61c48 |
if ((*k)->get_name() == "value")
|
|
|
a61c48 |
value = get_xml_node_text(*k);
|
|
|
a61c48 |
}
|
|
|
a61c48 |
meta[key] = value;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
if ((*i)->get_name() == "files")
|
|
|
a61c48 |
{
|
|
|
a61c48 |
xmlpp::Element::NodeList files_list = (*i)->get_children();
|
|
|
a61c48 |
for(xmlpp::Element::NodeList::iterator j = files_list.begin(); j != files_list.end(); j++)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if ((*j)->get_name() == "entry")
|
|
|
a61c48 |
{
|
|
|
a61c48 |
FileInfo info;
|
|
|
a61c48 |
xmlpp::Element::NodeList fields_list = (*j)->get_children();
|
|
|
a61c48 |
for(xmlpp::Element::NodeList::iterator k = fields_list.begin(); k != fields_list.end(); k++)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
if ((*k)->get_name() == "name")
|
|
|
a61c48 |
info.name = fix_slashes(get_xml_node_text(*k));
|
|
|
a61c48 |
if ((*k)->get_name() == "tmp-basename")
|
|
|
a61c48 |
info.tmp_filename = get_xml_node_text(*k);
|
|
|
a61c48 |
if ((*k)->get_name() == "is-directory")
|
|
|
a61c48 |
info.is_directory = get_xml_node_text(*k) == "true";
|
|
|
a61c48 |
if ((*k)->get_name() == "is-removed")
|
|
|
a61c48 |
info.is_removed = get_xml_node_text(*k) == "true";
|
|
|
a61c48 |
}
|
|
|
a61c48 |
if (!info.tmp_filename.empty())
|
|
|
0dde72 |
info.tmp_filename = temporary_directory + ETL_DIRECTORY_SEPARATOR + info.tmp_filename;
|
|
|
a61c48 |
files[info.name] = info;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
0dde72 |
this->tag = tag;
|
|
|
0dde72 |
this->temporary_directory = temporary_directory;
|
|
|
0dde72 |
this->temporary_filename_base = temporary_filename_base;
|
|
|
a61c48 |
return true;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
String
|
|
|
a61c48 |
FileSystemTemporary::generate_indexed_temporary_filename(const FileSystem::Handle &fs, const String &filename)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
String extension = filename_extension(filename);
|
|
|
a61c48 |
String sans_extension = filename_sans_extension(filename);
|
|
|
a61c48 |
for(int index = 1; index < 10000; ++index)
|
|
|
a61c48 |
{
|
|
|
a61c48 |
String indexed_filename = strprintf("%s_%04d%s", sans_extension.c_str(), index, extension.c_str());
|
|
|
a61c48 |
if (!fs->is_exists(indexed_filename))
|
|
|
a61c48 |
return indexed_filename;
|
|
|
a61c48 |
}
|
|
|
a61c48 |
assert(false);
|
|
|
a61c48 |
return String();
|
|
|
a61c48 |
}
|
|
|
a61c48 |
|
|
|
a61c48 |
/* === E N T R Y P O I N T ================================================= */
|
|
|
a61c48 |
|
|
|
a61c48 |
|