Add missing file to `make dist'.
[ttfautohint.git] / lib / taname.c
blobd089431f2ef64ba5b7e6ff381234946329f86b92
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 = *(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 /* we ignore the return value of `font->info' */
204 font->info(r->platform_id,
205 r->encoding_id,
206 r->language_id,
207 r->name_id,
208 &r->len,
209 &r->str,
210 font->info_data);
213 count++;
216 /* let the user modify `name' table entries */
217 if (font->info && font->info_post)
218 /* we ignore the return value of `font->info_post' */
219 font->info_post(font->info_data);
221 /* shrink name record array if necessary */
222 n->name_records = (Name_Record*)realloc(n->name_records,
223 count * sizeof (Name_Record));
224 n->name_count = count;
226 return TA_Err_Ok;
230 FT_Error
231 parse_lang_tag_records(FT_Byte** curp,
232 Naming_Table* n,
233 FT_Byte* buf,
234 FT_Byte* startp,
235 FT_Byte* endp)
237 FT_UShort i;
238 FT_Byte* p;
241 p = *curp;
243 if (!n->lang_tag_count)
244 return TA_Err_Ok;
246 /* allocate language tags array */
247 n->lang_tag_records = (Lang_Tag_Record*)calloc(
248 1, n->lang_tag_count * sizeof (Lang_Tag_Record));
249 if (!n->lang_tag_records)
250 return FT_Err_Out_Of_Memory;
252 /* walk over all language tag records (if any) */
253 for (i = 0; i < n->lang_tag_count; i++)
255 Lang_Tag_Record* r = &n->lang_tag_records[i];
257 FT_UShort offset;
258 FT_Byte* s;
261 r->len = *(p++) << 8;
262 r->len += *(p++);
264 offset = *(p++) << 8;
265 offset += *(p++);
267 s = buf + n->string_offset + offset;
269 /* ignore an invalid entry -- */
270 /* contrary to name records, we can't simply remove it */
271 /* because references to it should still work */
272 /* (we don't apply more fixes */
273 /* since ttfautohint is not a TrueType sanitizing tool) */
274 if (s < startp || s + r->len > endp)
275 continue;
277 /* we don't massage the data since we only make a copy */
278 r->str = (FT_Byte*)malloc(r->len);
279 if (!r->str)
280 return FT_Err_Out_Of_Memory;
282 memcpy(r->str, s, r->len);
285 return TA_Err_Ok;
289 /* we build a non-optimized `name' table, this is, */
290 /* we don't fold strings `foo' and `foobar' into one string */
292 static FT_Error
293 build_name_table(Naming_Table* n,
294 SFNT_Table* name_table)
296 FT_Byte* buf_new;
297 FT_Byte* buf_new_resized;
298 FT_ULong buf_new_len;
299 FT_ULong len;
301 FT_Byte* p;
302 FT_Byte* q;
303 FT_Byte* base;
305 FT_UShort i;
306 FT_UShort string_offset;
307 FT_ULong data_offset;
308 FT_ULong data_len;
311 /* we reallocate the array to its real size later on */
312 buf_new_len= 6 + 12 * n->name_count;
313 if (n->format == 1)
314 buf_new_len += 2 + 4 * n->lang_tag_count;
316 buf_new = (FT_Byte*)malloc(buf_new_len);
317 if (!buf_new)
318 return FT_Err_Out_Of_Memory;
320 /* note that the OpenType specification says that `string_offset' is the */
321 /* `offset to the start of string storage (from start of table)', */
322 /* but this isn't enforced by the major rendering engines */
323 /* as long as the final string offsets are valid */
324 string_offset = (buf_new_len <= 0xFFFF) ? buf_new_len : 0xFFFF;
326 p = buf_new;
328 *(p++) = HIGH(n->format);
329 *(p++) = LOW(n->format);
330 *(p++) = HIGH(n->name_count);
331 *(p++) = LOW(n->name_count);
332 *(p++) = HIGH(string_offset);
333 *(p++) = LOW(string_offset);
335 /* first pass */
337 data_len = 0;
338 for (i = 0; i < n->name_count; i++)
340 Name_Record* r = &n->name_records[i];
343 *(p++) = HIGH(r->platform_id);
344 *(p++) = LOW(r->platform_id);
345 *(p++) = HIGH(r->encoding_id);
346 *(p++) = LOW(r->encoding_id);
347 *(p++) = HIGH(r->language_id);
348 *(p++) = LOW(r->language_id);
349 *(p++) = HIGH(r->name_id);
350 *(p++) = LOW(r->name_id);
352 *(p++) = HIGH(r->len);
353 *(p++) = LOW(r->len);
355 /* the offset field gets filled in later */
356 p += 2;
358 data_len += r->len;
361 if (n->format == 1)
363 *(p++) = HIGH(n->lang_tag_count);
364 *(p++) = LOW(n->lang_tag_count);
366 for (i = 0; i < n->lang_tag_count; i++)
368 Lang_Tag_Record* r = &n->lang_tag_records[i];
371 *(p++) = HIGH(r->len);
372 *(p++) = LOW(r->len);
374 /* the offset field gets filled in later */
375 p += 2;
377 data_len += r->len;
381 if (buf_new_len + data_len > 2 * 0xFFFF)
383 /* the table would become too large, so we do nothing */
384 free(buf_new);
385 return TA_Err_Ok;
388 data_offset = buf_new_len;
390 /* reallocate the buffer to fit its real size */
391 buf_new_len += data_len;
392 /* make the allocated buffer length a multiple of 4 */
393 len = (buf_new_len + 3) & ~3;
395 buf_new_resized = (FT_Byte*)realloc(buf_new, len);
396 if (!buf_new_resized)
398 free(buf_new);
399 return FT_Err_Out_Of_Memory;
401 buf_new = buf_new_resized;
403 base = buf_new + string_offset;
404 p = buf_new + data_offset;
406 /* second pass */
408 /* the first name record offset */
409 q = &buf_new[6 + 10];
410 for (i = 0; i < n->name_count; i++)
412 Name_Record* r = &n->name_records[i];
415 /* fill in offset */
416 *q = HIGH(p - base);
417 *(q + 1) = LOW(p - base);
419 /* copy string */
420 memcpy(p, r->str, r->len);
422 p += r->len;
423 q += 12;
426 if (n->format == 1)
428 /* the first language tag record offset */
429 q = &buf_new[6 + 12 * n->name_count + 2 + 2];
430 for (i = 0; i < n->lang_tag_count; i++)
432 Lang_Tag_Record* r = &n->lang_tag_records[i];
435 /* fill in offset */
436 *q = HIGH(p - base);
437 *(q + 1) = LOW(p - base);
439 /* copy string */
440 memcpy(p, r->str, r->len);
442 p += r->len;
443 q += 4;
447 /* pad end of buffer with zeros */
448 switch (buf_new_len % 4)
450 case 1:
451 *(p++) = 0x00;
452 case 2:
453 *(p++) = 0x00;
454 case 3:
455 *(p++) = 0x00;
456 default:
457 break;
460 /* we are done; replace the old buffer with the new one */
461 free(name_table->buf);
463 name_table->buf = buf_new;
464 name_table->len = buf_new_len;
466 return TA_Err_Ok;
470 /* we handle the `name' table as optional; */
471 /* if there are problems not related to allocation, */
472 /* simply return (or continue, if possible) without signaling an error, */
473 /* and the original `name' table is not modified */
475 FT_Error
476 TA_sfnt_update_name_table(SFNT* sfnt,
477 FONT* font)
479 FT_Error error;
481 SFNT_Table* name_table;
482 FT_Byte* buf;
483 FT_ULong buf_len;
485 Naming_Table n;
487 FT_Byte* p;
488 FT_Byte* startp;
489 FT_Byte* endp;
491 FT_UShort i;
494 if (sfnt->name_idx == MISSING)
495 return TA_Err_Ok;
497 name_table = &font->tables[sfnt->name_idx];
498 buf = name_table->buf;
499 buf_len = name_table->len;
501 if (name_table->processed)
502 return TA_Err_Ok;
504 p = buf;
506 error = parse_name_header(&p, &n, buf_len, &startp, &endp);
507 if (error)
508 return TA_Err_Ok;
510 /* due to the structure of the `name' table, */
511 /* we must parse it completely, apply our changes, */
512 /* and rebuild it from scratch */
513 error = parse_name_records(&p, &n, buf, startp, endp, font);
514 if (error)
515 goto Exit;
517 error = parse_lang_tag_records(&p, &n, buf, startp, endp);
518 if (error)
519 goto Exit;
521 error = build_name_table(&n, name_table);
522 if (error)
523 goto Exit;
525 name_table->checksum = TA_table_compute_checksum(name_table->buf,
526 name_table->len);
528 Exit:
529 for (i = 0; i < n.name_count; i++)
530 free(n.name_records[i].str);
531 for (i = 0; i < n.lang_tag_count; i++)
532 free(n.lang_tag_records[i].str);
534 free(n.name_records);
535 free(n.lang_tag_records);
537 name_table->processed = 1;
539 return error;
542 /* end of taname.c */