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 #define LOG_TAG "Minikin"
20
21 #include <hb-ot.h>
22 #include <hb.h>
23
24 #include <cstdint>
25 #include <optional>
26 #include <string>
27 #include <vector>
28
29 #include "MinikinInternal.h"
30 #include "minikin/Constants.h"
31
32 namespace minikin {
33
34 namespace {
35
36 class SafeFontBufferReader {
37 public:
SafeFontBufferReader(const void * buffer,size_t size)38 SafeFontBufferReader(const void* buffer, size_t size)
39 : mBuffer(reinterpret_cast<const uint8_t*>(buffer)),
40 mSize(size),
41 mPos(0),
42 mError(false) {}
43
44 template <typename T>
readBE()45 T readBE() {
46 if (mError) return T();
47
48 if ((mSize - mPos) < sizeof(T)) {
49 mError = true;
50 return T();
51 }
52 const T* data = reinterpret_cast<const T*>(mBuffer + mPos);
53 mPos += sizeof(T);
54 return *data;
55 }
56
readU16()57 uint16_t readU16() {
58 if (mError) return 0;
59
60 if ((mSize - mPos) < 2) {
61 mError = true;
62 return 0;
63 }
64 uint16_t out = ((uint32_t)mBuffer[mPos]) << 8 | ((uint32_t)mBuffer[mPos + 1]);
65 mPos += 2;
66 return out;
67 };
68
readU32()69 uint32_t readU32() {
70 if (mError) return 0;
71
72 if ((mSize - mPos) < 4) {
73 mError = true;
74 return 0;
75 }
76
77 uint32_t out = ((uint32_t)mBuffer[mPos]) << 24 | ((uint32_t)mBuffer[mPos + 1]) << 16 |
78 ((uint32_t)mBuffer[mPos + 2]) << 8 | ((uint32_t)mBuffer[mPos + 3]);
79 mPos += 4;
80 return out;
81 };
82
seek(size_t pos)83 void seek(size_t pos) {
84 if (mError) return;
85
86 if (pos > mSize) {
87 mError = true;
88 } else {
89 mPos = pos;
90 }
91 }
92
remaining() const93 size_t remaining() const {
94 if (mError) return 0;
95 return mSize - mPos;
96 }
97
error() const98 bool error() const { return mError; }
99
100 private:
101 const uint8_t* mBuffer;
102 size_t mSize;
103 size_t mPos;
104 bool mError;
105 };
106
isPostScriptNameAllowedChar(char c)107 bool isPostScriptNameAllowedChar(char c) {
108 // OpenType spec says only ASCII codes 33 to 126, ecept for the '[', ']', '(', ')', '{', '}',
109 // '<', '>', '/', '%'.
110 if (!(33 <= c && c <= 126)) {
111 return false;
112 }
113 if (c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '<' ||
114 c == '>' || c == '/' || c == '%') {
115 return false;
116 }
117
118 return true;
119 }
120
121 } // namespace
122
123 // static
analyzeFontRevision(const uint8_t * head_data,size_t head_size,uint32_t * out)124 bool FontFileParser::analyzeFontRevision(const uint8_t* head_data, size_t head_size,
125 uint32_t* out) {
126 SafeFontBufferReader reader(head_data, head_size);
127
128 if (reader.remaining() < 8) {
129 return false; // At least head table has 8 bytes, for version and fontRevision
130 }
131
132 uint32_t majorVersion = reader.readU16();
133 if (reader.error()) return false;
134 uint32_t minorVersion = reader.readU16();
135 if (reader.error()) return false;
136
137 // Invalid head table header.
138 if (majorVersion != 1 && minorVersion != 0) return false;
139
140 *out = reader.readU32();
141 if (reader.error()) return false;
142 return true;
143 }
144
145 // static
checkPSName(const std::string & psName)146 bool FontFileParser::checkPSName(const std::string& psName) {
147 if (psName.size() > 63) return false;
148
149 for (auto c : psName) {
150 if (!isPostScriptNameAllowedChar(c)) {
151 return false;
152 }
153 }
154 return true;
155 }
156
FontFileParser(const void * buffer,size_t size,uint32_t index)157 FontFileParser::FontFileParser(const void* buffer, size_t size, uint32_t index)
158 : mFace(makeHbFace(buffer, size, index)) {}
159
FontFileParser(const HbFaceUniquePtr & face)160 FontFileParser::FontFileParser(const HbFaceUniquePtr& face)
161 : mFace(hb_face_reference(face.get())) {}
162
FontFileParser(const HbFontUniquePtr & font)163 FontFileParser::FontFileParser(const HbFontUniquePtr& font)
164 : mFace(hb_face_reference(hb_font_get_face(font.get()))) {}
165
~FontFileParser()166 FontFileParser::~FontFileParser() {}
167
168 // static
makeHbFace(const void * buffer,size_t size,uint32_t index)169 HbFaceUniquePtr FontFileParser::makeHbFace(const void* buffer, size_t size, uint32_t index) {
170 HbBlobUniquePtr blob(hb_blob_create(reinterpret_cast<const char*>(buffer), size,
171 HB_MEMORY_MODE_READONLY, nullptr, nullptr));
172 return HbFaceUniquePtr(hb_face_create(blob.get(), index));
173 }
174
getFontRevision() const175 std::optional<uint32_t> FontFileParser::getFontRevision() const {
176 if (!mFace) return std::optional<uint32_t>();
177
178 HbBlob headTable(mFace, MakeTag('h', 'e', 'a', 'd'));
179 if (!headTable) return std::optional<uint32_t>();
180
181 uint32_t out = 0;
182 if (!analyzeFontRevision(headTable.get(), headTable.size(), &out)) {
183 return std::optional<uint32_t>();
184 }
185
186 return out;
187 }
188
getPostScriptName() const189 std::optional<std::string> FontFileParser::getPostScriptName() const {
190 if (!mFace) return std::optional<std::string>();
191
192 unsigned int size = 64; // PostScript name is up to 63 characters.
193 char buf[64] = {};
194
195 uint32_t result = hb_ot_name_get_utf8(mFace.get(), HB_OT_NAME_ID_POSTSCRIPT_NAME,
196 HB_LANGUAGE_INVALID, &size, buf);
197
198 if (result == 0) { // not found.
199 return std::optional<std::string>();
200 }
201
202 std::string out(buf, size);
203
204 if (!checkPSName(out)) { // Contains invalid characters.
205 return std::optional<std::string>();
206 }
207
208 return out;
209 }
210
isPostScriptType1Font() const211 std::optional<bool> FontFileParser::isPostScriptType1Font() const {
212 if (!mFace) return std::optional<bool>();
213
214 HbBlob cffTable(mFace, MakeTag('C', 'F', 'F', ' '));
215 HbBlob cff2Table(mFace, MakeTag('C', 'F', 'F', '2'));
216 return cffTable || cff2Table;
217 }
218
219 } // namespace minikin
220