frontend/info.cpp: Use sds.
[ttfautohint.git] / frontend / info.cpp
blob9a2f6776b1366deb6f4c2c1297f2964d6ccbb537
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>
19 #include "info.h"
20 #include <sds.h>
21 #include <numberset.h>
24 #define TTFAUTOHINT_STRING "; ttfautohint"
25 #define TTFAUTOHINT_STRING_WIDE "\0;\0 \0t\0t\0f\0a\0u\0t\0o\0h\0i\0n\0t"
27 // build string that gets appended to the `Version' field(s)
29 extern "C" {
31 // return value 1 means allocation error, value 2 too long a string
33 int
34 build_version_string(Info_Data* idata)
36 // since we use `goto' we have to initialize variables before the jumps
37 unsigned char* data;
38 unsigned char* data_wide;
39 unsigned char* dt;
40 unsigned char* dtw;
41 char* s = NULL;
42 char strong[4];
43 int count;
44 int ret = 0;
45 sds d;
47 d = sdsempty();
49 d = sdscatprintf(d, TTFAUTOHINT_STRING " (v%s)", VERSION);
50 if (idata->dehint)
52 d = sdscat(d, " -d");
53 goto Dehint_only;
55 d = sdscatprintf(d, " -l %d", idata->hinting_range_min);
56 d = sdscatprintf(d, " -r %d", idata->hinting_range_max);
57 d = sdscatprintf(d, " -G %d", idata->hinting_limit);
58 d = sdscatprintf(d, " -x %d", idata->increase_x_height);
59 if (idata->fallback_stem_width)
60 d = sdscatprintf(d, " -H %d", idata->fallback_stem_width);
61 d = sdscatprintf(d, " -D %s", idata->default_script);
62 d = sdscatprintf(d, " -f %s", idata->fallback_script);
64 count = 0;
65 strong[0] = '\0';
66 strong[1] = '\0';
67 strong[2] = '\0';
68 strong[3] = '\0';
69 if (idata->gray_strong_stem_width)
70 strong[count++] = 'g';
71 if (idata->gdi_cleartype_strong_stem_width)
72 strong[count++] = 'G';
73 if (idata->dw_cleartype_strong_stem_width)
74 strong[count++] = 'D';
75 if (*strong)
76 d = sdscatprintf(d, " -w %s", strong);
77 else
78 d = sdscat(d, " -w \"\"");
80 if (idata->windows_compatibility)
81 d = sdscat(d, " -W");
82 if (idata->adjust_subglyphs)
83 d = sdscat(d, " -p");
84 if (idata->hint_composites)
85 d = sdscat(d, " -c");
86 if (idata->symbol)
87 d = sdscat(d, " -s");
89 if (idata->x_height_snapping_exceptions_string)
91 // only set specific value of `ret' for an allocation error,
92 // since syntax errors are handled in TTF_autohint
93 number_range* x_height_snapping_exceptions;
94 const char* pos = number_set_parse(
95 idata->x_height_snapping_exceptions_string,
96 &x_height_snapping_exceptions,
97 6, 0x7FFF);
98 if (*pos)
100 if (x_height_snapping_exceptions == NUMBERSET_ALLOCATION_ERROR)
101 ret = 1;
102 goto Fail;
105 s = number_set_show(x_height_snapping_exceptions, 6, 0x7FFF);
106 number_set_free(x_height_snapping_exceptions);
108 // ensure UTF16-BE version doesn't get too long
109 if (strlen(s) > 0xFFFF / 2 - sdslen(d))
111 ret = 2;
112 goto Fail;
115 d = sdscatprintf(d, " -X \"%s\"", s);
118 Dehint_only:
119 if (!d)
121 ret = 1;
122 goto Fail;
125 data = (unsigned char*)malloc(sdslen(d) + 1);
126 if (!data)
128 ret = 1;
129 goto Fail;
131 memcpy(data, d, sdslen(d) + 1);
133 idata->data = data;
134 idata->data_len = (unsigned short)sdslen(d);
136 // prepare UTF16-BE version data
137 idata->data_wide_len = 2 * idata->data_len;
138 data_wide = (unsigned char*)realloc(idata->data_wide,
139 idata->data_wide_len);
140 if (!data_wide)
142 ret = 1;
143 goto Fail;
145 idata->data_wide = data_wide;
147 dt = idata->data;
148 dtw = idata->data_wide;
149 for (unsigned short i = 0; i < idata->data_len; i++)
151 *(dtw++) = '\0';
152 *(dtw++) = *(dt++);
155 Exit:
156 free(s);
157 sdsfree(d);
159 return ret;
161 Fail:
162 free(idata->data);
163 free(idata->data_wide);
165 idata->data = NULL;
166 idata->data_wide = NULL;
167 idata->data_len = 0;
168 idata->data_wide_len = 0;
170 goto Exit;
175 info(unsigned short platform_id,
176 unsigned short encoding_id,
177 unsigned short /* language_id */,
178 unsigned short name_id,
179 unsigned short* len,
180 unsigned char** str,
181 void* user)
183 Info_Data* idata = (Info_Data*)user;
184 unsigned char ttfautohint_string[] = TTFAUTOHINT_STRING;
185 unsigned char ttfautohint_string_wide[] = TTFAUTOHINT_STRING_WIDE;
187 // we use memmem, so don't count the trailing \0 character
188 size_t ttfautohint_string_len = sizeof (TTFAUTOHINT_STRING) - 1;
189 size_t ttfautohint_string_wide_len = sizeof (TTFAUTOHINT_STRING_WIDE) - 1;
191 unsigned char* v;
192 unsigned short v_len;
193 unsigned char* s;
194 size_t s_len;
195 size_t offset;
197 // if it is a version string, append our data
198 if (name_id != 5)
199 return 0;
201 if (platform_id == 1
202 || (platform_id == 3 && !(encoding_id == 1
203 || encoding_id == 10)))
205 // one-byte or multi-byte encodings
206 v = idata->data;
207 v_len = idata->data_len;
208 s = ttfautohint_string;
209 s_len = ttfautohint_string_len;
210 offset = 2;
212 else
214 // (two-byte) UTF-16BE for everything else
215 v = idata->data_wide;
216 v_len = idata->data_wide_len;
217 s = ttfautohint_string_wide;
218 s_len = ttfautohint_string_wide_len;
219 offset = 4;
222 // if we already have an ttfautohint info string,
223 // remove it up to a following `;' character (or end of string)
224 unsigned char* s_start = (unsigned char*)memmem(*str, *len, s, s_len);
225 if (s_start)
227 unsigned char* s_end = s_start + offset;
228 unsigned char* limit = *str + *len;
230 while (s_end < limit)
232 if (*s_end == ';')
234 if (offset == 2)
235 break;
236 else
238 if (*(s_end - 1) == '\0') // UTF-16BE
240 s_end--;
241 break;
246 s_end++;
249 while (s_end < limit)
250 *s_start++ = *s_end++;
252 *len -= s_end - s_start;
255 // do nothing if the string would become too long
256 if (*len > 0xFFFF - v_len)
257 return 0;
259 unsigned short len_new = *len + v_len;
260 unsigned char* str_new = (unsigned char*)realloc(*str, len_new);
261 if (!str_new)
262 return 1;
264 *str = str_new;
265 memcpy(*str + *len, v, v_len);
266 *len = len_new;
268 return 0;
271 } // extern "C"
273 // end of info.cpp