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