From 693a68844c4763abc9a07d8d545792ee8dfbd271 Mon Sep 17 00:00:00 2001 From: David Capello <davidcapello@gmail.com> Date: Wed, 26 Oct 2016 19:37:42 -0300 Subject: [PATCH] New docio-lib to detect file format by content (fix #776) --- src/CMakeLists.txt | 1 + src/README.md | 4 +- src/app/CMakeLists.txt | 1 + src/app/file/ase_format.cpp | 1 + src/app/file/bmp_format.cpp | 3 +- src/app/file/file.cpp | 26 ++--- src/app/file/file_format.cpp | 7 +- src/app/file/file_format.h | 6 +- src/app/file/file_formats_manager.cpp | 22 ++-- src/app/file/file_formats_manager.h | 6 +- src/app/file/fli_format.cpp | 3 +- src/app/file/gif_format.cpp | 3 +- src/app/file/ico_format.cpp | 3 +- src/app/file/jpeg_format.cpp | 3 +- src/app/file/palette_file.cpp | 89 +++++++++------- src/app/file/pcx_format.cpp | 3 +- src/app/file/pixly_format.cpp | 1 + src/app/file/png_format.cpp | 1 + src/app/file/tga_format.cpp | 3 +- src/app/file/webp_format.cpp | 3 +- src/doc/LICENSE.txt | 2 +- src/doc/README.md | 2 +- src/docio/CMakeLists.txt | 9 ++ src/{iff => docio}/LICENSE.txt | 2 +- src/docio/README.md | 4 + src/docio/detect_format.cpp | 140 ++++++++++++++++++++++++++ src/docio/detect_format.h | 23 +++++ src/docio/file_format.h | 37 +++++++ src/iff/README.md | 4 - 29 files changed, 326 insertions(+), 86 deletions(-) create mode 100644 src/docio/CMakeLists.txt rename src/{iff => docio}/LICENSE.txt (96%) create mode 100644 src/docio/README.md create mode 100644 src/docio/detect_format.cpp create mode 100644 src/docio/detect_format.h create mode 100644 src/docio/file_format.h delete mode 100644 src/iff/README.md diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 65ee95ee1..e59d915c3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -109,6 +109,7 @@ add_subdirectory(gen) add_subdirectory(gfx) add_subdirectory(net) add_subdirectory(render) +add_subdirectory(docio) add_subdirectory(script) add_subdirectory(she) add_subdirectory(ui) diff --git a/src/README.md b/src/README.md index c67c5b937..99986a5e5 100644 --- a/src/README.md +++ b/src/README.md @@ -47,11 +47,11 @@ because they don't depend on any other component. ## Level 4 - * [iff](iff/) (base, doc, render): Image File Formats library (load/save documents). + * [docio](docio/) (base, flic): Load/save documents. ## Level 5 - * [app](app/) (allegro, base, doc, filters, fixmath, gfx, iff, pen, render, scripting, she, ui, undo, updater, webserver) + * [app](app/) (allegro, base, doc, docio, filters, fixmath, flic, gfx, pen, render, scripting, she, ui, undo, updater, webserver) ## Level 6 diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 8ddfa44cd..9bcf8a0fc 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -451,6 +451,7 @@ target_link_libraries(app-lib clip css-lib doc-lib + docio-lib filters-lib fixmath-lib flic-lib diff --git a/src/app/file/ase_format.cpp b/src/app/file/ase_format.cpp index 1f1f8aa42..1db1f49a3 100644 --- a/src/app/file/ase_format.cpp +++ b/src/app/file/ase_format.cpp @@ -145,6 +145,7 @@ private: class AseFormat : public FileFormat { const char* onGetName() const override { return "ase"; } const char* onGetExtensions() const override { return "ase,aseprite"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::ASE_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/bmp_format.cpp b/src/app/file/bmp_format.cpp index 64cc23542..be82a6869 100644 --- a/src/app/file/bmp_format.cpp +++ b/src/app/file/bmp_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -45,6 +45,7 @@ class BmpFormat : public FileFormat { const char* onGetName() const override { return "bmp"; } const char* onGetExtensions() const override { return "bmp"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::BMP_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/file.cpp b/src/app/file/file.cpp index 308a73785..7b19f78f6 100644 --- a/src/app/file/file.cpp +++ b/src/app/file/file.cpp @@ -28,6 +28,7 @@ #include "base/shared_ptr.h" #include "base/string.h" #include "doc/doc.h" +#include "docio/detect_format.h" #include "render/quantization.h" #include "render/render.h" #include "ui/alert.h" @@ -127,10 +128,7 @@ FileOp* FileOp::createLoadDocumentOperation(Context* context, const char* filena if (!fop) return nullptr; - // Get the extension of the filename (in lower case) - std::string extension = base::string_to_lower(base::get_file_extension(filename)); - - LOG("Loading file \"%s\" (%s)\n", filename, extension.c_str()); + LOG("Loading file \"%s\"\n", filename); // Does file exist? if (!base::is_file(filename)) { @@ -139,12 +137,12 @@ FileOp* FileOp::createLoadDocumentOperation(Context* context, const char* filena } // Get the format through the extension of the filename - fop->m_format = FileFormatsManager::instance() - ->getFileFormatByExtension(extension.c_str()); - + fop->m_format = FileFormatsManager::instance()->getFileFormat( + docio::detect_format(filename)); if (!fop->m_format || !fop->m_format->support(FILE_SUPPORT_LOAD)) { - fop->setError("%s can't load \"%s\" files\n", PACKAGE, extension.c_str()); + fop->setError("%s can't load \"%s\" file (\"%s\")\n", PACKAGE, + filename, base::get_file_extension(filename).c_str()); goto done; } @@ -228,17 +226,15 @@ FileOp* FileOp::createSaveDocumentOperation(const Context* context, fop->m_document = const_cast<Document*>(document); // Get the extension of the filename (in lower case) - std::string extension = base::string_to_lower(base::get_file_extension(filename)); - - LOG("Saving document \"%s\" (%s)\n", filename, extension.c_str()); + LOG("Saving document \"%s\"\n", filename); // Get the format through the extension of the filename - fop->m_format = FileFormatsManager::instance() - ->getFileFormatByExtension(extension.c_str()); - + fop->m_format = FileFormatsManager::instance()->getFileFormat( + docio::detect_format_by_file_extension(filename)); if (!fop->m_format || !fop->m_format->support(FILE_SUPPORT_SAVE)) { - fop->setError("%s can't save \"%s\" files\n", PACKAGE, extension.c_str()); + fop->setError("%s can't save \"%s\" file (\"%s\")\n", PACKAGE, + filename, base::get_file_extension(filename).c_str()); return fop.release(); } diff --git a/src/app/file/file_format.cpp b/src/app/file/file_format.cpp index 39f81735c..4c3a86632 100644 --- a/src/app/file/file_format.cpp +++ b/src/app/file/file_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -33,6 +33,11 @@ const char* FileFormat::extensions() const return onGetExtensions(); } +docio::FileFormat FileFormat::docioFormat() const +{ + return onGetDocioFormat(); +} + bool FileFormat::load(FileOp* fop) { ASSERT(support(FILE_SUPPORT_LOAD)); diff --git a/src/app/file/file_format.h b/src/app/file/file_format.h index ff74eb899..f9cd4cd56 100644 --- a/src/app/file/file_format.h +++ b/src/app/file/file_format.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -9,6 +9,7 @@ #pragma once #include "base/shared_ptr.h" +#include "docio/file_format.h" #include <vector> @@ -44,6 +45,8 @@ namespace app { const char* name() const; // File format name const char* extensions() const; // Extensions (e.g. "jpeg,jpg") + docio::FileFormat docioFormat() const; + bool load(FileOp* fop); #ifdef ENABLE_SAVE bool save(FileOp* fop); @@ -70,6 +73,7 @@ namespace app { protected: virtual const char* onGetName() const = 0; virtual const char* onGetExtensions() const = 0; + virtual docio::FileFormat onGetDocioFormat() const = 0; virtual int onGetFlags() const = 0; virtual bool onLoad(FileOp* fop) = 0; diff --git a/src/app/file/file_formats_manager.cpp b/src/app/file/file_formats_manager.cpp index b77a6ba6c..134b23771 100644 --- a/src/app/file/file_formats_manager.cpp +++ b/src/app/file/file_formats_manager.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -13,6 +13,7 @@ #include "app/file/file_format.h" #include "app/file/format_options.h" #include "base/string.h" +#include "docio/detect_format.h" #include <algorithm> #include <cstring> @@ -93,21 +94,12 @@ FileFormatsList::iterator FileFormatsManager::end() return m_formats.end(); } -FileFormat* FileFormatsManager::getFileFormatByExtension(const char* extension) const +FileFormat* FileFormatsManager::getFileFormat(const docio::FileFormat docioFormat) const { - char buf[512], *tok; - - for (FileFormat* ff : m_formats) { - std::strcpy(buf, ff->extensions()); - - for (tok=std::strtok(buf, ","); tok; - tok=std::strtok(NULL, ",")) { - if (base::utf8_icmp(extension, tok) == 0) - return ff; - } - } - - return NULL; + for (FileFormat* ff : m_formats) + if (ff->docioFormat() == docioFormat) + return ff; + return nullptr; } } // namespace app diff --git a/src/app/file/file_formats_manager.h b/src/app/file/file_formats_manager.h index 3eb04e626..e337c5341 100644 --- a/src/app/file/file_formats_manager.h +++ b/src/app/file/file_formats_manager.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -8,6 +8,8 @@ #define APP_FILE_FILE_FORMATS_MANAGER_H_INCLUDED #pragma once +#include "docio/file_format.h" + #include <vector> namespace app { @@ -34,7 +36,7 @@ namespace app { FileFormatsList::iterator begin(); FileFormatsList::iterator end(); - FileFormat* getFileFormatByExtension(const char* extension) const; + FileFormat* getFileFormat(const docio::FileFormat docioFormat) const; private: // Register one format. diff --git a/src/app/file/fli_format.cpp b/src/app/file/fli_format.cpp index e0a16fd56..9831f80d1 100644 --- a/src/app/file/fli_format.cpp +++ b/src/app/file/fli_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -27,6 +27,7 @@ using namespace base; class FliFormat : public FileFormat { const char* onGetName() const override { return "flc"; } const char* onGetExtensions() const override{ return "flc,fli"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::FLIC_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/gif_format.cpp b/src/app/file/gif_format.cpp index 20ded906c..e451c38fc 100644 --- a/src/app/file/gif_format.cpp +++ b/src/app/file/gif_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -63,6 +63,7 @@ class GifFormat : public FileFormat { const char* onGetName() const override { return "gif"; } const char* onGetExtensions() const override { return "gif"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::GIF_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/ico_format.cpp b/src/app/file/ico_format.cpp index 8fbcb6438..1dbce9adc 100644 --- a/src/app/file/ico_format.cpp +++ b/src/app/file/ico_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -26,6 +26,7 @@ using namespace base; class IcoFormat : public FileFormat { const char* onGetName() const override { return "ico"; } const char* onGetExtensions() const override { return "ico"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::ICO_IMAGES; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/jpeg_format.cpp b/src/app/file/jpeg_format.cpp index 930111f8d..71796c64c 100644 --- a/src/app/file/jpeg_format.cpp +++ b/src/app/file/jpeg_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -42,6 +42,7 @@ class JpegFormat : public FileFormat { const char* onGetName() const override { return "jpeg"; } const char* onGetExtensions() const override { return "jpeg,jpg"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::JPEG_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/palette_file.cpp b/src/app/file/palette_file.cpp index ab6d164f0..5c11c749b 100644 --- a/src/app/file/palette_file.cpp +++ b/src/app/file/palette_file.cpp @@ -24,6 +24,7 @@ #include "doc/layer.h" #include "doc/palette.h" #include "doc/sprite.h" +#include "docio/detect_format.h" #include <cstring> @@ -45,26 +46,34 @@ std::string get_writable_palette_extensions() return buf; } -Palette* load_palette(const char *filename) +Palette* load_palette(const char* filename) { - std::string ext = base::string_to_lower(base::get_file_extension(filename)); - Palette* pal = NULL; + docio::FileFormat docioFormat = docio::detect_format(filename); + Palette* pal = nullptr; + + switch (docioFormat) { + + case docio::FileFormat::COL_PALETTE: + pal = doc::file::load_col_file(filename); + break; + + case docio::FileFormat::GPL_PALETTE: + pal = doc::file::load_gpl_file(filename); + break; + + case docio::FileFormat::HEX_PALETTE: + pal = doc::file::load_hex_file(filename); + break; + + case docio::FileFormat::PAL_PALETTE: + pal = doc::file::load_pal_file(filename); + break; + + default: { + FileFormat* ff = FileFormatsManager::instance()->getFileFormat(docioFormat); + if (!ff || !ff->support(FILE_SUPPORT_LOAD)) + break; - if (ext == "col") { - pal = doc::file::load_col_file(filename); - } - else if (ext == "gpl") { - pal = doc::file::load_gpl_file(filename); - } - else if (ext == "hex") { - pal = doc::file::load_hex_file(filename); - } - else if (ext == "pal") { - pal = doc::file::load_pal_file(filename); - } - else { - FileFormat* ff = FileFormatsManager::instance()->getFileFormatByExtension(ext.c_str()); - if (ff && ff->support(FILE_SUPPORT_LOAD)) { base::UniquePtr<FileOp> fop( FileOp::createLoadDocumentOperation( nullptr, filename, @@ -85,6 +94,7 @@ Palette* load_palette(const char *filename) delete fop->releaseDocument(); fop->done(); } + break; } } @@ -94,26 +104,34 @@ Palette* load_palette(const char *filename) return pal; } -bool save_palette(const char *filename, const Palette* pal, int columns) +bool save_palette(const char* filename, const Palette* pal, int columns) { - std::string ext = base::string_to_lower(base::get_file_extension(filename)); + docio::FileFormat docioFormat = docio::detect_format_by_file_extension(filename); bool success = false; - if (ext == "col") { - success = doc::file::save_col_file(pal, filename); - } - else if (ext == "gpl") { - success = doc::file::save_gpl_file(pal, filename); - } - else if (ext == "hex") { - success = doc::file::save_hex_file(pal, filename); - } - else if (ext == "pal") { - success = doc::file::save_pal_file(pal, filename); - } - else { - FileFormat* ff = FileFormatsManager::instance()->getFileFormatByExtension(ext.c_str()); - if (ff && ff->support(FILE_SUPPORT_SAVE)) { + switch (docioFormat) { + + case docio::FileFormat::COL_PALETTE: + success = doc::file::save_col_file(pal, filename); + break; + + case docio::FileFormat::GPL_PALETTE: + success = doc::file::save_gpl_file(pal, filename); + break; + + case docio::FileFormat::HEX_PALETTE: + success = doc::file::save_hex_file(pal, filename); + break; + + case docio::FileFormat::PAL_PALETTE: + success = doc::file::save_pal_file(pal, filename); + break; + + default: { + FileFormat* ff = FileFormatsManager::instance()->getFileFormat(docioFormat); + if (!ff || !ff->support(FILE_SUPPORT_SAVE)) + break; + int w = (columns > 0 ? MID(0, columns, pal->size()): pal->size()); int h = (pal->size() / w) + (pal->size() % w > 0 ? 1: 0); @@ -150,6 +168,7 @@ bool save_palette(const char *filename, const Palette* pal, int columns) doc->close(); delete doc; + break; } } diff --git a/src/app/file/pcx_format.cpp b/src/app/file/pcx_format.cpp index 35a484d97..881c30764 100644 --- a/src/app/file/pcx_format.cpp +++ b/src/app/file/pcx_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -24,6 +24,7 @@ using namespace base; class PcxFormat : public FileFormat { const char* onGetName() const override { return "pcx"; } const char* onGetExtensions() const override { return "pcx"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::PCX_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/pixly_format.cpp b/src/app/file/pixly_format.cpp index 38e8720b0..c5bc5e581 100644 --- a/src/app/file/pixly_format.cpp +++ b/src/app/file/pixly_format.cpp @@ -31,6 +31,7 @@ using namespace base; class PixlyFormat : public FileFormat { const char* onGetName() const override { return "anim"; } const char* onGetExtensions() const override { return "anim"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::PIXLY_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/png_format.cpp b/src/app/file/png_format.cpp index 576e5ac5d..dd4ed596e 100644 --- a/src/app/file/png_format.cpp +++ b/src/app/file/png_format.cpp @@ -29,6 +29,7 @@ using namespace base; class PngFormat : public FileFormat { const char* onGetName() const override { return "png"; } const char* onGetExtensions() const override { return "png"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::PNG_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/tga_format.cpp b/src/app/file/tga_format.cpp index 211b59311..ee09ab4c2 100644 --- a/src/app/file/tga_format.cpp +++ b/src/app/file/tga_format.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2001-2015 David Capello +// Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -25,6 +25,7 @@ using namespace base; class TgaFormat : public FileFormat { const char* onGetName() const override { return "tga"; } const char* onGetExtensions() const override { return "tga"; } + docio::FileFormat onGetDocioFormat() const override { return docio::FileFormat::TARGA_IMAGE; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/app/file/webp_format.cpp b/src/app/file/webp_format.cpp index be6892d7a..842f7fa78 100644 --- a/src/app/file/webp_format.cpp +++ b/src/app/file/webp_format.cpp @@ -1,6 +1,6 @@ // Aseprite // Copyright (C) 2015 Gabriel Rauter -// Copyright (C) 2015 David Capello +// Copyright (C) 2015-2016 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -41,6 +41,7 @@ class WebPFormat : public FileFormat { const char* onGetName() const override { return "webp"; } const char* onGetExtensions() const override { return "webp"; } + docio::FileFormat onGetDocioFormat() const override { return docio::WEBP_ANIMATION; } int onGetFlags() const override { return FILE_SUPPORT_LOAD | diff --git a/src/doc/LICENSE.txt b/src/doc/LICENSE.txt index 7ed8f201a..0d2d81fd4 100644 --- a/src/doc/LICENSE.txt +++ b/src/doc/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2001-2015 David Capello +Copyright (c) 2001-2016 David Capello Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/src/doc/README.md b/src/doc/README.md index e32066553..6c5409397 100644 --- a/src/doc/README.md +++ b/src/doc/README.md @@ -1,4 +1,4 @@ # Aseprite Document Library -*Copyright (C) 2001-2015 David Capello* +*Copyright (C) 2001-2016 David Capello* > Distributed under [MIT license](LICENSE.txt) diff --git a/src/docio/CMakeLists.txt b/src/docio/CMakeLists.txt new file mode 100644 index 000000000..cf8a2cf6b --- /dev/null +++ b/src/docio/CMakeLists.txt @@ -0,0 +1,9 @@ +# Aseprite Document IO Library +# Copyright (c) 2016 David Capello + +add_library(docio-lib + detect_format.cpp) + +target_link_libraries(docio-lib + flic-lib + base-lib) diff --git a/src/iff/LICENSE.txt b/src/docio/LICENSE.txt similarity index 96% rename from src/iff/LICENSE.txt rename to src/docio/LICENSE.txt index aea0f6e8f..9a182c0f3 100644 --- a/src/iff/LICENSE.txt +++ b/src/docio/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2014 David Capello +Copyright (c) 2016 David Capello Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/src/docio/README.md b/src/docio/README.md new file mode 100644 index 000000000..34e04c3c6 --- /dev/null +++ b/src/docio/README.md @@ -0,0 +1,4 @@ +# Aseprite Document IO Library +*Copyright (C) 2016 David Capello* + +> Distributed under [MIT license](LICENSE.txt) diff --git a/src/docio/detect_format.cpp b/src/docio/detect_format.cpp new file mode 100644 index 000000000..686dd881c --- /dev/null +++ b/src/docio/detect_format.cpp @@ -0,0 +1,140 @@ +// Aseprite Document IO Library +// Copyright (c) 2016 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#include "docio/detect_format.h" + +#include "base/file_handle.h" +#include "base/path.h" +#include "base/string.h" +#include "flic/flic_details.h" + +#include <cstring> + +#define ASE_MAGIC_NUMBER 0xA5E0 +#define BMP_MAGIC_NUMBER 0x4D42 // "BM" +#define JPG_MAGIC_NUMBER 0xD8FF +#define GIF_87_STAMP "GIF87a" +#define GIF_89_STAMP "GIF89a" +#define PNG_MAGIC_DWORD1 0x474E5089 +#define PNG_MAGIC_DWORD2 0x0A1A0A0D + +namespace docio { + +FileFormat detect_format(const std::string& filename) +{ + FileFormat ff = detect_format_by_file_content(filename); + if (ff == FileFormat::UNKNOWN) + ff = detect_format_by_file_extension(filename); + return ff; +} + +FileFormat detect_format_by_file_content(const std::string& filename) +{ +#define IS_MAGIC_WORD(offset, word) \ + ((buf[offset+0] == (word & 0xff)) && \ + (buf[offset+1] == ((word & 0xff00) >> 8))) + +#define IS_MAGIC_DWORD(offset, dword) \ + ((buf[offset+0] == (dword & 0xff)) && \ + (buf[offset+1] == ((dword & 0xff00) >> 8)) && \ + (buf[offset+2] == ((dword & 0xff0000) >> 16)) && \ + (buf[offset+3] == ((dword & 0xff000000) >> 24))) + + base::FileHandle handle(base::open_file(filename.c_str(), "rb")); + if (!handle) + return FileFormat::ERROR; + + FILE* f = handle.get(); + unsigned char buf[8]; + int count = fread(buf, 1, 8, f); + + if (count >= 2) { + if (IS_MAGIC_WORD(0, BMP_MAGIC_NUMBER)) + return FileFormat::BMP_IMAGE; + + if (IS_MAGIC_WORD(0, JPG_MAGIC_NUMBER)) + return FileFormat::JPEG_IMAGE; + + if (count >= 6) { + if (std::strncmp((const char*)buf, GIF_87_STAMP, 6) == 0 || + std::strncmp((const char*)buf, GIF_89_STAMP, 6) == 0) + return FileFormat::GIF_ANIMATION; + + if (IS_MAGIC_WORD(4, ASE_MAGIC_NUMBER)) + return FileFormat::ASE_ANIMATION; + + if (IS_MAGIC_WORD(4, FLI_MAGIC_NUMBER) || + IS_MAGIC_WORD(4, FLC_MAGIC_NUMBER)) + return FileFormat::FLIC_ANIMATION; + + if (count >= 8) { + if (IS_MAGIC_DWORD(0, PNG_MAGIC_DWORD1) && + IS_MAGIC_DWORD(4, PNG_MAGIC_DWORD2)) + return FileFormat::PNG_IMAGE; + } + } + } + + return FileFormat::UNKNOWN; +} + +FileFormat detect_format_by_file_extension(const std::string& filename) +{ + // By extension + const std::string ext = base::string_to_lower(base::get_file_extension(filename)); + + if (ext == "ase" || + ext == "aseprite") + return FileFormat::ASE_ANIMATION; + + if (ext == "bmp") + return FileFormat::BMP_IMAGE; + + if (ext == "col") + return FileFormat::COL_PALETTE; + + if (ext == "flc" || + ext == "fli") + return FileFormat::FLIC_ANIMATION; + + if (ext == "gif") + return FileFormat::GIF_ANIMATION; + + if (ext == "gpl") + return FileFormat::GPL_PALETTE; + + if (ext == "hex") + return FileFormat::HEX_PALETTE; + + if (ext == "ico") + return FileFormat::ICO_IMAGES; + + if (ext == "jpg" || + ext == "jpeg") + return FileFormat::JPEG_IMAGE; + + if (ext == "pal") + return FileFormat::PAL_PALETTE; + + if (ext == "pcx") + return FileFormat::PCX_IMAGE; + + if (ext == "anim") + return FileFormat::PIXLY_ANIMATION; + + if (ext == "png") + return FileFormat::PNG_IMAGE; + + if (ext == "tga") + return FileFormat::TARGA_IMAGE; + + if (ext == "webp") + return FileFormat::WEBP_ANIMATION; + + return FileFormat::UNKNOWN; +} + +} // namespace docio diff --git a/src/docio/detect_format.h b/src/docio/detect_format.h new file mode 100644 index 000000000..d5a869164 --- /dev/null +++ b/src/docio/detect_format.h @@ -0,0 +1,23 @@ +// Aseprite Document IO Library +// Copyright (c) 2016 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifndef DOCIO_DETECT_FORMAT_H_INCLUDED +#define DOCIO_DETECT_FORMAT_H_INCLUDED +#pragma once + +#include "docio/file_format.h" + +#include <string> + +namespace docio { + +FileFormat detect_format(const std::string& filename); +FileFormat detect_format_by_file_content(const std::string& filename); +FileFormat detect_format_by_file_extension(const std::string& filename); + +} // namespace docio + +#endif diff --git a/src/docio/file_format.h b/src/docio/file_format.h new file mode 100644 index 000000000..bbf33b54b --- /dev/null +++ b/src/docio/file_format.h @@ -0,0 +1,37 @@ +// Aseprite Document IO Library +// Copyright (c) 2016 David Capello +// +// This file is released under the terms of the MIT license. +// Read LICENSE.txt for more information. + +#ifndef DOCIO_FILE_FORMAT_H_INCLUDED +#define DOCIO_FILE_FORMAT_H_INCLUDED +#pragma once + +namespace docio { + +enum class FileFormat { + ERROR = -1, + UNKNOWN = 0, + + ASE_ANIMATION, // Aseprite File Format + ASE_PALETTE, // Adobe Swatch Exchange + BMP_IMAGE, + COL_PALETTE, + FLIC_ANIMATION, + GIF_ANIMATION, + GPL_PALETTE, + HEX_PALETTE, + ICO_IMAGES, + JPEG_IMAGE, + PAL_PALETTE, + PCX_IMAGE, + PIXLY_ANIMATION, + PNG_IMAGE, + TARGA_IMAGE, + WEBP_ANIMATION, +}; + +} // namespace docio + +#endif diff --git a/src/iff/README.md b/src/iff/README.md deleted file mode 100644 index efe59b660..000000000 --- a/src/iff/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Aseprite Image File Formats Library -*Copyright (C) 2014 David Capello* - -> Distributed under [MIT license](LICENSE.txt)