LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
DictionaryCode.cpp
Go to the documentation of this file.
1// Copyright 2002-2013 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
6// NAUTITIA
7//
8// jys 16-DEC-2002
9//
10// DictionaryCode is the class which decodes linguistic properties
11//
12
13#include "linguisticProcessing/core/Dictionary/DictionaryCode.h"
14
15// #include "common/linguisticData/linguisticData.h"
19#include "common/misc/FileUtils.h"
20#include "common/misc/strwstrtools.h"
21
22// #include "linguisticProcessing/core/Tokenizer/Exceptions.h"
23#include "linguisticProcessing/core/Dictionary/ParseBinary.h"
25
26#include <time.h>
27#include <cstdio>
28#include <iostream>
29#include <fstream>
30#include <sstream>
31#include <wchar.h>
32
33#define CODE_HEADER_SIZE 12
34
35using namespace Lima;
37using namespace Lima::Common::LinguisticData;
38
39namespace Lima
40{
41namespace LinguisticProcessing
42{
43namespace Dictionary
44{
45
47
48DictionaryCode::DictionaryCode() :
50 _mask(new uint64_t[LinguisticData::single().getNbCategories()]),
51 _catBit(new uint64_t[LinguisticData::single().getNbCategories()]),
52 _codeHAccess(0),
53 _codes(0),
54 m_language()
55{
56}
57
58DictionaryCode::DictionaryCode(const DictionaryCode& dico) :
60 BinaryEntry(),
61 _mask(0),
62 _catBit(0),
63 _codeHAccess(NULL),
64 _codes(NULL),
65 m_language(std::numeric_limits<unsigned char>::max())
66{
67 // just to keep inoffensive copy by value
68}
69
70void DictionaryCode::init(
72 Manager* manager)
73
74{
81#ifdef DEBUG_CD
82 LDEBUG << "DictionaryCode::init";
83#endif
84 m_language=manager->getInitializationParameters().language;
85 std::string resourcesPath=Common::LinguisticData::LinguisticData::single().getResourcesPath();
86// QString codesListFileName;
87// try
88// {
89// codesListFileName = Common::Misc::findFileInPaths(resourcesPath.c_str(), unitConfiguration.getParamsValueAtKey("codeListFile").c_str());
90// }
91// catch (NoSuchParam& )
92// {
93// LERROR << "no param 'codeListFile' in DictionaryCode group for language " << (int) m_language;
94// throw InvalidConfiguration();
95// }
96// loadCodesMaps(codesListFileName);
97
98 QString codeFileName;
99 try
100 {
101 codeFileName = Common::Misc::findFileInPaths(resourcesPath.c_str(), unitConfiguration.getParamsValueAtKey("codeFile").c_str());
102 }
103 catch (NoSuchParam& )
104 {
105 LERROR << "no param 'codeFile' in DictionaryCode group for language " << (int) m_language;
106 throw InvalidConfiguration();
107 }
108
109 parse(codeFileName.toUtf8().constData());
110}
111
112
113DictionaryCode::~DictionaryCode()
114{
115 delete[] _mask; _mask = 0;
116 delete[] _catBit; _catBit = 0;
117 delete[] _codeHAccess; _codeHAccess = 0;
118 delete[] _codes; _codes = 0;
119}
120
121// Parses dictionary binary codes files, creates access method
122//There are steps :
123// 1- read beginning of code file to compute size and check consistency
124// 2- create code memory storage
125// 3- create category array
126// 4- create code arrays
127void DictionaryCode::parse(const std::string& codeFileName)
128{
129 // std::cerr << "DictionaryCode::parse(const codeFileName)" << std::endl;
130 // 1- read beginning of code file to compute size and check consistency
131 // std::cerr << "1- read beginning of code file to compute size and check consistency" << std::endl;
132 ParseBinary parseCode(codeFileName.c_str());
133 parseCode.advancePointer(4); // skip TimeStamp
134 // check compatibility number
135 if (parseCode.getNumber(4) != S2_DICTIONARY_VERSION)
137 uint64_t codeSize = parseCode.getNumber(4) - CODE_HEADER_SIZE;// without header
138 // 2- create code memory storage
139 // std::cerr << "2- create code memory storage" << std::endl;
140 _codes = new unsigned char[codeSize];
141 if (_codes == NULL) throw MemoryErrorException();
142 FILE *codeFile;
143 uint64_t readSize;
144 codeFile = fopen(codeFileName.c_str(), "rb");
145 if (codeFile == NULL)
146 {
147 std::string mes = "Open file error: " + codeFileName;
148 throw OpenFileException(mes);
149 }
150 fseek(codeFile, CODE_HEADER_SIZE, SEEK_SET); // skip header
151 readSize = fread(_codes, 1, codeSize, codeFile);
152 fclose(codeFile);
153 if (readSize != codeSize) throw ReadErrorException("readSize != codeSize in DictionaryCode::parse");
154 // 3- create category array
155 // std::cerr << "3- create category array" << std::endl;
156 unsigned char *ptr = _codes;
157 uint64_t num = getEncodedNumber(ptr);
158 unsigned char *endCategory = num + ptr;
159 while (ptr < endCategory)
160 {
161 uint64_t catEnum = getEncodedNumber(ptr);
162 if (catEnum > LinguisticData::single().getNbCategories()-1)
164 _mask[catEnum] = getEncodedNumber(ptr);
165 _catBit[catEnum] = getEncodedNumber(ptr);
166 }
167 // 4- create code arrays
168 // std::cerr << "4- create code arrays" << std::endl;
169 size_t maxLinguisticCode = LinguisticData::single().languageData(m_language).getNbMicroCategories();
170 _codeHAccess = new CodeHAccess[maxLinguisticCode + 1];
171 for (uint64_t i=0; i<CODE_H_ACCESS_TABLE_SIZE; i++)
172 {
173 _hTable[i]=NULL;
174 }
175 uint64_t num = getEncodedNumber(ptr);
176 unsigned char *endCode = num + ptr;
177 while (ptr < endCode)
178 {
179 LinguisticCode codeEnum = (LinguisticCode)getEncodedNumber(ptr);
180 uint64_t codeValue = getEncodedNumber(ptr);
181 if (codeEnum > maxLinguisticCode)
183 _codeHAccess[codeEnum]._enum = codeEnum;
184 _codeHAccess[codeEnum]._value = codeValue;
185 _codeHAccess[codeEnum]._stringAddr = ptr;
186 _codeHAccess[codeEnum]._next = _hTable[codeValue%CODE_H_ACCESS_TABLE_SIZE];
187 _hTable[codeValue%CODE_H_ACCESS_TABLE_SIZE] = &_codeHAccess[codeEnum];
188 nextField(ptr);
189 }
190 // std::cerr << "OUT DictionaryCode::parse(const std::string& codeFileName)" << std::endl;
191}
192
193// returns true if category of value is the supplied code
194bool DictionaryCode::isThisCode(const uint64_t property,
195 const LinguisticCategory category,
196 const LinguisticCode code) const
197{
198 if (category <= L_NONE || category > (LinguisticData::single().getNbCategories()-1))
199 throw BoundsErrorException();
200 if (code <= NONE_1 || code >= LinguisticData::single().languageData(m_language).getNbMicroCategories())
201 throw BoundsErrorException();
202 return (_codeHAccess[code]._value == (property & _mask[category]));
203}
204
205// returns category value in position from supplied code and category
206uint64_t DictionaryCode::categoryValue(const LinguisticCode code,
207 const LinguisticCategory category)
208{
209 if (category <= L_NONE || category >= LinguisticData::single().languageData(m_language).getNbMicroCategories())
210 throw BoundsErrorException();
211 if (code <= NONE_1 || code > LinguisticData::single().languageData(m_language).getNbMicroCategories())
212 throw BoundsErrorException();
213 return (_codeHAccess[code]._value) - (_catBit[category]);
214}
215
216uint64_t DictionaryCode::setCategory(
217 const uint64_t property,
218 const LinguisticCode code,
219 const LinguisticCategory category)
220{
221 uint64_t newCategoryValue = categoryValue(code, category);
222 uint64_t newProperty = ( property & (!_mask[category]) ) & newCategoryValue;
223 return newProperty;
224}
225
226// Returns code of value for the supplied category
227LinguisticCode DictionaryCode::code(const uint64_t property,
228 const LinguisticCategory category) const
229{
230 if (category <= L_NONE || category > (LinguisticData::single().getNbCategories()-1))
231 throw BoundsErrorException();
232 uint64_t codeValue = property & (_mask[category]) | (_catBit[category]);
233 CodeHAccess *codeHAccess = _hTable[codeValue%CODE_H_ACCESS_TABLE_SIZE];
234 while (codeHAccess != NULL)
235 {
236 if (codeHAccess->_value == codeValue)
237 return codeHAccess->_enum;
238 codeHAccess = codeHAccess->_next;
239 }
240 return NONE_1;
241}
242
243
245LinguisticCode DictionaryCode::unpositionedCode(const uint64_t property,
246 const LinguisticCategory category) const
247{
248 if (category <= L_NONE || category > (LinguisticData::single().getNbCategories()-1))
249 throw BoundsErrorException();
250 uint64_t codeValue = property;
251 uint64_t mask = _mask[category];
252 while ((mask & 1) == 0)
253 {
254 codeValue <<= 1;
255 mask >>= 1;
256 }
257 codeValue |= _catBit[category];
258 CodeHAccess *codeHAccess = _hTable[codeValue%CODE_H_ACCESS_TABLE_SIZE];
259 while (codeHAccess != NULL)
260 {
261 if (codeHAccess->_value == codeValue)
262 return codeHAccess->_enum;
263 codeHAccess = codeHAccess->_next;
264 }
265 return NONE_1;
266}
267
269LimaString DictionaryCode::stringCode(const uint64_t property,
270 const LinguisticCategory category) const
271{
272 if (category <= L_NONE || category > (LinguisticData::single().getNbCategories()-1))
273 throw BoundsErrorException();
274 uint64_t codeValue = property & _mask[category] | (_catBit[category]);
275 CodeHAccess *codeHAccess = _hTable[codeValue%CODE_H_ACCESS_TABLE_SIZE];
276 while (codeHAccess != NULL)
277 {
278 if (codeHAccess->_value == codeValue)
279 return getStringNoMove(codeHAccess->_stringAddr);
280 codeHAccess = codeHAccess->_next;
281 }
282 return LimaString();
283}
284
286LimaString DictionaryCode::stringCode(const LinguisticCode code) const
287{
288 if (code > LinguisticData::single().languageData(m_language).getNbMicroCategories()) throw BoundsErrorException();
289 if ((code == NONE_1) || (_codeHAccess[code]._stringAddr == 0))
290 return LimaString();
291 LimaString res = getStringNoMove(_codeHAccess[code]._stringAddr);
292// std::cerr << "stringCode(" << code << ") = " << Common::Misc::limastring2utf8stdstring(res) << std::endl;
293 return res;
294}
295
296/*
297void DictionaryCode::loadCodesMaps(const std::string& codesListFileName)
298{
299 std::ifstream codesListFile(codesListFileName.c_str());
300
301 if (!codesListFile.good())
302 {
303 std::ostringstream oss;
304 oss << "Cannot open " << codesListFileName << std::endl;
305 throw std::runtime_error(oss.str().c_str());
306 }
307 LinguisticCode current = 0;
308 while (codesListFile.good() && !codesListFile.eof())
309 {
310 std::string lineString;
311 getline(codesListFile, lineString);
312
313 // allow empty lines and comments
314 if ( (lineString.size() > 0) && (lineString[0] != '#') )
315 {
316 // allow to specify numbers
317 size_t pos = lineString.find(';');
318 if (pos != std::string::npos)
319 {
320 std::istringstream(lineString.substr(pos+1)) >> current;
321 lineString = lineString.substr(0,pos);
322 }
323 if (m_strCode.find(lineString) != m_strCode.end())
324 {
325 throw std::runtime_error("duplicated micro category " + lineString + " in " + codesListFileName);
326 }
327 m_codeStr.insert( std::make_pair(current, lineString));
328 m_strCode.insert( std::make_pair(lineString, current));
329 current++;
330 }
331 }
332 if (m_strCode.size() != m_codeStr.size())
333 {
334 throw std::runtime_error("code->str and str->code sizes differ after loading " + codesListFileName);
335 }
336}
337*/
339LinguisticCode DictionaryCode::code(const std::string& strCode) const
340{
341 return LinguisticData::single().languageData(m_language).getMicroCategory(strCode);
342}
343
344} //closing namespace Dictionary
345} //closing namespace LinguisticProcessing
346} //closing namespace Lima
#define CODE_HEADER_SIZE
#define LDEBUG
Definition LimaCommon.h:157
#define LERROR
Definition LimaCommon.h:161
#define DICTIONARYLOGINIT
Defines a Factory to create Object of type Base.
#define NONE_1
Definition StdBitset.h:339
return a message when a 'param' was not found
Use this exception to signal an error in one of the configuration files.
Definition LimaCommon.h:345
QString findFileInPaths(const QString &paths, const QString &fileName, const QChar &separator)
Find the given file in the given paths.
SimpleFactory< AbstractResource, DictionaryCode > dictionaryCodeFactory(DICTIONARYCODE_CLASSID)
NAUTITIA.
QString LimaString
Definition LimaString.h:33
STL namespace.
launch exception related to the configuration file parsing