/* File: file_aseprite.c Copyright (C) 2006-2009,2021 Christophe GRENIER This software 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 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #if !defined(SINGLE_FORMAT) || defined(SINGLE_FORMAT_aseprite) #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_STRING_H #include #endif #include #include "types.h" #include "filegen.h" #include "common.h" #ifdef DEBUG_ASEPRITE #include "log.h" #endif /* file format spec: https://github.com/aseprite/aseprite/blob/main/docs/ase-file-specs.md */ /*@ requires valid_register_header_check(file_stat); */ static void register_header_check_aseprite(file_stat_t *file_stat); const file_hint_t file_hint_aseprite= { .extension="aseprite", .description="LibreSprite/Aseprite .ase/.aseprite Files.", .max_filesize=PHOTOREC_MAX_FILE_SIZE, .recover=1, .enable_by_default=1, .register_header_check=®ister_header_check_aseprite }; struct aseprite_file_header { uint32_t file_size; uint16_t magic; /* must be 0xA5E0 */ uint16_t frames; /* number of frames */ uint16_t width; /* Width in pixels */ uint16_t height; /* Height in pixels */ uint16_t color_depth; /* Bits per pixel (32 bpp = RGBA; 16 bpp GRAYSCALE; 8 bpp INDEXED;) */ uint32_t flags; /* flags */ uint16_t speed; /* speed (miliseconds between frames) DEPRECATED: frame's frame duration field used instead. */ uint32_t reserved1; /* must be 0 */ uint32_t reserved2; /* must be 0 */ uint8_t pallete; /* Pallete entry (index). Only for indexed sprites. */ uint8_t reserved3[3]; /* must be 0 */ uint16_t ncolors; /* Number of colors (0 means 256 for old sprites) */ uint8_t pixel_width; /* Pixel ratio = pixel_width/pixel_height; If this or pixel_height equals to 0, pixel ratio = 1:1 */ uint8_t pixel_height; /* Pixel Height */ int16_t x_grid; /* X position on grid. */ int16_t y_grid; /* Y position on grid. */ uint16_t grid_w; /* Grid width. Zero if no grid. */ uint16_t grid_h; /* Grid Height. Zero if no grid. */ uint8_t reserved4[84]; /* For future. Set to zero (0). */ } __attribute__ ((gcc_struct, __packed__)); /*@ @ requires buffer_size >= sizeof(struct aseprite_file_header); @ requires separation: \separated(&file_hint_aseprite, buffer+(..), file_recovery, file_recovery_new); @ requires valid_header_check_param(buffer, buffer_size, safe_header_only, file_recovery, file_recovery_new); @ ensures valid_header_check_result(\result, file_recovery_new); @ assigns *file_recovery_new; */ static int header_check_aseprite(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new) { const struct aseprite_file_header *hdr= (const struct aseprite_file_header *)buffer; const unsigned int file_size = le32(hdr->file_size); const unsigned int frames = le16(hdr->frames); const unsigned int width = le16(hdr->width); const unsigned int height = le16(hdr->height); const unsigned int reserved1 = le32(hdr->reserved1); const unsigned int reserved2 = le32(hdr->reserved2); const unsigned int color_depth = le16(hdr->color_depth); #ifdef DEBUG_ASEPRITE log_info("file size %u\n", file_size); log_info("frames %u\n", frames); log_info("height %u\n", height); log_info("width %u\n", width); log_info("depth %u\n", color_depth); #endif if (file_size < sizeof(struct aseprite_file_header) || frames==0 || frames > 65535 || width==0 || width > 65535 || height==0 || height > 65535 || reserved1!=0 || reserved2!=0 || (color_depth!=8 && color_depth!=16 && color_depth!=32) ) return 0; reset_file_recovery(file_recovery_new); file_recovery_new->extension=file_hint_aseprite.extension; file_recovery_new->calculated_file_size=file_size; file_recovery_new->data_check=&data_check_size; file_recovery_new->file_check=&file_check_size; return 1; } /* Will register specific file header check function. */ static void register_header_check_aseprite(file_stat_t *file_stat) { static const unsigned char aseprite_header[2]={ 0xE0, 0xA5 }; register_header_check(4, aseprite_header,sizeof(aseprite_header), &header_check_aseprite, file_stat); } #endif