s/TA_NEXT_/NEXT_/.
[ttfautohint.git] / lib / taname.c
blob2ad1973c2cd127fcbcb5b60b00b01e8c986edfd5
1 /* taname.c */
3 /*
4 * Copyright (C) 2012-2015 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 = NEXT_USHORT(p);
66 n->name_count = NEXT_USHORT(p);
67 n->string_offset = NEXT_USHORT(p);
69 n->name_records = NULL;
70 n->lang_tag_records = NULL;
72 /* all name strings must be between `startp' and `endp' */
73 startp = buf + 6 + 12 * n->name_count;
74 endp = buf + buf_len;
76 /* format 1 also has language tag records */
77 if (n->format == 1)
79 FT_Byte* q;
82 q = startp;
83 if (q + 2 > endp)
84 return FT_Err_Invalid_Table;
86 n->lang_tag_count = NEXT_USHORT(q);
88 startp += 2 + 4 * n->lang_tag_count;
90 else
91 n->lang_tag_count = 0;
93 if (startp > endp)
94 return FT_Err_Invalid_Table;
96 *start = startp;
97 *end = endp;
98 *curp = p;
100 return TA_Err_Ok;
104 static FT_Error
105 parse_name_records(FT_Byte** curp,
106 Naming_Table* n,
107 FT_Byte* buf,
108 FT_Byte* startp,
109 FT_Byte* endp,
110 FONT* font)
112 FT_UShort i, count;
113 FT_Byte* p;
116 p = *curp;
118 if (!n->name_count)
119 return TA_Err_Ok;
121 /* allocate name records array */
122 n->name_records = (Name_Record*)calloc(1, n->name_count
123 * sizeof (Name_Record));
124 if (!n->name_records)
125 return FT_Err_Out_Of_Memory;
127 /* walk over all name records */
128 count = 0;
129 for (i = 0; i < n->name_count; i++)
131 Name_Record* r = &n->name_records[count];
133 FT_UShort offset;
134 FT_Byte* s;
135 FT_UShort l;
138 r->platform_id = NEXT_USHORT(p);
139 r->encoding_id = NEXT_USHORT(p);
140 r->language_id = NEXT_USHORT(p);
141 r->name_id = NEXT_USHORT(p);
143 r->len = NEXT_USHORT(p);
145 offset = NEXT_USHORT(p);
147 s = buf + n->string_offset + offset;
149 /* ignore invalid entries */
150 if (s < startp || s + r->len > endp)
151 continue;
153 /* mac encoding or non-Unicode Windows encoding? */
154 if (r->platform_id == 1
155 || (r->platform_id == 3 && !(r->encoding_id == 1
156 || r->encoding_id == 10)))
158 /* one-byte or multi-byte encodings */
160 /* skip everything after a NULL byte (if any) */
161 for (l = 0; l < r->len; l++)
162 if (!s[l])
163 break;
165 /* ignore zero-length entries */
166 if (!l)
167 continue;
169 r->len = l;
171 else
173 /* (two-byte) UTF-16BE for everything else */
175 /* we need an even number of bytes */
176 r->len &= ~1U;
178 /* ignore entries which contain only NULL bytes */
179 for (l = 0; l < r->len; l++)
180 if (s[l])
181 break;
182 if (l == r->len)
183 continue;
186 r->str = (FT_Byte*)malloc(r->len);
187 if (!r->str)
188 return FT_Err_Out_Of_Memory;
189 memcpy(r->str, s, r->len);
191 if (font->info)
193 /* we ignore the return value of `font->info' */
194 font->info(r->platform_id,
195 r->encoding_id,
196 r->language_id,
197 r->name_id,
198 &r->len,
199 &r->str,
200 font->info_data);
203 count++;
206 /* let the user modify `name' table entries */
207 if (font->info && font->info_post)
208 /* we ignore the return value of `font->info_post' */
209 font->info_post(font->info_data);
211 /* shrink name record array if necessary */
212 n->name_records = (Name_Record*)realloc(n->name_records,
213 count * sizeof (Name_Record));
214 n->name_count = count;
216 return TA_Err_Ok;
220 static FT_Error
221 parse_lang_tag_records(FT_Byte** curp,
222 Naming_Table* n,
223 FT_Byte* buf,
224 FT_Byte* startp,
225 FT_Byte* endp)
227 FT_UShort i;
228 FT_Byte* p;
231 p = *curp;
233 if (!n->lang_tag_count)
234 return TA_Err_Ok;
236 /* allocate language tags array */
237 n->lang_tag_records = (Lang_Tag_Record*)calloc(
238 1, n->lang_tag_count * sizeof (Lang_Tag_Record));
239 if (!n->lang_tag_records)
240 return FT_Err_Out_Of_Memory;
242 /* walk over all language tag records (if any) */
243 for (i = 0; i < n->lang_tag_count; i++)
245 Lang_Tag_Record* r = &n->lang_tag_records[i];
247 FT_UShort offset;
248 FT_Byte* s;
251 r->len = NEXT_USHORT(p);
253 offset = NEXT_USHORT(p);
255 s = buf + n->string_offset + offset;
257 /* ignore an invalid entry -- */
258 /* contrary to name records, we can't simply remove it */
259 /* because references to it should still work */
260 /* (we don't apply more fixes */
261 /* since ttfautohint is not a TrueType sanitizing tool) */
262 if (s < startp || s + r->len > endp)
263 continue;
265 /* we don't massage the data since we only make a copy */
266 r->str = (FT_Byte*)malloc(r->len);
267 if (!r->str)
268 return FT_Err_Out_Of_Memory;
270 memcpy(r->str, s, r->len);
273 return TA_Err_Ok;
277 /* we build a non-optimized `name' table, this is, */
278 /* we don't fold strings `foo' and `foobar' into one string */
280 static FT_Error
281 build_name_table(Naming_Table* n,
282 SFNT_Table* name_table)
284 FT_Byte* buf_new;
285 FT_Byte* buf_new_resized;
286 FT_ULong buf_new_len;
287 FT_ULong len;
289 FT_Byte* p;
290 FT_Byte* q;
291 FT_Byte* base;
293 FT_UShort i;
294 FT_UShort string_offset;
295 FT_ULong data_offset;
296 FT_ULong data_len;
299 /* we reallocate the array to its real size later on */
300 buf_new_len= 6 + 12 * n->name_count;
301 if (n->format == 1)
302 buf_new_len += 2 + 4 * n->lang_tag_count;
304 buf_new = (FT_Byte*)malloc(buf_new_len);
305 if (!buf_new)
306 return FT_Err_Out_Of_Memory;
308 /* note that the OpenType specification says that `string_offset' is the */
309 /* `offset to the start of string storage (from start of table)', */
310 /* but this isn't enforced by the major rendering engines */
311 /* as long as the final string offsets are valid */
312 string_offset = (buf_new_len <= 0xFFFF) ? buf_new_len : 0xFFFF;
314 p = buf_new;
316 *(p++) = HIGH(n->format);
317 *(p++) = LOW(n->format);
318 *(p++) = HIGH(n->name_count);
319 *(p++) = LOW(n->name_count);
320 *(p++) = HIGH(string_offset);
321 *(p++) = LOW(string_offset);
323 /* first pass */
325 data_len = 0;
326 for (i = 0; i < n->name_count; i++)
328 Name_Record* r = &n->name_records[i];
331 *(p++) = HIGH(r->platform_id);
332 *(p++) = LOW(r->platform_id);
333 *(p++) = HIGH(r->encoding_id);
334 *(p++) = LOW(r->encoding_id);
335 *(p++) = HIGH(r->language_id);
336 *(p++) = LOW(r->language_id);
337 *(p++) = HIGH(r->name_id);
338 *(p++) = LOW(r->name_id);
340 *(p++) = HIGH(r->len);
341 *(p++) = LOW(r->len);
343 /* the offset field gets filled in later */
344 p += 2;
346 data_len += r->len;
349 if (n->format == 1)
351 *(p++) = HIGH(n->lang_tag_count);
352 *(p++) = LOW(n->lang_tag_count);
354 for (i = 0; i < n->lang_tag_count; i++)
356 Lang_Tag_Record* r = &n->lang_tag_records[i];
359 *(p++) = HIGH(r->len);
360 *(p++) = LOW(r->len);
362 /* the offset field gets filled in later */
363 p += 2;
365 data_len += r->len;
369 if (buf_new_len + data_len > 2 * 0xFFFF)
371 /* the table would become too large, so we do nothing */
372 free(buf_new);
373 return TA_Err_Ok;
376 data_offset = buf_new_len;
378 /* reallocate the buffer to fit its real size */
379 buf_new_len += data_len;
380 /* make the allocated buffer length a multiple of 4 */
381 len = (buf_new_len + 3) & ~3U;
383 buf_new_resized = (FT_Byte*)realloc(buf_new, len);
384 if (!buf_new_resized)
386 free(buf_new);
387 return FT_Err_Out_Of_Memory;
389 buf_new = buf_new_resized;
391 base = buf_new + string_offset;
392 p = buf_new + data_offset;
394 /* second pass */
396 /* the first name record offset */
397 q = &buf_new[6 + 10];
398 for (i = 0; i < n->name_count; i++)
400 Name_Record* r = &n->name_records[i];
403 /* fill in offset */
404 *q = HIGH(p - base);
405 *(q + 1) = LOW(p - base);
407 /* copy string */
408 memcpy(p, r->str, r->len);
410 p += r->len;
411 q += 12;
414 if (n->format == 1)
416 /* the first language tag record offset */
417 q = &buf_new[6 + 12 * n->name_count + 2 + 2];
418 for (i = 0; i < n->lang_tag_count; i++)
420 Lang_Tag_Record* r = &n->lang_tag_records[i];
423 /* fill in offset */
424 *q = HIGH(p - base);
425 *(q + 1) = LOW(p - base);
427 /* copy string */
428 memcpy(p, r->str, r->len);
430 p += r->len;
431 q += 4;
435 /* pad end of buffer with zeros */
436 switch (buf_new_len % 4)
438 case 1:
439 *(p++) = 0x00;
440 case 2:
441 *(p++) = 0x00;
442 case 3:
443 *(p++) = 0x00;
444 default:
445 break;
448 /* we are done; replace the old buffer with the new one */
449 free(name_table->buf);
451 name_table->buf = buf_new;
452 name_table->len = buf_new_len;
454 return TA_Err_Ok;
458 /* we handle the `name' table as optional; */
459 /* if there are problems not related to allocation, */
460 /* simply return (or continue, if possible) without signaling an error, */
461 /* and the original `name' table is not modified */
463 FT_Error
464 TA_sfnt_update_name_table(SFNT* sfnt,
465 FONT* font)
467 FT_Error error;
469 SFNT_Table* name_table;
470 FT_Byte* buf;
471 FT_ULong buf_len;
473 Naming_Table n;
475 FT_Byte* p;
476 FT_Byte* startp;
477 FT_Byte* endp;
479 FT_UShort i;
482 if (sfnt->name_idx == MISSING)
483 return TA_Err_Ok;
485 name_table = &font->tables[sfnt->name_idx];
486 buf = name_table->buf;
487 buf_len = name_table->len;
489 if (name_table->processed)
490 return TA_Err_Ok;
492 p = buf;
494 error = parse_name_header(&p, &n, buf_len, &startp, &endp);
495 if (error)
496 return TA_Err_Ok;
498 /* due to the structure of the `name' table, */
499 /* we must parse it completely, apply our changes, */
500 /* and rebuild it from scratch */
501 error = parse_name_records(&p, &n, buf, startp, endp, font);
502 if (error)
503 goto Exit;
505 error = parse_lang_tag_records(&p, &n, buf, startp, endp);
506 if (error)
507 goto Exit;
509 error = build_name_table(&n, name_table);
510 if (error)
511 goto Exit;
513 name_table->checksum = TA_table_compute_checksum(name_table->buf,
514 name_table->len);
516 Exit:
517 for (i = 0; i < n.name_count; i++)
518 free(n.name_records[i].str);
519 for (i = 0; i < n.lang_tag_count; i++)
520 free(n.lang_tag_records[i].str);
522 free(n.name_records);
523 free(n.lang_tag_records);
525 name_table->processed = 1;
527 return error;
530 /* end of taname.c */