From cbb8da45cec860cd4979e74e6f89920fff0f604c Mon Sep 17 00:00:00 2001 From: marcsello Date: Fri, 6 Nov 2020 02:24:05 +0100 Subject: [PATCH] Implemented CAFF stuff --- CMakeLists.txt | 2 +- src/caff_tools.c | 197 +++++++++++++++++++++++++++++++++++++++++++++++ src/caff_tools.h | 57 ++++++++++++++ src/main.c | 27 +++++-- 4 files changed, 274 insertions(+), 9 deletions(-) create mode 100644 src/caff_tools.c create mode 100644 src/caff_tools.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6afb2c6..04d06ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,4 +3,4 @@ project(caff_previewer C) set(CMAKE_C_STANDARD 11) -add_executable(caff_previewer src/main.c src/magic_memory.c src/magic_memory.h src/ciff_tools.h src/ciff_tools.c src/libtarga.c src/libtarga.h src/pixeldata_utils.c src/pixeldata_utils.h src/utils.c src/utils.h) \ No newline at end of file +add_executable(caff_previewer src/main.c src/magic_memory.c src/magic_memory.h src/ciff_tools.h src/ciff_tools.c src/libtarga.c src/libtarga.h src/pixeldata_utils.c src/pixeldata_utils.h src/caff_tools.c src/caff_tools.h src/utils.c src/utils.h) \ No newline at end of file diff --git a/src/caff_tools.c b/src/caff_tools.c new file mode 100644 index 0000000..deda807 --- /dev/null +++ b/src/caff_tools.c @@ -0,0 +1,197 @@ +// +// Created by marcsello on 03/11/2020. +// + +#include "caff_tools.h" +#include "ciff_tools.h" +#include + +// Validator = Parses data and checks it's validity, but not returning the provided data. +// Parser = Parses data and checks it's validity, returns the parsed data. + +uint8_t parse_caff_header(uint8_t *data, uint64_t data_len, uint64_t *num_anim) { + + if (data_len != sizeof(caff_header_t)) { + return CAFF_PARSE_LENGTH_ERROR; + } + + caff_header_t *header_info = (caff_header_t *) data; + + if (header_info->magic != 0x46464143) { + return CAFF_PARSE_BAD_MAGIC; + } + + if (header_info->header_size != 20) { + return CAFF_PARSE_LENGTH_ERROR; + } + + if (header_info->num_anim == 0) { + return CAFF_PARSE_ANIMATION_COUNT_ERROR; + } + + *num_anim = header_info->num_anim; + + return CAFF_PARSE_SUCCESS; // Sikeres parsolás == Valid formátum + +} + +uint8_t validate_caff_credits(uint8_t *data, uint64_t data_len) { + + if (data_len < sizeof(credits_header_t)) { + return CAFF_PARSE_LENGTH_ERROR; + } + + credits_header_t *header_info = (credits_header_t *) data; + + if (header_info->month > 12 || header_info->month == 0) { + return CAFF_PARSE_BAD_DATE; + } + + uint8_t month_lengths[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + if (header_info->day > month_lengths[header_info->month - 1] || header_info->day == 0) { + return CAFF_PARSE_BAD_DATE; + } + + if (header_info->hour > 23) { + return CAFF_PARSE_BAD_DATE; + } + + if (header_info->minute > 60) { + return CAFF_PARSE_BAD_DATE; + } + + uint64_t calculated_len = header_info->creator_len + sizeof(credits_header_t); + + if (calculated_len != data_len) { + return CAFF_PARSE_LENGTH_ERROR; + } + + return CAFF_PARSE_SUCCESS; +} + +uint8_t validate_caff_animation(uint8_t *data, uint64_t data_len) { + + if (data_len < sizeof(animation_header_t)) { + return CAFF_PARSE_LENGTH_ERROR; + } + + animation_header_t *header_info = (animation_header_t *) data; + + + if (header_info->duration == 0) { + return CAFF_PARSE_NO_DURATION; + } + + // NOTE: Ciff validation is solved in the CIFF tools + uint8_t result = validate_ciff(data + sizeof(animation_header_t), data_len - sizeof(animation_header_t)); + + if (result != CIFF_PARSE_SUCCESS) { + return result; + } + + return CAFF_PARSE_SUCCESS; + +} + + +uint8_t validate_caff_file(uint8_t *data, uint64_t data_len) { + + uint8_t *p = data; + + uint64_t frame_counter = 0; + uint64_t len_remaining = data_len; + uint64_t expected_num_anim; + uint64_t num_anim = 0; + bool credits_found = false; + + while (len_remaining > 0) { + + if (len_remaining < sizeof(caff_frame_header_t)) { + return CAFF_PARSE_LENGTH_ERROR; + } + + caff_frame_header_t *frame_header = (caff_frame_header_t *) p; + + if (!( + frame_header->id == CAFF_FRAME_HEADER || + frame_header->id == CAFF_FRAME_CREDITS || + frame_header->id == CAFF_FRAME_ANIMATION)) { + return CAFF_PARSE_BAD_FRAME; + } + + if (frame_header->length > len_remaining) { + return CAFF_PARSE_LENGTH_ERROR; + } + + if ((frame_counter == 0 && frame_header->id != CAFF_FRAME_HEADER) || + (frame_counter > 0 && frame_header->id == CAFF_FRAME_HEADER)) { + return CAFF_PARSE_HEADER_ERROR; + } + + uint8_t result; + switch (frame_header->id) { + case CAFF_FRAME_HEADER: + result = parse_caff_header(p + sizeof(struct caff_frame_header_t), + frame_header->length, &expected_num_anim); + break; + case CAFF_FRAME_CREDITS: + result = validate_caff_credits(p + sizeof(struct caff_frame_header_t), frame_header->length); + credits_found = true; + break; + case CAFF_FRAME_ANIMATION: + result = validate_caff_animation(p + sizeof(struct caff_frame_header_t), frame_header->length); + num_anim++; + break; + } + + if (result != CAFF_PARSE_SUCCESS) { + return result; + } + + frame_counter++; + uint64_t seek_by = frame_header->length + sizeof(caff_frame_header_t); + len_remaining -= seek_by; + p += seek_by; + } + + if (expected_num_anim != num_anim) { + return CAFF_PARSE_ANIMATION_COUNT_ERROR; + } + + if (!credits_found) { + return CAFF_PARSE_NO_CREDITS_ERROR; + } + + + return CAFF_PARSE_SUCCESS; + +} + +uint8_t parse_caff_get_first_ciff(uint8_t *caff_data, uint64_t caff_data_len, uint8_t **ciff_ptr, uint64_t *ciff_len) { + + uint8_t result = validate_caff_file(caff_data, caff_data_len); + + if (result != CAFF_PARSE_SUCCESS) { + return result; + } + + // Seek for the first CIFF header + uint8_t *p = caff_data; + uint64_t caff_data_len_remaining = caff_data_len; + while (caff_data_len_remaining > 0) { + caff_frame_header_t *frame_header = (caff_frame_header_t *) p; + + if (frame_header->id == CAFF_FRAME_ANIMATION) { + *ciff_ptr = p + sizeof(caff_frame_header_t) + sizeof(animation_header_t); + *ciff_len = frame_header->length - sizeof(animation_header_t); + return CAFF_PARSE_SUCCESS; + } + + uint64_t seek_by = frame_header->length + sizeof(caff_frame_header_t); + caff_data_len_remaining -= seek_by; + p += seek_by; + } + + return CAFF_PARSE_ANIMATION_COUNT_ERROR; +} \ No newline at end of file diff --git a/src/caff_tools.h b/src/caff_tools.h new file mode 100644 index 0000000..9ab43dd --- /dev/null +++ b/src/caff_tools.h @@ -0,0 +1,57 @@ +// +// Created by marcsello on 03/11/2020. +// + +#ifndef CAFF_PREVIEWER_CAFF_TOOLS_H +#define CAFF_PREVIEWER_CAFF_TOOLS_H + +#include + +#define CAFF_PARSE_SUCCESS 0 +#define CAFF_PARSE_LENGTH_ERROR 1 +#define CAFF_PARSE_BAD_FRAME 2 +#define CAFF_PARSE_HEADER_ERROR 3 +#define CAFF_PARSE_ANIMATION_COUNT_ERROR 4 +#define CAFF_PARSE_NO_CREDITS_ERROR 5 +#define CAFF_PARSE_BAD_MAGIC 6 +#define CAFF_PARSE_BAD_DATE 7 +#define CAFF_PARSE_NO_DURATION 8 + +#define CAFF_FRAME_HEADER 0x1 +#define CAFF_FRAME_CREDITS 0x2 +#define CAFF_FRAME_ANIMATION 0x3 + + + +typedef struct __attribute__ ((packed)) caff_frame_header_t { + uint8_t id; + uint64_t length; +} caff_frame_header_t; + +typedef struct __attribute__ ((packed)) caff_header_t { // Note: CAFF Header lives inside a frame + uint32_t magic; //Should be to 0x46464143 (note the reversed order) + uint64_t header_size; // Constant 20??? + uint64_t num_anim; +} caff_header_t; + +typedef struct __attribute__ ((packed)) credits_header_t { // Note: CAFF Header lives inside a frame + uint16_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint64_t creator_len; +} credits_header_t; + + +typedef struct __attribute__ ((packed)) animation_header_t { + uint64_t duration; +} animation_header_t; + + +uint8_t validate_caff_file(uint8_t* data, uint64_t data_len); +uint8_t parse_caff_get_first_ciff(uint8_t* caff_data, uint64_t caff_data_len, uint8_t **ciff_ptr, uint64_t* ciff_len); + + +#endif //CAFF_PREVIEWER_CAFF_TOOLS_H + diff --git a/src/main.c b/src/main.c index 0a08880..7b0d850 100644 --- a/src/main.c +++ b/src/main.c @@ -6,33 +6,44 @@ #include "magic_memory.h" #include "pixeldata_utils.h" #include "ciff_tools.h" +#include "caff_tools.h" #include "utils.h" int main() { magic_memory_context_t *context = magic_memory_begin(); - uint8_t *ciff_file; - uint64_t ciff_size; - uint8_t result = read_file_to_mem(context, "/home/marcsello/Documents/etyetem/szamitobiztonsag/caff/1.ciff", - 67108864, &ciff_file, &ciff_size); + uint8_t *caff_file; + uint64_t caff_size; + uint8_t result = read_file_to_mem(context, "/home/marcsello/Documents/etyetem/szamitobiztonsag/caff/2.caff", + 67108864, &caff_file, &caff_size); if (result != FILE_READ_SUCCESS) { printf("File read failure: %d", result); return 1; } + uint8_t* ciff_ptr; + uint64_t ciff_size; + + result = parse_caff_get_first_ciff(caff_file,caff_size,&ciff_ptr, &ciff_size); + + if (result != CAFF_PARSE_SUCCESS) { + printf("CAFF Parse failure: %d", result); + return 1; + } + uint64_t width; uint64_t height; uint64_t pixel_data_starts; - result = get_pixel_data_from_ciff(ciff_file, ciff_size, &width, &height, &pixel_data_starts); + result = get_pixel_data_from_ciff(ciff_ptr, ciff_size, &width, &height, &pixel_data_starts); uint64_t pixel_data_size = width * height * 3; if (result == CIFF_PARSE_SUCCESS) { - uint8_t *flipped_image = (uint8_t *) magic_malloc(context, ciff_size - pixel_data_starts); - if (flip_image(ciff_file + pixel_data_starts, flipped_image, pixel_data_size, width, height) != + uint8_t *flipped_image = (uint8_t *) magic_malloc(context, caff_size - pixel_data_starts); + if (flip_image(ciff_ptr + pixel_data_starts, flipped_image, pixel_data_size, width, height) != IMAGE_FLIP_SUCCESS) { printf("Literally failed to flip the image"); } else { @@ -43,7 +54,7 @@ int main() { } else { - printf("%d", result); + printf("Failed to get pixel data: %d", result); }