Backup document data in a raw format directly on disk

This commit is contained in:
David Capello 2015-04-07 14:51:10 -03:00
parent 5c3e6e4863
commit 9ca4d15d74
4 changed files with 193 additions and 17 deletions

View File

@ -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

View File

@ -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 <fstream>
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<Layer*> layers;
{
OFSTREAM(os, "spr-" + base::convert_to<std::string>(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<std::string>(pal->id()));
write_palette(subos, pal);
}
for (FrameTag* tag : spr->frameTags()) {
OFSTREAM(subos, "frtag-" + base::convert_to<std::string>(tag->id()));
write_frame_tag(subos, tag);
}
for (Layer* lay : layers) {
OFSTREAM(os, "lay-" + base::convert_to<std::string>(lay->id()));
write32(os, lay->id());
write_string(os, lay->name());
write32(os, static_cast<int>(lay->flags())); // Flags
write16(os, static_cast<int>(lay->type())); // Type
if (lay->type() == ObjectType::LayerImage) {
CelConstIterator it, begin = static_cast<const LayerImage*>(lay)->getCelBegin();
CelConstIterator end = static_cast<const LayerImage*>(lay)->getCelEnd();
// Cels
write32(os, static_cast<const LayerImage*>(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<std::string>(cel->id()));
write_cel(os, cel);
}
// Images (CelData)
for (Cel* cel : spr->uniqueCels()) {
OFSTREAM(os, "img-" + base::convert_to<std::string>(cel->data()->id()));
write_celdata(os, cel->data());
write_image(os, cel->image());
}
}
} // namespace crash
} // namespace app

View File

@ -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 <string>
namespace app {
class Document;
namespace crash {
void write_document(const std::string& dir, app::Document* doc);
} // namespace crash
} // namespace app
#endif

View File

@ -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<std::string>(doc->id()) + ".ase");
TRACE("DataRecovery: Saving document '%s'...\n", fn.c_str());
std::string dir = base::join_path(m_path,
base::convert_to<std::string>(doc->id()));
TRACE("DataRecovery: Saving document '%s'...\n", dir.c_str());
FileOp* fop = fop_to_save_document(&ctx,
static_cast<app::Document*>(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()