1 /*
2 * Copyright © 2019 Google, Inc.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
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.
11 *
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
16 * DAMAGE.
17 *
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.
23 *
24 * Google Author(s): Garret Rieger
25 */
26
27 #include "options.hh"
28
29 #include "hb-subset-input.hh"
30
31 static gboolean
parse_nameids(const char * name,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)32 parse_nameids (const char *name,
33 const char *arg,
34 gpointer data,
35 GError **error G_GNUC_UNUSED)
36 {
37 subset_options_t *subset_opts = (subset_options_t *) data;
38 hb_set_t *name_ids = subset_opts->input->name_ids;
39
40 char last_name_char = name[strlen (name) - 1];
41
42 if (last_name_char != '+' && last_name_char != '-')
43 hb_set_clear (name_ids);
44
45 if (0 == strcmp (arg, "*"))
46 {
47 if (last_name_char == '-')
48 hb_set_del_range (name_ids, 0, 0x7FFF);
49 else
50 hb_set_add_range (name_ids, 0, 0x7FFF);
51 return true;
52 }
53
54 char *s = (char *) arg;
55 char *p;
56
57 while (s && *s)
58 {
59 while (*s && strchr (", ", *s))
60 s++;
61 if (!*s)
62 break;
63
64 errno = 0;
65 hb_codepoint_t u = strtoul (s, &p, 10);
66 if (errno || s == p)
67 {
68 hb_set_destroy (name_ids);
69 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
70 "Failed parsing nameID values at: '%s'", s);
71 return false;
72 }
73
74 if (last_name_char != '-')
75 {
76 hb_set_add (name_ids, u);
77 } else {
78 hb_set_del (name_ids, u);
79 }
80
81 s = p;
82 }
83
84 return true;
85 }
86
87 static gboolean
parse_drop_tables(const char * name,const char * arg,gpointer data,GError ** error G_GNUC_UNUSED)88 parse_drop_tables (const char *name,
89 const char *arg,
90 gpointer data,
91 GError **error G_GNUC_UNUSED)
92 {
93 subset_options_t *subset_opts = (subset_options_t *) data;
94 hb_set_t *drop_tables = subset_opts->input->drop_tables;
95
96 char last_name_char = name[strlen (name) - 1];
97
98 if (last_name_char != '+' && last_name_char != '-')
99 hb_set_clear (drop_tables);
100
101 char *s = strtok((char *) arg, ", ");
102 while (s)
103 {
104 if (strlen (s) > 4) // Table tags are at most 4 bytes.
105 {
106 g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE,
107 "Failed parsing table tag values at: '%s'", s);
108 return false;
109 }
110
111 hb_tag_t tag = hb_tag_from_string (s, strlen (s));
112
113 if (last_name_char != '-')
114 hb_set_add (drop_tables, tag);
115 else
116 hb_set_del (drop_tables, tag);
117
118 s = strtok(nullptr, ", ");
119 }
120
121 return true;
122 }
123
124 void
add_options(option_parser_t * parser)125 subset_options_t::add_options (option_parser_t *parser)
126 {
127 GOptionEntry entries[] =
128 {
129 {"no-hinting", 0, 0, G_OPTION_ARG_NONE, &this->input->drop_hints, "Whether to drop hints", nullptr},
130 {"retain-gids", 0, 0, G_OPTION_ARG_NONE, &this->input->retain_gids, "If set don't renumber glyph ids in the subset.", nullptr},
131 {"desubroutinize", 0, 0, G_OPTION_ARG_NONE, &this->input->desubroutinize, "Remove CFF/CFF2 use of subroutines", nullptr},
132 {"name-IDs", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_nameids, "Subset specified nameids", "list of int numbers"},
133 {"drop-tables", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."},
134 {"drop-tables+", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."},
135 {"drop-tables-", 0, 0, G_OPTION_ARG_CALLBACK, (gpointer) &parse_drop_tables, "Drop the specified tables.", "list of string table tags."},
136
137 {nullptr}
138 };
139 parser->add_group (entries,
140 "subset",
141 "Subset options:",
142 "Options subsetting",
143 this);
144 }
145