Inital commit
Signed-off-by: Balazs Toldi <balazs@toldi.eu>
This commit is contained in:
commit
0cf51dea87
7 changed files with 500 additions and 0 deletions
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
build/
|
||||||
|
parser
|
||||||
|
*.caff
|
||||||
|
*.jpg
|
||||||
|
*.jpeg
|
||||||
|
.vscode
|
13
Makefile
Normal file
13
Makefile
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -Wall -O2 -Werror -g
|
||||||
|
LDFLAGS = -ljpeg
|
||||||
|
TARGET = parser
|
||||||
|
SRC = main.c caff.c ciff.c
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET): $(SRC)
|
||||||
|
$(CC) $(CFLAGS) $(SRC) -o $(TARGET) $(LDFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET)
|
225
caff.c
Normal file
225
caff.c
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
#include "caff.h"
|
||||||
|
#include <webp/encode.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));
|
||||||
|
caff->credits = NULL;
|
||||||
|
caff->header = NULL;
|
||||||
|
caff_init_animation_list(&caff->animations);
|
||||||
|
// Check for malloc failure here.
|
||||||
|
size_t anim_count = 0;
|
||||||
|
while (!feof(file)) {
|
||||||
|
uint8_t id;
|
||||||
|
uint64_t length;
|
||||||
|
fread(&id, 1, 1, file);
|
||||||
|
fread(&length, 8, 1, file);
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case 0x1:
|
||||||
|
if(!caff->header)
|
||||||
|
caff->header = read_header(file);
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
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){
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
printf("Here!\n");
|
||||||
|
// You might want to append to a list of animations here.
|
||||||
|
CAFF_Animation* anim = read_animation(file);
|
||||||
|
|
||||||
|
caff_add_animation_list(&caff->animations,*anim);
|
||||||
|
free(anim);
|
||||||
|
printf("There!\n");
|
||||||
|
goto end;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknown block ID: %u\n", id);
|
||||||
|
goto end;
|
||||||
|
// Handle unknown block ID here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
|
||||||
|
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, 1, 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, 8, 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, 8, 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, 2, 1, file) != 1 ||
|
||||||
|
fread(&credits->month, 1, 1, file) != 1 ||
|
||||||
|
fread(&credits->day, 1, 1, file) != 1 ||
|
||||||
|
fread(&credits->hour, 1, 1, file) != 1 ||
|
||||||
|
fread(&credits->minute, 1, 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, 8, 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, 8, 1, file) != 1) {
|
||||||
|
printf("Failed to read duration from CAFF animation\n");
|
||||||
|
free(animation);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the CIFF image.
|
||||||
|
// Note: The read_ciff function needs to be defined to read a CIFF image from a file.
|
||||||
|
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);
|
||||||
|
}
|
46
caff.h
Normal file
46
caff.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef _CAFF_H_
|
||||||
|
#define _CAFF_H_
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "ciff.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char magic[4]; // The magic string 'CAFF'
|
||||||
|
uint64_t header_size; // The size of the header
|
||||||
|
uint64_t num_anim; // The number of animated CIFFs
|
||||||
|
} CAFF_Header;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t year; // Year of creation
|
||||||
|
uint8_t month; // Month of creation
|
||||||
|
uint8_t day; // Day of creation
|
||||||
|
uint8_t hour; // Hour of creation
|
||||||
|
uint8_t minute; // Minute of creation
|
||||||
|
uint64_t creator_len; // Length of the creator field
|
||||||
|
char* creator; // The creator of the CAFF file
|
||||||
|
} CAFF_Credits;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t duration; // Duration of the animation in milliseconds
|
||||||
|
CIFF* ciff; // The CIFF image
|
||||||
|
} CAFF_Animation;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
CAFF_Animation *array;
|
||||||
|
size_t length;
|
||||||
|
size_t size;
|
||||||
|
} CAFF_Animation_List;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
CAFF_Header* header; // The CAFF header
|
||||||
|
CAFF_Credits* credits; // The CAFF credits
|
||||||
|
CAFF_Animation_List animations; // The CAFF animations
|
||||||
|
} CAFF;
|
||||||
|
CAFF* caff_parse_file(const char* filename);
|
||||||
|
CAFF_Header* read_header(FILE* file);
|
||||||
|
CAFF_Credits* read_credits(FILE* file);
|
||||||
|
CAFF_Animation* read_animation(FILE* file);
|
||||||
|
void caff_free(CAFF* caff);
|
||||||
|
|
||||||
|
#endif
|
131
ciff.c
Normal file
131
ciff.c
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
#include "ciff.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <jpeglib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
CIFF* read_ciff(FILE* file) {
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
printf("Failed to open file!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CIFF* ciff = malloc(sizeof(CIFF));
|
||||||
|
if (!ciff) {
|
||||||
|
printf("Failed to allocate memory for CIFF structure\n");
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the header
|
||||||
|
fread(ciff->magic, 4, 1, file);
|
||||||
|
fread(&ciff->header_size, 8, 1, file);
|
||||||
|
fread(&ciff->content_size, 8, 1, file);
|
||||||
|
fread(&ciff->width, 8, 1, file);
|
||||||
|
fread(&ciff->height, 8, 1, file);
|
||||||
|
|
||||||
|
// Ensure the file is actually a CIFF file
|
||||||
|
if (strncmp(ciff->magic, "CIFF", 4) != 0) {
|
||||||
|
printf("File is not a CIFF file\n");
|
||||||
|
free(ciff);
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the caption
|
||||||
|
ciff->caption = malloc(ciff->header_size); // overestimate the size
|
||||||
|
if (!ciff->caption) {
|
||||||
|
printf("Failed to allocate memory for caption\n");
|
||||||
|
free(ciff);
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char c;
|
||||||
|
size_t i = 0;
|
||||||
|
do {
|
||||||
|
fread(&c, 1, 1, file);
|
||||||
|
ciff->caption[i++] = c;
|
||||||
|
} while (c != '\n');
|
||||||
|
ciff->caption[i] = '\0'; // null-terminate the string
|
||||||
|
size_t caption_lenth= i;
|
||||||
|
// Read the tags
|
||||||
|
ciff->tags = malloc(ciff->header_size-sizeof(char)*4-sizeof(uint64_t)*4-caption_lenth);
|
||||||
|
if (!ciff->tags) {
|
||||||
|
printf("Failed to allocate memory for tags\n");
|
||||||
|
free(ciff->caption);
|
||||||
|
free(ciff);
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
size_t header_loaded = sizeof(char)*4+sizeof(uint64_t)*4+caption_lenth;
|
||||||
|
printf("Header loaded: %ld/%ld\n",header_loaded,ciff->header_size);
|
||||||
|
while(header_loaded < ciff->header_size) {
|
||||||
|
fread(&c, 1, 1, file);
|
||||||
|
ciff->tags[i++] = c;
|
||||||
|
header_loaded += sizeof(char);
|
||||||
|
};
|
||||||
|
// Read the pixels
|
||||||
|
ciff->pixels = malloc(ciff->content_size);
|
||||||
|
if (!ciff->pixels) {
|
||||||
|
printf("Failed to allocate memory for pixel data\n");
|
||||||
|
free(ciff->caption);
|
||||||
|
free(ciff);
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
fread(ciff->pixels, ciff->content_size, 1, file);
|
||||||
|
|
||||||
|
|
||||||
|
return ciff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void generate_jpg(CIFF* ciff, const char* out_filename) {
|
||||||
|
struct jpeg_compress_struct cinfo;
|
||||||
|
struct jpeg_error_mgr jerr;
|
||||||
|
|
||||||
|
FILE* outfile = fopen(out_filename, "wb");
|
||||||
|
if (!outfile) {
|
||||||
|
printf("Failed to open output file: %s\n", out_filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cinfo.err = jpeg_std_error(&jerr);
|
||||||
|
jpeg_create_compress(&cinfo);
|
||||||
|
|
||||||
|
jpeg_stdio_dest(&cinfo, outfile);
|
||||||
|
|
||||||
|
cinfo.image_width = ciff->width;
|
||||||
|
cinfo.image_height = ciff->height;
|
||||||
|
cinfo.input_components = 3; // number of color components per pixel
|
||||||
|
cinfo.in_color_space = JCS_RGB; // color space of input image
|
||||||
|
|
||||||
|
jpeg_set_defaults(&cinfo);
|
||||||
|
|
||||||
|
jpeg_start_compress(&cinfo, TRUE);
|
||||||
|
|
||||||
|
JSAMPROW row_pointer[1];
|
||||||
|
while (cinfo.next_scanline < cinfo.image_height) {
|
||||||
|
row_pointer[0] = &ciff->pixels[cinfo.next_scanline * ciff->width * 3];
|
||||||
|
jpeg_write_scanlines(&cinfo, row_pointer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
jpeg_finish_compress(&cinfo);
|
||||||
|
|
||||||
|
fclose(outfile);
|
||||||
|
|
||||||
|
jpeg_destroy_compress(&cinfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void free_ciff(CIFF* ciff) {
|
||||||
|
free(ciff->caption);
|
||||||
|
free(ciff->pixels);
|
||||||
|
free(ciff->tags);
|
||||||
|
free(ciff);
|
||||||
|
}
|
24
ciff.h
Normal file
24
ciff.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#ifndef _CIFF_H_
|
||||||
|
#define _CIFF_H_
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#define MAX_PATH_LEN 1024
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char magic[4];
|
||||||
|
uint64_t header_size;
|
||||||
|
uint64_t content_size;
|
||||||
|
uint64_t width;
|
||||||
|
uint64_t height;
|
||||||
|
char* caption;
|
||||||
|
char* tags;
|
||||||
|
uint8_t* pixels;
|
||||||
|
} CIFF;
|
||||||
|
|
||||||
|
CIFF* read_ciff(FILE* file);
|
||||||
|
void generate_jpg(CIFF* ciff, const char* out_filename);
|
||||||
|
void free_ciff(CIFF* ciff);
|
||||||
|
|
||||||
|
#endif
|
55
main.c
Normal file
55
main.c
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ciff.h"
|
||||||
|
#include "caff.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc != 3 || (strcmp(argv[1], "-ciff") != 0 && strcmp(argv[1], "-caff") != 0))
|
||||||
|
{
|
||||||
|
printf("Usage: %s <-ciff|-caff> <input.ciff|input.caff>\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
bool is_caff = strcmp(argv[1], "-caff") == 0;
|
||||||
|
char *input_path = argv[2];
|
||||||
|
char jpg_path[MAX_PATH_LEN + 1];
|
||||||
|
strncpy(jpg_path, input_path, MAX_PATH_LEN-1);
|
||||||
|
char *extension = strrchr(jpg_path, '.');
|
||||||
|
if (extension)
|
||||||
|
{
|
||||||
|
strncpy(extension, ".jpeg", MAX_PATH_LEN - (extension - jpg_path));
|
||||||
|
}
|
||||||
|
printf("%s\n", jpg_path);
|
||||||
|
CIFF *ciff;
|
||||||
|
CAFF *caff = NULL;
|
||||||
|
if (is_caff)
|
||||||
|
{
|
||||||
|
caff = caff_parse_file(input_path);
|
||||||
|
ciff = caff->animations.array[0].ciff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FILE *ciff_file = fopen(input_path, "rb");
|
||||||
|
ciff = read_ciff(ciff_file);
|
||||||
|
}
|
||||||
|
if (!ciff)
|
||||||
|
{
|
||||||
|
printf("Failed to read CIFF file: %s\n", input_path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_jpg(ciff, jpg_path);
|
||||||
|
if (is_caff)
|
||||||
|
{
|
||||||
|
caff_free(caff);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
free_ciff(ciff);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue