1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "minikin/FontFileParser.h"
18
19 #include <hb-ot.h>
20 #include <hb.h>
21
22 #include <cstdint>
23 #include <optional>
24 #include <string>
25 #include <vector>
26
27 #include "MinikinInternal.h"
28 #include "minikin/Constants.h"
29
30 namespace minikin {
31
32 namespace {
33
34 class SafeFontBufferReader {
35 public:
SafeFontBufferReader(const void * buffer,size_t size)36 SafeFontBufferReader(const void* buffer, size_t size)
37 : mBuffer(reinterpret_cast<const uint8_t*>(buffer)),
38 mSize(size),
39 mPos(0),
40 mError(false) {}
41
42 template <typename T>
readBE()43 T readBE() {
44 if (mError) return T();
45
46 if ((mSize - mPos) < sizeof(T)) {
47 mError = true;
48 return T();
49 }
50 const T* data = reinterpret_cast<const T*>(mBuffer + mPos);
51 mPos += sizeof(T);
52 return *data;
53 }
54
readU16()55 uint16_t readU16() {
56 if (mError) return 0;
57
58 if ((mSize - mPos) < 2) {
59 mError = true;
60 return 0;
61 }
62 uint16_t out = ((uint32_t)mBuffer[mPos]) << 8 | ((uint32_t)mBuffer[mPos + 1]);
63 mPos += 2;
64 return out;
65 };
66
readU32()67 uint32_t readU32() {
68 if (mError) return 0;
69
70 if ((mSize - mPos) < 4) {
71 mError = true;
72 return 0;
73 }
74
75 uint32_t out = ((uint32_t)mBuffer[mPos]) << 24 | ((uint32_t)mBuffer[mPos + 1]) << 16 |
76 ((uint32_t)mBuffer[mPos + 2]) << 8 | ((uint32_t)mBuffer[mPos + 3]);
77 mPos += 4;
78 return out;
79 };
80
seek(size_t pos)81 void seek(size_t pos) {
82 if (mError) return;
83
84 if (pos > mSize) {
85 mError = true;
86 } else {
87 mPos = pos;
88 }
89 }
90
remaining() const91 size_t remaining() const {
92 if (mError) return 0;
93 return mSize - mPos;
94 }
95
error() const96 bool error() const { return mError; }
97
98 private:
99 const uint8_t* mBuffer;
100 size_t mSize;
101 size_t mPos;
102 bool mError;
103 };
104
isPostScriptNameAllowedChar(char c)105 bool isPostScriptNameAllowedChar(char c) {
106 // OpenType spec says only ASCII codes 33 to 126, ecept for the '[', ']', '(', ')', '{', '}',
107 // '<', '>', '/', '%'.
108 if (!(33 <= c && c <= 126)) {
109 return false;
110 }
111 if (c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '<' ||
112 c == '>' || c == '/' || c == '%') {
113 return false;
114 }
115
116 return true;
117 }
118
119 } // namespace
120
121 // static
analyzeFontRevision(const uint8_t * head_data,size_t head_size,uint32_t * out)122 bool FontFileParser::analyzeFontRevision(const uint8_t* head_data, size_t head_size,
123 uint32_t* out) {
124 SafeFontBufferReader reader(head_data, head_size);
125
126 if (reader.remaining() < 8) {
127 return false; // At least head table has 8 bytes, for version and fontRevision
128 }
129
130 uint32_t majorVersion = reader.readU16();
131 if (reader.error()) return false;
132 uint32_t minorVersion = reader.readU16();
133 if (reader.error()) return false;
134
135 // Invalid head table header.
136 if (majorVersion != 1 && minorVersion != 0) return false;
137
138 *out = reader.readU32();
139 if (reader.error()) return false;
140 return true;
141 }
142
143 // static
checkPSName(const std::string & psName)144 bool FontFileParser::checkPSName(const std::string& psName) {
145 if (psName.size() > 63) return false;
146
147 for (auto c : psName) {
148 if (!isPostScriptNameAllowedChar(c)) {
149 return false;
150 }
151 }
152 return true;
153 }
154
FontFileParser(const void * buffer,size_t size,uint32_t index)155 FontFileParser::FontFileParser(const void* buffer, size_t size, uint32_t index)
156 : mFace(makeHbFace(buffer, size, index)) {}
157
FontFileParser(const HbFaceUniquePtr & face)158 FontFileParser::FontFileParser(const HbFaceUniquePtr& face)
159 : mFace(hb_face_reference(face.get())) {}
160
FontFileParser(const HbFontUniquePtr & font)161 FontFileParser::FontFileParser(const HbFontUniquePtr& font)
162 : mFace(hb_face_reference(hb_font_get_face(font.get()))) {}
163
~FontFileParser()164 FontFileParser::~FontFileParser() {}
165
166 // static
makeHbFace(const void * buffer,size_t size,uint32_t index)167 HbFaceUniquePtr FontFileParser::makeHbFace(const void* buffer, size_t size, uint32_t index) {
168 HbBlobUniquePtr blob(hb_blob_create(reinterpret_cast<const char*>(buffer), size,
169 HB_MEMORY_MODE_READONLY, nullptr, nullptr));
170 return HbFaceUniquePtr(hb_face_create(blob.get(), index));
171 }
172
getFontRevision() const173 std::optional<uint32_t> FontFileParser::getFontRevision() const {
174 if (!mFace) return std::optional<uint32_t>();
175
176 HbBlob headTable(mFace, MakeTag('h', 'e', 'a', 'd'));
177 if (!headTable) return std::optional<uint32_t>();
178
179 uint32_t out = 0;
180 if (!analyzeFontRevision(headTable.get(), headTable.size(), &out)) {
181 return std::optional<uint32_t>();
182 }
183
184 return out;
185 }
186
getPostScriptName() const187 std::optional<std::string> FontFileParser::getPostScriptName() const {
188 if (!mFace) return std::optional<std::string>();
189
190 unsigned int size = 64; // PostScript name is up to 63 characters.
191 char buf[64] = {};
192
193 uint32_t result = hb_ot_name_get_utf8(mFace.get(), HB_OT_NAME_ID_POSTSCRIPT_NAME,
194 HB_LANGUAGE_INVALID, &size, buf);
195
196 if (result == 0) { // not found.
197 return std::optional<std::string>();
198 }
199
200 std::string out(buf, size);
201
202 if (!checkPSName(out)) { // Contains invalid characters.
203 return std::optional<std::string>();
204 }
205
206 return out;
207 }
208
isPostScriptType1Font() const209 std::optional<bool> FontFileParser::isPostScriptType1Font() const {
210 if (!mFace) return std::optional<bool>();
211
212 HbBlob cffTable(mFace, MakeTag('C', 'F', 'F', ' '));
213 HbBlob cff2Table(mFace, MakeTag('C', 'F', 'F', '2'));
214 return cffTable || cff2Table;
215 }
216
217 } // namespace minikin
218