2015-04-08 01:51:10 +08:00
|
|
|
// 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
|
|
|
|
|
2015-04-09 07:05:05 +08:00
|
|
|
#include "app/crash/write_document.h"
|
2015-04-08 01:51:10 +08:00
|
|
|
|
|
|
|
#include "app/document.h"
|
|
|
|
#include "base/convert_to.h"
|
2015-04-09 07:05:05 +08:00
|
|
|
#include "base/fs.h"
|
2015-04-08 01:51:10 +08:00
|
|
|
#include "base/path.h"
|
|
|
|
#include "base/serialization.h"
|
|
|
|
#include "base/string.h"
|
2015-04-09 07:05:05 +08:00
|
|
|
#include "base/unique_ptr.h"
|
2015-04-08 01:51:10 +08:00
|
|
|
#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>
|
2015-04-08 04:53:31 +08:00
|
|
|
#include <map>
|
2015-04-08 01:51:10 +08:00
|
|
|
|
|
|
|
namespace app {
|
|
|
|
namespace crash {
|
|
|
|
|
|
|
|
using namespace base::serialization;
|
|
|
|
using namespace base::serialization::little_endian;
|
|
|
|
using namespace doc;
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
2015-04-09 07:05:05 +08:00
|
|
|
#define OFSTREAM(dir, name, fn) \
|
|
|
|
std::ofstream name(base::from_utf8(base::join_path(dir, fn)), std::ofstream::binary);
|
2015-04-08 01:51:10 +08:00
|
|
|
#else
|
2015-04-09 07:05:05 +08:00
|
|
|
#define OFSTREAM(dir, name, fn) \
|
2015-04-10 00:47:21 +08:00
|
|
|
std::ofstream name(base::join_path(dir, fn).c_str(), std::ofstream::binary);
|
2015-04-08 01:51:10 +08:00
|
|
|
#endif
|
|
|
|
|
2015-04-08 04:53:31 +08:00
|
|
|
namespace {
|
2015-04-08 01:51:10 +08:00
|
|
|
|
2015-04-08 04:53:31 +08:00
|
|
|
typedef std::map<ObjectId, ObjectVersion> Versions;
|
|
|
|
static std::map<ObjectId, Versions> g_documentObjects;
|
2015-04-08 01:51:10 +08:00
|
|
|
|
2015-04-09 07:05:05 +08:00
|
|
|
template<typename T, typename WriteFunc>
|
|
|
|
void save_object(const char* prefix, T* obj, WriteFunc write_func, Versions& versions, const std::string& dir)
|
|
|
|
{
|
|
|
|
if (!obj->version())
|
|
|
|
obj->incrementVersion();
|
|
|
|
|
|
|
|
if (versions[obj->id()] != obj->version()) {
|
2015-04-09 08:32:41 +08:00
|
|
|
OFSTREAM(dir, s, prefix ? prefix + base::convert_to<std::string>(obj->id()): "doc");
|
2015-04-09 07:05:05 +08:00
|
|
|
write_func(s, obj);
|
|
|
|
versions[obj->id()] = obj->version();
|
|
|
|
|
|
|
|
TRACE(" - %s %d saved with version %d\n",
|
|
|
|
prefix, obj->id(), obj->version());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
TRACE(" - Ignoring %s %d (version %d already saved)\n",
|
|
|
|
prefix, obj->id(), obj->version());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-09 08:32:41 +08:00
|
|
|
void write_document_file(std::ofstream& s, app::Document* doc)
|
|
|
|
{
|
|
|
|
write32(s, doc->sprite()->id());
|
|
|
|
write_string(s, doc->filename());
|
|
|
|
}
|
|
|
|
|
2015-04-08 04:53:31 +08:00
|
|
|
void write_sprite(std::ofstream& s, Sprite* spr)
|
|
|
|
{
|
2015-04-09 07:05:05 +08:00
|
|
|
write8(s, spr->pixelFormat());
|
|
|
|
write16(s, spr->width());
|
|
|
|
write16(s, spr->height());
|
2015-04-08 04:53:31 +08:00
|
|
|
write32(s, spr->transparentColor());
|
|
|
|
|
|
|
|
// Frame durations
|
|
|
|
write32(s, spr->totalFrames());
|
|
|
|
for (frame_t fr = 0; fr < spr->totalFrames(); ++fr)
|
|
|
|
write32(s, spr->frameDuration(fr));
|
2015-04-09 07:05:05 +08:00
|
|
|
|
|
|
|
// IDs of all main layers
|
|
|
|
std::vector<Layer*> layers;
|
|
|
|
spr->getLayersList(layers);
|
|
|
|
write32(s, layers.size());
|
|
|
|
for (Layer* lay : layers)
|
|
|
|
write32(s, lay->id());
|
|
|
|
|
|
|
|
// IDs of all palettes
|
|
|
|
write32(s, spr->getPalettes().size());
|
|
|
|
for (Palette* pal : spr->getPalettes())
|
|
|
|
write32(s, pal->id());
|
2015-04-08 04:53:31 +08:00
|
|
|
}
|
2015-04-08 01:51:10 +08:00
|
|
|
|
2015-04-08 04:53:31 +08:00
|
|
|
void write_layer_structure(std::ofstream& s, Layer* lay)
|
|
|
|
{
|
|
|
|
write32(s, static_cast<int>(lay->flags())); // Flags
|
|
|
|
write16(s, static_cast<int>(lay->type())); // Type
|
2015-04-09 07:05:05 +08:00
|
|
|
write_string(s, lay->name());
|
2015-04-08 01:51:10 +08:00
|
|
|
|
2015-04-08 04:53:31 +08:00
|
|
|
if (lay->type() == ObjectType::LayerImage) {
|
|
|
|
CelConstIterator it, begin = static_cast<const LayerImage*>(lay)->getCelBegin();
|
|
|
|
CelConstIterator end = static_cast<const LayerImage*>(lay)->getCelEnd();
|
2015-04-08 01:51:10 +08:00
|
|
|
|
|
|
|
// Cels
|
2015-04-08 04:53:31 +08:00
|
|
|
write32(s, static_cast<const LayerImage*>(lay)->getCelsCount());
|
|
|
|
for (it=begin; it != end; ++it) {
|
|
|
|
const Cel* cel = *it;
|
|
|
|
write32(s, cel->id());
|
|
|
|
}
|
2015-04-08 01:51:10 +08:00
|
|
|
}
|
2015-04-08 04:53:31 +08:00
|
|
|
}
|
2015-04-08 01:51:10 +08:00
|
|
|
|
2015-04-08 04:53:31 +08:00
|
|
|
} // anonymous namespace
|
2015-04-08 01:51:10 +08:00
|
|
|
|
2015-04-09 07:05:05 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Public API
|
|
|
|
|
|
|
|
void write_document(const std::string& dir, app::Document* doc)
|
2015-04-08 04:53:31 +08:00
|
|
|
{
|
|
|
|
Versions& versions = g_documentObjects[doc->id()];
|
|
|
|
Sprite* spr = doc->sprite();
|
2015-04-09 07:05:05 +08:00
|
|
|
|
2015-04-09 08:32:41 +08:00
|
|
|
save_object(nullptr, doc, write_document_file, versions, dir);
|
2015-04-09 07:05:05 +08:00
|
|
|
save_object("spr", spr, write_sprite, versions, dir);
|
2015-04-08 01:51:10 +08:00
|
|
|
|
2015-04-08 04:53:31 +08:00
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Create one stream for each object
|
2015-04-08 01:51:10 +08:00
|
|
|
|
2015-04-08 04:53:31 +08:00
|
|
|
for (Palette* pal : spr->getPalettes())
|
2015-04-09 07:05:05 +08:00
|
|
|
save_object("pal", pal, write_palette, versions, dir);
|
2015-04-08 04:53:31 +08:00
|
|
|
|
|
|
|
for (FrameTag* frtag : spr->frameTags())
|
2015-04-09 07:05:05 +08:00
|
|
|
save_object("frtag", frtag, write_frame_tag, versions, dir);
|
2015-04-08 04:53:31 +08:00
|
|
|
|
|
|
|
std::vector<Layer*> layers;
|
|
|
|
spr->getLayersList(layers);
|
|
|
|
for (Layer* lay : layers)
|
2015-04-09 07:05:05 +08:00
|
|
|
save_object("lay", lay, write_layer_structure, versions, dir);
|
2015-04-08 04:53:31 +08:00
|
|
|
|
|
|
|
for (Cel* cel : spr->cels())
|
2015-04-09 07:05:05 +08:00
|
|
|
save_object("cel", cel, write_cel, versions, dir);
|
2015-04-08 01:51:10 +08:00
|
|
|
|
|
|
|
// Images (CelData)
|
|
|
|
for (Cel* cel : spr->uniqueCels()) {
|
2015-04-09 07:05:05 +08:00
|
|
|
save_object("celdata", cel->data(), write_celdata, versions, dir);
|
|
|
|
save_object("img", cel->image(), write_image, versions, dir);
|
2015-04-08 01:51:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-09 07:05:05 +08:00
|
|
|
void delete_document_internals(app::Document* doc)
|
|
|
|
{
|
|
|
|
ASSERT(doc);
|
|
|
|
auto it = g_documentObjects.find(doc->id());
|
|
|
|
|
|
|
|
// The document could not be inside g_documentObjects in case it was
|
|
|
|
// never saved by the backup process.
|
|
|
|
if (it != g_documentObjects.end())
|
|
|
|
g_documentObjects.erase(it);
|
|
|
|
}
|
|
|
|
|
2015-04-08 01:51:10 +08:00
|
|
|
} // namespace crash
|
|
|
|
} // namespace app
|