Tizen 2.1 base
[platform/core/uifw/ise-engine-sunpinyin.git] / src / slm / tslmendian / slm_file.cpp
1 /*
2  * Copyright (c) 2009 Kov Chai <tchaikov@gmail.com>
3  *
4  * The contents of this file are subject to the terms of either the GNU Lesser
5  * General Public License Version 2.1 only ("LGPL") or the Common Development and
6  * Distribution License ("CDDL")(collectively, the "License"). You may not use this
7  * file except in compliance with the License. You can obtain a copy of the CDDL at
8  * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
9  * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
10  * specific language governing permissions and limitations under the License. When
11  * distributing the software, include this License Header Notice in each file and
12  * include the full text of the License in the License file as well as the
13  * following notice:
14  *
15  * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
16  * (CDDL)
17  * For Covered Software in this distribution, this License shall be governed by the
18  * laws of the State of California (excluding conflict-of-law provisions).
19  * Any litigation relating to this License shall be subject to the jurisdiction of
20  * the Federal Courts of the Northern District of California and the state courts
21  * of the State of California, with venue lying in Santa Clara County, California.
22  *
23  * Contributor(s):
24  *
25  * If you wish your version of this file to be governed by only the CDDL or only
26  * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
27  * include this software in this distribution under the [CDDL or LGPL Version 2.1]
28  * license." If you don't indicate a single choice of license, a recipient has the
29  * option to distribute your version of this file under either the CDDL or the LGPL
30  * Version 2.1, or to extend the choice of license to its licensees as provided
31  * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
32  * Version 2 license, then the option applies only if the new code is made subject
33  * to such option by the copyright holder.
34  */
35
36 /*
37  * the layout of binary file
38  * - N : uin23_t
39  * - usingLogPr : uint32_t
40  * - slm.getLevelSize(0..N) : uint32_t * N
41  * - pr_table() : float * 1<<CThreadSlm::BITS_PR    # padding with 0.0F
42  * - bow_table() : float * 1 <<CThreadSlm::BITS_BOW # padding with 0.0F
43  * - node[0][] : CThreadSlm::TNode * slm.getLevelSize(0)
44  * - node[1][] : CThreadSlm::TNode * slm.getLevelSize(1)
45  * - ...
46  * - node[N-1][] : CThreadSlm::TNode * slm.getLevelSize(N-1)
47  * - leaf[N-1][] : CThreadSlm::TLeaf * slm.getLevelSize(N)
48  */
49
50 #include <arpa/inet.h>
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <fcntl.h>
54 #include <unistd.h>
55 #include <numeric>
56 #include <algorithm>
57 #include <iostream>
58 #include <cassert>
59
60
61 #include "slm_file.h"
62 #include "writer.h"
63
64 using namespace std;
65
66 // for convenience
67 typedef CThreadSlm::TNode TNode;
68 typedef CThreadSlm::TLeaf TLeaf;
69
70 // byte order reversed CThreadSlm::TLeaf small-endian presentation on big-endian machine
71 // 5-bits padding before m_pr_lo so that m_pr_lo is 4-byte aligned
72 //
73 // would be easier if m_bon is 28 bits long
74 struct Leaf_BE {
75     unsigned m_wid       : 18;
76     unsigned m_pr_lo     : 14;
77     unsigned padding     : 5;
78     unsigned m_bon       : 23;
79     unsigned m_bol       : 2;
80     unsigned m_pr_hi     : 2;
81 };
82
83 CThreadSlm::TLeaf
84 leaf_betole(const CThreadSlm::TLeaf& v)
85 {
86     // since the CThreadSlm::TLeaf `protects' its bits, we duplicated a `public' one
87     struct Leaf_LE_ {
88         unsigned m_wid       : 18;
89         unsigned m_pr_lo     : 14;
90         unsigned m_bon       : 23;
91         unsigned m_bol       : 2;
92         unsigned m_pr_hi     : 2;
93     };
94
95     Leaf_BE be_leaf = change_byte_order(*(Leaf_BE*)(&v));
96     be_leaf.padding = 0;
97
98     TLeaf leaf;
99     Leaf_LE_* le_leaf = (Leaf_LE_*)(&leaf);
100     le_leaf->m_wid = be_leaf.m_wid;
101     le_leaf->m_pr_lo = be_leaf.m_pr_lo;
102     le_leaf->m_bon = be_leaf.m_bon;
103     le_leaf->m_bol = be_leaf.m_bol;
104     le_leaf->m_pr_hi = be_leaf.m_pr_hi;
105     return leaf;
106 }
107
108 // byte order reversed little-endian presentation
109 // 5-bits padding at end of struct
110 struct Leaf_LE_ {
111     unsigned padding     : 5;
112     unsigned m_pr_hi     : 2;
113     unsigned m_bol       : 2;
114     unsigned m_bon       : 23;
115     unsigned m_pr_lo     : 14;
116     unsigned m_wid       : 18;
117 };
118
119 TLeaf
120 leaf_letobe(const TLeaf& v)
121 {
122     // since the TLeaf `protects' its bits, we duplicated a `public' one
123     struct Leaf_BE_ {
124         unsigned m_pr_hi     : 2;
125         unsigned m_bol       : 2;
126         unsigned m_bon       : 23;
127         unsigned m_pr_lo     : 14;
128         unsigned m_wid       : 18;
129     };
130
131
132     Leaf_LE_ le_leaf = change_byte_order(*(Leaf_LE_*)(&v));
133     le_leaf.padding = 0;
134
135     TLeaf leaf;
136     Leaf_BE_* be_leaf = (Leaf_BE_*)(&leaf);
137     be_leaf->m_wid = le_leaf.m_wid;
138     be_leaf->m_pr_lo = le_leaf.m_pr_lo;
139     be_leaf->m_bon = le_leaf.m_bon;
140     be_leaf->m_bol = le_leaf.m_bol;
141     be_leaf->m_pr_hi = le_leaf.m_pr_hi;
142     return leaf;
143 }
144
145 template<typename Type>
146 Type
147 read_value(char*& buf, bool do_swap)
148 {
149     Type v = *(Type*)buf;
150     if (do_swap) {
151         v = change_byte_order(v);
152     }
153     buf += sizeof(v);
154     return v;
155 }
156
157 // change the byte order of all elements in the array in place
158 template<typename Type>
159 Type*
160 read_values(char*& buf, size_t len, bool do_swap)
161 {
162     Type* begin = (Type*)buf;
163     Type* end = begin + len;
164
165     if (do_swap) {
166         for (Type* p = begin; p != end; ++p) {
167             *p = change_byte_order(*p);
168         }
169     }
170     buf = (char*)end;
171     return begin;
172 }
173
174
175 typedef TLeaf (*convert_func_t)(const TLeaf&);
176
177 template<>
178 TLeaf* read_values<TLeaf
179                    >(char*& buf, size_t len, bool do_swap)
180 {
181     TLeaf* begin = (TLeaf*)buf;
182     TLeaf* end = begin + len;
183     convert_func_t convert =
184         (CThreadSlmFile::getHostEndian() ==
185          BIG_ENDIAN) ? leaf_letobe : leaf_betole;
186
187     if (do_swap) {
188         for (TLeaf* p = begin; p != end; ++p) {
189             *p = convert(*p);
190         }
191     }
192     buf = (char*)end;
193     return begin;
194 }
195
196 template<typename Type>
197 size_t
198 write_value(FILE* fp, const Type& value, bool do_swap)
199 {
200     Type v = value;
201     if (do_swap) {
202         v = change_byte_order(v);
203     }
204     return fwrite(&v, sizeof(v), 1, fp) * sizeof(v);
205 }
206
207 template<typename Type>
208 size_t
209 write_values(FILE* fp, Type* const begin, size_t len, bool do_swap)
210 {
211     const Type* end = begin + len;
212     if (do_swap) {
213         for (Type* p = begin; p != end; ++p) {
214             *p = change_byte_order(*p);
215         }
216     }
217     return fwrite(begin, sizeof(Type), end - begin, fp) * sizeof(Type);
218 }
219
220 template<>
221 size_t write_values<TLeaf
222                     >(FILE* fp, TLeaf* const begin, size_t len, bool do_swap)
223 {
224     const TLeaf* end = begin + len;
225     convert_func_t convert =
226         (CThreadSlmFile::getHostEndian() ==
227          BIG_ENDIAN) ? leaf_betole : leaf_letobe;
228     if (do_swap) {
229         for (TLeaf* p = begin; p != end; ++p) {
230             *p = convert(*p);
231         }
232     }
233     return fwrite(begin, sizeof(TLeaf), end - begin, fp) * sizeof(TLeaf);
234 }
235
236 CThreadSlmFile::CThreadSlmFile()
237     : m_buf(NULL),
238       m_N(0), m_usingLogPr(0), m_levelSizes(NULL), m_prTable(NULL),
239       m_bowTable(NULL),
240       m_nnode(0), m_nodes(NULL), m_nleaf(0), m_leafs(NULL)
241 {
242 }
243
244 // TODO: may need consolidate this class with CThreadSlm
245 bool
246 CThreadSlmFile::load(const char* fname)
247 {
248     assert(m_buf == NULL);
249
250     int fd = open(fname, O_RDONLY);
251     ssize_t len = lseek(fd, 0, SEEK_END);
252     lseek(fd, 0, SEEK_SET);
253     m_buf = new char[len];
254     if (read(fd, m_buf, len) != len) {
255         delete [] m_buf;
256         m_buf = NULL;
257         cerr << "Failed to read from " << fname << endl;
258         return false;
259     }
260     close(fd);
261
262     char* buf = m_buf;
263     bool do_swap = (getEndian() != getHostEndian());
264
265     m_N = read_value<uint32_t>(buf, do_swap);
266     m_usingLogPr = read_value<uint32_t>(buf, do_swap);
267
268     m_levelSizes = read_values<uint32_t>(buf, m_N + 1, do_swap);
269     m_prTable = read_values<float>(buf, 1 << CThreadSlm::BITS_PR, do_swap);
270     m_bowTable = read_values<float>(buf, 1 << CThreadSlm::BITS_BOW, do_swap);
271
272     m_nnode = accumulate(m_levelSizes, m_levelSizes + m_N, 0);
273     m_nodes = read_values<TNode>(buf, m_nnode, do_swap);
274     m_nleaf = m_levelSizes[m_N];
275     m_leafs = read_values<TLeaf>(buf, m_nleaf, do_swap);
276
277     m_bufLen = len;
278     return(m_buf + len == buf);
279 }
280
281 size_t
282 CThreadSlmFile::save(const char* fname, int endian)
283 {
284     bool do_swap = (endian != getHostEndian());
285     FILE* fp = fopen(fname, "wb");
286     size_t nwrite = 0;
287     nwrite += write_value(fp, m_N, do_swap);
288     nwrite += write_value(fp, m_usingLogPr, do_swap);
289     nwrite += write_values(fp, m_levelSizes, m_N + 1, do_swap);
290     nwrite += write_values(fp, m_prTable, 1 << CThreadSlm::BITS_PR, do_swap);
291     nwrite += write_values(fp, m_bowTable, 1 << CThreadSlm::BITS_BOW, do_swap);
292     nwrite += write_values(fp, m_nodes, m_nnode, do_swap);
293     nwrite += write_values(fp, m_leafs, m_nleaf, do_swap);
294     fclose(fp);
295     return nwrite;
296 }
297
298 size_t
299 CThreadSlmFile::size() const
300 {
301     return m_bufLen;
302 }
303
304 CThreadSlmFile::~CThreadSlmFile()
305 {
306     delete [] m_buf;
307     m_buf = NULL;
308 }
309
310 int
311 CThreadSlmFile::getEndian() const
312 {
313     assert(m_buf != NULL);
314     // assuming the N of this lm is not larger than 0x0100 0000
315     return (*(uint8_t*)m_buf) == 0 ? BIG_ENDIAN : LITTLE_ENDIAN;
316 }
317
318 int
319 CThreadSlmFile::getHostEndian()
320 {
321     return htons(0x0001) == 0x0100 ? LITTLE_ENDIAN : BIG_ENDIAN;
322 }
323