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