From: Rafał Długołęcki Date: Sun, 21 Aug 2016 03:50:58 +0000 (+0200) Subject: Initial commit X-Git-Tag: 0.1^0 X-Git-Url: https://git.dlugolecki.net.pl/?a=commitdiff_plain;h=5dbec35c09d6cda59c97a177de59fe6e1b4f0fe9;p=aaf.git Initial commit --- 5dbec35c09d6cda59c97a177de59fe6e1b4f0fe9 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a4cb824 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +aaf: + gcc main.c aaf.c -I./ -g -Wall -pedantic -o aaf + +clean: + rm -f aaf + rm -f FONT-* diff --git a/README b/README new file mode 100644 index 0000000..2d94652 --- /dev/null +++ b/README @@ -0,0 +1,9 @@ +aaf, a C library for reading AAF files +-------------------------------------- + +AAF Font File Format is used to store fonts in Fallout 1&2. + +Code is based on file format specification from: +http://falloutmods.wikia.com/wiki/AAF_File_Format + +Author: Rafał Długołęcki diff --git a/aaf.c b/aaf.c new file mode 100644 index 0000000..b692af8 --- /dev/null +++ b/aaf.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include + +#include "aaf.h" + +int read_aaf(FILE * in, struct aaf * _aaf) +{ + size_t elements = 0; + int i; + + assert(in != NULL); + assert(_aaf != NULL); + + elements = fread(_aaf, sizeof(struct aaf), 1, in); + if (elements == 0) { + perror("Unable to correctly read input file"); + return 1; + } + + if (strncmp("AAFF", _aaf->signature, 4) != 0) { + fprintf(stderr, "Invalid sigature of input file\n"); + return 2; + } + + _aaf->max_h = be16toh(_aaf->max_h); + _aaf->gap_h = be16toh(_aaf->gap_h); + _aaf->space_width = be16toh(_aaf->space_width); + _aaf->gap_v = be16toh(_aaf->gap_v); + + for (i = 0; i < AAF_GLYPH_MAX; i++) { + _aaf->glyphs[i].w = be16toh(_aaf->glyphs[i].w); + _aaf->glyphs[i].h = be16toh(_aaf->glyphs[i].h); + _aaf->glyphs[i].off = be32toh(_aaf->glyphs[i].off); + } + + return 0; +} + +void free_aaf_glyph_data(struct aaf_glyph_data ** data) +{ + int i; + + assert(data); + + for (i = 0; i < AAF_GLYPH_MAX; i++) { + if (data[i]) { + free(data[i]->pixels); + free(data[i]); + data[i] = NULL; + } + } + + free(data); + data = NULL; +} + +struct aaf_glyph_data ** read_aaf_glyph_data(FILE * in, struct aaf * _aaf) +{ + struct aaf_glyph_data ** data = NULL; + long offset; + int i; + + assert(in != NULL); + assert(_aaf != NULL); + + offset = ftell(in); + + data = malloc(sizeof(struct aaf_glyph_data*) * AAF_GLYPH_MAX); + + for (i = 0; i < AAF_GLYPH_MAX; i++) { + const struct aaf_glyph * glyph = &(_aaf->glyphs[i]); + + data[i] = NULL; + + if ((glyph->w * glyph->h) == 0) { + continue; + } + + data[i] = malloc(sizeof(struct aaf_glyph_data)); + if (data[i] == NULL) { + perror("Unable to allocate memory for glyph data"); + free_aaf_glyph_data(data); + fseek(in, offset, SEEK_SET); + return NULL; + } + + data[i]->pixels = malloc(sizeof(uint8_t) * glyph->w * glyph->h); + if (data[i]->pixels == NULL) { + perror("Unable to allocate memory for glyph pixel data"); + free_aaf_glyph_data(data); + fseek(in, offset, SEEK_SET); + return NULL; + } + + fseek(in, sizeof(struct aaf) + glyph->off, SEEK_SET); + fread(data[i]->pixels, sizeof(uint8_t), glyph->w * glyph->h, in); + } + + fseek(in, offset, SEEK_SET); + + return data; +} + +int write_aaf_glyph_as_pgm(FILE * out, const struct aaf_glyph * glyph, const struct aaf_glyph_data * data) +{ + int w = 0; + int h = 0; + int error = 0; + + assert(out != NULL); + assert(glyph != NULL); + assert(data != NULL); + + error = fprintf(out, "%s\n%d %d\n%d\n", + "P2", + glyph->w, + glyph->h, + 9 + ); + + if (error < 0) { + perror("Unable to write PGM header"); + return error; + } + + for (h = 0; h < glyph->h; h++) { + for (w = 0; w < glyph->w; w++) { + error = fprintf(out, "%d", + data->pixels[h * glyph->w + w] + ); + + if (error < 0) { + perror("Unabe to write PGM image data"); + return error; + } + + if (w + 1 < glyph->w) { + fputc(' ', out); + } + } + + fputc('\n', out); + } + + return 0; +} diff --git a/aaf.h b/aaf.h new file mode 100644 index 0000000..ac87f06 --- /dev/null +++ b/aaf.h @@ -0,0 +1,71 @@ +#ifndef __AAF_H +#define __AAF_H + +#include +#include + +#define AAF_GLYPH_MAX 256 + +struct aaf_glyph { + uint16_t w; + uint16_t h; + uint32_t off; +}; + +struct aaf { + char signature[4]; + uint16_t max_h; + uint16_t gap_h; + uint16_t space_width; + uint16_t gap_v; + + struct aaf_glyph glyphs[AAF_GLYPH_MAX]; +}; + +struct aaf_glyph_data { + /* variable size array of values 0-9 */ + uint8_t * pixels; +}; + +/** + * Reads AAF informations about font + * + * @param in opened stream for reading + * @param _aaf reference to structure where read informations will be stored + * + * @return when succesful function returns 0, otherwise non-zero value + */ +int read_aaf(FILE * in, struct aaf * _aaf); + +/** + * Reads AAF glyph data from input stream + * Returned structure is an array with number of elements equal to AAF_GLYPH_MAX. + * Every X element of array relates to _aaf->glyphs[X]. + * Structure should be freed using free_aaf_glyph_data function. + * + * @param in opened input stream + * @param _aaf pointer to AAF header information + * + * @return when succesful returns pointer to newly allocated array of struct + * aaf_glyph_data. On error NULL is returned. + */ +struct aaf_glyph_data ** read_aaf_glyph_data(FILE * in, struct aaf * _aaf); + +/** + * Function used to free data allocated using read_aaf_glyph_data. + * + * @param data pointer to array of glyph data + */ +void free_aaf_glyph_data(struct aaf_glyph_data ** data); + +/** + * Writes AAF glyph as PGM image + * + * @param out opened output stream for writting + * @param glyph glyph description + * @param data glyph data + * @return 0 if data was written succesfully, negative value when error occured + */ +int write_aaf_glyph_as_pgm(FILE * out, const struct aaf_glyph * glyph, const struct aaf_glyph_data * data); + +#endif /* __AAF_H */ diff --git a/main.c b/main.c new file mode 100644 index 0000000..4afe9b8 --- /dev/null +++ b/main.c @@ -0,0 +1,86 @@ +#include +#include + +#include "aaf.h" + + +int main(int argc, char ** argv) +{ + FILE * in = NULL; + + if (argc <= 1) { + puts("Fallout 1 AAF converter"); + puts("Converts INPUT.AAF file into set of PGM images"); + printf("\n\tUsage: %s INPUT\n\n", argv[0]); + } + else { + struct aaf _aaf; + struct aaf_glyph_data ** glyph_data = NULL; + int i = 0; + + in = fopen(argv[1], "r"); + if (in == NULL) { + perror("Unable to open file for conversion"); + return errno; + } + + if (read_aaf(in, &_aaf) != 0) { + fprintf(stderr, "Problem occured when trying to read AAF file\n"); + fclose(in); + return 1; + } + + glyph_data = read_aaf_glyph_data(in, &_aaf); + if (glyph_data == NULL) { + fprintf(stderr, "Problem occured when trying to read AAF glyph data\n"); + fclose(in); + return 2; + } + + for (i = 0; i < AAF_GLYPH_MAX; i++) { + const struct aaf_glyph * glyph = &(_aaf.glyphs[i]); + const struct aaf_glyph_data * data = glyph_data[i]; + + FILE * out = NULL; + char filename[13] = { + 'F', 'O', 'N', 'T', '-', '0', '0', '0', '.', 'P', 'G', 'M' + }; + + if ((glyph->w * glyph->h) == 0) { + continue; + } + + if (i / 100) { + filename[5] = i / 100 + '0'; + } + if ((i % 100) / 10) { + filename[6] = (i % 100) / 10 + '0'; + } + if (i % 10) { + filename[7] = i % 10 + '0'; + } + + out = fopen(filename, "w"); + if (out == NULL) { + perror("Unable to open file for writing glyph"); + free_aaf_glyph_data(glyph_data); + fclose(in); + return 3; + } + + if (write_aaf_glyph_as_pgm(out, glyph, data)) { + fprintf(stderr, "Error occured when trying to write glyph into PGM\n"); + fclose(out); + free_aaf_glyph_data(glyph_data); + fclose(in); + return 4; + } + fclose(out); + } + + free_aaf_glyph_data(glyph_data); + fclose(in); + } + + return 0; +}