1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "cmap_parser.h"
17
18 #include "texgine/utils/exlog.h"
19
20 #include "opentype_basic_type.h"
21
22 namespace OHOS {
23 namespace Rosen {
24 namespace TextEngine {
25 #define FORMAT4 4
26 #define FORMAT12 12
27 #define SEG_SIZE 2
28 #define SEG_OFFSET 3
29 #define OFFSET 1
30
31 struct CmapSubtable {
32 OpenTypeBasicType::Uint16 format;
33 };
34
35 namespace {
36 struct EncodingRecord {
37 OpenTypeBasicType::Uint16 platformID;
38 OpenTypeBasicType::Uint16 encodingID;
39 OpenTypeBasicType::Uint32 subtableOffset;
40
GetSubtableOHOS::Rosen::TextEngine::__anon29456ac20111::EncodingRecord41 const struct CmapSubtable *GetSubtable(const void *data) const
42 {
43 return reinterpret_cast<const struct CmapSubtable *>(
44 reinterpret_cast<const char *>(data) + subtableOffset.Get());
45 }
46 };
47
48 struct CmapTable {
49 OpenTypeBasicType::Uint16 version;
50 OpenTypeBasicType::Uint16 numTables;
51 struct EncodingRecord encodingRecords[];
52 };
53
54 struct CmapSubtableFormat4 {
55 struct CmapSubtable base;
56 OpenTypeBasicType::Uint16 length;
57 OpenTypeBasicType::Uint16 language;
58 OpenTypeBasicType::Uint16 segCountX2;
59 OpenTypeBasicType::Uint16 searchRange;
60 OpenTypeBasicType::Uint16 entrySelector;
61 OpenTypeBasicType::Uint16 rangeShift;
62 OpenTypeBasicType::Uint16 array[];
63
GetSegCountOHOS::Rosen::TextEngine::__anon29456ac20111::CmapSubtableFormat464 int16_t GetSegCount() const
65 {
66 return segCountX2.Get() / SEG_SIZE;
67 }
68
GetEndCodesOHOS::Rosen::TextEngine::__anon29456ac20111::CmapSubtableFormat469 const OpenTypeBasicType::Uint16 *GetEndCodes() const
70 {
71 return array;
72 }
73
GetStartCodesOHOS::Rosen::TextEngine::__anon29456ac20111::CmapSubtableFormat474 const OpenTypeBasicType::Uint16 *GetStartCodes() const
75 {
76 return array + GetSegCount() + OFFSET;
77 }
78
GetIdDeltasOHOS::Rosen::TextEngine::__anon29456ac20111::CmapSubtableFormat479 const OpenTypeBasicType::Int16 *GetIdDeltas() const
80 {
81 return reinterpret_cast<const OpenTypeBasicType::Int16 *>(array + GetSegCount() * SEG_SIZE + OFFSET);
82 }
83
GetIdRangeOffsetsOHOS::Rosen::TextEngine::__anon29456ac20111::CmapSubtableFormat484 const OpenTypeBasicType::Uint16 *GetIdRangeOffsets() const
85 {
86 return array + GetSegCount() * SEG_OFFSET + OFFSET;
87 }
88 };
89
90 struct SequentialMapGroup {
91 OpenTypeBasicType::Uint32 startCharCode;
92 OpenTypeBasicType::Uint32 endCharCode;
93 OpenTypeBasicType::Uint32 startGlyphId;
94 };
95
96 struct CmapSubtableFormat12 {
97 struct CmapSubtable base;
98 OpenTypeBasicType::Uint16 reserved;
99 OpenTypeBasicType::Uint32 length;
100 OpenTypeBasicType::Uint32 language;
101 OpenTypeBasicType::Uint32 numGroups;
102 struct SequentialMapGroup groups[];
103 };
104 } // namespace
105
Parse(const char * data,int32_t size)106 int CmapParser::Parse(const char *data, int32_t size)
107 {
108 int ret = 1;
109 if (data == nullptr) {
110 return ret;
111 }
112
113 const auto &cmap = *reinterpret_cast<const struct CmapTable *>(data);
114 for (auto i = 0; i < cmap.numTables.Get(); i++) {
115 const auto &record = cmap.encodingRecords[i];
116 const auto &subtable = *record.GetSubtable(data);
117 if (subtable.format.Get() == FORMAT4) {
118 auto offset = record.subtableOffset.Get();
119 if (ret = ParseFormat4(subtable, size - offset); ret) {
120 LOGSO_FUNC_LINE(WARN) << "ParseFormat4 failed with " << ret;
121 } else {
122 ret = 0;
123 }
124 }
125
126 if (subtable.format.Get() == FORMAT12) {
127 auto offset = record.subtableOffset.Get();
128 if (ret = ParseFormat12(subtable, size - offset); ret) {
129 LOGSO_FUNC_LINE(WARN) << "ParseFormat12 failed with " << ret;
130 } else {
131 ret = 0;
132 }
133 }
134 }
135 return ret;
136 }
137
GetGlyphId(int32_t codepoint) const138 int32_t CmapParser::GetGlyphId(int32_t codepoint) const
139 {
140 return ranges_.GetGlyphId(codepoint);
141 }
142
Dump() const143 void CmapParser::Dump() const
144 {
145 ranges_.Dump();
146 }
147
ParseFormat4(const CmapSubtable & subtable,const std::size_t size)148 int CmapParser::ParseFormat4(const CmapSubtable &subtable, const std::size_t size)
149 {
150 const auto &subtable4 = *reinterpret_cast<const struct CmapSubtableFormat4 *>(&subtable);
151 const auto &endCodes = subtable4.GetEndCodes();
152 const auto &startCodes = subtable4.GetStartCodes();
153 const auto &idDeltas = subtable4.GetIdDeltas();
154 const auto &idRangeOffsets = subtable4.GetIdRangeOffsets();
155
156 if (size < sizeof(CmapSubtableFormat4)) {
157 return 1;
158 }
159
160 if (size < sizeof(CmapSubtableFormat4) + sizeof(uint16_t) * (subtable4.GetSegCount() * FORMAT4 + 1)) {
161 return 1;
162 }
163
164 for (int16_t i = 0; i < subtable4.GetSegCount(); i++) {
165 uint32_t end = endCodes[i].Get();
166 uint32_t start = startCodes[i].Get();
167 if (end < start) {
168 return 1;
169 }
170
171 uint32_t idRangeOffset = idRangeOffsets[i].Get();
172 if (idRangeOffset == 0) {
173 int32_t delta = idDeltas[i].Get();
174 ParseFormat4NoOffset(delta, start, end);
175 } else {
176 for (uint32_t j = start; j <= end; j++) {
177 const auto &gid = idRangeOffsets[idRangeOffset / 2 + i + j - start].Get();
178 if (gid) {
179 ranges_.AddRange({j, j + 1, gid});
180 }
181 }
182 }
183 }
184 return 0;
185 }
186
ParseFormat4NoOffset(int32_t delta,uint32_t start,uint32_t end)187 void CmapParser::ParseFormat4NoOffset(int32_t delta, uint32_t start, uint32_t end)
188 {
189 if (((static_cast<uint32_t>(delta) + end) & 0xffff) > end - start) {
190 ranges_.AddRange({start, end + 1, delta});
191 } else {
192 for (uint32_t j = start; j <= end; j++) {
193 if ((j + static_cast<uint32_t>(delta)) & 0xffff) {
194 ranges_.AddRange({j, j + 1, delta});
195 }
196 }
197 }
198 }
199
ParseFormat12(const CmapSubtable & subtable,const std::size_t size)200 int CmapParser::ParseFormat12(const CmapSubtable &subtable, const std::size_t size)
201 {
202 const auto &subtable12 = *reinterpret_cast<const struct CmapSubtableFormat12 *>(&subtable);
203 const auto &length = subtable12.length.Get();
204
205 if (size < sizeof(CmapSubtableFormat12)) {
206 return 1;
207 }
208
209 if (size < length) {
210 return 1;
211 }
212
213 for (uint32_t i = 0; i < subtable12.numGroups.Get(); i++) {
214 const auto &[scc, ecc, sgi] = subtable12.groups[i];
215 int32_t delta = static_cast<int32_t>(scc.Get());
216 delta -= static_cast<int32_t>(sgi.Get());
217 ranges_.AddRange({scc.Get(), ecc.Get() + 1, delta});
218 }
219 return 0;
220 }
221 } // namespace TextEngine
222 } // namespace Rosen
223 } // namespace OHOS
224