--- /dev/null
+aaf:
+ gcc main.c aaf.c -I./ -g -Wall -pedantic -o aaf
+
+clean:
+ rm -f aaf
+ rm -f FONT-*
--- /dev/null
+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 <kontakt@dlugolecki.net.pl>
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <assert.h>
+#include <endian.h>
+
+#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;
+}
--- /dev/null
+#ifndef __AAF_H
+#define __AAF_H
+
+#include <stdio.h>
+#include <stdint.h>
+
+#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 */
--- /dev/null
+#include <stdio.h>
+#include <errno.h>
+
+#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;
+}