Initial commit 0.1
authorRafał Długołęcki <rafal@dlugolecki.net.pl>
Sun, 21 Aug 2016 03:50:58 +0000 (05:50 +0200)
committerRafał Długołęcki <rafal@dlugolecki.net.pl>
Sun, 21 Aug 2016 03:50:58 +0000 (05:50 +0200)
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
aaf.c [new file with mode: 0644]
aaf.h [new file with mode: 0644]
main.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
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 <kontakt@dlugolecki.net.pl>
diff --git a/aaf.c b/aaf.c
new file mode 100644 (file)
index 0000000..b692af8
--- /dev/null
+++ b/aaf.c
@@ -0,0 +1,150 @@
+#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;
+}
diff --git a/aaf.h b/aaf.h
new file mode 100644 (file)
index 0000000..ac87f06
--- /dev/null
+++ b/aaf.h
@@ -0,0 +1,71 @@
+#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 */
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..4afe9b8
--- /dev/null
+++ b/main.c
@@ -0,0 +1,86 @@
+#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;
+}