• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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