1// Aseprite
2// Copyright (C) 2018-2020 Igara Studio S.A.
3// Copyright (C) 2001-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/crash/write_document.h"
13
14#include "app/crash/doc_format.h"
15#include "app/crash/internals.h"
16#include "app/doc.h"
17#include "base/convert_to.h"
18#include "base/fs.h"
19#include "base/fstream_path.h"
20#include "base/serialization.h"
21#include "base/string.h"
22#include "doc/cancel_io.h"
23#include "doc/cel.h"
24#include "doc/cel_data_io.h"
25#include "doc/cel_io.h"
26#include "doc/cels_range.h"
27#include "doc/frame.h"
28#include "doc/image_io.h"
29#include "doc/layer.h"
30#include "doc/layer_tilemap.h"
31#include "doc/palette.h"
32#include "doc/palette_io.h"
33#include "doc/slice.h"
34#include "doc/slice_io.h"
35#include "doc/sprite.h"
36#include "doc/string_io.h"
37#include "doc/tag.h"
38#include "doc/tag_io.h"
39#include "doc/tileset.h"
40#include "doc/tileset_io.h"
41#include "doc/tilesets.h"
42#include "doc/user_data_io.h"
43#include "fixmath/fixmath.h"
44
45#include <fstream>
46#include <map>
47
48namespace app {
49namespace crash {
50
51using namespace base::serialization;
52using namespace base::serialization::little_endian;
53using namespace doc;
54
55namespace {
56
57static std::map<ObjectId, ObjVersionsMap> g_docVersions;
58static std::map<ObjectId, base::paths> g_deleteFiles;
59
60class Writer {
61public:
62 Writer(const std::string& dir, Doc* doc, doc::CancelIO* cancel)
63 : m_dir(dir)
64 , m_doc(doc)
65 , m_objVersions(g_docVersions[doc->id()])
66 , m_deleteFiles(g_deleteFiles[doc->id()])
67 , m_cancel(cancel) {
68 }
69
70 bool saveDocument() {
71 Sprite* spr = m_doc->sprite();
72
73 // Save from objects without children (e.g. images), to aggregated
74 // objects (e.g. cels, layers, etc.)
75
76 for (Palette* pal : spr->getPalettes())
77 if (!saveObject("pal", pal, &Writer::writePalette))
78 return false;
79
80 if (spr->hasTilesets()) {
81 for (Tileset* tset : *spr->tilesets())
82 if (!saveObject("tset", tset, &Writer::writeTileset))
83 return false;
84 }
85
86 for (Tag* frtag : spr->tags())
87 if (!saveObject("frtag", frtag, &Writer::writeFrameTag))
88 return false;
89
90 for (Slice* slice : spr->slices())
91 if (!saveObject("slice", slice, &Writer::writeSlice))
92 return false;
93
94 // Get all layers (visible, hidden, subchildren, etc.)
95 LayerList layers = spr->allLayers();
96
97 // Save original cel data (skip links)
98 for (Layer* lay : layers) {
99 CelList cels;
100 lay->getCels(cels);
101
102 for (Cel* cel : cels) {
103 if (cel->link()) // Skip link
104 continue;
105
106 if (!saveObject("img", cel->image(), &Writer::writeImage))
107 return false;
108
109 if (!saveObject("celdata", cel->data(), &Writer::writeCelData))
110 return false;
111 }
112 }
113
114 // Save all cels (original and links)
115 for (Layer* lay : layers) {
116 CelList cels;
117 lay->getCels(cels);
118
119 for (Cel* cel : cels)
120 if (!saveObject("cel", cel, &Writer::writeCel))
121 return false;
122 }
123
124 // Save all layers (top level, groups, children, etc.)
125 for (Layer* lay : layers)
126 if (!saveObject("lay", lay, &Writer::writeLayerStructure))
127 return false;
128
129 if (!saveObject("spr", spr, &Writer::writeSprite))
130 return false;
131
132 if (!saveObject("doc", m_doc, &Writer::writeDocumentFile))
133 return false;
134
135 // Delete old files after all files are correctly saved.
136 deleteOldVersions();
137 return true;
138 }
139
140private:
141
142 bool isCanceled() const {
143 return (m_cancel && m_cancel->isCanceled());
144 }
145
146 bool writeDocumentFile(std::ofstream& s, Doc* doc) {
147 write32(s, doc->sprite()->id());
148 write_string(s, doc->filename());
149 write16(s, DOC_FORMAT_VERSION_LAST);
150 return true;
151 }
152
153 bool writeSprite(std::ofstream& s, Sprite* spr) {
154 // Header
155 write8(s, int(spr->colorMode()));
156 write16(s, spr->width());
157 write16(s, spr->height());
158 write32(s, spr->transparentColor());
159 write32(s, spr->totalFrames());
160
161 // Frame durations
162 for (frame_t fr = 0; fr < spr->totalFrames(); ++fr)
163 write32(s, spr->frameDuration(fr));
164
165 // IDs of all tilesets
166 write32(s, spr->hasTilesets() ? spr->tilesets()->size(): 0);
167 if (spr->hasTilesets()) {
168 for (Tileset* tileset : *spr->tilesets())
169 write32(s, tileset->id());
170 }
171
172 // IDs of all main layers
173 write32(s, spr->allLayersCount());
174 writeAllLayersID(s, 0, spr->root());
175
176 // IDs of all palettes
177 write32(s, spr->getPalettes().size());
178 for (Palette* pal : spr->getPalettes())
179 write32(s, pal->id());
180
181 // IDs of all frame tags
182 write32(s, spr->tags().size());
183 for (Tag* frtag : spr->tags())
184 write32(s, frtag->id());
185
186 // IDs of all slices
187 write32(s, spr->slices().size());
188 for (const Slice* slice : spr->slices())
189 write32(s, slice->id());
190
191 // Color Space
192 writeColorSpace(s, spr->colorSpace());
193
194 // Grid bounds
195 writeGridBounds(s, spr->gridBounds());
196
197 // Write Sprite User Data
198 writeUserData(s, spr->userData());
199
200 return true;
201 }
202
203 bool writeUserData(std::ofstream& s, const UserData& userData) {
204 write_string(s, userData.text());
205 write32(s, (uint32_t)userData.color());
206 return true;
207 }
208
209 bool writeGridBounds(std::ofstream& s, const gfx::Rect& grid) {
210 write16(s, (int16_t)grid.x);
211 write16(s, (int16_t)grid.y);
212 write16(s, grid.w);
213 write16(s, grid.h);
214 return true;
215 }
216
217 bool writeColorSpace(std::ofstream& s, const gfx::ColorSpaceRef& colorSpace) {
218 write16(s, colorSpace->type());
219 write16(s, colorSpace->flags());
220 write32(s, fixmath::ftofix(colorSpace->gamma()));
221
222 auto& rawData = colorSpace->rawData();
223 write32(s, rawData.size());
224 if (rawData.size() > 0)
225 s.write((const char*)&rawData[0], rawData.size());
226
227 write_string(s, colorSpace->name());
228 return true;
229 }
230
231 void writeAllLayersID(std::ofstream& s, ObjectId parentId, const LayerGroup* group) {
232 for (const Layer* lay : group->layers()) {
233 write32(s, lay->id());
234 write32(s, parentId);
235
236 if (lay->isGroup())
237 writeAllLayersID(s, lay->id(), static_cast<const LayerGroup*>(lay));
238 }
239 }
240
241 bool writeLayerStructure(std::ofstream& s, Layer* lay) {
242 write32(s, static_cast<int>(lay->flags())); // Flags
243 write16(s, static_cast<int>(lay->type())); // Type
244 write_string(s, lay->name());
245
246 switch (lay->type()) {
247
248 case ObjectType::LayerImage:
249 case ObjectType::LayerTilemap: {
250 // Tileset index
251 if (lay->type() == ObjectType::LayerTilemap)
252 write32(s, static_cast<const LayerTilemap*>(lay)->tilesetIndex());
253
254 CelConstIterator it, begin = static_cast<const LayerImage*>(lay)->getCelBegin();
255 CelConstIterator end = static_cast<const LayerImage*>(lay)->getCelEnd();
256
257 // Blend mode & opacity
258 write16(s, (int)static_cast<const LayerImage*>(lay)->blendMode());
259 write8(s, static_cast<const LayerImage*>(lay)->opacity());
260
261 // Cels
262 write32(s, static_cast<const LayerImage*>(lay)->getCelsCount());
263 for (it=begin; it != end; ++it) {
264 const Cel* cel = *it;
265 write32(s, cel->id());
266 }
267 break;
268 }
269
270 case ObjectType::LayerGroup:
271 // Do nothing (the layer parent/children structure is saved in
272 // writeSprite/writeAllLayersID() functions)
273 break;
274 }
275
276 // Save user data
277 write_user_data(s, lay->userData());
278 return true;
279 }
280
281 bool writeCel(std::ofstream& s, Cel* cel) {
282 write_cel(s, cel);
283 return true;
284 }
285
286 bool writeCelData(std::ofstream& s, CelData* celdata) {
287 write_celdata(s, celdata);
288 return true;
289 }
290
291 bool writeImage(std::ofstream& s, Image* img) {
292 return write_image(s, img, m_cancel);
293 }
294
295 bool writePalette(std::ofstream& s, Palette* pal) {
296 write_palette(s, pal);
297 return true;
298 }
299
300 bool writeTileset(std::ofstream& s, Tileset* tileset) {
301 write_tileset(s, tileset);
302 return true;
303 }
304
305 bool writeFrameTag(std::ofstream& s, Tag* frameTag) {
306 write_tag(s, frameTag);
307 return true;
308 }
309
310 bool writeSlice(std::ofstream& s, Slice* slice) {
311 write_slice(s, slice);
312 return true;
313 }
314
315 template<typename T>
316 bool saveObject(const char* prefix, T* obj, bool (Writer::*writeMember)(std::ofstream&, T*)) {
317 if (isCanceled())
318 return false;
319
320 if (!obj->version())
321 obj->incrementVersion();
322
323 ObjVersions& versions = m_objVersions[obj->id()];
324 if (versions.newer() == obj->version())
325 return true;
326
327 std::string fn = prefix;
328 fn.push_back('-');
329 fn += base::convert_to<std::string>(obj->id());
330
331 std::string fullfn = base::join_path(m_dir, fn);
332 std::string oldfn = fullfn + "." + base::convert_to<std::string>(versions.older());
333 fullfn += "." + base::convert_to<std::string>(obj->version());
334
335 std::ofstream s(FSTREAM_PATH(fullfn), std::ofstream::binary);
336 write32(s, 0); // Leave a room for the magic number
337 if (!(this->*writeMember)(s, obj)) // Write the object
338 return false;
339
340 // Flush all data. In this way we ensure that the magic number is
341 // the last thing being written in the file.
342 s.flush();
343
344 // Write the magic number
345 s.seekp(0);
346 write32(s, MAGIC_NUMBER);
347
348 // Remove the older version
349 if (versions.older() && base::is_file(oldfn))
350 m_deleteFiles.push_back(oldfn);
351
352 // Rotate versions and add the latest one
353 versions.rotateRevisions(obj->version());
354
355 TRACE(" - Saved %s #%d v%d\n", prefix, obj->id(), obj->version());
356 return true;
357 }
358
359 void deleteOldVersions() {
360 while (!m_deleteFiles.empty() && !isCanceled()) {
361 std::string file = m_deleteFiles.back();
362 m_deleteFiles.erase(m_deleteFiles.end()-1);
363
364 try {
365 TRACE(" - Deleting <%s>\n", file.c_str());
366 base::delete_file(file);
367 }
368 catch (const std::exception&) {
369 TRACE(" - Cannot delete <%s>\n", file.c_str());
370 }
371 }
372 }
373
374 std::string m_dir;
375 Doc* m_doc;
376 ObjVersionsMap& m_objVersions;
377 base::paths& m_deleteFiles;
378 doc::CancelIO* m_cancel;
379};
380
381} // anonymous namespace
382
383//////////////////////////////////////////////////////////////////////
384// Public API
385
386bool write_document(const std::string& dir,
387 Doc* doc,
388 doc::CancelIO* cancel)
389{
390 Writer writer(dir, doc, cancel);
391 return writer.saveDocument();
392}
393
394void delete_document_internals(Doc* doc)
395{
396 ASSERT(doc);
397
398 // The document could not be inside g_documentObjects in case it was
399 // never saved by the backup process.
400 {
401 auto it = g_docVersions.find(doc->id());
402 if (it != g_docVersions.end())
403 g_docVersions.erase(it);
404 }
405 {
406 auto it = g_deleteFiles.find(doc->id());
407 if (it != g_deleteFiles.end())
408 g_deleteFiles.erase(it);
409 }
410}
411
412} // namespace crash
413} // namespace app
414