Add skeleton for target dictionary bin map generation
[mim] / util / converter.py
1 #!/usr/bin/python
2 ########################################################################
3 ##
4 ##  Copyright (C) 2009  MiM
5 ##
6 ##          Contact: Handspring <xhealer@gmail.com>
7 ##
8 ##          AUTHOR: Alsor Zhou <alsor.zhou@gmail.com>
9 ##
10 ##  This file is part of MiM Pinyin.
11 ##
12 ##  This is free software: you can redistribute it and/or modify
13 ##  it under the terms of the GNU General Public License as published by
14 ##  the Free Software Foundation, either version 3 of the License, or
15 ##  (at your option) any later version.
16 ##
17 ##  This is distributed in the hope that it will be useful,
18 ##  but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ##  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ##  GNU General Public License for more details.
21 ##
22 ##  You should have received a copy of the GNU General Public License
23 ##  along with Sigil.  If not, see <http://www.gnu.org/licenses/>.
24 ##
25 ########################################################################
26
27 import getopt
28 import sys
29 import os.path
30 import zlib
31
32 DEBUG           = True
33
34 # Global ERROR DEFINATION
35 ERR_PARAMS      = 2
36 ERR_UNKOWN      = 255
37
38 def PRINT(v):
39     '''Print wrapper with debug function supported
40     
41     Never use this function in production (always output) code '''
42     if DEBUG == True:
43         print v
44         
45 def license():
46     '''
47 Copyright (C) 2009  MiM
48
49       Contact: Handspring <xhealer@gmail.com>
50
51       AUTHOR:
52
53 This file is part of MiM Pinyin.
54
55 This is free software: you can redistribute it and/or modify
56 it under the terms of the GNU General Public License as published by
57 the Free Software Foundation, either version 3 of the License, or
58 (at your option) any later version.
59
60 This is distributed in the hope that it will be useful,
61 but WITHOUT ANY WARRANTY; without even the implied warranty of
62 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
63 GNU General Public License for more details.
64
65 You should have received a copy of the GNU General Public License
66 along with Sigil.  If not, see <http://www.gnu.org/licenses/>.
67     '''
68     print license.__doc__
69
70 def usage():
71     '''converter.py [options] SRC [options...DEST]
72     -s SRC  :   specify dictionary source
73     -t DEST :   save converted binary map into DEST
74     -c SRC  :   syntax check SRC, without converstion
75     -d DEST :   generate dummy dictionary bin map
76
77     GNU long option style
78     --source SRC : same with '-s SRC'
79     --target DEST: same with '-t DEST'    
80     --check  SRC : same with '-c SRC'
81     --dummy  DEST: same with '-d DEST'
82     '''
83     print usage.__doc__
84
85 def version():
86     '''MiM pinyin dictionary converter version 0.0.1 Handspring <xhealer@gmail.com>'''
87     print version.__doc__
88     
89 # Target file segmentation layout
90 tgt_delimitor           = "\n"
91 tgt_file_start_index    = 0
92 tgt_header_start_offset = 0
93 tgt_st1_offset          = 100
94 tgt_st2_offset          = 200
95 tgt_table_a_offset      = 300
96 tgt_table_b_offset      = 400
97
98 tgt_global_position_ind = 0
99 # Header definition
100 #  Example header fileds:
101 #    Fn:dictionary.bin\n
102 #    Ver:0.2\n
103 #    Authors:Jackson\n
104 #    ActiveChunkTableFlag:A\n
105 #    ChunkTableAOffset:300
106 #    ChunkTableBOffset:400
107 #    ChunkSize:65535\n
108 #    CRC32:\n
109 tgt_header_delemitor_str = ":"
110 tgt_header_fn_str        = "Fn"
111 tgt_header_version_str   = "Ver"
112 tgt_header_author_str    = "Authors"
113 tgt_header_actf_str      = "ActiveChunkTableFlag"
114 tgt_header_ctao_str      = "ChunkTableAOffset"
115 tgt_header_ctbo_str      = "ChunkTableBOffset"
116 tgt_header_chunk_size_str= "ChunkSize"
117 tgt_header_crc_str       = "CRC32"
118
119 # Chunk Table offset
120 tgt_ctable_flag_offset           = 0
121 tgt_ctable_flag_fld_siz          = 2   # bytes
122 tgt_ctable_chk_base_offset       = 2
123 tgt_ctable_chk_base_fld_size     = 2   # bytes, 65535 maximize
124 tgt_ctable_chk_acroyn_fld_size   = 2
125 tgt_ctable_chk_offset_fld_size   = 2
126 tgt_ctable_chk_size_fld_size     = 2
127
128 # Internal function definition
129 def generate_header(fn, ver, authors, actf, ctao, ctbo, csize):
130     '''Generate target file header.
131     @param fn: file name
132     @param ver: dictionary version
133     @param authors: dictionary authors
134     @param actf: active chunk table flag (A/B) 
135     @param ctao: chunk table A offset
136     @param ctbo: chunk table B offset
137     @param csize: chunk size (fixed)
138     
139     @return header: header string with crc32 computed
140     '''
141     crc32  = None
142     header = None
143     header += tgt_header_fn_str + tgt_header_delemitor_str + fn + tgt_delimitor
144     header += tgt_header_version_str + tgt_header_delemitor_str + ver + tgt_delimitor
145     header += tgt_header_version_str + tgt_header_delemitor_str + authors + tgt_delimitor
146     crc32  = crc32(header); # FIXME: should we crc the timestamp?
147     header += tgt_header_version_str + tgt_header_delemitor_str + actf + tgt_delimitor
148     header += tgt_header_version_str + tgt_header_delemitor_str + ctao + tgt_delimitor
149     header += tgt_header_version_str + tgt_header_delemitor_str + ctbo + tgt_delimitor
150     header += tgt_header_version_str + tgt_header_delemitor_str + csize + tgt_delimitor
151     header += tgt_header_version_str + tgt_header_delemitor_str + crc32
152     
153     PRINT(generate_header.__doc__)
154     return header
155
156 def generate_st1():
157     '''Generate static table 1.
158     '''
159     PRINT(generate_st1.__doc__)
160
161 def generate_st2():
162     '''Generate static table 2.
163     '''
164     PRINT(generate_st2.__doc__)
165
166 def generate_ctable_a():
167     '''Chunk Table A generation.
168     Example chunk table:
169     0------------2------------4--------6--------8------10-------12-------14----16
170     | Table flag | Chunk Base | Acroyn | Offset | Size | Acroyn | Offset | Size |  
171     '''
172     PRINT(generate_ctable_a.__doc__)
173
174 def generate_ctable_b():
175     '''Chunk Table B generation.
176     Example chunk table:
177     0------------2------------4--------6--------8------10-------12-------14----16
178     | Table flag | Chunk Base | Acroyn | Offset | Size | Acroyn | Offset | Size |  
179     '''
180     PRINT(generate_ctable_b.__doc__)
181
182 def generate_dictionary():
183     '''
184     Normally, target data file have 2 dictionary map for data integrity. The 
185     active map is used for memory holding, and reflash the inactivie map under 
186     some mechanism.
187     '''
188     PRINT(generate_dictionary.__doc__)
189
190 def gen_dummy_dict_binmap():
191     '''Generate dummy dictionary bin map.
192     
193     '''
194     generate_header("dictionary.bin", "0.2", "Jackson", "A", 300, 400, 65535);
195     PRINT(gen_dummy_dict_binmap.__doc__)
196
197 def convert(src, dest):
198     '''Convertion from original text format dictionary to binary map.
199     
200     @param  src : text format dictionary
201     @param  dest: binary map dictionary
202     
203     @return None
204     '''
205     PRINT(convert.__doc__)
206
207 def check(src):
208     '''Check syntax format of orignal text format dictionary
209     
210     @param  src : text format dictionary
211     
212     @return True without syntax error, False else.
213     '''
214     PRINT(check.__doc__)
215     
216 def main(argv):
217     '''Main business logic
218     
219     @param  argv : sys.argv[1:]
220     @return error code if any
221     '''
222
223     # handle parameter parse
224     valid_args = "hvVt:c:s:d"
225     valid_long_args = ["help", "version", "source", "target", "check", "dummy"]
226     src = None
227     dest = None
228     
229     try:
230         opts, args = getopt.getopt(argv, valid_args, valid_long_args)
231     except getopt.GetoptError, err:
232         print str(err)
233         license()
234         usage()
235         sys.exit(ERR_PARAMS)
236     output = None
237     verbose = False
238     for o, a in opts:
239         if o in ("-s", "--source"):
240             if a == None:
241                 assert False, "No dictionary source specified"
242                 usage()
243                 sys.exit(ERR_PARAMS)
244             # no dest specified, use same filename as src to store file
245             if dest == None:
246                 basename = os.path.basename(src)
247                 dest = os.path.splitext(basename)[0]
248                 dest = os.path.join(dest, ".bin")
249             src = a
250             convert(src, dest)
251         elif o in ("-t", "--target"):
252             dest = a
253         elif o in ("-d", "--dummy"):
254             gen_dummy_dict_binmap()
255         elif o in ("-c", "--check"):
256             check(a)
257         elif o == "-v":
258             verbose = True
259         elif o in ("-h", "--help"):
260             usage()
261             sys.exit()
262         elif o in ("-V", "--version"):
263             version()
264         else:
265             usage()
266
267 if __name__ == "__main__":
268     main(sys.argv[1:])