Minor.
[ttfautohint.git] / lib / taname.c
blob0365ad02d29e4b76739beed5d1fee281f45a5018
1 /* taname.c */
3 /*
4 * Copyright (C) 2012-2014 by Werner Lemberg.
6 * This file is part of the ttfautohint library, and may only be used,
7 * modified, and distributed under the terms given in `COPYING'. By
8 * continuing to use, modify, or distribute this file you indicate that you
9 * have read `COPYING' and understand and accept it fully.
11 * The file `COPYING' mentioned in the previous paragraph is distributed
12 * with the ttfautohint library.
16 #include <string.h>
17 #include "ta.h"
20 typedef struct Lang_Tag_Record_
22 FT_UShort len;
23 FT_Byte* str;
24 } Lang_Tag_Record;
26 typedef struct Name_Record_
28 FT_UShort platform_id;
29 FT_UShort encoding_id;
30 FT_UShort language_id;
31 FT_UShort name_id;
33 FT_UShort len;
34 FT_Byte* str;
35 } Name_Record;
37 typedef struct Naming_Table_
39 FT_UShort format;
40 FT_UShort string_offset;
42 FT_UShort name_count;
43 Name_Record* name_records;
45 FT_UShort lang_tag_count;
46 Lang_Tag_Record* lang_tag_records;
47 } Naming_Table;
50 static FT_Error
51 parse_name_header(FT_Byte** curp,
52 Naming_Table* n,
53 FT_ULong buf_len,
54 FT_Byte** start,
55 FT_Byte** end)
57 FT_Byte* buf = *curp;
58 FT_Byte* p;
59 FT_Byte* startp;
60 FT_Byte* endp;
63 p = *curp;
65 n->format = *(p++) << 8;
66 n->format += *(p++);
67 n->name_count = *(p++) << 8;
68 n->name_count += *(p++);
69 n->string_offset = *(p++) << 8;
70 n->string_offset += *(p++);
72 n->name_records = NULL;
73 n->lang_tag_records = NULL;
75 /* all name strings must be between `startp' and `endp' */
76 startp = buf + 6 + 12 * n->name_count;
77 endp = buf + buf_len;
79 /* format 1 also has language tag records */
80 if (n->format == 1)
82 FT_Byte* q;
85 q = startp;
86 if (q + 2 > endp)
87 return FT_Err_Invalid_Table;
89 n->lang_tag_count = *(q++) << 8;
90 n->lang_tag_count += *q;
92 startp += 2 + 4 * n->lang_tag_count;
94 else
95 n->lang_tag_count = 0;
97 if (startp > endp)
98 return FT_Err_Invalid_Table;
100 *start = startp;
101 *end = endp;
102 *curp = p;
104 return TA_Err_Ok;
108 static FT_Error
109 parse_name_records(FT_Byte** curp,
110 Naming_Table* n,
111 FT_Byte* buf,
112 FT_Byte* startp,
113 FT_Byte* endp,
114 FONT* font)
116 FT_UShort i, count;
117 FT_Byte* p;
120 p = *curp;
122 if (!n->name_count)
123 return TA_Err_Ok;
125 /* allocate name records array */
126 n->name_records = (Name_Record*)calloc(1, n->name_count
127 * sizeof (Name_Record));
128 if (!n->name_records)
129 return FT_Err_Out_Of_Memory;
131 /* walk over all name records */
132 count = 0;
133 for (i = 0; i < n->name_count; i++)
135 Name_Record* r = &n->name_records[count];
137 FT_UShort offset;
138 FT_Byte* s;
139 FT_UShort l;
142 r->platform_id = *(p++) << 8;
143 r->platform_id += *(p++);
144 r->encoding_id = *(p++) << 8;
145 r->encoding_id += *(p++);
146 r->language_id = *(p++) << 8;
147 r->language_id += *(p++);
148 r->name_id = *(p++) << 8;
149 r->name_id += *(p++);
151 r->len = *(p++) << 8;
152 r->len += *(p++);
154 offset = *(p++) << 8;
155 offset += *(p++);
157 s = buf + n->string_offset + offset;
159 /* ignore invalid entries */
160 if (s < startp || s + r->len > endp)
161 continue;
163 /* mac encoding or non-Unicode Windows encoding? */
164 if (r->platform_id == 1
165 || (r->platform_id == 3 && !(r->encoding_id == 1
166 || r->encoding_id == 10)))
168 /* one-byte or multi-byte encodings */
170 /* skip everything after a NULL byte (if any) */
171 for (l = 0; l < r->len; l++)
172 if (!s[l])
173 break;
175 /* ignore zero-length entries */
176 if (!l)
177 continue;
179 r->len = l;
181 else
183 /* (two-byte) UTF-16BE for everything else */
185 /* we need an even number of bytes */
186 r->len &= ~1;
188 /* ignore entries which contain only NULL bytes */
189 for (l = 0; l < r->len; l++)
190 if (s[l])
191 break;
192 if (l == r->len)
193 continue;
196 r->str = (FT_Byte*)malloc(r->len);
197 if (!r->str)
198 return FT_Err_Out_Of_Memory;
199 memcpy(r->str, s, r->len);
201 if (font->info)
203 if (font->info(r->platform_id,
204 r->encoding_id,
205 r->language_id,
206 r->name_id,
207 &r->len,
208 &r->str,
209 font->info_data))
210 continue;
212 count++;
215 /* shrink name record array if necessary */
216 n->name_records = (Name_Record*)realloc(n->name_records,
217 count * sizeof (Name_Record));
218 n->name_count = count;
220 return TA_Err_Ok;
224 FT_Error
225 parse_lang_tag_records(FT_Byte** curp,
226 Naming_Table* n,
227 FT_Byte* buf,
228 FT_Byte* startp,
229 FT_Byte* endp)
231 FT_UShort i;
232 FT_Byte* p;
235 p = *curp;
237 if (!n->lang_tag_count)
238 return TA_Err_Ok;
240 /* allocate language tags array */
241 n->lang_tag_records = (Lang_Tag_Record*)calloc(
242 1, n->lang_tag_count * sizeof (Lang_Tag_Record));
243 if (!n->lang_tag_records)
244 return FT_Err_Out_Of_Memory;
246 /* walk over all language tag records (if any) */
247 for (i = 0; i < n->lang_tag_count; i++)
249 Lang_Tag_Record* r = &n->lang_tag_records[i];
251 FT_UShort offset;
252 FT_Byte* s;
255 r->len = *(p++) << 8;
256 r->len += *(p++);
258 offset = *(p++) << 8;
259 offset += *(p++);
261 s = buf + n->string_offset + offset;
263 /* ignore an invalid entry -- */
264 /* contrary to name records, we can't simply remove it */
265 /* because references to it should still work */
266 /* (we don't apply more fixes */
267 /* since ttfautohint is not a TrueType sanitizing tool) */
268 if (s < startp || s + r->len > endp)
269 continue;
271 /* we don't massage the data since we only make a copy */
272 r->str = (FT_Byte*)malloc(r->len);
273 if (!r->str)
274 return FT_Err_Out_Of_Memory;
276 memcpy(r->str, s, r->len);
279 return TA_Err_Ok;
283 /* we build a non-optimized `name' table, this is, */
284 /* we don't fold strings `foo' and `foobar' into one string */
286 static FT_Error
287 build_name_table(Naming_Table* n,
288 SFNT_Table* name_table)
290 FT_Byte* buf_new;
291 FT_Byte* buf_new_resized;
292 FT_ULong buf_new_len;
293 FT_ULong len;
295 FT_Byte* p;
296 FT_Byte* q;
297 FT_Byte* base;
299 FT_UShort i;
300 FT_UShort string_offset;
301 FT_ULong data_offset;
302 FT_ULong data_len;
305 /* we reallocate the array to its real size later on */
306 buf_new_len= 6 + 12 * n->name_count;
307 if (n->format == 1)
308 buf_new_len += 2 + 4 * n->lang_tag_count;
310 buf_new = (FT_Byte*)malloc(buf_new_len);
311 if (!buf_new)
312 return FT_Err_Out_Of_Memory;
314 /* note that the OpenType specification says that `string_offset' is the */
315 /* `offset to the start of string storage (from start of table)', */
316 /* but this isn't enforced by the major rendering engines */
317 /* as long as the final string offsets are valid */
318 string_offset = (buf_new_len <= 0xFFFF) ? buf_new_len : 0xFFFF;
320 p = buf_new;
322 *(p++) = HIGH(n->format);
323 *(p++) = LOW(n->format);
324 *(p++) = HIGH(n->name_count);
325 *(p++) = LOW(n->name_count);
326 *(p++) = HIGH(string_offset);
327 *(p++) = LOW(string_offset);
329 /* first pass */
331 data_len = 0;
332 for (i = 0; i < n->name_count; i++)
334 Name_Record* r = &n->name_records[i];
337 *(p++) = HIGH(r->platform_id);
338 *(p++) = LOW(r->platform_id);
339 *(p++) = HIGH(r->encoding_id);
340 *(p++) = LOW(r->encoding_id);
341 *(p++) = HIGH(r->language_id);
342 *(p++) = LOW(r->language_id);
343 *(p++) = HIGH(r->name_id);
344 *(p++) = LOW(r->name_id);
346 *(p++) = HIGH(r->len);
347 *(p++) = LOW(r->len);
349 /* the offset field gets filled in later */
350 p += 2;
352 data_len += r->len;
355 if (n->format == 1)
357 *(p++) = HIGH(n->lang_tag_count);
358 *(p++) = LOW(n->lang_tag_count);
360 for (i = 0; i < n->lang_tag_count; i++)
362 Lang_Tag_Record* r = &n->lang_tag_records[i];
365 *(p++) = HIGH(r->len);
366 *(p++) = LOW(r->len);
368 /* the offset field gets filled in later */
369 p += 2;
371 data_len += r->len;
375 if (buf_new_len + data_len > 2 * 0xFFFF)
377 /* the table would become too large, so we do nothing */
378 free(buf_new);
379 return TA_Err_Ok;
382 data_offset = buf_new_len;
384 /* reallocate the buffer to fit its real size */
385 buf_new_len += data_len;
386 /* make the allocated buffer length a multiple of 4 */
387 len = (buf_new_len + 3) & ~3;
389 buf_new_resized = (FT_Byte*)realloc(buf_new, len);
390 if (!buf_new_resized)
392 free(buf_new);
393 return FT_Err_Out_Of_Memory;
395 buf_new = buf_new_resized;
397 base = buf_new + string_offset;
398 p = buf_new + data_offset;
400 /* second pass */
402 /* the first name record offset */
403 q = &buf_new[6 + 10];
404 for (i = 0; i < n->name_count; i++)
406 Name_Record* r = &n->name_records[i];
409 /* fill in offset */
410 *q = HIGH(p - base);
411 *(q + 1) = LOW(p - base);
413 /* copy string */
414 memcpy(p, r->str, r->len);
416 p += r->len;
417 q += 12;
420 if (n->format == 1)
422 /* the first language tag record offset */
423 q = &buf_new[6 + 12 * n->name_count + 2 + 2];
424 for (i = 0; i < n->lang_tag_count; i++)
426 Lang_Tag_Record* r = &n->lang_tag_records[i];
429 /* fill in offset */
430 *q = HIGH(p - base);
431 *(q + 1) = LOW(p - base);
433 /* copy string */
434 memcpy(p, r->str, r->len);
436 p += r->len;
437 q += 4;
441 /* pad end of buffer with zeros */
442 switch (buf_new_len % 4)
444 case 1:
445 *(p++) = 0x00;
446 case 2:
447 *(p++) = 0x00;
448 case 3:
449 *(p++) = 0x00;
450 default:
451 break;
454 /* we are done; replace the old buffer with the new one */
455 free(name_table->buf);
457 name_table->buf = buf_new;
458 name_table->len = buf_new_len;
460 return TA_Err_Ok;
464 /* we handle the `name' table as optional; */
465 /* if there are problems not related to allocation, */
466 /* simply return (or continue, if possible) without signaling an error, */
467 /* and the original `name' table is not modified */
469 FT_Error
470 TA_sfnt_update_name_table(SFNT* sfnt,
471 FONT* font)
473 FT_Error error;
475 SFNT_Table* name_table;
476 FT_Byte* buf;
477 FT_ULong buf_len;
479 Naming_Table n;
481 FT_Byte* p;
482 FT_Byte* startp;
483 FT_Byte* endp;
485 FT_UShort i;
488 if (sfnt->name_idx == MISSING)
489 return TA_Err_Ok;
491 name_table = &font->tables[sfnt->name_idx];
492 buf = name_table->buf;
493 buf_len = name_table->len;
495 if (name_table->processed)
496 return TA_Err_Ok;
498 p = buf;
500 error = parse_name_header(&p, &n, buf_len, &startp, &endp);
501 if (error)
502 return TA_Err_Ok;
504 /* due to the structure of the `name' table, */
505 /* we must parse it completely, apply our changes, */
506 /* and rebuild it from scratch */
507 error = parse_name_records(&p, &n, buf, startp, endp, font);
508 if (error)
509 goto Exit;
511 error = parse_lang_tag_records(&p, &n, buf, startp, endp);
512 if (error)
513 goto Exit;
515 error = build_name_table(&n, name_table);
516 if (error)
517 goto Exit;
519 name_table->checksum = TA_table_compute_checksum(name_table->buf,
520 name_table->len);
522 Exit:
523 for (i = 0; i < n.name_count; i++)
524 free(n.name_records[i].str);
525 for (i = 0; i < n.lang_tag_count; i++)
526 free(n.lang_tag_records[i].str);
528 free(n.name_records);
529 free(n.lang_tag_records);
531 name_table->processed = 1;
533 return error;
536 /* end of taname.c */