1 /*
2  * Copyright 2011 kubtek <kubtek@mail.com>
3  *
4  * This file is part of StarDict.
5  *
6  * StarDict is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * StarDict is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with StarDict.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef _STDDICT_HPP_
21 #define _STDDICT_HPP_
22 
23 #include "stardict_libconfig.h"
24 
25 #include <glib.h>
26 #include <string>
27 #include <vector>
28 #include <list>
29 #include <map>
30 
31 #include "dictbase.h"
32 #include "collation.h"
33 #include "dictbase.h"
34 #include "storage.h"
35 #include "libcommon.h"
36 #include "dictitemid.h"
37 
38 const int MAX_FUZZY_DISTANCE= 3; // at most MAX_FUZZY_DISTANCE-1 differences allowed when find similar words
39 const int MAX_MATCH_ITEM_PER_LIB=100;
40 
41 /* Collation support. Effects word list sort order. */
42 enum CollationLevelType {
43 	/* Do not use collation functions */
44 	CollationLevel_NONE = 0,
45 	/* Use collation function to sort word list.
46 	 * Only one collation function may be selected per index or synonym file.
47 	 * To change the collation function, the dictionary must be reloaded.
48 	 * The collation function is selected once for all dictionaries at startup.
49 	 * To switch to this mode open the Preferences dialog,
50 	 * Dictionary, Cache; check "Sort word list by collation function" and
51 	 * select a collation function. */
52 	CollationLevel_SINGLE = 1,
53 	/* Use collation to sort word list.
54 	 * Multiple collation functions may be used per index or synonym file.
55 	 * Collation functions are loaded on the first use (to be precise, the word
56 	 * list is sorted according the selected collation function on the first use).
57 	 * This mode is not fully implemented. User interface does not
58 	 * provide an option to switch to this mode. */
59 	CollationLevel_MULTI = 2,
60 };
61 
62 extern gint stardict_strcmp(const gchar *s1, const gchar *s2);
63 extern gint stardict_server_collate(const gchar *str1, const gchar *str2, CollationLevelType CollationLevel, CollateFunctions func, int servercollatefunc);
64 
65 
66 class show_progress_t {
67 public:
~show_progress_t()68 	virtual ~show_progress_t() {}
notify_about_start(const std::string & title)69 	virtual void notify_about_start(const std::string& title) {}
notify_about_work()70 	virtual void notify_about_work() {}
71 };
72 
73 enum CacheFileType {
74 	CacheFileType_oft,
75 	CacheFileType_clt,
76 	CacheFileType_server_clt,
77 };
78 
79 /* url and saveurl parameters that appear on the same level, function parameters,
80  * for example, normally have the following meaning.
81  * url - the real file, the cache was build for. That file exists in file system.
82  * saveurl - the file that url represents. Use saveurl to construct cache file name.
83  * Often url = saveurl.
84  * They may be different in the case url is a compressed index, then saveurl
85  * names uncompressed index. For example,
86  * url = ".../mydict.idx.gz"
87  * saveurl = ".../mydict.idx"
88  *
89  * for uncompressed index:
90  * url = ".../mydict.idx"
91  * saveurl = ".../mydict.idx"
92  *
93  * Cache file searching algorithm
94  *
95  * This algorithm is used in load_cache and save_cache functions.
96  * 1. Search for cache file in the directory of the saveurl parameter.
97  * 1.1. Build primary file name: saveurl + ".oft". (We use here .oft file as example)
98  * 1.2. Check if that file is the target cache file. If yes, stop search.
99  * 1.3. Build next file name: dirname(saveurl) + "/" + basename(saveurl) + "(" + num + ")" + ext(saveurl) + ".oft"
100  * 1.4. num++, goto 1.2.
101  * 2. Search for cache file in the user cache directory (app_dirs->get_user_cache_dir()).
102  * 2.1. Build primary file name: user_cache_dir + filename(saveurl) + ".oft"
103  * ...
104  * */
105 class cache_file {
106 public:
107 	cache_file(CacheFileType _cachefiletype, CollateFunctions _cltfunc);
108 	~cache_file();
109 	/* Return value: true - success, false - fault.
110 	 * If loaded successfully, mf contains the loaded file,
111 	 * wordoffset points to the portion of the mapped file containing offsets.
112 	 * If load failed, mf and wordoffset are not changed. */
113 	bool load_cache(const std::string& url, const std::string& saveurl, glong filedatasize);
114 	/* (Re)create cache file. Member data do not change.
115 	 * Content of the cache file is build from wordoffset array and parameters of this function.
116 	 * Note that this function does not load the saved file, mf member is not used. */
117 	bool save_cache(const std::string& saveurl) const;
118 	// datasize in bytes
119 	void allocate_wordoffset(size_t _npages);
get_wordoffset(size_t ind)120 	guint32& get_wordoffset(size_t ind)
121 	{
122 		return wordoffset[ind];
123 	}
get_wordoffset(void)124 	guint32* get_wordoffset(void)
125 	{
126 		return wordoffset;
127 	}
get_CollateFunction(void)128 	CollateFunctions get_CollateFunction(void) const
129 	{
130 		return cltfunc;
131 	}
132 
133 private:
134 	/* If mf != NULL, then wordoffset points to part of mapped file, it should not be freed.
135 	 * Otherwise wordoffset must be freed with g_free. */
136 	guint32 *wordoffset;
137 	/* size of the wordoffset array */
138 	size_t npages;
139 	CacheFileType cachefiletype;
140 	MapFile *mf;
141 	CollateFunctions cltfunc;
142 	/* The following functions do not change member data, they return result though parameters. */
143 	bool build_primary_cache_filename_in_user_cache(const std::string& url, std::string &cachefilename, bool create) const;
144 	MapFile* find_and_load_cache_file(const gchar *filename, const std::string &url, const std::string &saveurl, glong filedatasize, int next) const;
145 	FILE* find_and_open_for_overwrite_cache_file(const gchar *filename, const std::string &saveurl, int next, std::string &cfilename) const;
146 	gchar *get_next_filename(
147 		const gchar *dirname, const gchar *basename, int num,
148 		const gchar *extendname) const;
149 	void build_primary_cache_filename(const std::string &url,
150 		std::string &filename) const;
151 };
152 
153 class idxsyn_file;
154 class collation_file : public cache_file {
155 public:
156 	collation_file(idxsyn_file *_idx_file, CacheFileType _cachefiletype,
157 		CollateFunctions _CollateFunction);
158 	bool lookup(const char *str, glong &idx, glong &idx_suggest);
159 	const gchar *GetWord(glong idx);
160 	glong GetOrigIndex(glong cltidx);
161 private:
162 	idxsyn_file *idx_file;
163 };
164 
165 /* This class serves as root for classes representing index and synonym files.
166  * The class provides two main services getWord and Lookup and
167  * declares get_key and lookup pure virtual functions that must be implemented in derived classes.
168  *
169  * We may access the underlying index (synonym) file either directly or
170  * in the order specified by collate function.
171  * Direct access to the underlying file is possible immediately after the derived class completed
172  * initialization process (which include assigning protected wordcount member).
173  * To access the file in collate function order, additional initialization is required.
174  *
175  * First, you must specify the underlying index (synonym) file url with collate_save_info method.
176  * Second, you must initialize the collation object with collate_load method.
177  * This class is initialized either for CollationLevel_SINGLE or for CollationLevel_MULTI
178  * collation level type.
179  *
180  * In the CollationLevel_SINGLE case, clt_file is initialized.
181  * Now getWord and Lookup may be called with CollationLevel = CollationLevel_SINGLE,
182  * get_clt_file() returns non-NULL collation file.
183  *
184  * In the CollationLevel_MULTI case, clt_files[your_collate_func] is initialized.
185  * Since now, you may invoke getWord and Lookup with CollationLevel = CollationLevel_MULTI,
186  * servercollatefunc = your_collate_func. get_clt_file(your_collate_func) returns non-NULL.
187  * In fact, for getWord and Lookup invoke the collate_load internally, should a need be.
188  */
189 class idxsyn_file {
190 public:
191 	idxsyn_file();
192 	virtual ~idxsyn_file();
193 	const gchar *getWord(glong idx, CollationLevelType CollationLevel, int servercollatefunc);
194 	bool Lookup(const char *str, glong &idx, glong &idx_suggest, CollationLevelType CollationLevel, int servercollatefunc);
195 	virtual const gchar *get_key(glong idx) = 0;
196 	virtual bool lookup(const char *str, glong &idx, glong &idx_suggest) = 0;
197 	void collate_save_info(const std::string& _url, const std::string& _saveurl);
198 	void collate_load(CollateFunctions collf, CollationLevelType CollationLevel, show_progress_t *sp = 0);
get_clt_file(void)199 	collation_file * get_clt_file(void) { return clt_file; }
get_clt_file(size_t ind)200 	collation_file * get_clt_file(size_t ind) { return clt_files[ind]; }
get_word_count(void)201 	glong get_word_count(void) const { return wordcount; }
202 private:
203 	collation_file * collate_load_impl(
204 		const std::string& _url, const std::string& _saveurl,
205 		CollateFunctions collf, show_progress_t *sp, CacheFileType CacheType);
206 	std::string url;
207 	std::string saveurl;
208 	collation_file *clt_file;
209 	collation_file *clt_files[COLLATE_FUNC_NUMS];
210 protected:
211 	// number of words in the index
212 	glong wordcount;
213 };
214 
215 class index_file : public idxsyn_file {
216 public:
217 	/* get_data and get_key_and_data methods return their result through these
218 	 * members. */
219 	guint32 wordentry_offset;
220 	guint32 wordentry_size;
221 
222 	static index_file* Create(const std::string& filebasename,
223 		const char* mainext, std::string& fullfilename);
224 	virtual bool load(const std::string& url, gulong wc, gulong fsize,
225 			  bool CreateCacheFile, CollationLevelType CollationLevel,
226 			  CollateFunctions _CollateFunction, show_progress_t *sp) = 0;
227 	virtual void get_data(glong idx) = 0;
228 	virtual const gchar *get_key_and_data(glong idx) = 0;
229 	virtual bool lookup(const char *str, glong &idx, glong &idx_suggest) = 0;
230 };
231 
232 class synonym_file : public idxsyn_file {
233 public:
234 	guint32 wordentry_index;
235 
236 	synonym_file();
237 	~synonym_file();
238 	bool load(const std::string& url, gulong wc, bool CreateCacheFile,
239 		CollationLevelType CollationLevel, CollateFunctions _CollateFunction,
240 		show_progress_t *sp);
241 private:
242 	const gchar *get_key(glong idx);
243 	bool lookup(const char *str, glong &idx, glong &idx_suggest);
244 
245 	static const gint ENTR_PER_PAGE=32;
246 	gulong npages;
247 
248 	/* offset cache file. Contains offsets in the original synonym file.
249 	 * Selected collation level and collate function have no effect on this cache. */
250 	cache_file oft_file;
251 	FILE *synfile;
252 
253 	gchar wordentry_buf[MAX_INDEX_KEY_SIZE+sizeof(guint32)];
254 	struct index_entry {
255 		glong idx;
256 		std::string keystr;
assignindex_entry257 		void assign(glong i, const std::string& str) {
258 			idx=i;
259 			keystr.assign(str);
260 		}
261 	};
262 	index_entry first, last, middle, real_last;
263 
264 	struct page_entry {
265 		gchar *keystr;
266 		guint32 index;
267 	};
268 	std::vector<gchar> page_data;
269 	struct page_t {
270 		glong idx;
271 		page_entry entries[ENTR_PER_PAGE];
272 
page_tpage_t273 		page_t(): idx(-1) {}
274 		void fill(gchar *data, gint nent, glong idx_);
275 	} page;
276 	gulong load_page(glong page_idx);
277 	const gchar *read_first_on_page_key(glong page_idx);
278 	const gchar *get_first_on_page_key(glong page_idx);
279 };
280 
281 class Dict : public DictBase {
282 private:
283 	/* in file name encoding */
284 	std::string ifo_file_name;
285 	std::string bookname; // in utf-8
286 	std::string dicttype; // in utf-8
287 
288 	/* ifofilename in file name encoding */
289 	bool load_ifofile(const std::string& ifofilename, gulong &idxfilesize, glong &wordcount, glong &synwordcount);
290 public:
291 	std::auto_ptr<index_file> idx_file;
292 	std::auto_ptr<synonym_file> syn_file;
293 	ResourceStorage *storage;
294 
295 	Dict();
296 	~Dict();
297 	/* ifofilename in file name encoding */
298 	bool load(const std::string &ifofilename, bool CreateCacheFile,
299 		CollationLevelType CollationLevel, CollateFunctions CollateFunction,
300 		show_progress_t *sp);
301 
narticles()302 	glong narticles() const { return idx_file->get_word_count(); }
303 	glong nsynarticles() const;
dict_name()304 	const std::string& dict_name() const { return bookname; }
dict_type()305 	const std::string& dict_type() const { return dicttype; }
ifofilename()306 	const std::string& ifofilename() const { return ifo_file_name; }
id()307 	DictItemId id() const { return DictItemId(ifo_file_name); }
308 
get_data(glong index)309 	gchar *get_data(glong index)
310 	{
311 		idx_file->get_data(index);
312 		return DictBase::GetWordData(idx_file->wordentry_offset, idx_file->wordentry_size);
313 	}
get_key_and_data(glong index,const gchar ** key,guint32 * offset,guint32 * size)314 	void get_key_and_data(glong index, const gchar **key, guint32 *offset, guint32 *size)
315 	{
316 		*key = idx_file->get_key_and_data(index);
317 		*offset = idx_file->wordentry_offset;
318 		*size = idx_file->wordentry_size;
319 	}
Lookup(const char * str,glong & idx,glong & idx_suggest,CollationLevelType CollationLevel,int servercollatefunc)320 	bool Lookup(const char *str, glong &idx, glong &idx_suggest, CollationLevelType CollationLevel, int servercollatefunc)
321 	{
322 		return idx_file->Lookup(str, idx, idx_suggest, CollationLevel, servercollatefunc);
323 	}
324 	bool LookupSynonym(const char *str, glong &synidx, glong &synidx_suggest, CollationLevelType CollationLevel, int servercollatefunc);
325 	bool LookupWithRule(GPatternSpec *pspec, glong *aIndex, int iBuffLen);
326 	bool LookupWithRuleSynonym(GPatternSpec *pspec, glong *aIndex, int iBuffLen);
327 	bool LookupWithRegex(GRegex *regex, glong *aIndex, int iBuffLen);
328 	bool LookupWithRegexSynonym(GRegex *regex, glong *aIndex, int iBuffLen);
329 	gint GetOrigWordCount(glong& iWordIndex, bool isidx);
330 	bool GetWordPrev(glong iWordIndex, glong &pidx, bool isidx, CollationLevelType CollationLevel, int servercollatefunc);
331 	void GetWordNext(glong &iWordIndex, bool isidx, CollationLevelType CollationLevel, int servercollatefunc);
332 };
333 
334 struct CurrentIndex {
335 	glong idx;
336 	glong idx_suggest;
337 	glong synidx;
338 	glong synidx_suggest;
339 };
340 
341 class Libs {
342 public:
343 	/* func is only used when level is CollationLevel_SINGLE,
344 	 * otherwise function must be COLLATE_FUNC_NONE. */
345 	Libs(show_progress_t *sp, bool create_cache_files, CollationLevelType level, CollateFunctions func);
346 	~Libs();
set_show_progress(show_progress_t * sp)347 	void set_show_progress(show_progress_t *sp) {
348 		if (sp)
349 			show_progress = sp;
350 		else
351 			show_progress = &default_show_progress;
352 	}
get_show_progress(void)353 	show_progress_t *get_show_progress(void) const
354 	{
355 		return show_progress;
356 	}
get_CollationLevel()357 	CollationLevelType get_CollationLevel() const { return CollationLevel; }
get_CollateFunction()358 	CollateFunctions get_CollateFunction() const { return CollateFunction; }
359 	bool load_dict(const std::string& url, show_progress_t *sp);
360 #ifdef SD_SERVER_CODE
361 	void LoadFromXML();
362 	void SetServerDictMask(std::vector<InstantDictIndex> &dictmask, const char *dicts, int max, int level);
363 	void LoadCollateFile(std::vector<InstantDictIndex> &dictmask, CollateFunctions cltfuc);
364 	const std::string *get_dir_info(const char *path);
365 	const std::string *get_dict_info(const char *uid, bool is_short);
366 	const std::string &get_fromto_info();
367 	std::string get_dicts_list(const char *dicts, int max_dict_count, int userLevel);
368 	int get_dict_level(const char *uid);
369 #endif
370 #ifdef SD_CLIENT_CODE
371 	bool find_lib_by_id(const DictItemId& filename, size_t &iLib);
372 	void load(const std::list<std::string> &load_list);
373 	void reload(const std::list<std::string> &load_list, CollationLevelType NewCollationLevel, CollateFunctions collf);
374 #endif
375 
narticles(size_t idict)376 	glong narticles(size_t idict) const { return oLib[idict]->narticles(); }
nsynarticles(size_t idict)377 	glong nsynarticles(size_t idict) const { return oLib[idict]->nsynarticles(); }
dict_name(size_t idict)378 	const std::string& dict_name(size_t idict) const { return oLib[idict]->dict_name(); }
dict_type(size_t idict)379 	const std::string& dict_type(size_t idict) const { return oLib[idict]->dict_type(); }
has_dict()380 	bool has_dict() const { return !oLib.empty(); }
381 
poGetWord(glong iIndex,size_t iLib,int servercollatefunc)382 	const gchar * poGetWord(glong iIndex,size_t iLib, int servercollatefunc) const {
383 		return oLib[iLib]->idx_file->getWord(iIndex, CollationLevel, servercollatefunc);
384 	}
poGetOrigWord(glong iIndex,size_t iLib)385 	const gchar * poGetOrigWord(glong iIndex,size_t iLib) const {
386 		return oLib[iLib]->idx_file->getWord(iIndex, CollationLevel_NONE, 0);
387 	}
poGetSynonymWord(glong iSynonymIndex,size_t iLib,int servercollatefunc)388 	const gchar * poGetSynonymWord(glong iSynonymIndex,size_t iLib, int servercollatefunc) const {
389 		return oLib[iLib]->syn_file->getWord(iSynonymIndex, CollationLevel, servercollatefunc);
390 	}
poGetOrigSynonymWord(glong iSynonymIndex,size_t iLib)391 	const gchar * poGetOrigSynonymWord(glong iSynonymIndex,size_t iLib) const {
392 		return oLib[iLib]->syn_file->getWord(iSynonymIndex, CollationLevel_NONE, 0);
393 	}
poGetOrigSynonymWordIdx(glong iSynonymIndex,size_t iLib)394 	glong poGetOrigSynonymWordIdx(glong iSynonymIndex, size_t iLib) const {
395 		oLib[iLib]->syn_file->getWord(iSynonymIndex, CollationLevel_NONE, 0);
396 		return oLib[iLib]->syn_file->wordentry_index;
397 	}
398 	glong CltIndexToOrig(glong cltidx, size_t iLib, int servercollatefunc);
399 	glong CltSynIndexToOrig(glong cltidx, size_t iLib, int servercollatefunc);
poGetOrigWordData(glong iIndex,size_t iLib)400 	gchar * poGetOrigWordData(glong iIndex,size_t iLib) {
401 		if (iIndex==INVALID_INDEX)
402 			return NULL;
403 		return oLib[iLib]->get_data(iIndex);
404 	}
405 	const gchar *GetSuggestWord(const gchar *sWord, CurrentIndex *iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc);
406 	const gchar *poGetCurrentWord(CurrentIndex *iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc);
407 	const gchar *poGetNextWord(const gchar *word, CurrentIndex *iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc);
408 	const gchar *poGetPreWord(const gchar *word, CurrentIndex *iCurrent, std::vector<InstantDictIndex> &dictmask, int servercollatefunc);
LookupWord(const gchar * sWord,glong & iWordIndex,glong & idx_suggest,size_t iLib,int servercollatefunc)409 	bool LookupWord(const gchar* sWord, glong& iWordIndex, glong &idx_suggest, size_t iLib, int servercollatefunc) {
410 		return oLib[iLib]->Lookup(sWord, iWordIndex, idx_suggest, CollationLevel, servercollatefunc);
411 	}
LookupSynonymWord(const gchar * sWord,glong & iSynonymIndex,glong & synidx_suggest,size_t iLib,int servercollatefunc)412 	bool LookupSynonymWord(const gchar* sWord, glong& iSynonymIndex, glong &synidx_suggest, size_t iLib, int servercollatefunc) {
413 		return oLib[iLib]->LookupSynonym(sWord, iSynonymIndex, synidx_suggest, CollationLevel, servercollatefunc);
414 	}
415 	bool LookupSimilarWord(const gchar* sWord, glong &iWordIndex, glong &idx_suggest, size_t iLib, int servercollatefunc);
416 	bool LookupSynonymSimilarWord(const gchar* sWord, glong &iSynonymWordIndex, glong &synidx_suggest, size_t iLib, int servercollatefunc);
417 	bool SimpleLookupWord(const gchar* sWord, glong &iWordIndex, glong &idx_suggest, size_t iLib, int servercollatefunc);
418 	bool SimpleLookupSynonymWord(const gchar* sWord, glong &iWordIndex, glong &synidx_suggest, size_t iLib, int servercollatefunc);
GetOrigWordCount(glong & iWordIndex,size_t iLib,bool isidx)419 	gint GetOrigWordCount(glong& iWordIndex, size_t iLib, bool isidx) {
420 		return oLib[iLib]->GetOrigWordCount(iWordIndex, isidx);
421 	}
GetWordPrev(glong iWordIndex,glong & pidx,size_t iLib,bool isidx,int servercollatefunc)422 	bool GetWordPrev(glong iWordIndex, glong &pidx, size_t iLib, bool isidx, int servercollatefunc) {
423 		return oLib[iLib]->GetWordPrev(iWordIndex, pidx, isidx, CollationLevel, servercollatefunc);
424 	}
GetWordNext(glong & iWordIndex,size_t iLib,bool isidx,int servercollatefunc)425 	void GetWordNext(glong &iWordIndex, size_t iLib, bool isidx, int servercollatefunc) {
426 		oLib[iLib]->GetWordNext(iWordIndex, isidx, CollationLevel, servercollatefunc);
427 	}
428 
429 	bool LookupWithFuzzy(const gchar *sWord, gchar *reslist[], gint reslist_size, std::vector<InstantDictIndex> &dictmask);
430 	gint LookupWithRule(const gchar *sWord, gchar *reslist[], std::vector<InstantDictIndex> &dictmask);
431 	gint LookupWithRegex(const gchar *sWord, gchar *reslist[], std::vector<InstantDictIndex> &dictmask);
432 
433 	typedef void (*updateSearchDialog_func)(gpointer data, gdouble fraction);
434 	bool LookupData(const gchar *sWord, std::vector<gchar *> *reslist, updateSearchDialog_func func, gpointer data, bool *cancel, std::vector<InstantDictIndex> &dictmask);
435 	StorageType GetStorageType(size_t iLib);
436 	FileHolder GetStorageFilePath(size_t iLib, const std::string &key);
437 	const char *GetStorageFileContent(size_t iLib, const std::string &key);
438 private:
439 	void init_collations();
440 	void free_collations();
441 	bool LookupSimilarWordTryWord(const gchar *sTryWord, const gchar *sWord,
442 		int servercollatefunc, size_t iLib,
443 		glong &iIndex, glong &idx_suggest, gint &best_match);
444 	/* Validate and fix collate parameters */
445 	static void ValidateCollateParams(CollationLevelType& level, CollateFunctions& func);
446 
447 	std::vector<Dict *> oLib;
448 	int iMaxFuzzyDistance;
449 	show_progress_t *show_progress;
450 	bool CreateCacheFile;
451 	CollationLevelType CollationLevel;
452 	CollateFunctions CollateFunction;
453 	static show_progress_t default_show_progress;
454 
455 #ifdef SD_SERVER_CODE
456 	struct DictInfoItem;
457 	struct DictInfoDirItem {
~DictInfoDirItemDictInfoDirItem458 		~DictInfoDirItem() {
459 			for (std::list<DictInfoItem *>::iterator i = info_item_list.begin(); i!= info_item_list.end(); ++i) {
460 				delete (*i);
461 			}
462 		}
463 		std::string info_string;
464 		std::string name;
465 		std::string dirname;
466 		unsigned int dictcount;
467 		std::list<DictInfoItem *> info_item_list;
468 	};
469 	struct DictInfoDictItem {
470 		std::string info_string;
471 		std::string short_info_string;
472 		std::string uid;
473 		std::string download;
474 		std::string from;
475 		std::string to;
476 		unsigned int level;
477 		unsigned int id;
478 	};
479 	struct DictInfoItem {
~DictInfoItemDictInfoItem480 		~DictInfoItem() {
481 			if (isdir == 1)
482 				delete dir;
483 			else if (isdir == 0)
484 				delete dict;
485 		}
486 		int isdir;
487 		union {
488 			DictInfoDirItem *dir;
489 			DictInfoDictItem *dict;
490 			std::string *linkuid;
491 		};
492 	};
493 	DictInfoItem *root_info_item;
494 	std::map<std::string, DictInfoDictItem *> uidmap;
495 	void LoadXMLDir(const char *dir, DictInfoItem *info_item);
496 	void GenLinkDict(DictInfoItem *info_item);
497 
498 	struct ParseUserData {
499 		Libs *oLibs;
500 		const char *dir;
501 		DictInfoItem *info_item;
502 		bool indict;
503 		std::string path;
504 		std::string uid;
505 		std::string level;
506 		std::string download;
507 		std::string from;
508 		std::string to;
509 		bool inlinkdict;
510 		std::string linkuid;
511 	};
512 	static void func_parse_start_element(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error);
513 	static void func_parse_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error);
514 	static void func_parse_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error);
515 
516 	struct FromToInfo {
517 		std::string uid;
518 		std::string bookname;
519 	};
520 	struct FromTo {
521 		std::string to;
522 		std::list<FromToInfo> fromto_info;
523 	};
524 	std::string cache_fromto;
525 	void gen_fromto_info(struct DictInfoItem *info_item, std::map<std::string, std::list<FromTo> > &map_fromto);
526 #endif
527 };
528 
529 
530 #endif//!_STDDICT_HPP_
531