This commit includes the following changes: - Fixed segfault after a caff parse results in NULL - Fixed segfault when caff has no animation - Fixed segfault when the animation header is smaller, than it needs to - Added new testcases - Better testing system Signed-off-by: Balazs Toldi <balazs@toldi.eu>
263 lines
No EOL
6.7 KiB
C
263 lines
No EOL
6.7 KiB
C
#include "caff.h"
|
|
|
|
void print_credits(CAFF_Credits *credits)
|
|
{
|
|
printf("Creator:%s\n", credits->creator);
|
|
printf("Date:%d.%d.%d %d:%d\n", credits->year, credits->month, credits->day, credits->hour, credits->minute);
|
|
}
|
|
|
|
void caff_init_animation_list(CAFF_Animation_List *a)
|
|
{
|
|
a->array = NULL;
|
|
a->length = 0;
|
|
a->size = 0;
|
|
}
|
|
|
|
void caff_add_animation_list(CAFF_Animation_List *a, CAFF_Animation element)
|
|
{
|
|
if (a->length == a->size)
|
|
{
|
|
a->size = (a->size == 0) ? 1 : a->size * 2;
|
|
CAFF_Animation *new_array = realloc(a->array, a->size * sizeof(CAFF_Animation));
|
|
if (!new_array)
|
|
{
|
|
printf("Failed to allocate memory!\n");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
a->array = new_array;
|
|
}
|
|
a->array[a->length++] = element;
|
|
}
|
|
|
|
void caff_free_animtion_list(CAFF_Animation_List *a)
|
|
{
|
|
free(a->array);
|
|
a->array = NULL;
|
|
a->length = a->size = 0;
|
|
}
|
|
|
|
CAFF *caff_parse_file(const char *filename)
|
|
{
|
|
FILE *file = fopen(filename, "rb");
|
|
if (!file)
|
|
{
|
|
printf("Failed to open CAFF file: %s\n", filename);
|
|
return NULL;
|
|
}
|
|
|
|
CAFF *caff = malloc(sizeof(CAFF));
|
|
if (!caff)
|
|
{
|
|
printf("Failed to allocate memory for CAFF!\n");
|
|
return NULL;
|
|
}
|
|
caff->bytes_read = 0;
|
|
caff->credits = NULL;
|
|
caff->header = NULL;
|
|
caff_init_animation_list(&caff->animations);
|
|
|
|
size_t anim_count = 0;
|
|
while (!feof(file))
|
|
{
|
|
uint8_t id;
|
|
uint64_t length;
|
|
fread(&id, sizeof(uint8_t), 1, file);
|
|
fread(&length, sizeof(uint64_t), 1, file);
|
|
|
|
switch (id)
|
|
{
|
|
case 0x1:
|
|
// Do not replace the header after it is initialized
|
|
if (!caff->header)
|
|
caff->header = read_header(file);
|
|
break;
|
|
case 0x2:
|
|
// Do not replace the credits after it is initialized
|
|
if (!caff->credits)
|
|
caff->credits = read_credits(file);
|
|
print_credits(caff->credits);
|
|
break;
|
|
case 0x3:
|
|
anim_count++;
|
|
if (caff->header && caff->header->num_anim == anim_count)
|
|
{
|
|
fclose(file);
|
|
return caff;
|
|
}
|
|
// You might want to append to a list of animations here.
|
|
CAFF_Animation *anim = read_animation(file);
|
|
if(anim){
|
|
caff_add_animation_list(&caff->animations, *anim);
|
|
}
|
|
|
|
free(anim);
|
|
// We only need the first image now...
|
|
fclose(file);
|
|
return caff;
|
|
default:
|
|
// Random bytes should not cause an error
|
|
printf("Unknown block ID: %u\n", id);
|
|
fclose(file);
|
|
if(anim_count == 0){
|
|
free(caff);
|
|
caff = NULL;
|
|
}
|
|
return caff;
|
|
}
|
|
}
|
|
|
|
fclose(file);
|
|
printf("Parse END!\n");
|
|
return caff;
|
|
}
|
|
|
|
CAFF_Header *read_header(FILE *file)
|
|
{
|
|
CAFF_Header *header = malloc(sizeof(CAFF_Header));
|
|
if (!header)
|
|
{
|
|
printf("Failed to allocate memory for CAFF header\n");
|
|
return NULL;
|
|
}
|
|
|
|
// Read the magic string.
|
|
if (fread(header->magic, sizeof(char), 4, file) != 4)
|
|
{
|
|
printf("Failed to read magic string from CAFF header\n");
|
|
free(header);
|
|
return NULL;
|
|
}
|
|
|
|
// Check the magic string.
|
|
if (strncmp(header->magic, "CAFF", 4) != 0)
|
|
{
|
|
printf("Invalid magic string in CAFF header\n");
|
|
free(header);
|
|
return NULL;
|
|
}
|
|
|
|
// Read the header size.
|
|
if (fread(&header->header_size, sizeof(uint64_t), 1, file) != 1)
|
|
{
|
|
printf("Failed to read header size from CAFF header\n");
|
|
free(header);
|
|
return NULL;
|
|
}
|
|
|
|
// Read the number of animations.
|
|
if (fread(&header->num_anim, sizeof(uint64_t), 1, file) != 1)
|
|
{
|
|
printf("Failed to read number of animations from CAFF header\n");
|
|
free(header);
|
|
return NULL;
|
|
}
|
|
|
|
return header;
|
|
}
|
|
|
|
CAFF_Credits *read_credits(FILE *file)
|
|
{
|
|
CAFF_Credits *credits = malloc(sizeof(CAFF_Credits));
|
|
if (!credits)
|
|
{
|
|
printf("Failed to allocate memory for CAFF credits\n");
|
|
return NULL;
|
|
}
|
|
|
|
// Read the creation date and time.
|
|
if (fread(&credits->year, sizeof(uint16_t), 1, file) != 1 ||
|
|
fread(&credits->month, sizeof(uint8_t), 1, file) != 1 ||
|
|
fread(&credits->day, sizeof(uint8_t), 1, file) != 1 ||
|
|
fread(&credits->hour, sizeof(uint8_t), 1, file) != 1 ||
|
|
fread(&credits->minute, sizeof(uint8_t), 1, file) != 1)
|
|
{
|
|
printf("Failed to read creation date and time from CAFF credits\n");
|
|
free(credits);
|
|
return NULL;
|
|
}
|
|
|
|
// Read the length of the creator field.
|
|
if (fread(&credits->creator_len, sizeof(uint64_t), 1, file) != 1)
|
|
{
|
|
printf("Failed to read length of creator field from CAFF credits\n");
|
|
free(credits);
|
|
return NULL;
|
|
}
|
|
|
|
// Allocate memory for the creator field.
|
|
credits->creator = malloc(credits->creator_len + 1);
|
|
if (!credits->creator)
|
|
{
|
|
printf("Failed to allocate memory for creator field in CAFF credits\n");
|
|
free(credits);
|
|
return NULL;
|
|
}
|
|
|
|
// Read the creator field.
|
|
if (fread(credits->creator, 1, credits->creator_len, file) != credits->creator_len)
|
|
{
|
|
printf("Failed to read creator field from CAFF credits\n");
|
|
free(credits->creator);
|
|
free(credits);
|
|
return NULL;
|
|
}
|
|
|
|
// Null-terminate the creator string.
|
|
credits->creator[credits->creator_len] = '\0';
|
|
|
|
return credits;
|
|
}
|
|
|
|
CAFF_Animation *read_animation(FILE *file)
|
|
{
|
|
CAFF_Animation *animation = malloc(sizeof(CAFF_Animation));
|
|
if (!animation)
|
|
{
|
|
printf("Failed to allocate memory for CAFF animation\n");
|
|
return NULL;
|
|
}
|
|
|
|
// Read the duration.
|
|
if (fread(&animation->duration, sizeof(uint64_t), 1, file) != 1)
|
|
{
|
|
printf("Failed to read duration from CAFF animation\n");
|
|
free(animation);
|
|
return NULL;
|
|
}
|
|
|
|
// Read the CIFF image.
|
|
animation->ciff = read_ciff(file);
|
|
if (!animation->ciff)
|
|
{
|
|
printf("Failed to read CIFF image from CAFF animation\n");
|
|
free(animation);
|
|
return NULL;
|
|
}
|
|
|
|
return animation;
|
|
}
|
|
|
|
void caff_free(CAFF *caff)
|
|
{
|
|
// Free the header
|
|
free(caff->header);
|
|
caff->header = NULL;
|
|
|
|
// Free the credits
|
|
if (caff->credits->creator)
|
|
{
|
|
free(caff->credits->creator);
|
|
}
|
|
free(caff->credits);
|
|
caff->credits = NULL;
|
|
|
|
// Free the animations
|
|
for (size_t i = 0; i < caff->animations.length; i++)
|
|
{
|
|
free_ciff(caff->animations.array[i].ciff);
|
|
}
|
|
caff_free_animtion_list(&caff->animations);
|
|
|
|
// Finally, free the CAFF struct itself
|
|
free(caff);
|
|
} |