diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 8efb811ed..f1a8b2a9d 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -227,6 +227,7 @@ add_library(app-lib context_flags.cpp crash/backup_observer.cpp crash/data_recovery.cpp + crash/document_io.cpp crash/session.cpp document.cpp document_api.cpp diff --git a/src/app/crash/document_io.cpp b/src/app/crash/document_io.cpp new file mode 100644 index 000000000..e2f5bfef6 --- /dev/null +++ b/src/app/crash/document_io.cpp @@ -0,0 +1,150 @@ +// Aseprite +// Copyright (C) 2001-2015 David Capello +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "app/crash/document_io.h" + +#include "app/document.h" +#include "base/convert_to.h" +#include "base/path.h" +#include "base/serialization.h" +#include "base/string.h" +#include "doc/cel.h" +#include "doc/cel_data_io.h" +#include "doc/cel_io.h" +#include "doc/cels_range.h" +#include "doc/frame.h" +#include "doc/frame_tag.h" +#include "doc/frame_tag_io.h" +#include "doc/image_io.h" +#include "doc/layer.h" +#include "doc/palette.h" +#include "doc/palette_io.h" +#include "doc/sprite.h" +#include "doc/string_io.h" + +#include + +namespace app { +namespace crash { + +using namespace base::serialization; +using namespace base::serialization::little_endian; +using namespace doc; + +#ifdef _WIN32 + #define OFSTREAM(name, fn) \ + std::ofstream name(base::from_utf8(base::join_path(path, fn))); +#else + #define OFSTREAM(name, fn) \ + std::ofstream name(base::join_path(path, fn)); +#endif + +void write_document(const std::string& path, app::Document* doc) +{ + Sprite* spr = doc->sprite(); + std::vector layers; + + { + OFSTREAM(os, "spr-" + base::convert_to(spr->id())); + + write32(os, spr->id()); + write8(os, spr->pixelFormat()); + write32(os, spr->width()); + write32(os, spr->height()); + write32(os, spr->transparentColor()); + + // Frame durations + write32(os, spr->totalFrames()); + for (frame_t fr = 0; fr < spr->totalFrames(); ++fr) + write32(os, spr->frameDuration(fr)); + + // Palettes + write32(os, spr->getPalettes().size()); + for (Palette* pal : spr->getPalettes()) + write32(os, pal->id()); + + // Frame tags + write32(os, spr->frameTags().size()); + for (FrameTag* tag : spr->frameTags()) + write32(os, tag->id()); + + // Layers + spr->getLayersList(layers); + write32(os, layers.size()); + for (Layer* lay : layers) + write32(os, lay->id()); + + // Cels + int celCount = 0; + for (Cel* cel : spr->cels()) + ++celCount; + write32(os, celCount); + for (Cel* cel : spr->cels()) + write32(os, cel->id()); + + // Images (CelData) + int uniqueCelCount = 0; + for (Cel* cel : spr->uniqueCels()) + ++uniqueCelCount; + write32(os, uniqueCelCount); + for (Cel* cel : spr->uniqueCels()) + write32(os, cel->data()->id()); + } + + ////////////////////////////////////////////////////////////////////// + // Create one stream for each object + + for (Palette* pal : spr->getPalettes()) { + OFSTREAM(subos, "pal-" + base::convert_to(pal->id())); + write_palette(subos, pal); + } + + for (FrameTag* tag : spr->frameTags()) { + OFSTREAM(subos, "frtag-" + base::convert_to(tag->id())); + write_frame_tag(subos, tag); + } + + for (Layer* lay : layers) { + OFSTREAM(os, "lay-" + base::convert_to(lay->id())); + write32(os, lay->id()); + write_string(os, lay->name()); + + write32(os, static_cast(lay->flags())); // Flags + write16(os, static_cast(lay->type())); // Type + + if (lay->type() == ObjectType::LayerImage) { + CelConstIterator it, begin = static_cast(lay)->getCelBegin(); + CelConstIterator end = static_cast(lay)->getCelEnd(); + + // Cels + write32(os, static_cast(lay)->getCelsCount()); + for (it=begin; it != end; ++it) { + const Cel* cel = *it; + write32(os, cel->id()); + } + } + } + + for (Cel* cel : spr->cels()) { + OFSTREAM(os, "cel-" + base::convert_to(cel->id())); + write_cel(os, cel); + } + + // Images (CelData) + for (Cel* cel : spr->uniqueCels()) { + OFSTREAM(os, "img-" + base::convert_to(cel->data()->id())); + write_celdata(os, cel->data()); + write_image(os, cel->image()); + } +} + +} // namespace crash +} // namespace app diff --git a/src/app/crash/document_io.h b/src/app/crash/document_io.h new file mode 100644 index 000000000..558b67367 --- /dev/null +++ b/src/app/crash/document_io.h @@ -0,0 +1,23 @@ +// Aseprite +// Copyright (C) 2001-2015 David Capello +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. + +#ifndef APP_CRASH_WRITE_DOCUMENT_H_INCLUDED +#define APP_CRASH_WRITE_DOCUMENT_H_INCLUDED +#pragma once + +#include + +namespace app { +class Document; +namespace crash { + + void write_document(const std::string& dir, app::Document* doc); + +} // namespace crash +} // namespace app + +#endif diff --git a/src/app/crash/session.cpp b/src/app/crash/session.cpp index 827f6a6f5..a3f64a45e 100644 --- a/src/app/crash/session.cpp +++ b/src/app/crash/session.cpp @@ -12,6 +12,7 @@ #include "app/crash/session.h" #include "app/context.h" +#include "app/crash/document_io.h" #include "app/document.h" #include "app/document_access.h" #include "app/file/file.h" @@ -20,6 +21,7 @@ #include "base/fs.h" #include "base/path.h" #include "base/process.h" +#include "base/string.h" namespace app { namespace crash { @@ -43,7 +45,7 @@ bool Session::isRunning() bool Session::isEmpty() { for (auto& item : base::list_files(m_path)) { - if (base::get_file_extension(item) == "ase") + if (base::is_directory(item)) return false; } return true; @@ -63,8 +65,15 @@ void Session::create(base::pid pid) void Session::removeFromDisk() { - base::delete_file(pidFilename()); - base::remove_directory(m_path); + if (base::is_file(pidFilename())) + base::delete_file(pidFilename()); + + try { + base::remove_directory(m_path); + } + catch (const std::exception&) { + // Is not empty + } } void Session::saveDocumentChanges(app::Document* doc) @@ -72,22 +81,15 @@ void Session::saveDocumentChanges(app::Document* doc) DocumentReader reader(doc); DocumentWriter writer(reader); app::Context ctx; - std::string fn = base::join_path(m_path, - base::convert_to(doc->id()) + ".ase"); - TRACE("DataRecovery: Saving document '%s'...\n", fn.c_str()); + std::string dir = base::join_path(m_path, + base::convert_to(doc->id())); + TRACE("DataRecovery: Saving document '%s'...\n", dir.c_str()); - FileOp* fop = fop_to_save_document(&ctx, - static_cast(doc), fn.c_str(), ""); - if (!fop) { - TRACE("DataRecovery: Cannot create save file operation\n"); - return; - } + if (!base::is_directory(dir)) + base::make_directory(dir); - fop_operate(fop, NULL); - fop_done(fop); - if (fop->has_error()) - TRACE("DataRecovery: Error saving changes '%s'\n", fop->error.c_str()); - fop_free(fop); + // Save document information + write_document(dir, doc); } void Session::loadPid()