Dict.cc 5.22 KB
Newer Older
Kristian Høgsberg's avatar
Kristian Høgsberg committed
1 2 3 4 5 6 7 8
//========================================================================
//
// Dict.cc
//
// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================

9 10 11 12
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
13 14 15
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
16 17 18
// Copyright (C) 2005 Kristian Høgsberg <krh@redhat.com>
// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
// Copyright (C) 2007-2008 Julien Rebetez <julienr@svn.gnome.org>
19
// Copyright (C) 2008, 2010, 2013, 2014, 2017 Albert Astals Cid <aacid@kde.org>
20
// Copyright (C) 2010 Paweł Wiejacha <pawel.wiejacha@gmail.com>
21
// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
22
// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
23
// Copyright (C) 2014 Scott West <scott.gregory.west@gmail.com>
24
// Copyright (C) 2017 Adrian Johnson <ajohnson@redneon.com>
25
// Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de>
26 27 28 29 30 31
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================

Kristian Høgsberg's avatar
Kristian Høgsberg committed
32 33 34 35 36 37
#include <config.h>

#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif

38
#include <algorithm>
39

Kristian Høgsberg's avatar
Kristian Høgsberg committed
40 41 42
#include "XRef.h"
#include "Dict.h"

43
#ifdef MULTITHREADED
44
#  define dictLocker()   MutexLocker locker(&mutex)
45
#else
46
#  define dictLocker()
47
#endif
Kristian Høgsberg's avatar
Kristian Høgsberg committed
48 49 50 51
//------------------------------------------------------------------------
// Dict
//------------------------------------------------------------------------

52
constexpr int SORT_LENGTH_LOWER_LIMIT = 32;
53

54 55 56
struct Dict::CmpDictEntry {
  bool operator()(const DictEntry &lhs, const DictEntry &rhs) const {
    return lhs.first < rhs.first;
57
  }
58 59 60 61 62 63 64
  bool operator()(const DictEntry &lhs, const char *rhs) const {
    return lhs.first < rhs;
  }
  bool operator()(const char *lhs, const DictEntry &rhs) const {
    return lhs < rhs.first;
  }
};
65

Kristian Høgsberg's avatar
Kristian Høgsberg committed
66 67 68
Dict::Dict(XRef *xrefA) {
  xref = xrefA;
  ref = 1;
69
#ifdef MULTITHREADED
70 71
  gInitMutex(&mutex);
#endif
72 73

  sorted = false;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
74 75
}

76
Dict::Dict(const Dict* dictA) {
77 78
  xref = dictA->xref;
  ref = 1;
79
#ifdef MULTITHREADED
80 81
  gInitMutex(&mutex);
#endif
82

83 84 85
  entries.reserve(dictA->entries.size());
  for (const auto& entry : dictA->entries) {
    entries.emplace_back(entry.first, entry.second.copy());
86
  }
87 88

  sorted = dictA->sorted;
89 90
}

91
Dict *Dict::copy(XRef *xrefA) const {
92
  dictLocker();
93 94
  Dict *dictA = new Dict(this);
  dictA->xref = xrefA;
95 96 97
  for (auto &entry : dictA->entries) {
    if (entry.second.getType() == objDict) {
      entry.second = Object(entry.second.getDict()->copy(xrefA));
98 99 100 101 102
    }
  }
  return dictA;
}

Kristian Høgsberg's avatar
Kristian Høgsberg committed
103
Dict::~Dict() {
104
#ifdef MULTITHREADED
105 106 107 108
  gDestroyMutex(&mutex);
#endif
}

109
void Dict::add(const char *key, Object &&val) {
110
  dictLocker();
111 112 113 114
  if (entries.size() >= SORT_LENGTH_LOWER_LIMIT) {
    if (!sorted) {
      std::sort(entries.begin(), entries.end(), CmpDictEntry{});
      sorted = true;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
115
    }
116 117 118 119 120
    const auto pos = std::upper_bound(entries.begin(), entries.end(), key, CmpDictEntry{});
    entries.emplace(pos, key, std::move(val));
  } else {
    entries.emplace_back(key, std::move(val));
    sorted = false;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
121 122 123
  }
}

124
inline const Dict::DictEntry *Dict::find(const char *key) const {
125
  if (sorted) {
126 127 128
    const auto pos = std::lower_bound(entries.begin(), entries.end(), key, CmpDictEntry{});
    if (pos != entries.end() && pos->first == key) {
      return &*pos;
129 130
    }
  } else {
131 132 133 134 135
    const auto pos = std::find_if(entries.rbegin(), entries.rend(), [key](const DictEntry& entry) {
      return entry.first == key;
    });
    if (pos != entries.rend()) {
      return &*pos;
136
    }
Kristian Høgsberg's avatar
Kristian Høgsberg committed
137
  }
138
  return nullptr;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
139 140
}

141 142
inline Dict::DictEntry *Dict::find(const char *key) {
  return const_cast<DictEntry *>(const_cast<const Dict *>(this)->find(key));
143 144
}

145
void Dict::remove(const char *key) {
146
  dictLocker();
147
  if (auto *entry = find(key)) {
148
    if (sorted) {
149 150
      const auto index = entry - &entries.front();
      entries.erase(entries.begin() + index);
151 152 153 154
    } else {
      swap(*entry, entries.back());
      entries.pop_back();
    }
155 156 157
  }
}

Albert Astals Cid's avatar
Albert Astals Cid committed
158 159
void Dict::set(const char *key, Object &&val) {
  if (val.isNull()) {
160 161 162
    remove(key);
    return;
  }
163 164 165
  dictLocker();
  if (auto *entry = find(key)) {
    entry->second = std::move(val);
166
  } else {
167
    add(key, std::move(val));
168 169 170 171
  }
}


172
GBool Dict::is(const char *type) const {
173 174 175 176
  if (const auto *entry = find("Type")) {
    return entry->second.isName(type);
  }
  return gFalse;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
177 178
}

179
Object Dict::lookup(const char *key, int recursion) const {
180 181 182 183
  if (const auto *entry = find(key)) {
    return entry->second.fetch(xref, recursion);
  }
  return Object(objNull);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
184 185
}

186
Object Dict::lookupNF(const char *key) const {
187 188 189 190
  if (const auto *entry = find(key)) {
    return entry->second.copy();
  }
  return Object(objNull);
Kristian Høgsberg's avatar
Kristian Høgsberg committed
191 192
}

193
GBool Dict::lookupInt(const char *key, const char *alt_key, int *value) const
194
{
195 196 197
  auto obj1 = lookup(key);
  if (obj1.isNull() && alt_key != nullptr) {
    obj1 = lookup(alt_key);
198
  }
199 200 201
  if (obj1.isInt()) {
    *value = obj1.getInt();
    return gTrue;
202
  }
203
  return gFalse;
Kristian Høgsberg's avatar
Kristian Høgsberg committed
204
}
205 206 207 208

GBool Dict::hasKey(const char *key) const {
  return find(key) != nullptr;
}