aseprite/src/app/file/file.cpp

913 lines
24 KiB
C++
Raw Normal View History

/* Aseprite
2013-01-27 12:13:13 -03:00
* Copyright (C) 2001-2013 David Capello
2007-09-18 23:57:02 +00:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
2007-09-18 23:57:02 +00:00
#include "config.h"
#endif
2007-09-18 23:57:02 +00:00
#include "app/app.h"
#include "app/ui/status_bar.h"
#include "base/mutex.h"
#include "base/scoped_lock.h"
#include "base/shared_ptr.h"
#include "base/string.h"
#include "app/console.h"
#include "app/document.h"
#include "app/file/file.h"
#include "app/file/file_format.h"
#include "app/file/file_formats_manager.h"
#include "app/file/format_options.h"
#include "app/modules/gui.h"
#include "app/modules/palettes.h"
#include "raster/quantization.h"
#include "raster/raster.h"
2012-06-17 22:49:58 -03:00
#include "ui/alert.h"
2007-09-18 23:57:02 +00:00
#include <allegro.h>
#include <string.h>
namespace app {
using namespace base;
static FileOp* fop_new(FileOpType type);
static void fop_prepare_for_sequence(FileOp* fop);
2007-09-18 23:57:02 +00:00
static FileFormat* get_fileformat(const char* extension);
static int split_filename(const char* filename, char* left, char* right, int* width);
2007-09-18 23:57:02 +00:00
void get_readable_extensions(char* buf, int size)
2007-09-18 23:57:02 +00:00
{
2011-01-16 17:27:18 -03:00
FileFormatsList::iterator it = FileFormatsManager::instance().begin();
FileFormatsList::iterator end = FileFormatsManager::instance().end();
2007-09-18 23:57:02 +00:00
/* clear the string */
ustrncpy(buf, empty_string, size);
2007-09-18 23:57:02 +00:00
/* insert file format */
2011-01-16 17:27:18 -03:00
for (; it != end; ++it) {
if ((*it)->support(FILE_SUPPORT_LOAD)) {
if (ustrcmp(buf, empty_string) != 0)
ustrncat(buf, ",", size);
2011-01-16 17:27:18 -03:00
ustrncat(buf, (*it)->extensions(), size);
}
2007-09-18 23:57:02 +00:00
}
}
void get_writable_extensions(char* buf, int size)
2007-09-18 23:57:02 +00:00
{
2011-01-16 17:27:18 -03:00
FileFormatsList::iterator it = FileFormatsManager::instance().begin();
FileFormatsList::iterator end = FileFormatsManager::instance().end();
2007-09-18 23:57:02 +00:00
/* clear the string */
ustrncpy(buf, empty_string, size);
2007-09-18 23:57:02 +00:00
/* insert file format */
2011-01-16 17:27:18 -03:00
for (; it != end; ++it) {
if ((*it)->support(FILE_SUPPORT_SAVE)) {
if (ustrcmp(buf, empty_string) != 0)
ustrncat(buf, ",", size);
2011-01-16 17:27:18 -03:00
ustrncat(buf, (*it)->extensions(), size);
}
2007-09-18 23:57:02 +00:00
}
}
Document* load_document(const char* filename)
2007-09-18 23:57:02 +00:00
{
Document* document;
/* TODO add a option to configure what to do with the sequence */
FileOp *fop = fop_to_load_document(filename, FILE_LOAD_SEQUENCE_NONE);
if (!fop)
return NULL;
/* operate in this same thread */
fop_operate(fop, NULL);
fop_done(fop);
fop_post_load(fop);
if (fop->has_error()) {
Console console;
console.printf(fop->error.c_str());
}
document = fop->document;
fop_free(fop);
return document;
}
int save_document(Document* document)
{
int ret;
FileOp* fop = fop_to_save_document(document);
if (!fop)
return -1;
/* operate in this same thread */
fop_operate(fop, NULL);
fop_done(fop);
if (fop->has_error()) {
Console console;
console.printf(fop->error.c_str());
}
ret = (!fop->has_error() ? 0: -1);
fop_free(fop);
2007-09-18 23:57:02 +00:00
return ret;
}
FileOp* fop_to_load_document(const char* filename, int flags)
{
FileOp *fop;
fop = fop_new(FileOpLoad);
if (!fop)
return NULL;
/* get the extension of the filename (in lower case) */
std::string extension = base::string_to_lower(get_extension(filename));
2007-09-18 23:57:02 +00:00
PRINTF("Loading file \"%s\" (%s)\n", filename, extension.c_str());
2007-09-18 23:57:02 +00:00
/* does file exist? */
if (!file_exists(filename, FA_ALL, NULL)) {
fop_error(fop, "File not found: \"%s\"\n", filename);
goto done;
2007-09-18 23:57:02 +00:00
}
/* get the format through the extension of the filename */
fop->format = get_fileformat(extension.c_str());
if (!fop->format ||
2011-01-16 17:27:18 -03:00
!fop->format->support(FILE_SUPPORT_LOAD)) {
fop_error(fop, "ASEPRITE can't load \"%s\" files\n", extension.c_str());
goto done;
}
2007-09-18 23:57:02 +00:00
/* use the "sequence" interface */
2011-01-16 17:27:18 -03:00
if (fop->format->support(FILE_SUPPORT_SEQUENCES)) {
/* prepare to load a sequence */
fop_prepare_for_sequence(fop);
2007-09-18 23:57:02 +00:00
/* per now, we want load just one file */
fop->seq.filename_list.push_back(filename);
2007-09-18 23:57:02 +00:00
/* don't load the sequence (just the one file/one frame) */
if (!(flags & FILE_LOAD_SEQUENCE_NONE)) {
char buf[512], left[512], right[512];
int c, width, start_from;
/* first of all, we must generate the list of files to load in the
sequence... */
/* check is this could be a sequence */
start_from = split_filename(filename, left, right, &width);
if (start_from >= 0) {
/* try to get more file names */
for (c=start_from+1; ; c++) {
/* get the next file name */
usprintf(buf, "%s%0*d%s", left, width, c, right);
/* if the file doesn't exist, we doesn't need more files to load */
if (!exists(buf))
break;
/* add this file name to the list */
fop->seq.filename_list.push_back(buf);
}
2007-09-18 23:57:02 +00:00
}
/* TODO add a better dialog to edit file-names */
if ((flags & FILE_LOAD_SEQUENCE_ASK) &&
App::instance()->isGui()) {
/* really want load all files? */
if ((fop->seq.filename_list.size() > 1) &&
(ui::Alert::show("Notice"
"<<Possible animation with:"
"<<%s"
"<<Load the sequence of bitmaps?"
"||&Agree||&Skip",
get_filename(filename)) != 1)) {
/* if the user replies "Skip", we need just one file name (the
first one) */
if (fop->seq.filename_list.size() > 1) {
fop->seq.filename_list.erase(fop->seq.filename_list.begin()+1,
fop->seq.filename_list.end());
}
}
2007-09-18 23:57:02 +00:00
}
}
}
else
fop->filename = filename;
2007-09-18 23:57:02 +00:00
/* load just one frame */
if (flags & FILE_LOAD_ONE_FRAME)
fop->oneframe = true;
done:;
return fop;
2007-09-18 23:57:02 +00:00
}
FileOp* fop_to_save_document(Document* document)
2007-09-18 23:57:02 +00:00
{
char extension[32], buf[2048];
FileOp *fop;
2007-09-18 23:57:02 +00:00
bool fatal;
fop = fop_new(FileOpSave);
if (!fop)
return NULL;
/* document to save */
fop->document = document;
/* get the extension of the filename (in lower case) */
ustrcpy(extension, get_extension(fop->document->getFilename()));
2007-09-18 23:57:02 +00:00
ustrlwr(extension);
PRINTF("Saving document \"%s\" (%s)\n", fop->document->getFilename(), extension);
2007-09-18 23:57:02 +00:00
/* get the format through the extension of the filename */
fop->format = get_fileformat(extension);
if (!fop->format ||
2011-01-16 17:27:18 -03:00
!fop->format->support(FILE_SUPPORT_SAVE)) {
fop_error(fop, "ASEPRITE can't save \"%s\" files\n", extension);
return fop;
2007-09-18 23:57:02 +00:00
}
/* warnings */
ustrcpy(buf, empty_string);
fatal = false;
2007-09-18 23:57:02 +00:00
/* check image type support */
switch (fop->document->getSprite()->getPixelFormat()) {
2007-09-18 23:57:02 +00:00
case IMAGE_RGB:
2011-01-16 17:27:18 -03:00
if (!(fop->format->support(FILE_SUPPORT_RGB))) {
usprintf(buf+ustrlen(buf), "<<- %s", "RGB format");
fatal = true;
2007-09-18 23:57:02 +00:00
}
2011-01-16 17:27:18 -03:00
if (!(fop->format->support(FILE_SUPPORT_RGBA)) &&
fop->document->getSprite()->needAlpha()) {
usprintf(buf+ustrlen(buf), "<<- %s", "Alpha channel");
2007-09-18 23:57:02 +00:00
}
break;
case IMAGE_GRAYSCALE:
2011-01-16 17:27:18 -03:00
if (!(fop->format->support(FILE_SUPPORT_GRAY))) {
usprintf(buf+ustrlen(buf), "<<- Grayscale format");
fatal = true;
2007-09-18 23:57:02 +00:00
}
2011-01-16 17:27:18 -03:00
if (!(fop->format->support(FILE_SUPPORT_GRAYA)) &&
fop->document->getSprite()->needAlpha()) {
usprintf(buf+ustrlen(buf), "<<- Alpha channel");
2007-09-18 23:57:02 +00:00
}
break;
case IMAGE_INDEXED:
2011-01-16 17:27:18 -03:00
if (!(fop->format->support(FILE_SUPPORT_INDEXED))) {
usprintf(buf+ustrlen(buf), "<<- Indexed format");
fatal = true;
2007-09-18 23:57:02 +00:00
}
break;
}
// check frames support
if (fop->document->getSprite()->getTotalFrames() > 1) {
2011-01-16 17:27:18 -03:00
if (!fop->format->support(FILE_SUPPORT_FRAMES) &&
!fop->format->support(FILE_SUPPORT_SEQUENCES)) {
usprintf(buf+ustrlen(buf), "<<- Frames");
2011-01-16 17:27:18 -03:00
}
2007-09-18 23:57:02 +00:00
}
// layers support
if (fop->document->getSprite()->getFolder()->getLayersCount() > 1) {
2011-01-16 17:27:18 -03:00
if (!(fop->format->support(FILE_SUPPORT_LAYERS))) {
usprintf(buf+ustrlen(buf), "<<- Layers");
2007-09-18 23:57:02 +00:00
}
}
2010-09-30 21:38:01 -03:00
// Palettes support.
if (fop->document->getSprite()->getPalettes().size() > 1) {
2011-01-16 17:27:18 -03:00
if (!fop->format->support(FILE_SUPPORT_PALETTES) &&
!fop->format->support(FILE_SUPPORT_SEQUENCES)) {
usprintf(buf+ustrlen(buf), "<<- Palette changes between frames");
2007-09-18 23:57:02 +00:00
}
}
/* show the confirmation alert */
if (ugetc(buf)) {
/* interative */
if (App::instance()->isGui()) {
int ret;
2007-09-18 23:57:02 +00:00
if (fatal)
ret = ui::Alert::show("Error<<File format \"%s\" doesn't support:%s"
"||&Close",
fop->format->name(), buf);
2007-09-18 23:57:02 +00:00
else
ret = ui::Alert::show("Warning<<File format \"%s\" doesn't support:%s"
"<<Do you want continue?"
"||&Yes||&No",
fop->format->name(), buf);
2007-09-18 23:57:02 +00:00
/* operation can't be done (by fatal error) or the user cancel
the operation */
if ((fatal) || (ret != 1)) {
fop_free(fop);
return NULL;
}
}
/* no interactive & fatal error? */
else if (fatal) {
fop_error(fop, buf);
return fop;
2007-09-18 23:57:02 +00:00
}
}
2011-01-16 17:27:18 -03:00
// Use the "sequence" interface.
if (fop->format->support(FILE_SUPPORT_SEQUENCES)) {
fop_prepare_for_sequence(fop);
// To save one frame
if (fop->document->getSprite()->getTotalFrames() == 1) {
fop->seq.filename_list.push_back(fop->document->getFilename());
}
// To save more frames
else {
char buf[256], left[256], right[256];
2012-07-08 21:09:09 -03:00
int width, start_from;
start_from = split_filename(fop->document->getFilename(), left, right, &width);
if (start_from < 0) {
start_from = 0;
width =
(fop->document->getSprite()->getTotalFrames() < 10)? 1:
(fop->document->getSprite()->getTotalFrames() < 100)? 2:
(fop->document->getSprite()->getTotalFrames() < 1000)? 3: 4;
2007-09-18 23:57:02 +00:00
}
2012-07-08 21:09:09 -03:00
for (FrameNumber frame(0); frame<fop->document->getSprite()->getTotalFrames(); ++frame) {
/* get the name for this frame */
usprintf(buf, "%s%0*d%s", left, width, start_from+frame, right);
fop->seq.filename_list.push_back(buf);
}
}
}
else
fop->filename = fop->document->getFilename();
// Configure output format?
2011-01-16 17:27:18 -03:00
if (fop->format->support(FILE_SUPPORT_GET_FORMAT_OPTIONS)) {
SharedPtr<FormatOptions> format_options = fop->format->getFormatOptions(fop);
2011-01-16 17:27:18 -03:00
// Does the user cancelled the operation?
2008-03-29 04:24:36 +00:00
if (format_options == NULL) {
fop_free(fop);
return NULL;
}
2008-03-29 04:24:36 +00:00
fop->seq.format_options = format_options;
fop->document->setFormatOptions(format_options);
}
return fop;
}
// Executes the file operation: loads or saves the sprite.
//
// It can be called from a different thread of the one used
// by fop_to_load_sprite() or fop_to_save_sprite().
//
// After this function you must to mark the "fop" as "done" calling
// fop_done() function.
void fop_operate(FileOp *fop, IFileOpProgress* progress)
{
ASSERT(fop != NULL);
ASSERT(!fop_is_done(fop));
fop->progressInterface = progress;
// Load //////////////////////////////////////////////////////////////////////
if (fop->type == FileOpLoad &&
fop->format != NULL &&
2011-01-16 17:27:18 -03:00
fop->format->support(FILE_SUPPORT_LOAD)) {
// Load a sequence
if (fop->is_sequence()) {
2012-07-08 21:09:09 -03:00
int image_index = 0;
Image* old_image;
bool loadres;
// Default palette
fop->seq.palette->makeBlack();
// TODO set_palette for each frame???
#define SEQUENCE_IMAGE() \
do { \
image_index = fop->document \
->getSprite() \
->getStock()->addImage(fop->seq.image); \
\
fop->seq.last_cel->setImage(image_index); \
fop->seq.layer->addCel(fop->seq.last_cel); \
\
if (fop->document->getSprite()->getPalette(frame) \
->countDiff(fop->seq.palette, NULL, NULL) > 0) { \
fop->seq.palette->setFrame(frame); \
fop->document->getSprite()->setPalette(fop->seq.palette, true); \
} \
\
old_image = fop->seq.image; \
fop->seq.image = NULL; \
fop->seq.last_cel = NULL; \
} while (0)
/* load the sequence */
2012-07-08 21:09:09 -03:00
FrameNumber frames(fop->seq.filename_list.size());
FrameNumber frame(0);
old_image = NULL;
fop->seq.has_alpha = false;
fop->seq.progress_offset = 0.0f;
fop->seq.progress_fraction = 1.0f / (double)frames;
std::vector<std::string>::iterator it = fop->seq.filename_list.begin();
std::vector<std::string>::iterator end = fop->seq.filename_list.end();
for (; it != end; ++it) {
fop->filename = it->c_str();
// Call the "load" procedure to read the first bitmap.
loadres = fop->format->load(fop);
if (!loadres) {
fop_error(fop, "Error loading frame %d from file \"%s\"\n",
frame+1, fop->filename.c_str());
}
// For the first frame...
if (!old_image) {
// Error reading the first frame
if (!loadres || !fop->document || !fop->seq.last_cel) {
2013-03-30 19:53:52 -03:00
delete fop->seq.image;
delete fop->seq.last_cel;
delete fop->document;
fop->document = NULL;
break;
}
// Read ok
else {
2013-03-30 19:53:52 -03:00
// Add the keyframe
SEQUENCE_IMAGE();
}
}
2013-03-30 19:53:52 -03:00
// For other frames
else {
2013-03-30 19:53:52 -03:00
// All done (or maybe not enough memory)
if (!loadres || !fop->seq.last_cel) {
2013-03-30 19:53:52 -03:00
delete fop->seq.image;
delete fop->seq.last_cel;
break;
}
2013-03-30 19:53:52 -03:00
// Compare the old frame with the new one
#if USE_LINK // TODO this should be configurable through a check-box
if (image_count_diff(old_image, fop->seq.image)) {
SEQUENCE_IMAGE();
}
2013-03-30 19:53:52 -03:00
// We don't need this image
else {
2013-03-30 19:53:52 -03:00
delete fop->seq.image;
2013-03-30 19:53:52 -03:00
// But add a link frame
fop->seq.last_cel->image = image_index;
layer_add_frame(fop->seq.layer, fop->seq.last_cel);
fop->seq.last_image = NULL;
fop->seq.last_cel = NULL;
}
#else
SEQUENCE_IMAGE();
#endif
}
2007-09-18 23:57:02 +00:00
2012-07-08 21:09:09 -03:00
++frame;
fop->seq.progress_offset += fop->seq.progress_fraction;
}
fop->filename = *fop->seq.filename_list.begin();
2007-09-18 23:57:02 +00:00
// Final setup
if (fop->document != NULL) {
// Configure the layer as the 'Background'
if (!fop->seq.has_alpha)
fop->seq.layer->configureAsBackground();
// Set the frames range
fop->document->getSprite()->setTotalFrames(frame);
// Sets special options from the specific format (e.g. BMP
// file can contain the number of bits per pixel).
fop->document->setFormatOptions(fop->seq.format_options);
}
}
// Direct load from one file.
else {
// Call the "load" procedure.
2011-01-16 17:27:18 -03:00
if (!fop->format->load(fop))
fop_error(fop, "Error loading sprite from file \"%s\"\n",
fop->filename.c_str());
}
}
// Save //////////////////////////////////////////////////////////////////////
else if (fop->type == FileOpSave &&
fop->format != NULL &&
fop->format->support(FILE_SUPPORT_SAVE)) {
// Save a sequence
if (fop->is_sequence()) {
2011-01-16 17:27:18 -03:00
ASSERT(fop->format->support(FILE_SUPPORT_SEQUENCES));
Sprite* sprite = fop->document->getSprite();
// Create a temporary bitmap
fop->seq.image = Image::create(sprite->getPixelFormat(),
sprite->getWidth(),
sprite->getHeight());
if (fop->seq.image != NULL) {
fop->seq.progress_offset = 0.0f;
fop->seq.progress_fraction = 1.0f / (double)sprite->getTotalFrames();
// For each frame in the sprite.
2012-07-08 21:09:09 -03:00
for (FrameNumber frame(0); frame < sprite->getTotalFrames(); ++frame) {
// Draw the "frame" in "fop->seq.image"
sprite->render(fop->seq.image, 0, 0, frame);
// Setup the palette.
sprite->getPalette(frame)->copyColorsTo(fop->seq.palette);
// Setup the filename to be used.
fop->filename = fop->seq.filename_list[frame];
// Call the "save" procedure... did it fail?
if (!fop->format->save(fop)) {
fop_error(fop, "Error saving frame %d in the file \"%s\"\n",
frame+1, fop->filename.c_str());
break;
}
2007-09-18 23:57:02 +00:00
fop->seq.progress_offset += fop->seq.progress_fraction;
}
fop->filename = *fop->seq.filename_list.begin();
2007-09-18 23:57:02 +00:00
// Destroy the image
2013-03-30 19:53:52 -03:00
delete fop->seq.image;
}
else {
fop_error(fop, "Not enough memory for the temporary bitmap.\n");
}
2007-09-18 23:57:02 +00:00
}
// Direct save to a file.
2007-09-18 23:57:02 +00:00
else {
// Call the "save" procedure.
2011-01-16 17:27:18 -03:00
if (!fop->format->save(fop))
fop_error(fop, "Error saving the sprite in the file \"%s\"\n",
fop->filename.c_str());
2007-09-18 23:57:02 +00:00
}
}
// Progress = 100%
fop_progress(fop, 1.0f);
}
// After mark the 'fop' as 'done' you must to free it calling fop_free().
void fop_done(FileOp *fop)
{
// Finally done.
scoped_lock lock(*fop->mutex);
fop->done = true;
}
void fop_stop(FileOp *fop)
{
scoped_lock lock(*fop->mutex);
if (!fop->done)
fop->stop = true;
}
FileOp::~FileOp()
{
if (this->format)
this->format->destroyData(this);
delete this->seq.palette;
delete this->mutex;
}
void fop_free(FileOp *fop)
{
2010-10-03 13:50:01 -03:00
delete fop;
}
void fop_post_load(FileOp* fop)
{
if (fop->document == NULL)
return;
// Set the filename.
if (fop->is_sequence())
fop->document->setFilename(fop->seq.filename_list.begin()->c_str());
else
fop->document->setFilename(fop->filename.c_str());
bool result = fop->format->postLoad(fop);
if (!result) {
// Destroy the document
delete fop->document;
fop->document = NULL;
return;
}
if (fop->document->getSprite() != NULL) {
// Creates a suitable palette for RGB images
if (fop->document->getSprite()->getPixelFormat() == IMAGE_RGB &&
fop->document->getSprite()->getPalettes().size() <= 1 &&
2012-07-08 21:09:09 -03:00
fop->document->getSprite()->getPalette(FrameNumber(0))->isBlack()) {
SharedPtr<Palette> palette
(quantization::create_palette_from_rgb(fop->document->getSprite(),
FrameNumber(0)));
fop->document->getSprite()->resetPalettes();
fop->document->getSprite()->setPalette(palette, false);
}
}
fop->document->markAsSaved();
}
void fop_sequence_set_format_options(FileOp* fop, const SharedPtr<FormatOptions>& format_options)
{
ASSERT(fop->seq.format_options == NULL);
2008-03-29 04:24:36 +00:00
fop->seq.format_options = format_options;
}
void fop_sequence_set_color(FileOp *fop, int index, int r, int g, int b)
{
fop->seq.palette->setEntry(index, _rgba(r, g, b, 255));
}
void fop_sequence_get_color(FileOp *fop, int index, int *r, int *g, int *b)
{
2011-03-24 18:36:19 -03:00
uint32_t c = fop->seq.palette->getEntry(index);
*r = _rgba_getr(c);
*g = _rgba_getg(c);
*b = _rgba_getb(c);
}
Image* fop_sequence_image(FileOp* fop, PixelFormat pixelFormat, int w, int h)
{
Sprite* sprite;
// Create the image
if (!fop->document) {
sprite = new Sprite(pixelFormat, w, h, 256);
try {
LayerImage* layer = new LayerImage(sprite);
// Add the layer
sprite->getFolder()->addLayer(layer);
// Done
fop->document = new Document(sprite);
fop->seq.layer = layer;
}
catch (...) {
delete sprite;
throw;
}
2007-09-18 23:57:02 +00:00
}
else {
sprite = fop->document->getSprite();
if (sprite->getPixelFormat() != pixelFormat)
return NULL;
2007-09-18 23:57:02 +00:00
}
if (fop->seq.last_cel) {
fop_error(fop, "Error: called two times \"fop_sequence_image()\".\n");
return NULL;
}
// Create a bitmap
Image* image = Image::create(pixelFormat, w, h);
fop->seq.image = image;
fop->seq.last_cel = new Cel(fop->seq.frame++, 0);
return image;
}
void fop_error(FileOp *fop, const char *format, ...)
{
char buf_error[4096];
va_list ap;
va_start(ap, format);
uvszprintf(buf_error, sizeof(buf_error), format, ap);
va_end(ap);
// Concatenate the new error
{
scoped_lock lock(*fop->mutex);
fop->error += buf_error;
}
}
void fop_progress(FileOp *fop, double progress)
{
scoped_lock lock(*fop->mutex);
if (fop->is_sequence()) {
fop->progress =
fop->seq.progress_offset +
fop->seq.progress_fraction*progress;
}
else {
fop->progress = progress;
}
if (fop->progressInterface)
fop->progressInterface->ackFileOpProgress(progress);
}
double fop_get_progress(FileOp *fop)
{
double progress;
{
scoped_lock lock(*fop->mutex);
progress = fop->progress;
}
return progress;
}
// Returns true when the file operation finished, this means, when the
// fop_operate() routine ends.
bool fop_is_done(FileOp *fop)
{
bool done;
{
scoped_lock lock(*fop->mutex);
done = fop->done;
}
return done;
}
bool fop_is_stop(FileOp *fop)
{
bool stop;
{
scoped_lock lock(*fop->mutex);
stop = fop->stop;
}
return stop;
}
static FileOp* fop_new(FileOpType type)
{
FileOp* fop = new FileOp;
fop->type = type;
fop->format = NULL;
fop->format_data = NULL;
fop->document = NULL;
fop->mutex = new base::mutex();
fop->progress = 0.0f;
fop->progressInterface = NULL;
fop->done = false;
fop->stop = false;
fop->oneframe = false;
fop->seq.palette = NULL;
fop->seq.image = NULL;
fop->seq.progress_offset = 0.0f;
fop->seq.progress_fraction = 0.0f;
2012-07-08 21:09:09 -03:00
fop->seq.frame = FrameNumber(0);
fop->seq.layer = NULL;
fop->seq.last_cel = NULL;
return fop;
}
static void fop_prepare_for_sequence(FileOp* fop)
{
2012-07-08 21:09:09 -03:00
fop->seq.palette = new Palette(FrameNumber(0), 256);
fop->seq.format_options.reset();
2007-09-18 23:57:02 +00:00
}
static FileFormat* get_fileformat(const char* extension)
2007-09-18 23:57:02 +00:00
{
2011-01-16 17:27:18 -03:00
FileFormatsList::iterator it = FileFormatsManager::instance().begin();
FileFormatsList::iterator end = FileFormatsManager::instance().end();
2007-09-18 23:57:02 +00:00
char buf[512], *tok;
2011-01-16 17:27:18 -03:00
for (; it != end; ++it) {
ustrcpy(buf, (*it)->extensions());
2007-09-18 23:57:02 +00:00
for (tok=ustrtok(buf, ","); tok;
tok=ustrtok(NULL, ",")) {
if (ustricmp(extension, tok) == 0)
return (*it);
2007-09-18 23:57:02 +00:00
}
}
return NULL;
}
// Splits a file-name like "my_ani0000.pcx" to "my_ani" and ".pcx",
// returning the number of the center; returns "-1" if the function
// can't split anything
static int split_filename(const char* filename, char* left, char* right, int* width)
2007-09-18 23:57:02 +00:00
{
char *ptr, *ext;
char buf[16];
int chr, ret;
// Get the extension.
ext = get_extension(filename);
2007-09-18 23:57:02 +00:00
// With extension.
2007-09-18 23:57:02 +00:00
if ((ext) && (*ext)) {
// Left side (the filename without the extension and without the '.').
2007-09-18 23:57:02 +00:00
ext--;
*ext = 0;
ustrcpy(left, filename);
2007-09-18 23:57:02 +00:00
*ext = '.';
// Right side (the extension with the '.').
ustrcpy(right, ext);
2007-09-18 23:57:02 +00:00
}
// Without extension (without right side).
2007-09-18 23:57:02 +00:00
else {
ustrcpy(left, filename);
ustrcpy(right, empty_string);
2007-09-18 23:57:02 +00:00
}
// Remove all trailing numbers in the "left" side, and pass they to "buf".
2007-09-18 23:57:02 +00:00
ptr = buf+9;
ptr[1] = 0;
ret = -1;
if (width)
*width = 0;
for (;;) {
chr = ugetat(left, -1);
2007-09-18 23:57:02 +00:00
if ((chr >= '0') && (chr <= '9')) {
ret = 0;
if (ptr >= buf) {
*(ptr--) = chr;
2007-09-18 23:57:02 +00:00
if (width)
(*width)++;
2007-09-18 23:57:02 +00:00
}
uremove(left, -1);
}
else
break;
}
// Convert the "buf" to integer and return it.
2007-09-18 23:57:02 +00:00
if (ret == 0) {
while (ptr >= buf)
*(ptr--) = '0';
ret = ustrtol(buf, NULL, 10);
2007-09-18 23:57:02 +00:00
}
return ret;
}
} // namespace app