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