Minor.
[ttfautohint.git] / frontend / info.cpp
blob325598186cd29b6da4fc7a8f3d9cb934d2010779
1 // info.cpp
3 // Copyright (C) 2012-2014 by Werner Lemberg.
4 //
5 // This file is part of the ttfautohint library, and may only be used,
6 // modified, and distributed under the terms given in `COPYING'. By
7 // continuing to use, modify, or distribute this file you indicate that you
8 // have read `COPYING' and understand and accept it fully.
9 //
10 // The file `COPYING' mentioned in the previous paragraph is distributed
11 // with the ttfautohint library.
14 #include <config.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 // the next header file is from gnulib defining function `base_name',
19 // which is a replacement for `basename' that works on Windows also
20 #include "dirname.h"
22 #include "info.h"
23 #include <sds.h>
24 #include <numberset.h>
27 #define TTFAUTOHINT_STRING "; ttfautohint"
28 #define TTFAUTOHINT_STRING_WIDE "\0;\0 \0t\0t\0f\0a\0u\0t\0o\0h\0i\0n\0t"
31 extern "C" {
33 // build string that gets appended to the `Version' field(s)
34 // return value 1 means allocation error, value 2 too long a string
35 int
36 build_version_string(Info_Data* idata)
38 // since we use `goto' we have to initialize variables before the jumps
39 unsigned char* info_string;
40 unsigned char* info_string_wide;
41 unsigned char* dt;
42 unsigned char* dtw;
43 char* s = NULL;
44 char strong[4];
45 int count;
46 int ret = 0;
47 sds d;
49 d = sdsempty();
51 d = sdscatprintf(d, TTFAUTOHINT_STRING " (v%s)", VERSION);
52 if (!idata->detailed)
53 goto Skip;
55 if (idata->dehint)
57 d = sdscat(d, " -d");
58 goto Skip;
60 d = sdscatprintf(d, " -l %d", idata->hinting_range_min);
61 d = sdscatprintf(d, " -r %d", idata->hinting_range_max);
62 d = sdscatprintf(d, " -G %d", idata->hinting_limit);
63 d = sdscatprintf(d, " -x %d", idata->increase_x_height);
64 if (idata->fallback_stem_width)
65 d = sdscatprintf(d, " -H %d", idata->fallback_stem_width);
66 d = sdscatprintf(d, " -D %s", idata->default_script);
67 d = sdscatprintf(d, " -f %s", idata->fallback_script);
68 if (idata->control_name)
70 char* bn = base_name(idata->control_name);
71 d = sdscatprintf(d, " -m \"%s\"", bn ? bn : idata->control_name);
72 free(bn);
75 count = 0;
76 strong[0] = '\0';
77 strong[1] = '\0';
78 strong[2] = '\0';
79 strong[3] = '\0';
80 if (idata->gray_strong_stem_width)
81 strong[count++] = 'g';
82 if (idata->gdi_cleartype_strong_stem_width)
83 strong[count++] = 'G';
84 if (idata->dw_cleartype_strong_stem_width)
85 strong[count++] = 'D';
86 if (*strong)
87 d = sdscatprintf(d, " -w %s", strong);
88 else
89 d = sdscat(d, " -w \"\"");
91 if (idata->windows_compatibility)
92 d = sdscat(d, " -W");
93 if (idata->adjust_subglyphs)
94 d = sdscat(d, " -p");
95 if (idata->hint_composites)
96 d = sdscat(d, " -c");
97 if (idata->symbol)
98 d = sdscat(d, " -s");
99 if (idata->TTFA_info)
100 d = sdscat(d, " -t");
102 if (idata->x_height_snapping_exceptions_string)
104 // only set specific value of `ret' for an allocation error,
105 // since syntax errors are handled in TTF_autohint
106 number_range* x_height_snapping_exceptions;
107 const char* pos = number_set_parse(
108 idata->x_height_snapping_exceptions_string,
109 &x_height_snapping_exceptions,
110 6, 0x7FFF);
111 if (*pos)
113 if (x_height_snapping_exceptions == NUMBERSET_ALLOCATION_ERROR)
114 ret = 1;
115 goto Fail;
118 s = number_set_show(x_height_snapping_exceptions, 6, 0x7FFF);
119 number_set_free(x_height_snapping_exceptions);
121 // ensure UTF16-BE version doesn't get too long
122 if (strlen(s) > 0xFFFF / 2 - sdslen(d))
124 ret = 2;
125 goto Fail;
128 d = sdscatprintf(d, " -X \"%s\"", s);
131 Skip:
132 if (!d)
134 ret = 1;
135 goto Fail;
138 info_string = (unsigned char*)malloc(sdslen(d) + 1);
139 if (!info_string)
141 ret = 1;
142 goto Fail;
144 memcpy(info_string, d, sdslen(d) + 1);
146 idata->info_string = info_string;
147 idata->info_string_len = (unsigned short)sdslen(d);
149 // prepare UTF16-BE version data
150 idata->info_string_wide_len = 2 * idata->info_string_len;
151 info_string_wide = (unsigned char*)realloc(idata->info_string_wide,
152 idata->info_string_wide_len);
153 if (!info_string_wide)
155 ret = 1;
156 goto Fail;
158 idata->info_string_wide = info_string_wide;
160 dt = idata->info_string;
161 dtw = idata->info_string_wide;
162 for (unsigned short i = 0; i < idata->info_string_len; i++)
164 *(dtw++) = '\0';
165 *(dtw++) = *(dt++);
168 Exit:
169 free(s);
170 sdsfree(d);
172 return ret;
174 Fail:
175 free(idata->info_string);
176 free(idata->info_string_wide);
178 idata->info_string = NULL;
179 idata->info_string_wide = NULL;
180 idata->info_string_len = 0;
181 idata->info_string_wide_len = 0;
183 goto Exit;
187 static int
188 info_name_id_5(unsigned short platform_id,
189 unsigned short encoding_id,
190 unsigned short* len,
191 unsigned char** str,
192 Info_Data* idata)
194 unsigned char ttfautohint_string[] = TTFAUTOHINT_STRING;
195 unsigned char ttfautohint_string_wide[] = TTFAUTOHINT_STRING_WIDE;
197 // we use memmem, so don't count the trailing \0 character
198 size_t ttfautohint_string_len = sizeof (TTFAUTOHINT_STRING) - 1;
199 size_t ttfautohint_string_wide_len = sizeof (TTFAUTOHINT_STRING_WIDE) - 1;
201 unsigned char* v;
202 unsigned short v_len;
203 unsigned char* s;
204 size_t s_len;
205 size_t offset;
207 if (platform_id == 1
208 || (platform_id == 3 && !(encoding_id == 1
209 || encoding_id == 10)))
211 // one-byte or multi-byte encodings
212 v = idata->info_string;
213 v_len = idata->info_string_len;
214 s = ttfautohint_string;
215 s_len = ttfautohint_string_len;
216 offset = 2;
218 else
220 // (two-byte) UTF-16BE for everything else
221 v = idata->info_string_wide;
222 v_len = idata->info_string_wide_len;
223 s = ttfautohint_string_wide;
224 s_len = ttfautohint_string_wide_len;
225 offset = 4;
228 // if we already have an ttfautohint info string,
229 // remove it up to a following `;' character (or end of string)
230 unsigned char* s_start = (unsigned char*)memmem(*str, *len, s, s_len);
231 if (s_start)
233 unsigned char* s_end = s_start + offset;
234 unsigned char* limit = *str + *len;
236 while (s_end < limit)
238 if (*s_end == ';')
240 if (offset == 2)
241 break;
242 else
244 if (*(s_end - 1) == '\0') // UTF-16BE
246 s_end--;
247 break;
252 s_end++;
255 while (s_end < limit)
256 *s_start++ = *s_end++;
258 *len -= s_end - s_start;
261 // do nothing if the string would become too long
262 if (*len > 0xFFFF - v_len)
263 return 0;
265 unsigned short len_new = *len + v_len;
266 unsigned char* str_new = (unsigned char*)realloc(*str, len_new);
267 if (!str_new)
268 return 1;
270 *str = str_new;
271 memcpy(*str + *len, v, v_len);
272 *len = len_new;
274 return 0;
279 info(unsigned short platform_id,
280 unsigned short encoding_id,
281 unsigned short /* language_id */,
282 unsigned short name_id,
283 unsigned short* len,
284 unsigned char** str,
285 void* user)
287 Info_Data* idata = (Info_Data*)user;
289 // if it is a version string, append our data
290 if (name_id == 5)
291 return info_name_id_5(platform_id, encoding_id, len, str, idata);
293 return 0;
296 } // extern "C"
298 // end of info.cpp