xref: /aosp_15_r20/external/pdfium/core/fpdfapi/cmaps/fpdf_cmaps.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fpdfapi/cmaps/fpdf_cmaps.h"
8 
9 #include <algorithm>
10 
11 #include "third_party/base/check.h"
12 
13 namespace fxcmap {
14 
15 namespace {
16 
17 struct SingleCmap {
18   uint16_t code;
19   uint16_t cid;
20 };
21 
22 struct RangeCmap {
23   uint16_t low;
24   uint16_t high;
25   uint16_t cid;
26 };
27 
FindNextCMap(const CMap * pMap)28 const CMap* FindNextCMap(const CMap* pMap) {
29   return pMap->m_UseOffset ? pMap + pMap->m_UseOffset : nullptr;
30 }
31 
32 }  // namespace
33 
CIDFromCharCode(const CMap * pMap,uint32_t charcode)34 uint16_t CIDFromCharCode(const CMap* pMap, uint32_t charcode) {
35   DCHECK(pMap);
36   const uint16_t loword = static_cast<uint16_t>(charcode);
37   if (charcode >> 16) {
38     while (pMap) {
39       if (pMap->m_pDWordMap) {
40         const DWordCIDMap* begin = pMap->m_pDWordMap;
41         const auto* end = begin + pMap->m_DWordCount;
42         const auto* found = std::lower_bound(
43             begin, end, charcode,
44             [](const DWordCIDMap& element, uint32_t charcode) {
45               uint16_t hiword = static_cast<uint16_t>(charcode >> 16);
46               if (element.m_HiWord != hiword)
47                 return element.m_HiWord < hiword;
48               return element.m_LoWordHigh < static_cast<uint16_t>(charcode);
49             });
50         if (found != end && loword >= found->m_LoWordLow &&
51             loword <= found->m_LoWordHigh) {
52           return found->m_CID + loword - found->m_LoWordLow;
53         }
54       }
55       pMap = FindNextCMap(pMap);
56     }
57     return 0;
58   }
59 
60   while (pMap && pMap->m_pWordMap) {
61     switch (pMap->m_WordMapType) {
62       case CMap::Type::kSingle: {
63         const auto* begin =
64             reinterpret_cast<const SingleCmap*>(pMap->m_pWordMap);
65         const auto* end = begin + pMap->m_WordCount;
66         const auto* found = std::lower_bound(
67             begin, end, loword, [](const SingleCmap& element, uint16_t code) {
68               return element.code < code;
69             });
70         if (found != end && found->code == loword)
71           return found->cid;
72         break;
73       }
74       case CMap::Type::kRange: {
75         const auto* begin =
76             reinterpret_cast<const RangeCmap*>(pMap->m_pWordMap);
77         const auto* end = begin + pMap->m_WordCount;
78         const auto* found = std::lower_bound(
79             begin, end, loword, [](const RangeCmap& element, uint16_t code) {
80               return element.high < code;
81             });
82         if (found != end && loword >= found->low && loword <= found->high)
83           return found->cid + loword - found->low;
84         break;
85       }
86     }
87     pMap = FindNextCMap(pMap);
88   }
89 
90   return 0;
91 }
92 
CharCodeFromCID(const CMap * pMap,uint16_t cid)93 uint32_t CharCodeFromCID(const CMap* pMap, uint16_t cid) {
94   // TODO(dsinclair): This should be checking both pMap->m_WordMap and
95   // pMap->m_DWordMap. There was a second while() but it was never reached as
96   // the first always returns. Investigate and determine how this should
97   // really be working. (https://codereview.chromium.org/2235743003 removed the
98   // second while loop.)
99   DCHECK(pMap);
100   while (pMap) {
101     switch (pMap->m_WordMapType) {
102       case CMap::Type::kSingle: {
103         const auto* pCur =
104             reinterpret_cast<const SingleCmap*>(pMap->m_pWordMap);
105         const auto* pEnd = pCur + pMap->m_WordCount;
106         while (pCur < pEnd) {
107           if (pCur->cid == cid)
108             return pCur->code;
109           ++pCur;
110         }
111         break;
112       }
113       case CMap::Type::kRange: {
114         const auto* pCur = reinterpret_cast<const RangeCmap*>(pMap->m_pWordMap);
115         const auto* pEnd = pCur + pMap->m_WordCount;
116         while (pCur < pEnd) {
117           if (cid >= pCur->cid && cid <= pCur->cid + pCur->high - pCur->low)
118             return pCur->low + cid - pCur->cid;
119           ++pCur;
120         }
121         break;
122       }
123     }
124     pMap = FindNextCMap(pMap);
125   }
126   return 0;
127 }
128 
129 }  // namespace fxcmap
130