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