1 // Copyright 2014 PDFium Authors. All rights reserved.
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 namespace {
12
13 struct SingleCmap {
14 uint16_t code;
15 uint16_t cid;
16 };
17
18 struct RangeCmap {
19 uint16_t low;
20 uint16_t high;
21 uint16_t cid;
22 };
23
FindNextCMap(const FXCMAP_CMap * pMap)24 const FXCMAP_CMap* FindNextCMap(const FXCMAP_CMap* pMap) {
25 return pMap->m_UseOffset ? pMap + pMap->m_UseOffset : nullptr;
26 }
27
28 } // namespace
29
FindEmbeddedCMap(pdfium::span<const FXCMAP_CMap> pCMaps,ByteStringView bsName)30 const FXCMAP_CMap* FindEmbeddedCMap(pdfium::span<const FXCMAP_CMap> pCMaps,
31 ByteStringView bsName) {
32 for (size_t i = 0; i < pCMaps.size(); i++) {
33 if (bsName == pCMaps[i].m_Name)
34 return &pCMaps[i];
35 }
36 return nullptr;
37 }
38
CIDFromCharCode(const FXCMAP_CMap * pMap,uint32_t charcode)39 uint16_t CIDFromCharCode(const FXCMAP_CMap* pMap, uint32_t charcode) {
40 ASSERT(pMap);
41 const uint16_t loword = static_cast<uint16_t>(charcode);
42 if (charcode >> 16) {
43 while (pMap) {
44 if (pMap->m_pDWordMap) {
45 const FXCMAP_DWordCIDMap* begin = pMap->m_pDWordMap;
46 const auto* end = begin + pMap->m_DWordCount;
47 const auto* found = std::lower_bound(
48 begin, end, charcode,
49 [](const FXCMAP_DWordCIDMap& element, uint32_t charcode) {
50 uint16_t hiword = static_cast<uint16_t>(charcode >> 16);
51 if (element.m_HiWord != hiword)
52 return element.m_HiWord < hiword;
53 return element.m_LoWordHigh < static_cast<uint16_t>(charcode);
54 });
55 if (found != end && loword >= found->m_LoWordLow &&
56 loword <= found->m_LoWordHigh) {
57 return found->m_CID + loword - found->m_LoWordLow;
58 }
59 }
60 pMap = FindNextCMap(pMap);
61 }
62 return 0;
63 }
64
65 while (pMap && pMap->m_pWordMap) {
66 switch (pMap->m_WordMapType) {
67 case FXCMAP_CMap::Single: {
68 const auto* begin =
69 reinterpret_cast<const SingleCmap*>(pMap->m_pWordMap);
70 const auto* end = begin + pMap->m_WordCount;
71 const auto* found = std::lower_bound(
72 begin, end, loword, [](const SingleCmap& element, uint16_t code) {
73 return element.code < code;
74 });
75 if (found != end && found->code == loword)
76 return found->cid;
77 break;
78 }
79 case FXCMAP_CMap::Range: {
80 const auto* begin =
81 reinterpret_cast<const RangeCmap*>(pMap->m_pWordMap);
82 const auto* end = begin + pMap->m_WordCount;
83 const auto* found = std::lower_bound(
84 begin, end, loword, [](const RangeCmap& element, uint16_t code) {
85 return element.high < code;
86 });
87 if (found != end && loword >= found->low && loword <= found->high)
88 return found->cid + loword - found->low;
89 break;
90 }
91 default: {
92 NOTREACHED();
93 break;
94 }
95 }
96 pMap = FindNextCMap(pMap);
97 }
98
99 return 0;
100 }
101
CharCodeFromCID(const FXCMAP_CMap * pMap,uint16_t cid)102 uint32_t CharCodeFromCID(const FXCMAP_CMap* pMap, uint16_t cid) {
103 // TODO(dsinclair): This should be checking both pMap->m_WordMap and
104 // pMap->m_DWordMap. There was a second while() but it was never reached as
105 // the first always returns. Investigate and determine how this should
106 // really be working. (https://codereview.chromium.org/2235743003 removed the
107 // second while loop.)
108 ASSERT(pMap);
109 while (pMap) {
110 switch (pMap->m_WordMapType) {
111 case FXCMAP_CMap::Single: {
112 const auto* pCur =
113 reinterpret_cast<const SingleCmap*>(pMap->m_pWordMap);
114 const auto* pEnd = pCur + pMap->m_WordCount;
115 while (pCur < pEnd) {
116 if (pCur->cid == cid)
117 return pCur->code;
118 ++pCur;
119 }
120 break;
121 }
122 case FXCMAP_CMap::Range: {
123 const auto* pCur = reinterpret_cast<const RangeCmap*>(pMap->m_pWordMap);
124 const auto* pEnd = pCur + pMap->m_WordCount;
125 while (pCur < pEnd) {
126 if (cid >= pCur->cid && cid <= pCur->cid + pCur->high - pCur->low)
127 return pCur->low + cid - pCur->cid;
128 ++pCur;
129 }
130 break;
131 }
132 default: {
133 NOTREACHED();
134 break;
135 }
136 }
137 pMap = FindNextCMap(pMap);
138 }
139 return 0;
140 }
141