about summary refs log tree commit diff
path: root/lib/ppmdfont.c
blob: d2be215da67bbf098eeae4f968bc0163036465a7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <string.h>

#include "netpbm/mallocvar.h"
#include "pm.h"
#include "ppmdfont.h"


extern struct ppmd_font ppmd_standardfont;

static const struct ppmd_font * currentFontP = &ppmd_standardfont;

static void
readGlyphHeader(FILE *                    const ifP,
                struct ppmd_glyphHeader * const glyphHeaderP) {

    glyphHeaderP->commandCount = fgetc(ifP);
    glyphHeaderP->skipBefore   = fgetc(ifP);
    glyphHeaderP->skipAfter    = fgetc(ifP);
}



static void
readGlyphCommand(FILE *                     const ifP,
                 struct ppmd_glyphCommand * const glyphCommandP) {

    glyphCommandP->verb = fgetc(ifP);
    glyphCommandP->x    = fgetc(ifP);
    glyphCommandP->y    = fgetc(ifP);
}



static void
readCharacter(FILE *              const ifP,
              struct ppmd_glyph * const glyphP) {

    unsigned int commandNum;
    struct ppmd_glyphCommand * commandList;

    readGlyphHeader(ifP, &glyphP->header);

    MALLOCARRAY(commandList, glyphP->header.commandCount);

    if (commandList == NULL)
        pm_error("Insufficient memory to create a %u-command "
                 "command list.", glyphP->header.commandCount);

    for (commandNum = 0;
         commandNum < glyphP->header.commandCount;
         ++commandNum) {

        readGlyphCommand(ifP, &commandList[commandNum]);
    }
    glyphP->commandList = commandList;
}



static void
readFontHeader(FILE *                   const ifP,
               struct ppmd_fontHeader * const fontHeaderP) {

    size_t rc;

    rc = fread(&fontHeaderP->signature, 1, sizeof(fontHeaderP->signature),
               ifP);

    if (rc != sizeof(fontHeaderP->signature))
        pm_error("Unable to read the header from the font file.  "
                 "errno=%d (%s)", errno, strerror(errno));

    fontHeaderP->format         = fgetc(ifP);
    fontHeaderP->characterCount = fgetc(ifP);
    fontHeaderP->firstCodePoint = fgetc(ifP);
}



void
ppmd_set_font(const struct ppmd_font * const newFontP) {

    currentFontP = newFontP;
}



const struct ppmd_font *
ppmd_get_font(void) {

    return currentFontP;
}



void
ppmd_read_font(FILE *                        const ifP,
               const struct ppmd_font **     const fontPP) {

    unsigned int relativeCodePoint;
    struct ppmd_glyph * glyphTable;
    struct ppmd_font * fontP;

    MALLOCVAR(fontP);
    if (fontP == NULL)
        pm_error("Insufficient memory for font header");

    readFontHeader(ifP, &fontP->header);

    MALLOCARRAY(glyphTable, fontP->header.characterCount);
    if (glyphTable == NULL)
        pm_error("Insufficient memory to store %u characters",
                 fontP->header.characterCount);

    for (relativeCodePoint = 0;
         relativeCodePoint < fontP->header.characterCount;
         ++relativeCodePoint) {

        readCharacter(ifP, &glyphTable[relativeCodePoint]);
    }
    fontP->glyphTable = glyphTable;
    *fontPP = fontP;
}



void
ppmd_free_font(const struct ppmd_font * const fontP) {

    unsigned int relativeCodePoint;

    for (relativeCodePoint = 0;
         relativeCodePoint < fontP->header.characterCount;
         ++relativeCodePoint) {

        free((void*)fontP->glyphTable[relativeCodePoint].commandList);
    }
    free((void*)fontP->glyphTable);
    free((void*)fontP);
}