2 * Copyright © 2019 Google, Inc.
4 * This is part of HarfBuzz, a text shaping library.
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 * Google Author(s): Garret Rieger
29 #include "hb-subset-input.hh"
32 parse_gids (const char *name G_GNUC_UNUSED,
35 GError **error G_GNUC_UNUSED)
37 subset_options_t *subset_opts = (subset_options_t *) data;
38 hb_set_t *gids = subset_opts->input->glyphs;
40 char *s = (char *) arg;
45 while (*s && strchr (", ", *s))
51 hb_codepoint_t start_code = strtoul (s, &p, 10);
52 if (s[0] == '-' || errno || s == p)
54 hb_set_destroy (gids);
55 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
56 "Failed parsing gids values at: '%s'", s);
60 if (p && p[0] == '-') //gid ranges
63 hb_codepoint_t end_code = strtoul (s, &p, 10);
64 if (s[0] == '-' || errno || s == p)
66 hb_set_destroy (gids);
67 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
68 "Failed parsing gids values at: '%s'", s);
72 if (end_code < start_code)
74 hb_set_destroy (gids);
75 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
76 "Invalid gids range value %u-%u", start_code, end_code);
79 hb_set_add_range (gids, start_code, end_code);
83 hb_set_add (gids, start_code);
92 parse_nameids (const char *name,
95 GError **error G_GNUC_UNUSED)
97 subset_options_t *subset_opts = (subset_options_t *) data;
98 hb_set_t *name_ids = subset_opts->input->name_ids;
100 char last_name_char = name[strlen (name) - 1];
102 if (last_name_char != '+' && last_name_char != '-')
103 hb_set_clear (name_ids);
105 if (0 == strcmp (arg, "*"))
107 if (last_name_char == '-')
108 hb_set_del_range (name_ids, 0, 0x7FFF);
110 hb_set_add_range (name_ids, 0, 0x7FFF);
114 char *s = (char *) arg;
119 while (*s && strchr (", ", *s))
125 hb_codepoint_t u = strtoul (s, &p, 10);
128 hb_set_destroy (name_ids);
129 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
130 "Failed parsing nameID values at: '%s'", s);
134 if (last_name_char != '-')
136 hb_set_add (name_ids, u);
138 hb_set_del (name_ids, u);
148 parse_name_languages (const char *name,
151 GError **error G_GNUC_UNUSED)
153 subset_options_t *subset_opts = (subset_options_t *) data;
154 hb_set_t *name_languages = subset_opts->input->name_languages;
156 char last_name_char = name[strlen (name) - 1];
158 if (last_name_char != '+' && last_name_char != '-')
159 hb_set_clear (name_languages);
161 if (0 == strcmp (arg, "*"))
163 if (last_name_char == '-')
164 hb_set_del_range (name_languages, 0, 0x5FFF);
166 hb_set_add_range (name_languages, 0, 0x5FFF);
170 char *s = (char *) arg;
175 while (*s && strchr (", ", *s))
181 hb_codepoint_t u = strtoul (s, &p, 10);
184 hb_set_destroy (name_languages);
185 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
186 "Failed parsing name_languages values at: '%s'", s);
190 if (last_name_char != '-')
192 hb_set_add (name_languages, u);
194 hb_set_del (name_languages, u);
204 parse_drop_tables (const char *name,
207 GError **error G_GNUC_UNUSED)
209 subset_options_t *subset_opts = (subset_options_t *) data;
210 hb_set_t *drop_tables = subset_opts->input->drop_tables;
212 char last_name_char = name[strlen (name) - 1];
214 if (last_name_char != '+' && last_name_char != '-')
215 hb_set_clear (drop_tables);
217 char *s = strtok((char *) arg, ", ");
220 if (strlen (s) > 4) // Table tags are at most 4 bytes.
222 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
223 "Failed parsing table tag values at: '%s'", s);
227 hb_tag_t tag = hb_tag_from_string (s, strlen (s));
229 if (last_name_char != '-')
230 hb_set_add (drop_tables, tag);
232 hb_set_del (drop_tables, tag);
234 s = strtok(nullptr, ", ");
241 subset_options_t::add_options (option_parser_t *parser)
243 GOptionEntry entries[] =
245 {"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->input->drop_hints, "Whether to drop hints", nullptr},
246 {"retain-gids", 0, 0, G_OPTION_ARG_NONE, &this->input->retain_gids, "If set don't renumber glyph ids in the subset.", nullptr},
247 {"gids", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_gids, "Specify glyph IDs or ranges to include in the subset", "list of comma/whitespace-separated int numbers or ranges"},
248 {"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->input->desubroutinize, "Remove CFF/CFF2 use of subroutines", nullptr},
249 {"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers"},
250 {"name-legacy", 0, 0, G_OPTION_ARG_NONE, &this->input->name_legacy, "Keep legacy (non-Unicode) 'name' table entries", nullptr},
251 {"name-languages", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_name_languages, "Subset nameRecords with specified language IDs", "list of int numbers"},
252 {"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."},
253 {"drop-tables+", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."},
254 {"drop-tables-", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."},
258 parser->add_group (entries,
261 "Options subsetting",