Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libe-book/src/lib/EBOOKLanguageManager.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/*
3
 * This file is part of the libe-book project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#ifdef HAVE_CONFIG_H
11
#include "config.h"
12
#endif
13
14
#include "EBOOKLanguageManager.h"
15
16
#include <cstdlib>
17
#include <stdexcept>
18
19
#ifdef WITH_LIBLANGTAG
20
#include <liblangtag/langtag.h>
21
#endif
22
23
#include "libebook_utils.h"
24
25
namespace libebook
26
{
27
28
using std::shared_ptr;
29
using std::unordered_map;
30
using std::unordered_set;
31
32
using librevenge::RVNGPropertyList;
33
34
using std::string;
35
36
#ifdef WITH_LIBLANGTAG
37
namespace
38
{
39
40
const shared_ptr<lt_tag_t> parseTag(const std::string &lang)
41
{
42
  const shared_ptr<lt_tag_t> tag(lt_tag_new(), lt_tag_unref);
43
  lt_error_t *error = nullptr;
44
  lt_tag_parse(tag.get(), lang.c_str(), &error);
45
  if (error && lt_error_is_set(error, LT_ERR_ANY))
46
  {
47
    lt_error_unref(error);
48
    return shared_ptr<lt_tag_t>();
49
  }
50
  return tag;
51
}
52
53
const std::string makeFullTag(const shared_ptr<lt_tag_t> &tag)
54
{
55
  lt_error_t *error = nullptr;
56
  const shared_ptr<char> full(lt_tag_transform(tag.get(), &error), std::free);
57
  if (error && lt_error_is_set(error, LT_ERR_ANY))
58
  {
59
    lt_error_unref(error);
60
    return lt_tag_get_string(tag.get());
61
  }
62
  return full.get();
63
}
64
65
}
66
#endif
67
68
struct EBOOKLanguageManager::LangDB
69
{
70
  LangDB();
71
72
  unordered_map<string, string> m_db;
73
};
74
75
EBOOKLanguageManager::LangDB::LangDB()
76
0
  : m_db()
77
0
{
78
#ifdef WITH_LIBLANGTAG
79
  shared_ptr<lt_lang_db_t> langDB(lt_db_get_lang(), lt_lang_db_unref);
80
  shared_ptr<lt_iter_t> it(LT_ITER_INIT(langDB.get()), lt_iter_finish);
81
  lt_pointer_t key(nullptr);
82
  lt_pointer_t value(nullptr);
83
  while (lt_iter_next(it.get(), &key, &value))
84
  {
85
    const auto *const tag = reinterpret_cast<const char *>(key);
86
    auto *const lang = reinterpret_cast<lt_lang_t *>(value);
87
    m_db[lt_lang_get_name(lang)] = tag;
88
  }
89
#endif
90
0
}
91
92
EBOOKLanguageManager::EBOOKLanguageManager()
93
5.08k
  : m_tagMap()
94
5.08k
  , m_invalidTags()
95
5.08k
  , m_langMap()
96
5.08k
  , m_invalidLangs()
97
5.08k
  , m_propsMap()
98
5.08k
  , m_langDB()
99
5.08k
{
100
5.08k
}
101
102
const std::string EBOOKLanguageManager::addTag(const std::string &tag)
103
565k
{
104
#ifdef WITH_LIBLANGTAG
105
  // Check if the tag is already known
106
  const unordered_map<string, string>::const_iterator it = m_tagMap.find(tag);
107
  if (it != m_tagMap.end())
108
    return it->second;
109
  // Check if the tag was previously rejected as invalid
110
  const unordered_set<string>::const_iterator invIt = m_invalidTags.find(tag);
111
  if (invIt != m_invalidTags.end())
112
    return "";
113
114
  const shared_ptr<lt_tag_t> &langTag = parseTag(tag);
115
  if (!langTag)
116
  {
117
    m_invalidTags.insert(tag);
118
    return "";
119
  }
120
121
  const string fullTag(makeFullTag(langTag));
122
  m_tagMap[tag] = fullTag;
123
  addProperties(fullTag);
124
125
  return fullTag;
126
#else
127
565k
  return tag;
128
565k
#endif
129
565k
}
130
131
const std::string EBOOKLanguageManager::addLanguage(const std::string &lang)
132
446k
{
133
#ifdef WITH_LIBLANGTAG
134
  // Check if the lang is already known
135
  const unordered_map<string, string>::const_iterator it = m_langMap.find(lang);
136
  if (it != m_langMap.end())
137
    return it->second;
138
  // Check if the lang was previously rejected as invalid
139
  const unordered_set<string>::const_iterator invIt = m_invalidLangs.find(lang);
140
  if (invIt != m_invalidLangs.end())
141
    return "";
142
143
  const unordered_map<string, string>::const_iterator langIt = getLangDB().m_db.find(lang);
144
  if (langIt == getLangDB().m_db.end())
145
  {
146
    m_invalidLangs.insert(lang);
147
    return "";
148
  }
149
150
  const shared_ptr<lt_tag_t> &langTag = parseTag(langIt->second);
151
  if (!langTag)
152
    throw std::logic_error("cannot parse tag that came from liblangtag language DB");
153
154
  const string fullTag(makeFullTag(langTag));
155
  m_langMap[lang] = fullTag;
156
  addProperties(fullTag);
157
158
  return fullTag;
159
#else
160
446k
  (void) lang;
161
446k
  return "";
162
446k
#endif
163
446k
}
164
165
const std::string EBOOKLanguageManager::getLanguage(const std::string &tag) const
166
0
{
167
#ifdef WITH_LIBLANGTAG
168
  const shared_ptr<lt_tag_t> &langTag = parseTag(tag);
169
  if (!langTag)
170
    throw std::logic_error("cannot parse tag that has been successfully parsed before");
171
  return lt_lang_get_name(lt_tag_get_language(langTag.get()));
172
#else
173
0
  (void) tag;
174
0
  return "";
175
0
#endif
176
0
}
177
178
const EBOOKLanguageManager::LangDB &EBOOKLanguageManager::getLangDB() const
179
0
{
180
0
  if (!m_langDB)
181
0
    m_langDB.reset(new LangDB());
182
0
  return *m_langDB;
183
0
}
184
185
void EBOOKLanguageManager::addProperties(const std::string &tag)
186
0
{
187
#ifdef WITH_LIBLANGTAG
188
  const shared_ptr<lt_tag_t> &langTag = parseTag(tag);
189
  if (!langTag)
190
    throw std::logic_error("cannot parse tag that has been successfully parsed before");
191
192
  RVNGPropertyList props;
193
  const lt_lang_t *const lang = lt_tag_get_language(langTag.get());
194
  if (lang)
195
    props.insert("fo:language", lt_lang_get_tag(lang));
196
  const lt_region_t *const region = lt_tag_get_region(langTag.get());
197
  if (region)
198
    props.insert("fo:country", lt_region_get_tag(region));
199
  const lt_script_t *const script = lt_tag_get_script(langTag.get());
200
  if (script)
201
    props.insert("fo:script", lt_script_get_tag(script));
202
203
  m_propsMap[tag] = props;
204
#else
205
0
  (void) tag;
206
0
#endif
207
0
}
208
209
void EBOOKLanguageManager::writeProperties(const std::string &tag, librevenge::RVNGPropertyList &props) const
210
119k
{
211
#ifdef WITH_LIBLANGTAG
212
  const unordered_map<string, RVNGPropertyList>::const_iterator it = m_propsMap.find(tag);
213
  if (it == m_propsMap.end())
214
  {
215
    EBOOK_DEBUG_MSG(("EBOOKLanguageManager::writeProperties: unknown tag %s\n", tag.c_str()));
216
    return;
217
  }
218
  for (RVNGPropertyList::Iter iter(it->second); !iter.last(); iter.next())
219
    props.insert(iter.key(), iter()->getStr());
220
#else
221
119k
  (void) tag;
222
119k
  (void) props;
223
119k
#endif
224
119k
}
225
226
}
227
228
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */