Line | Count | Source |
1 | | // Copyright (c) 2009-2017 The OTS Authors. All rights reserved. |
2 | | // Use of this source code is governed by a BSD-style license that can be |
3 | | // found in the LICENSE file. |
4 | | |
5 | | #include "post.h" |
6 | | |
7 | | #include "maxp.h" |
8 | | |
9 | | // post - PostScript |
10 | | // http://www.microsoft.com/typography/otspec/post.htm |
11 | | |
12 | | namespace ots { |
13 | | |
14 | 89.8k | bool OpenTypePOST::Parse(const uint8_t *data, size_t length) { |
15 | 89.8k | Buffer table(data, length); |
16 | | |
17 | 89.8k | if (!table.ReadU32(&this->version)) { |
18 | 70 | return Error("Failed to read table version"); |
19 | 70 | } |
20 | | |
21 | 89.7k | if (this->version != 0x00010000 && |
22 | 10.3k | this->version != 0x00020000 && |
23 | 5.68k | this->version != 0x00030000) { |
24 | | // 0x00025000 is deprecated. We don't accept it. |
25 | 454 | return Error("Unsupported table version 0x%x", this->version); |
26 | 454 | } |
27 | | |
28 | 89.2k | if (!table.ReadU32(&this->italic_angle) || |
29 | 89.0k | !table.ReadS16(&this->underline) || |
30 | 89.0k | !table.ReadS16(&this->underline_thickness) || |
31 | 88.9k | !table.ReadU32(&this->is_fixed_pitch) || |
32 | | // We don't care about the memory usage fields. We'll set all these to |
33 | | // zero when serialising |
34 | 88.9k | !table.Skip(16)) { |
35 | 401 | return Error("Failed to read table header"); |
36 | 401 | } |
37 | | |
38 | 88.8k | if (this->underline_thickness < 0) { |
39 | 10.3k | this->underline_thickness = 1; |
40 | 10.3k | } |
41 | | |
42 | 88.8k | if (this->version == 0x00010000 || this->version == 0x00030000) { |
43 | 84.2k | return true; |
44 | 84.2k | } |
45 | | |
46 | | // We have a version 2 table with a list of Pascal strings at the end |
47 | | |
48 | 4.67k | uint16_t num_glyphs = 0; |
49 | 4.67k | if (!table.ReadU16(&num_glyphs)) { |
50 | 44 | return Error("Failed to read numberOfGlyphs"); |
51 | 44 | } |
52 | | |
53 | 4.62k | OpenTypeMAXP* maxp = static_cast<OpenTypeMAXP*> |
54 | 4.62k | (GetFont()->GetTable(OTS_TAG_MAXP)); |
55 | 4.62k | if (!maxp) { |
56 | 0 | return Error("Missing required maxp table"); |
57 | 0 | } |
58 | | |
59 | 4.62k | if (num_glyphs == 0) { |
60 | 2.61k | if (maxp->num_glyphs > 258) { |
61 | 1 | return Error("Can't have no glyphs in the post table if there are more " |
62 | 1 | "than 258 glyphs in the font"); |
63 | 1 | } |
64 | | // workaround for fonts in http://www.fontsquirrel.com/fontface |
65 | | // (e.g., yataghan.ttf). |
66 | 2.61k | this->version = 0x00010000; |
67 | 2.61k | return Warning("Table version is 1, but no glyph names are found"); |
68 | 2.61k | } |
69 | | |
70 | 2.01k | if (num_glyphs != maxp->num_glyphs) { |
71 | | // Note: Fixedsys500c.ttf seems to have inconsistent num_glyphs values. |
72 | 61 | return Error("Bad number of glyphs: %d", num_glyphs); |
73 | 61 | } |
74 | | |
75 | 1.94k | this->glyph_name_index.resize(num_glyphs); |
76 | 208k | for (unsigned i = 0; i < num_glyphs; ++i) { |
77 | 206k | if (!table.ReadU16(&this->glyph_name_index[i])) { |
78 | 38 | return Error("Failed to read glyph name %d", i); |
79 | 38 | } |
80 | | // Note: A strict interpretation of the specification requires name indexes |
81 | | // are less than 32768. This, however, excludes fonts like unifont.ttf |
82 | | // which cover all of unicode. |
83 | 206k | } |
84 | | |
85 | | // Now we have an array of Pascal strings. We have to check that they are all |
86 | | // valid and read them in. |
87 | 1.91k | const size_t strings_offset = table.offset(); |
88 | 1.91k | const uint8_t *strings = data + strings_offset; |
89 | 1.91k | const uint8_t *strings_end = data + length; |
90 | | |
91 | 216k | for (;;) { |
92 | 216k | if (strings == strings_end) break; |
93 | 214k | const unsigned string_length = *strings; |
94 | 214k | if (strings + 1 + string_length > strings_end) { |
95 | 38 | return Error("Bad string length %d", string_length); |
96 | 38 | } |
97 | 214k | if (std::memchr(strings + 1, '\0', string_length)) { |
98 | 60 | return Error("Bad string of length %d", string_length); |
99 | 60 | } |
100 | 214k | this->names.push_back( |
101 | 214k | std::string(reinterpret_cast<const char*>(strings + 1), string_length)); |
102 | 214k | strings += 1 + string_length; |
103 | 214k | } |
104 | 1.81k | const unsigned num_strings = this->names.size(); |
105 | | |
106 | | // check that all the references are within bounds |
107 | 207k | for (unsigned i = 0; i < num_glyphs; ++i) { |
108 | 205k | unsigned offset = this->glyph_name_index[i]; |
109 | 205k | if (offset < 258) { |
110 | 40.5k | continue; |
111 | 40.5k | } |
112 | | |
113 | 165k | offset -= 258; |
114 | 165k | if (offset >= num_strings) { |
115 | 43 | return Error("Bad string index %d", offset); |
116 | 43 | } |
117 | 165k | } |
118 | | |
119 | 1.77k | return true; |
120 | 1.81k | } |
121 | | |
122 | 46.6k | bool OpenTypePOST::Serialize(OTSStream *out) { |
123 | | // OpenType with CFF glyphs must have v3 post table. |
124 | 46.6k | if (GetFont()->GetTable(OTS_TAG_CFF) && this->version != 0x00030000) { |
125 | 4 | Warning("Only version supported for fonts with CFF table is 0x00030000" |
126 | 4 | " not 0x%x", this->version); |
127 | 4 | this->version = 0x00030000; |
128 | 4 | } |
129 | | |
130 | 46.6k | if (!out->WriteU32(this->version) || |
131 | 46.6k | !out->WriteU32(this->italic_angle) || |
132 | 46.6k | !out->WriteS16(this->underline) || |
133 | 46.6k | !out->WriteS16(this->underline_thickness) || |
134 | 46.6k | !out->WriteU32(this->is_fixed_pitch) || |
135 | 46.6k | !out->WriteU32(0) || |
136 | 46.6k | !out->WriteU32(0) || |
137 | 46.6k | !out->WriteU32(0) || |
138 | 46.6k | !out->WriteU32(0)) { |
139 | 8 | return Error("Failed to write post header"); |
140 | 8 | } |
141 | | |
142 | 46.6k | if (this->version != 0x00020000) { |
143 | 46.3k | return true; // v1.0 and v3.0 does not have glyph names. |
144 | 46.3k | } |
145 | | |
146 | 321 | const uint16_t num_indexes = |
147 | 321 | static_cast<uint16_t>(this->glyph_name_index.size()); |
148 | 321 | if (num_indexes != this->glyph_name_index.size() || |
149 | 321 | !out->WriteU16(num_indexes)) { |
150 | 0 | return Error("Failed to write number of indices"); |
151 | 0 | } |
152 | | |
153 | 87.7k | for (uint16_t i = 0; i < num_indexes; ++i) { |
154 | 87.4k | if (!out->WriteU16(this->glyph_name_index[i])) { |
155 | 0 | return Error("Failed to write name index %d", i); |
156 | 0 | } |
157 | 87.4k | } |
158 | | |
159 | | // Now we just have to write out the strings in the correct order |
160 | 113k | for (unsigned i = 0; i < this->names.size(); ++i) { |
161 | 112k | const std::string& s = this->names[i]; |
162 | 112k | const uint8_t string_length = static_cast<uint8_t>(s.size()); |
163 | 112k | if (string_length != s.size() || |
164 | 112k | !out->Write(&string_length, 1)) { |
165 | 0 | return Error("Failed to write string %d", i); |
166 | 0 | } |
167 | | // Some ttf fonts (e.g., frank.ttf on Windows Vista) have zero-length name. |
168 | | // We allow them. |
169 | 112k | if (string_length > 0 && !out->Write(s.data(), string_length)) { |
170 | 0 | return Error("Failed to write string length for string %d", i); |
171 | 0 | } |
172 | 112k | } |
173 | | |
174 | 321 | return true; |
175 | 321 | } |
176 | | |
177 | | } // namespace ots |