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 /*
21  * Implementation of class to work with GtkTree
22  * based StarDict's dictionaries
23  */
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27 
28 #include <cstring>
29 #include "file-utils.h"
30 #include "utils.h"
31 
32 #include "treedict.h"
33 
34 GtkTreeStore *TreeDict::model=NULL;
35 
TreeDict()36 TreeDict::TreeDict()
37 {
38 	if (model)
39 		return;
40 
41 	// It is said G_TYPE_UINT will always be 32 bit.
42 	// see http://bugzilla.gnome.org/show_bug.cgi?id=337966
43 	model = gtk_tree_store_new (3, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT); //word, offset, size
44 }
45 
load(const std::string & ifofilename)46 bool TreeDict::load(const std::string& ifofilename)
47 {
48 	gulong tdxfilesize;
49 	if (!load_ifofile(ifofilename, &tdxfilesize))
50 		return false;
51 
52 	if(!DictBase::load(ifofilename.substr(0, ifofilename.length()-sizeof(".ifo")+1),
53 		"dict"))
54 		return false;
55 
56 	std::string fullfilename(ifofilename);
57 	fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "tdx.gz");
58 
59 	gchar *buffer= NULL;
60 	if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) {
61 		gzFile in;
62 		in = gzopen(fullfilename.c_str(),"rb");
63 		if (in == NULL) {
64 			//g_print("Open file %s failed!\n",idxfilename);
65 			return false;
66 		}
67 
68 		buffer = (gchar *)g_malloc(tdxfilesize);
69 
70 		gulong len;
71 		len = gzread(in, buffer, tdxfilesize);
72 		if (len < 0) {
73 			g_free(buffer);
74 			return false;
75 		}
76 		gzclose(in);
77 		if (len != tdxfilesize) {
78 			g_free(buffer);
79 			return false;
80 		}
81 	} else {
82 		fullfilename.erase(fullfilename.length()-sizeof(".gz")+1, sizeof(".gz")-1);
83 		FILE *file;
84 		if (!(file = fopen (fullfilename.c_str(), "rb"))) {
85 			//g_print("Open file %s failed!\n",fullfilename);
86 			return false;
87 		}
88 		buffer = (gchar *)g_malloc(tdxfilesize);
89 		gulong read_len;
90 		read_len = fread(buffer, 1, tdxfilesize, file);
91 		fclose(file);
92 		if (read_len!=tdxfilesize) {
93 			g_free(buffer);
94 			return false;
95 		}
96 	}
97 
98 	gchar *tmp_buffer = buffer;
99 	load_model(&tmp_buffer, NULL, 1); // tmp_buffer will be changed.
100 	g_free(buffer);
101 	return true;
102 }
103 
load_ifofile(const std::string & ifofilename,gulong * tdxfilesize)104 bool TreeDict::load_ifofile(const std::string& ifofilename, gulong *tdxfilesize)
105 {
106 	DictInfo dict_info;
107 	if (!dict_info.load_from_ifo_file(ifofilename, DictInfoType_TreeDict))
108 		return false;
109 
110 	*tdxfilesize = dict_info.get_index_file_size();
111 	sametypesequence=dict_info.get_sametypesequence();
112 
113 	return true;
114 }
115 
load_model(gchar ** buffer,GtkTreeIter * parent,guint32 count)116 void TreeDict::load_model(gchar **buffer, GtkTreeIter *parent, guint32 count)
117 {
118 	GtkTreeIter iter;
119 	gchar *p1;
120 	guint32 offset, size, subentry_count;
121 
122 	for (guint32 i=0; i< count; i++) {
123 		p1 = *buffer + strlen(*buffer) +1;
124 		offset = g_ntohl(get_uint32(p1));
125 		p1 += sizeof(guint32);
126 		size = g_ntohl(get_uint32(p1));
127 		p1 += sizeof(guint32);
128 		subentry_count = g_ntohl(get_uint32(p1));
129 		p1 += sizeof(guint32);
130 		gtk_tree_store_append(model, &iter, parent);
131 		gtk_tree_store_set(model, &iter, 0, *buffer, 1, offset, 2, size, -1);
132 		*buffer = p1;
133 		if (subentry_count)
134 			load_model(buffer, &iter, subentry_count);
135 	}
136 }
137 
138 
139 /**************************************************/
TreeDicts()140 TreeDicts::TreeDicts()
141 {
142 }
143 
~TreeDicts()144 TreeDicts::~TreeDicts()
145 {
146 	for (std::vector<TreeDict *>::iterator it=oTreeDict.begin();
147 	     it!=oTreeDict.end(); ++it)
148 		delete *it;
149 }
150 
load_dict(const std::string & url)151 void TreeDicts::load_dict(const std::string& url)
152 {
153 	TreeDict *lib = new TreeDict;
154 	if (lib->load(url))
155 		oTreeDict.push_back(lib);
156 	else
157 		delete lib;
158 }
159 
160 class TreeDictLoader {
161 public:
TreeDictLoader(TreeDicts & td_)162 	TreeDictLoader(TreeDicts& td_) : td(td_) {}
operator ()(const std::string & url,bool disable)163 	void operator()(const std::string& url, bool disable) {
164 		if (!disable)
165 			td.load_dict(url);
166 	}
167 private:
168 	TreeDicts& td;
169 };
170 
Load(const strlist_t & tree_dicts_dirs,const strlist_t & order_list,const strlist_t & disable_list)171 GtkTreeStore* TreeDicts::Load(const strlist_t& tree_dicts_dirs,
172 			      const strlist_t& order_list,
173 			      const strlist_t& disable_list)
174 {
175 	TreeDictLoader load(*this);
176 	for_each_file(tree_dicts_dirs, ".ifo", order_list, disable_list, load);
177 
178 	return TreeDict::get_model();
179 }
180 
poGetWordData(guint32 offset,guint32 size,int iTreeDict)181 gchar* TreeDicts::poGetWordData(guint32 offset, guint32 size, int iTreeDict)
182 {
183 	return oTreeDict[iTreeDict]->GetWordData(offset, size);
184 }
185