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
|
#include "support/util.h"
#include "otfcc/sfnt-builder.h"
#define OTFCC_CHR(a,b,c,d) ( ((a)<<24) | ((b)<<16) | ((c)<<8) | (d) )
static uint32_t buf_checksum(caryll_Buffer *buffer) {
uint32_t actualLength = (uint32_t)buflen(buffer);
buflongalign(buffer);
uint32_t sum = 0;
{
uint32_t *start = (uint32_t *)buffer->data;
uint32_t *end = start + ((actualLength + 3) & ~3) / sizeof(uint32_t);
while (start < end) {
sum += otfcc_endian_convert32(*start++);
}
}
return sum;
}
static otfcc_SFNTTableEntry *createSegment(uint32_t tag, caryll_Buffer *buffer) {
otfcc_SFNTTableEntry *table;
NEW(table);
table->tag = tag;
table->length = (uint32_t)buflen(buffer);
buflongalign(buffer);
table->buffer = buffer;
uint32_t sum = 0;
{
uint32_t *start = (uint32_t *)buffer->data;
uint32_t *end = start + ((table->length + 3) & ~3) / sizeof(uint32_t);
while (start < end) {
sum += otfcc_endian_convert32(*start++);
}
}
table->checksum = sum;
return table;
}
otfcc_SFNTBuilder *otfcc_newSFNTBuilder(uint32_t header, const otfcc_Options *options) {
otfcc_SFNTBuilder *builder;
NEW(builder);
builder->count = 0;
builder->header = header;
builder->tables = NULL;
builder->options = options;
return builder;
}
void otfcc_deleteSFNTBuilder(otfcc_SFNTBuilder *builder) {
if (!builder) return;
otfcc_SFNTTableEntry *item, *tmp;
HASH_ITER(hh, builder->tables, item, tmp) {
HASH_DEL(builder->tables, item);
buffree(item->buffer);
FREE(item);
}
FREE(builder);
}
void otfcc_SFNTBuilder_pushTable(otfcc_SFNTBuilder *builder, uint32_t tag, caryll_Buffer *buffer) {
if (!builder || !buffer) return;
otfcc_SFNTTableEntry *item;
const otfcc_Options *options = builder->options;
HASH_FIND_INT(builder->tables, &tag, item);
if (!item) {
item = createSegment(tag, buffer);
HASH_ADD_INT(builder->tables, tag, item);
logProgress("OpenType table %c%c%c%c successfully built.\n", (tag >> 24) & 0xff,
(tag >> 16) & 0xff, (tag >> 8) & 0xff, tag & 0xff);
} else {
buffree(buffer);
}
}
static int byTag(otfcc_SFNTTableEntry *a, otfcc_SFNTTableEntry *b) {
return (a->tag - b->tag);
}
caryll_Buffer *otfcc_SFNTBuilder_serialize(otfcc_SFNTBuilder *builder) {
caryll_Buffer *buffer = bufnew();
if (!builder) return buffer;
uint16_t nTables = HASH_COUNT(builder->tables);
uint16_t searchRange = (nTables < 16 ? 8 : nTables < 32 ? 16 : nTables < 64 ? 32 : 64) * 16;
bufwrite32b(buffer, builder->header);
bufwrite16b(buffer, nTables);
bufwrite16b(buffer, searchRange);
bufwrite16b(buffer, (nTables < 16 ? 3 : nTables < 32 ? 4 : nTables < 64 ? 5 : 6));
bufwrite16b(buffer, nTables * 16 - searchRange);
otfcc_SFNTTableEntry *table;
size_t offset = 12 + nTables * 16;
size_t headOffset = offset;
HASH_SORT(builder->tables, byTag);
foreach_hash(table, builder->tables) {
// write table directory
bufwrite32b(buffer, table->tag);
bufwrite32b(buffer, table->checksum);
bufwrite32b(buffer, (uint32_t)offset);
bufwrite32b(buffer, table->length);
size_t cp = buffer->cursor;
bufseek(buffer, offset);
bufwrite_buf(buffer, table->buffer);
bufseek(buffer, cp);
// record where the [head] is
if (table->tag == OTFCC_CHR('h','e','a','d')) { headOffset = offset; }
offset += buflen(table->buffer);
}
// write head.checksumAdjust
uint32_t wholeChecksum = buf_checksum(buffer);
bufseek(buffer, headOffset + 8);
bufwrite32b(buffer, 0xB1B0AFBA - wholeChecksum);
return buffer;
}
|