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/cmap_int.h"
8
9 #include <algorithm>
10
11 #include "core/fpdfapi/cpdf_modulemgr.h"
12 #include "core/fpdfapi/font/cpdf_fontglobals.h"
13 #include "core/fpdfapi/page/cpdf_pagemodule.h"
14
15 namespace {
16
FindNextCMap(const FXCMAP_CMap * pMap)17 const FXCMAP_CMap* FindNextCMap(const FXCMAP_CMap* pMap) {
18 return pMap->m_UseOffset ? pMap + pMap->m_UseOffset : nullptr;
19 }
20
21 } // namespace
22
FPDFAPI_FindEmbeddedCMap(const ByteString & bsName,int charset,int coding)23 const FXCMAP_CMap* FPDFAPI_FindEmbeddedCMap(const ByteString& bsName,
24 int charset,
25 int coding) {
26 CPDF_FontGlobals* pFontGlobals =
27 CPDF_ModuleMgr::Get()->GetPageModule()->GetFontGlobals();
28
29 const FXCMAP_CMap* pCMaps;
30 uint32_t count;
31 std::tie(count, pCMaps) = pFontGlobals->GetEmbeddedCharset(charset);
32 for (uint32_t i = 0; i < count; i++) {
33 if (bsName == pCMaps[i].m_Name)
34 return &pCMaps[i];
35 }
36 return nullptr;
37 }
38
FPDFAPI_CIDFromCharCode(const FXCMAP_CMap * pMap,uint32_t charcode)39 uint16_t FPDFAPI_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) {
66 if (!pMap->m_pWordMap)
67 return 0;
68 if (pMap->m_WordMapType == FXCMAP_CMap::Single) {
69 struct SingleCmap {
70 uint16_t code;
71 uint16_t cid;
72 };
73 const auto* begin = reinterpret_cast<const SingleCmap*>(pMap->m_pWordMap);
74 const auto* end = begin + pMap->m_WordCount;
75 const auto* found = std::lower_bound(
76 begin, end, loword, [](const SingleCmap& element, uint16_t code) {
77 return element.code < code;
78 });
79 if (found != end && found->code == loword)
80 return found->cid;
81 } else {
82 ASSERT(pMap->m_WordMapType == FXCMAP_CMap::Range);
83 struct RangeCmap {
84 uint16_t low;
85 uint16_t high;
86 uint16_t cid;
87 };
88 const auto* begin = reinterpret_cast<const RangeCmap*>(pMap->m_pWordMap);
89 const auto* end = begin + pMap->m_WordCount;
90 const auto* found = std::lower_bound(
91 begin, end, loword, [](const RangeCmap& element, uint16_t code) {
92 return element.high < code;
93 });
94 if (found != end && loword >= found->low && loword <= found->high)
95 return found->cid + loword - found->low;
96 }
97 pMap = FindNextCMap(pMap);
98 }
99 return 0;
100 }
101
FPDFAPI_CharCodeFromCID(const FXCMAP_CMap * pMap,uint16_t cid)102 uint32_t FPDFAPI_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 if (pMap->m_WordMapType == FXCMAP_CMap::Single) {
111 const uint16_t* pCur = pMap->m_pWordMap;
112 const uint16_t* pEnd = pMap->m_pWordMap + pMap->m_WordCount * 2;
113 while (pCur < pEnd) {
114 if (pCur[1] == cid)
115 return pCur[0];
116
117 pCur += 2;
118 }
119 } else {
120 ASSERT(pMap->m_WordMapType == FXCMAP_CMap::Range);
121 const uint16_t* pCur = pMap->m_pWordMap;
122 const uint16_t* pEnd = pMap->m_pWordMap + pMap->m_WordCount * 3;
123 while (pCur < pEnd) {
124 if (cid >= pCur[2] && cid <= pCur[2] + pCur[1] - pCur[0])
125 return pCur[0] + cid - pCur[2];
126
127 pCur += 3;
128 }
129 }
130 pMap = FindNextCMap(pMap);
131 }
132 return 0;
133 }
134