• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Winner Microelectronics Co., Ltd. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <time.h>
17 #include <stdio.h>
18 #include <errno.h>
19 #include <ctype.h>
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <getopt.h>
24 #include <dirent.h>
25 #include <unistd.h>
26 #include <stdarg.h>
27 #ifdef __MINGW32__
28 #include <windows.h>
29 #else
30 #include <signal.h>
31 #include <pthread.h>
32 #include <termios.h>
33 #include <sys/ioctl.h>
34 #endif
35 
36 #define WM_TOOL_PATH_MAX                      256
37 #define WM_TOOL_ONCE_READ_LEN                 1024
38 
39 #define WM_TOOL_RUN_IMG_HEADER_LEN            0x100
40 
41 #define WM_TOOL_SECBOOT_IMG_ADDR             (0x2100)
42 #define WM_TOOL_SECBOOT_HEADER_LEN           (0x100)
43 #define WM_TOOL_SECBOOT_HEADER_POS           (WM_TOOL_SECBOOT_IMG_ADDR - WM_TOOL_SECBOOT_HEADER_LEN)
44 
45 #define WM_TOOL_IMG_HEAD_MAGIC_NO            (0xA0FFFF9F)
46 
47 #define WM_TOOL_DEFAULT_BAUD_RATE             115200
48 
49 #define WM_TOOL_DOWNLOAD_TIMEOUT_SEC          (60 * 1)
50 
51 #define WM_TOOL_USE_1K_XMODEM                  1  /* 1 for use 1k_xmodem 0 for xmodem */
52 
53 #define WM_TOOL_IMAGE_VERSION_LEN              16
54 
55 /* Xmodem Frame form: <SOH><blk #><255-blk #><--128 data bytes--><CRC hi><CRC lo> */
56 #define XMODEM_SOH 0x01
57 #define XMODEM_STX 0x02
58 #define XMODEM_EOT 0x04
59 #define XMODEM_ACK 0x06
60 #define XMODEM_NAK 0x15
61 #define XMODEM_CAN 0x18
62 #define XMODEM_CRC_CHR 'C'
63 #define XMODEM_CRC_SIZE 2      /* Crc_High Byte + Crc_Low Byte */
64 #define XMODEM_FRAME_ID_SIZE 2 /* Frame_Id + 255-Frame_Id */
65 #define XMODEM_DATA_SIZE_SOH 128   /* for Xmodem protocol */
66 #define XMODEM_DATA_SIZE_STX 1024 /* for 1K xmodem protocol */
67 
68 #if (WM_TOOL_USE_1K_XMODEM)
69 #define XMODEM_DATA_SIZE  XMODEM_DATA_SIZE_STX
70 #define XMODEM_HEAD XMODEM_STX
71 #else
72 #define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_SOH
73 #define XMODEM_HEAD XMODEM_SOH
74 #endif
75 
76 #ifdef WM_DEBUG
77 #define WM_TOOL_DBG_PRINT       wm_tool_printf
78 #else
79 #define WM_TOOL_DBG_PRINT(...)
80 #endif
81 
82 typedef enum {
83     WM_TOOL_DL_ACTION_NONE = 0,
84     WM_TOOL_DL_ACTION_AT,
85     WM_TOOL_DL_ACTION_RTS
86 } wm_tool_dl_action_e;
87 
88 typedef enum {
89     WM_TOOL_DL_ERASE_NONE = 0,
90     WM_TOOL_DL_ERASE_ALL
91 } wm_tool_dl_erase_e;
92 
93 typedef enum {
94     WM_TOOL_DL_TYPE_IMAGE = 0,
95     WM_TOOL_DL_TYPE_FLS
96 } wm_tool_dl_type_e;
97 
98 typedef enum {
99     WM_TOOL_LAYOUT_TYPE_1M = 0,
100     WM_TOOL_LAYOUT_TYPE_2M = 3
101 } wm_tool_layout_type_e;
102 
103 typedef enum {
104     WM_TOOL_ZIP_TYPE_UNCOMPRESS = 0,
105     WM_TOOL_ZIP_TYPE_COMPRESS
106 } wm_tool_zip_type_e;
107 
108 typedef enum {
109     WM_TOOL_CRC32_REFLECT_OUTPUT = 1,
110     WM_TOOL_CRC32_REFLECT_INPUT  = 2
111 } wm_tool_crc32_reflect_e;
112 
113 typedef enum {
114     WM_TOOL_SHOW_LOG_NONE = 0,
115     WM_TOOL_SHOW_LOG_STR,
116     WM_TOOL_SHOW_LOG_HEX
117 } wm_tool_show_log_e;
118 
119 typedef struct {
120     unsigned int   magic_no;
121     unsigned short img_type;
122     unsigned short zip_type;
123     unsigned int   run_img_addr;
124     unsigned int   run_img_len;
125     unsigned int   img_header_addr;
126     unsigned int   upgrade_img_addr;
127     unsigned int   run_org_checksum;
128     unsigned int   upd_no;
129     unsigned char  ver[WM_TOOL_IMAGE_VERSION_LEN];
130     unsigned int   reserved0;
131     unsigned int   reserved1;
132     unsigned int   next_boot;
133     unsigned int   hd_checksum;
134 } wm_tool_firmware_booter_t;
135 
136 const static char *wm_tool_version = "1.0.4";
137 
138 static int wm_tool_show_usage = 0;
139 static int wm_tool_list_com   = 0;
140 static int wm_tool_show_ver   = 0;
141 
142 static char wm_tool_serial_path[WM_TOOL_PATH_MAX] = "/dev/ttyS0";
143 static unsigned int wm_tool_download_serial_rate  = WM_TOOL_DEFAULT_BAUD_RATE;
144 static unsigned int wm_tool_normal_serial_rate    = WM_TOOL_DEFAULT_BAUD_RATE;
145 
146 static wm_tool_dl_action_e wm_tool_dl_action = WM_TOOL_DL_ACTION_NONE;
147 static wm_tool_dl_erase_e  wm_tool_dl_erase  = WM_TOOL_DL_ERASE_NONE;
148 static wm_tool_dl_type_e   wm_tool_dl_type   = WM_TOOL_DL_TYPE_IMAGE;
149 static char *wm_tool_download_image = NULL;
150 
151 static char *wm_tool_input_binary = NULL;
152 static char *wm_tool_output_image = NULL;
153 static char *wm_tool_secboot_image = NULL;
154 static unsigned int wm_tool_src_binary_len = 0;
155 static unsigned int wm_tool_src_binary_crc = 0;
156 static int wm_tool_is_debug = 0;
157 static char wm_tool_image_version[WM_TOOL_IMAGE_VERSION_LEN];
158 static wm_tool_layout_type_e wm_tool_image_type = WM_TOOL_LAYOUT_TYPE_1M;
159 static wm_tool_zip_type_e wm_tool_zip_type = WM_TOOL_ZIP_TYPE_COMPRESS;
160 static unsigned int wm_tool_upd_addr = 0x8090000;
161 static unsigned int wm_tool_run_addr = 0x8002400;
162 
163 static unsigned int wm_tool_image_header = 0x8002000;
164 static unsigned int wm_tool_next_image_header = 0x0;
165 static unsigned int wm_tool_image_upd_no = 0x0;
166 
167 static unsigned int wm_tool_file_crc = 0xFFFFFFFF;
168 
169 static wm_tool_show_log_e wm_tool_show_log_type = WM_TOOL_SHOW_LOG_NONE;
170 
171 #ifdef __MINGW32__
172 
173 #ifndef CBR_2000000
174 #define CBR_2000000 2000000
175 #endif
176 
177 #ifndef CBR_1000000
178 #define CBR_1000000 1000000
179 #endif
180 
181 #ifndef CBR_921600
182 #define CBR_921600 921600
183 #endif
184 
185 #ifndef CBR_460800
186 #define CBR_460800 460800
187 #endif
188 
189 static DWORD wm_tool_uart_block = 0;
190 
191 static HANDLE wm_tool_uart_handle = NULL;
192 
193 const static int wm_tool_uart_speed_array[] = {CBR_2000000, CBR_1000000, CBR_921600, CBR_460800, CBR_115200, CBR_38400,
194                                                CBR_19200,   CBR_9600,    CBR_4800,   CBR_2400,   CBR_1200};
195 #else /* __MINGW32__ */
196 
197 #ifndef B2000000
198 #define B2000000 2000000
199 #endif
200 
201 #ifndef B1000000
202 #define B1000000 1000000
203 #endif
204 
205 #ifndef B921600
206 #define B921600 921600
207 #endif
208 
209 #ifndef B460800
210 #define B460800 460800
211 #endif
212 
213 static int wm_tool_uart_fd = -1;
214 
215 static struct termios wm_tool_saved_serial_cfg;
216 
217 const static int wm_tool_uart_speed_array[] = {B2000000, B1000000, B921600, B460800, B115200, B38400,
218                                                B19200,   B9600,    B4800,   B2400,   B1200};
219 
220 #endif /* __MINGW32__ */
221 
222 const static int wm_tool_uart_name_array[] = {2000000, 1000000, 921600, 460800, 115200, 38400,
223                                               19200,   9600,    4800,   2400,   1200};
224 
225 const static unsigned char wm_tool_chip_cmd_b115200[]  = {0x21, 0x0a, 0x00, 0x97, 0x4b, 0x31, \
226                                                           0x00, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00};
227 const static unsigned char wm_tool_chip_cmd_b460800[]  = {0x21, 0x0a, 0x00, 0x07, 0x00, 0x31, \
228                                                           0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x00};
229 const static unsigned char wm_tool_chip_cmd_b921600[]  = {0x21, 0x0a, 0x00, 0x5d, 0x50, 0x31, \
230                                                           0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00};
231 const static unsigned char wm_tool_chip_cmd_b1000000[] = {0x21, 0x0a, 0x00, 0x5e, 0x3d, 0x31, \
232                                                           0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00};
233 const static unsigned char wm_tool_chip_cmd_b2000000[] = {0x21, 0x0a, 0x00, 0xef, 0x2a, 0x31, \
234                                                           0x00, 0x00, 0x00, 0x80, 0x84, 0x1e, 0x00};
235 
236 const static unsigned char wm_tool_chip_cmd_get_mac[]  = {0x21, 0x06, 0x00, 0xea, 0x2d, 0x38, 0x00, 0x00, 0x00};
237 
238 static const unsigned int wm_tool_crc32_tab[] = {0x00000000L, 0x77073096L, 0xee0e612cL,
239     0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
240     0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL,
241     0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L,
242     0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L,
243     0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL,
244     0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L,
245     0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L,
246     0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L,
247     0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L,
248     0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L,
249     0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L,
250     0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL,
251     0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL,
252     0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L,
253     0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL,
254     0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L,
255     0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L,
256     0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL,
257     0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL,
258     0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL,
259     0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L,
260     0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL,
261     0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L,
262     0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L,
263     0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
264     0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L,
265     0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L,
266     0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L,
267     0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL,
268     0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L,
269     0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L,
270     0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L,
271     0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL,
272     0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L,
273     0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL,
274     0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L,
275     0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L,
276     0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L,
277     0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL,
278     0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL,
279     0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L,
280     0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL,
281     0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L,
282     0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L,
283     0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L,
284     0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL,
285     0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L,
286     0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L,
287     0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL,
288     0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L,
289     0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL};
290 
291 static void wm_tool_signal_proc_entry(void);
292 static void wm_tool_stdin_to_uart(void);
293 
294 /* ============================ zlib gzip ================================== */
295 
296 #define ALLOC(size) zcalloc((voidp)0, 1, size)
297 #define TRYFREE(p) {if (p) zcfree((voidp)0, p);}
298 
299 #define BINARY  0
300 #define ASCII   1
301 #define UNKNOWN 2
302 
303 #define STORED_BLOCK 0
304 #define STATIC_TREES 1
305 #define DYN_TREES    2
306 
307 #define REP_3_6      16
308 #define REPZ_3_10    17
309 #define REPZ_11_138  18
310 
311 #define MAX_BL_BITS 7
312 
313 #define BASE 65521 /* largest prime smaller than 65536 */
314 #define NMAX 5552
315 
316 #define DO1(buf)  do {
317     s1 += *buf++; \
318     s2 += s1; \
319 } while (0)
320 #define DO2(buf)  do {
321     DO1(buf); \
322     DO1(buf); \
323 } while (0)
324 #define DO4(buf)  do {
325     DO2(buf); \
326     DO2(buf); \
327 } while (0)
328 #define DO8(buf)  do {
329     DO4(buf); \
330     DO4(buf); \
331 } while (0)
332 #define DO16(buf) do {
333     DO8(buf); \
334     DO8(buf); \
335 } while (0)
336 
337 #define Z_OK            0
338 #define Z_STREAM_END    1
339 #define Z_ERRNO        (-1)
340 #define Z_STREAM_ERROR (-2)
341 #define Z_DATA_ERROR   (-3)
342 #define Z_MEM_ERROR    (-4)
343 #define Z_BUF_ERROR    (-5)
344 
345 #define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
346 
347 #define Z_BEST_SPEED             1
348 #define Z_BEST_COMPRESSION       9
349 #define Z_DEFAULT_COMPRESSION  (-1)
350 
351 #define DEFLATED   8
352 
353 #ifndef WBITS
354 # define WBITS   15 /* 32K window */
355 #endif
356 
357 #ifndef MEM_LEVEL
358 # define MEM_LEVEL  8
359 #endif
360 
361 #define Z_BUFSIZE 4096
362 
363 #define GZ_MAGIC_1 0x1f
364 #define GZ_MAGIC_2 0x8b
365 
366 #ifndef OS_CODE
367 #  define OS_CODE  0x03  /* assume Unix */
368 #endif
369 
370 #ifndef TOO_FAR
371 #  define TOO_FAR 4096
372 #endif
373 
374 #define Z_NO_FLUSH      0
375 #define Z_FINISH        4
376 
377 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
378 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
379 #define ORIG_NAME    0x08 /* bit 3 set: original file name present */
380 #define COMMENT      0x10 /* bit 4 set: file comment present */
381 #define RESERVED     0xE0 /* bits 5..7: reserved */
382 
383 #define LENGTH_CODES 29 /* number of length codes, not counting the special END_BLOCK code */
384 #define LITERALS  256 /* number of literal bytes 0..255 */
385 #define L_CODES (LITERALS+1+LENGTH_CODES) /* number of Literal or Length codes, including the END_BLOCK code */
386 #define D_CODES   30 /* number of distance codes */
387 #define BL_CODES  19 /* number of codes used to transfer the bit lengths */
388 #define HEAP_SIZE (2*L_CODES+1) /* maximum heap size */
389 
390 #define END_BLOCK 256
391 
392 #define MAX_BITS 15
393 
394 #define MAX_MEM_LEVEL 9
395 
396 #define MIN_MATCH  3
397 #define MAX_MATCH  258
398 
399 #define Z_UNKNOWN  2
400 
401 #define INIT_STATE    42
402 #define BUSY_STATE   113
403 #define FINISH_STATE 666
404 
405 #define NIL 0
406 
407 #define Z_FILTERED            1
408 #define Z_HUFFMAN_ONLY        2
409 #define Z_DEFAULT_STRATEGY    0
410 
411 #define SMALLEST 1
412 
413 #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
414 
415 #define UPDATE_HASH(s, h, c) ((h) = (((h)<<(s)->hash_shift) ^ (c)) & (s)->hash_mask)
416 
417 #define ERR_RETURN(strm, err) return ((strm)->msg=z_errmsg[1-(err)], (err))
418 
419 #define put_byte(s, c) {(s)->pending_buf[(s)->pending++] = (c);}
420 
421 #define put_short(s, w) do { \
422     put_byte((s), (uch)((w) & 0xff)); \
423     put_byte((s), (uch)((ush)(w) >> 8)); \
424 } while (0)
425 
426 #define INSERT_STRING(s, str, match_head) \
427     (UPDATE_HASH((s), (s)->ins_h, (s)->window[(str) + MIN_MATCH - 1]), \
428     (s)->prev[(str) & (s)->w_mask] = (match_head) = (s)->head[(s)->ins_h], \
429     (s)->head[(s)->ins_h] = (str))
430 
431 #define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
432 
433 #define check_match(s, start, match, length)
434 
435 #define d_code(dist) \
436     ((dist) < 256 ? dist_code[dist] : dist_code[256 + ((dist) >> 7)])
437 
438 #define FLUSH_BLOCK_ONLY(s, eof) do { \
439     ct_flush_block((s), ((s)->block_start >= 0L ? \
440                 (char*)&(s)->window[(unsigned)(s)->block_start] : \
441                 (char*)Z_NULL), (long)(s)->strstart - (s)->block_start, (eof)); \
442     (s)->block_start = (s)->strstart; \
443     flush_pending((s)->strm); \
444 } while (0)
445 
446 #define FLUSH_BLOCK(s, eof) do { \
447     FLUSH_BLOCK_ONLY(s, eof); \
448     if ((s)->strm->avail_out == 0) return 1; \
449 } while (0)
450 
451 #define send_code(s, c, tree) send_bits((s), (tree)[c].Code, (tree)[c].Len)
452 
453 #define MAX(a, b) ((a) >= (b) ? (a) : (b))
454 
455 #define Buf_size (8 * 2*sizeof(char))
456 
457 #define smaller(tree, n, m, depth) \
458     ((tree)[n].Freq < (tree)[m].Freq || \
459     ((tree)[n].Freq == (tree)[m].Freq && (depth)[n] <= (depth)[m]))
460 
461 #define pqremove(s, tree, top) do { \
462     top = (s)->heap[SMALLEST]; \
463     (s)->heap[SMALLEST] = (s)->heap[(s)->heap_len--]; \
464     pqdownheap(s, tree, SMALLEST); \
465 } while (0)
466 
467 #ifndef local
468 #  define local static
469 #endif
470 
471 #ifndef __P
472 #define __P(args)  args
473 #endif
474 
475 #define ZALLOC(strm, items, size) \
476                (*((strm)->zalloc))((strm)->opaque, (items), (size))
477 #define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidp)(addr))
478 #define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
479 
480 #define Assert(cond, msg)
481 
482 #ifndef Byte
483   typedef unsigned char  Byte;  /* 8 bits */
484 #endif
485 #ifndef uInt
486   typedef unsigned int   uInt;  /* may be 16 or 32 bits */
487 #endif
488 #ifndef uLong
489   typedef unsigned long  uLong; /* 32 bits or more */
490 #endif
491 typedef Byte *voidp;
492 typedef voidp gzFile;
493 typedef unsigned char  uch;
494 typedef unsigned long  ulg;
495 typedef unsigned short ush;
496 typedef ush Pos;
497 typedef unsigned IPos;
498 
499 typedef voidp (*alloc_func) __P((voidp opaque, uInt items, uInt size));
500 typedef void  (*free_func)  __P((voidp opaque, voidp address));
501 
502 typedef uLong (*check_func) __P((uLong check, Byte *buf, uInt len));
503 
504 typedef struct z_stream_s {
505     Byte     *next_in;  /* next input byte */
506     uInt     avail_in;  /* number of bytes available at next_in */
507     uLong    total_in;  /* total nb of input bytes read so far */
508 
509     Byte     *next_out; /* next output byte should be put there */
510     uInt     avail_out; /* remaining free space at next_out */
511     uLong    total_out; /* total nb of bytes output so far */
512 
513     char     *msg;      /* last error message, NULL if no error */
514     struct internal_state *state; /* not visible by applications */
515 
516     alloc_func zalloc;  /* used to allocate the internal state */
517     free_func  zfree;   /* used to free the internal state */
518     voidp      opaque;  /* private data object passed to zalloc and zfree */
519 
520     Byte     data_type; /* best guess about the data type: ascii or binary */
521 } z_stream;
522 
523 typedef struct gz_stream {
524     z_stream stream;
525     int      z_err;   /* error code for last stream operation */
526     int      z_eof;   /* set if end of input file */
527     FILE     *file;   /* .gz file */
528     Byte     *inbuf;  /* input buffer */
529     Byte     *outbuf; /* output buffer */
530     uLong    crc;     /* crc32 of uncompressed data */
531     char     *msg;    /* error message */
532     char     *path;   /* path name for debugging only */
533     int      transparent; /* 1 if input file is not a .gz file */
534     char     mode;    /* 'w' or 'r' */
535 } gz_stream;
536 
537 /* Data structure describing a single value and its code string. */
538 typedef struct ct_data_s {
539     union {
540         ush  freq;       /* frequency count */
541         ush  code;       /* bit string */
542     } fc;
543     union {
544         ush  dad;        /* father node in Huffman tree */
545         ush  len;        /* length of bit string */
546     } dl;
547 } ct_data;
548 
549 struct static_tree_desc_s {
550     ct_data *static_tree;        /* static tree or NULL */
551     int     *extra_bits;         /* extra bits for each code or NULL */
552     int     extra_base;          /* base index for extra_bits */
553     int     elems;               /* max number of elements in the tree */
554     int     max_length;          /* max bit length for the codes */
555 };
556 
557 typedef struct static_tree_desc_s  static_tree_desc;
558 
559 typedef struct tree_desc_s {
560     ct_data *dyn_tree;           /* the dynamic tree */
561     int     max_code;            /* largest code with non zero frequency */
562     static_tree_desc *stat_desc; /* the corresponding static tree */
563 } tree_desc;
564 
565 typedef struct inflate_huft_s inflate_huft;
566 struct inflate_huft_s {
567     union {
568         struct {
569             char Exop;        /* number of extra bits or operation */
570             char Bits;        /* number of bits in this code or subcode */
571         } what;
572         Byte *pad;          /* pad structure to a power of 2 (4 bytes for */
573     } word;               /*  16-bit, 8 bytes for 32-bit machines) */
574     union {
575         uInt Base;          /* literal, length base, or distance base */
576         inflate_huft *Next; /* pointer to next level of table */
577     } more;
578 };
579 
580 /* inflate codes private state */
581 struct inflate_codes_state {
582   /* mode */
583     enum {       /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
584         START,   /* x: set up for LEN */
585         LEN,     /* i: get length/literal/eob next */
586         LENEXT,  /* i: getting length extra (have base) */
587         DIST,    /* i: get distance next */
588         DISTEXT, /* i: getting distance extra */
589         COPY,    /* o: copying bytes in window, waiting for space */
590         LIT,     /* o: got literal, waiting for output space */
591         WASH,    /* o: got eob, possibly still output waiting */
592         END,     /* x: got eob and all data flushed */
593         BAD     /* x: got error */
594     } mode;      /* current inflate_codes mode */
595 
596   /* mode dependent information */
597     uInt len;
598     union {
599         struct {
600             inflate_huft *tree;    /* pointer into tree */
601             uInt need;        /* bits needed */
602         } code;        /* if LEN or DIST, where in tree */
603         uInt lit;        /* if LIT, literal */
604         struct {
605             uInt get;            /* bits to get for extra */
606             uInt dist;        /* distance back to copy from */
607         } copy;        /* if EXT or COPY, where and how much */
608     } sub;        /* submode */
609 
610     /* mode independent information */
611     Byte lbits;        /* ltree bits decoded per branch */
612     Byte dbits;        /* dtree bits decoder per branch */
613     inflate_huft *ltree;        /* literal/length/eob tree */
614     inflate_huft *dtree;        /* distance tree */
615 };
616 
617 /* inflate blocks semi-private state */
618 struct inflate_blocks_state {
619   /* mode */
620     enum {
621         TYPE,      /* get type bits (3, including end bit) */
622         LENS,      /* get lengths for stored */
623         STORED,    /* processing stored block */
624         TABLE,     /* get table lengths */
625         BTREE,     /* get bit lengths tree for a dynamic block */
626         DTREE,     /* get length, distance trees for a dynamic block */
627         CODES,     /* processing fixed or dynamic block */
628         DRY,       /* output remaining window bytes */
629         DONE,      /* finished last block, done */
630         INF_ERROR  /* got a data error--stuck here */
631     } mode;        /* current inflate_block mode */
632 
633   /* mode dependent information */
634     union {
635         uInt left;        /* if STORED, bytes left to copy */
636         struct {
637             uInt table;         /* table lengths (14 bits) */
638             uInt index;         /* index into blens (or border) */
639             uInt *blens;        /* bit lengths of codes */
640             uInt bb;            /* bit length tree depth */
641             inflate_huft *tb;        /* bit length decoding tree */
642         } trees;        /* if DTREE, decoding info for trees */
643         struct inflate_codes_state
644             *codes;        /* if CODES, current state */
645     } sub;        /* submode */
646     uInt last;        /* true if this block is the last block */
647 
648     /* mode independent information */
649     uInt bitk;        /* bits in bit buffer */
650     uLong bitb;        /* bit buffer */
651     Byte *window;        /* sliding window */
652     Byte *end;        /* one byte after sliding window */
653     Byte *read;        /* window read pointer */
654     Byte *write;        /* window write pointer */
655     check_func checkfn;   /* check function */
656     uLong check;        /* check on output */
657 };
658 
659 typedef struct internal_state {
660     z_stream *strm;      /* pointer back to this zlib stream */
661     int   status;        /* as the name implies */
662     Byte *pending_buf;   /* output still pending */
663     Byte *pending_out;   /* next pending byte to output to the stream */
664     int   pending;       /* nb of bytes in the pending buffer */
665     uLong adler;         /* adler32 of uncompressed data */
666     int   noheader;      /* suppress zlib header and adler32 */
667     Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
668     Byte  method;        /* STORED (for zip only) or DEFLATED */
669 
670             /* used by deflate.c: */
671 
672     uInt  w_size;        /* LZ77 window size (32K by default) */
673     uInt  w_bits;        /* log2(w_size)  (8..16) */
674     uInt  w_mask;        /* w_size - 1 */
675 
676     Byte *window;
677     /* Sliding window. Input bytes are read into the second half of the window,
678      * and move to the first half later to keep a dictionary of at least wSize
679      * bytes. With this organization, matches are limited to a distance of
680      * wSize-MAX_MATCH bytes, but this ensures that IO is always
681      * performed with a length multiple of the block size. Also, it limits
682      * the window size to 64K, which is quite useful on MSDOS.
683      * To do: use the user input buffer as sliding window.
684      */
685 
686     ulg window_size;
687     /* Actual size of window: 2*wSize, except when the user input buffer
688      * is directly used as sliding window.
689      */
690 
691     Pos *prev;
692     /* Link to older string with same hash index. To limit the size of this
693      * array to 64K, this link is maintained only for the last 32K strings.
694      * An index in this array is thus a window index modulo 32K.
695      */
696 
697     Pos *head; /* Heads of the hash chains or NIL. */
698 
699     uInt  ins_h;          /* hash index of string to be inserted */
700     uInt  hash_size;      /* number of elements in hash table */
701     uInt  hash_bits;      /* log2(hash_size) */
702     uInt  hash_mask;      /* hash_size-1 */
703 
704     uInt  hash_shift;
705     /* Number of bits by which ins_h must be shifted at each input
706      * step. It must be such that after MIN_MATCH steps, the oldest
707      * byte no longer takes part in the hash key, that is:
708      *   hash_shift * MIN_MATCH >= hash_bits
709      */
710 
711     long block_start;
712     /* Window position at the beginning of the current output block. Gets
713      * negative when the window is moved backwards.
714      */
715 
716     uInt match_length;           /* length of best match */
717     IPos prev_match;             /* previous match */
718     int match_available;         /* set if previous match exists */
719     uInt strstart;               /* start of string to insert */
720     uInt match_start;            /* start of matching string */
721     uInt lookahead;              /* number of valid bytes ahead in window */
722 
723     uInt prev_length;
724     /* Length of the best match at previous step. Matches not greater than this
725      * are discarded. This is used in the lazy match evaluation.
726      */
727 
728     uInt max_chain_length;
729     /* To speed up deflation, hash chains are never searched beyond this
730      * length.  A higher limit improves compression ratio but degrades the
731      * speed.
732      */
733 
734     uInt max_lazy_match;
735     /* Attempt to find a better match only when the current match is strictly
736      * smaller than this value. This mechanism is used only for compression
737      * levels >= 4.
738      */
739 #define max_insert_length  max_lazy_match
740     /* Insert new strings in the hash table only if the match length is not
741      * greater than this length. This saves time but degrades compression.
742      * max_insert_length is used only for compression levels <= 3.
743      */
744 
745     int level;    /* compression level (1..9) */
746     int strategy; /* favor or force Huffman coding */
747 
748     uInt good_match;
749     /* Use a faster search when the previous match is longer than this */
750 
751     int nice_match; /* Stop searching when current match exceeds this */
752 
753             /* used by trees.c: */
754 
755     ct_data dyn_ltree[HEAP_SIZE];   /* literal and length tree */
756     ct_data dyn_dtree[2*D_CODES+1]; /* distance tree */
757     ct_data bl_tree[2*BL_CODES+1];  /* Huffman tree for the bit lengths */
758 
759     tree_desc l_desc;               /* descriptor for literal tree */
760     tree_desc d_desc;               /* descriptor for distance tree */
761     tree_desc bl_desc;              /* descriptor for bit length tree */
762 
763     ush bl_count[MAX_BITS+1];
764     /* number of codes at each bit length for an optimal tree */
765 
766     int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
767     int heap_len;               /* number of elements in the heap */
768     int heap_max;               /* element of largest frequency */
769     /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
770      * The same heap array is used to build all trees.
771      */
772 
773     uch depth[2*L_CODES+1];
774     /* Depth of each subtree used as tie breaker for trees of equal frequency
775      */
776 
777     uch *l_buf;           /* buffer for literals or lengths */
778 
779     uInt  lit_bufsize;
780     /* Size of match buffer for literals/lengths.  There are 4 reasons for
781      * limiting lit_bufsize to 64K:
782      *   - frequencies can be kept in 16 bit counters
783      *   - if compression is not successful for the first block, all input
784      *     data is still in the window so we can still emit a stored block even
785      *     when input comes from standard input.  (This can also be done for
786      *     all blocks if lit_bufsize is not greater than 32K.)
787      *   - if compression is not successful for a file smaller than 64K, we can
788      *     even emit a stored file instead of a stored block (saving 5 bytes).
789      *     This is applicable only for zip (not gzip or zlib).
790      *   - creating new Huffman trees less frequently may not provide fast
791      *     adaptation to changes in the input data statistics. (Take for
792      *     example a binary file with poorly compressible code followed by
793      *     a highly compressible string table.) Smaller buffer sizes give
794      *     fast adaptation but have of course the overhead of transmitting
795      *     trees more frequently.
796      *   - I can't count above 4
797      */
798 
799     uInt last_lit;      /* running index in l_buf */
800 
801     ush *d_buf;
802     /* Buffer for distances. To simplify the code, d_buf and l_buf have
803      * the same number of elements. To use different lengths, an extra flag
804      * array would be necessary.
805      */
806 
807     ulg opt_len;        /* bit length of current block with optimal trees */
808     ulg static_len;     /* bit length of current block with static trees */
809     ulg compressed_len; /* total bit length of compressed file */
810     uInt matches;       /* number of string matches in current block */
811 
812 #ifdef DEBUG
813     ulg bits_sent;      /* bit length of the compressed data */
814 #endif
815 
816     ush bi_buf;
817     /* Output buffer. bits are inserted starting at the bottom (least
818      * significant bits).
819      */
820     int bi_valid;
821     /* Number of valid bits in bi_buf.  All bits above the last valid bit
822      * are always zero.
823      */
824 
825     /* mode */
826     enum {
827         METHOD,    /* waiting for method byte */
828         FLAG,    /* waiting for flag byte */
829         BLOCKS,    /* decompressing blocks */
830         CHECK4,    /* four check bytes to go */
831         CHECK3,    /* three check bytes to go */
832         CHECK2,    /* two check bytes to go */
833         CHECK1,    /* one check byte to go */
834     }
835     mode;        /* current inflate mode */
836 
837   /* mode dependent information */
838     union {
839         uInt method;    /* if FLAGS, method byte */
840         struct inflate_blocks_state
841             *blocks;        /* if BLOCKS, current state */
842         struct {
843             uLong was;        /* computed check value */
844             uLong need;        /* stream check value */
845         } check;        /* if CHECK, check values to compare */
846     } sub;    /* submode */
847 
848     /* mode independent information */
849     int  nowrap;        /* flag for no wrapper */
850     uInt wbits;          /* log2(window size)  (8..15, defaults to 15) */
851 } deflate_state;
852 
853 typedef struct config_s {
854     ush good_length; /* reduce lazy search above this match length */
855     ush max_lazy;    /* do not perform lazy search above this match length */
856     ush nice_length; /* quit search above this match length */
857     ush max_chain;
858 } config;
859 
860 char *z_errmsg[] = {
861     "stream end",          /* Z_STREAM_END    1 */
862     "",                    /* Z_OK            0 */
863     "file error",          /* Z_ERRNO        (-1) */
864     "stream error",        /* Z_STREAM_ERROR (-2) */
865     "data error",          /* Z_DATA_ERROR   (-3) */
866     "insufficient memory", /* Z_MEM_ERROR    (-4) */
867     "buffer error",        /* Z_BUF_ERROR    (-5) */
868     ""};
869 
870 local int base_length[LENGTH_CODES];
871 local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
872    = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
873 local uch length_code[MAX_MATCH-MIN_MATCH+1];
874 local int base_dist[D_CODES];
875 local int extra_dbits[D_CODES] /* extra bits for each distance code */
876    = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
877 local ct_data static_ltree[L_CODES+2];
878 local uch dist_code[512];
879 local int base_dist[D_CODES];
880 local ct_data static_dtree[D_CODES];
881 
882 local static_tree_desc  static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
883 
884 local static_tree_desc  static_d_desc = {static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
885 
886 local int extra_blbits[BL_CODES] /* extra bits for each bit length code */
887    = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
888 
889 local static_tree_desc  static_bl_desc = {(ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS};
890 
891 local uch bl_order[BL_CODES]
892    = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
893 
894 local config configuration_table[10] = {
895 /* good lazy nice chain */
896     {0,    0,  0,    0},   /* 0 */  /* store only */
897     {4,    4,  8,    4},   /* 1 */  /* maximum speed, no lazy matches */
898     {4,    5, 16,    8},   /* 2 */
899     {4,    6, 32,   32},   /* 3 */
900     {4,    4, 16,   16},   /* 4 */  /* lazy matches */
901     {8,   16, 32,   32},   /* 5 */
902     {8,   16, 128, 128},   /* 6 */
903     {8,   32, 128, 256},   /* 7 */
904     {32, 128, 258, 1024},  /* 8 */
905     {32, 258, 258, 4096}}; /* 9 */ /* maximum compression */
906 
907 #define FIXEDH 530    /* number of hufts used by fixed tables */
908 local inflate_huft fixed_mem[FIXEDH];
909 
910 #define next more.Next
911 
912 #define Freq fc.freq
913 #define Code fc.code
914 #define Dad  dl.dad
915 #define Len  dl.len
916 
917 local voidp zcalloc (opaque, items, size)
918     voidp opaque;
919     unsigned items;
920     unsigned size;
921 {
922     return calloc(items, size);
923 }
924 
925 local void  zcfree (opaque, ptr)
926     voidp opaque;
927     voidp ptr;
928 {
929     free(ptr);
930 }
931 
932 local uLong crc32(crc, buf, len)
933     uLong crc;
934     Byte *buf;
935     uInt len;
936 {
937     if (buf == Z_NULL) {
938         return 0L;
939     }
940     crc = crc ^ 0xffffffffL;
941     if (len) {
942         do {
943             crc = wm_tool_crc32_tab[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); // 8:byte alignment
944         } while (--len);
945     }
946     return crc ^ 0xffffffffL;
947 }
948 
949 local void zmemcpy(dest, source, len)
950     Byte* dest;
951     Byte* source;
952     uInt  len;
953 {
954     if (len == 0) {
955         return;
956     }
957     do {
958     *dest++ = *source++; /* ??? to be unrolled */
959     } while (--len != 0);
960 }
961 
962 local void zmemzero(dest, len)
963     Byte* dest;
964     uInt  len;
965 {
966     if (len == 0) {
967         return;
968     }
969     do {
970         *dest++ = 0;  /* ??? to be unrolled */
971     } while (--len != 0);
972 }
973 
974 local uLong adler32(adler, buf, len)
975     uLong adler;
976     Byte *buf;
977     uInt len;
978 {
979     unsigned long s1 = adler & 0xffff;
980     unsigned long s2 = (adler >> 16) & 0xffff; // 16:byte alignment
981     int k;
982 
983     if (buf == Z_NULL) {
984         return 1L;
985     }
986 
987     while (len > 0) {
988         k = len < NMAX ? len : NMAX;
989         len -= k;
990         while (k >= 16) { // 16:byte alignment
991             DO16(buf);
992             k -= 16; // 16:byte alignment
993         }
994         if (k != 0) {
995             do {
996                 DO1(buf);
997             } while (--k);
998         }
999         s1 %= BASE;
1000         s2 %= BASE;
1001     }
1002     return (s2 << 16) | s1; // 16:byte alignment
1003 }
1004 
1005 local int read_buf(strm, buf, size)
1006     z_stream *strm;
1007     char *buf;
1008     unsigned size;
1009 {
1010     unsigned len = strm->avail_in;
1011 
1012     if (len > size) {
1013         len = size;
1014     }
1015     if (len == 0) {
1016         return 0;
1017     }
1018 
1019     strm->avail_in  -= len;
1020 
1021     if (!strm->state->noheader) {
1022         strm->state->adler = adler32(strm->state->adler, strm->next_in, len);
1023     }
1024     zmemcpy((Byte *)buf, strm->next_in, len);
1025     strm->next_in  += len;
1026     strm->total_in += len;
1027 
1028     return (int)len;
1029 }
1030 
1031 local int inflate_trees_free(t, z)
1032 inflate_huft *t;    /* table to free */
1033 z_stream *z;        /* for zfree function */
1034 /* Free the malloc'ed tables built by huft_build(), which makes a linked
1035    list of the tables it made, with the links in a dummy first entry of
1036    each table. */
1037 {
1038     register inflate_huft *p, *q;
1039 
1040     /* Don't free fixed trees */
1041     if (t >= fixed_mem && t <= fixed_mem + FIXEDH) {
1042         return Z_OK;
1043     }
1044 
1045     /* Go through linked list, freeing from the malloced (t[-1]) address. */
1046     p = t;
1047     while (p != Z_NULL) {
1048         q = (--p)->next;
1049         ZFREE(z, p);
1050         p = q;
1051     }
1052     return Z_OK;
1053 }
1054 
1055 local void inflate_codes_free(c, z)
1056 struct inflate_codes_state *c;
1057 z_stream *z;
1058 {
1059     inflate_trees_free(c->dtree, z);
1060     inflate_trees_free(c->ltree, z);
1061     ZFREE(z, c);
1062 }
1063 
1064 local int inflate_blocks_free(s, z, c)
1065 struct inflate_blocks_state *s;
1066 z_stream *z;
1067 uLong *c;
1068 {
1069     if (s->checkfn != Z_NULL) {
1070         *c = s->check;
1071     }
1072     if (s->mode == BTREE || s->mode == DTREE) {
1073         ZFREE(z, s->sub.trees.blens);
1074     }
1075     if (s->mode == CODES) {
1076         inflate_codes_free(s->sub.codes, z);
1077     }
1078     ZFREE(z, s->window);
1079     ZFREE(z, s);
1080     return Z_OK;
1081 }
1082 
1083 local int deflateEnd (strm)
1084     z_stream *strm;
1085 {
1086     if (strm == Z_NULL || strm->state == Z_NULL) {
1087         return Z_STREAM_ERROR;
1088     }
1089 
1090     TRY_FREE(strm, strm->state->window);
1091     TRY_FREE(strm, strm->state->prev);
1092     TRY_FREE(strm, strm->state->head);
1093     TRY_FREE(strm, strm->state->pending_buf);
1094 
1095     ZFREE(strm, strm->state);
1096     strm->state = Z_NULL;
1097 
1098     return Z_OK;
1099 }
1100 
1101 local int inflateEnd(z)
1102 z_stream *z;
1103 {
1104     uLong c;
1105 
1106     if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) {
1107         return Z_STREAM_ERROR;
1108     }
1109     if (z->state->mode == BLOCKS) {
1110         inflate_blocks_free(z->state->sub.blocks, z, &c);
1111     }
1112     ZFREE(z, z->state);
1113     z->state = Z_NULL;
1114     return Z_OK;
1115 }
1116 
1117 local int destroy (s)
1118     gz_stream *s;
1119 {
1120     int err = Z_OK;
1121 
1122     if (!s) return {
1123         Z_STREAM_ERROR;
1124     }
1125 
1126     TRYFREE(s->inbuf);
1127     TRYFREE(s->outbuf);
1128     TRYFREE((voidp)s->path);
1129     TRYFREE((voidp)s->msg);
1130 
1131     if (s->stream.state != NULL) {
1132         if (s->mode == 'w') {
1133             err = deflateEnd(&(s->stream));
1134         } else if (s->mode == 'r') {
1135             err = inflateEnd(&(s->stream));
1136         }
1137     }
1138     if (s->file != NULL && fclose(s->file)) {
1139         err = Z_ERRNO;
1140     }
1141     if (s->z_err < 0) {
1142         err = s->z_err;
1143     }
1144     zcfree((voidp)0, (voidp)s);
1145     return err;
1146 }
1147 
1148 local void putLong (file, x)
1149     FILE *file;
1150     uLong x;
1151 {
1152     int n;
1153     for (n = 0; n < 4; n++) { // 4:byte alignment
1154         fputc((int)(x & 0xff), file);
1155         x >>= 8; // 8:byte alignment
1156     }
1157 }
1158 
1159 local uLong getLong (buf)
1160     Byte *buf;
1161 {
1162     uLong x = 0;
1163     Byte *p = buf + 4; // 4:byte alignment
1164 
1165     do {
1166         x <<= 8; // 8:byte alignment
1167         x |= *--p;
1168     } while (p != buf);
1169     return x;
1170 }
1171 
1172 local unsigned bi_reverse(code, len)
1173     unsigned code; /* the value to invert */
1174     int len;       /* its bit length */
1175 {
1176     register unsigned res = 0;
1177     do {
1178         res |= code & 1;
1179         code >>= 1, res <<= 1;
1180     } while (--len > 0);
1181     return res >> 1;
1182 }
1183 
1184 local void gen_codes (tree, max_code, bl_count)
1185     ct_data *tree;             /* the tree to decorate */
1186     int max_code;              /* largest code with non zero frequency */
1187     ush bl_count[];            /* number of codes at each bit length */
1188 {
1189     ush next_code[MAX_BITS+1]; /* next code value for each bit length */
1190     ush code = 0;              /* running code value */
1191     int bits;                  /* bit index */
1192     int n;                     /* code index */
1193 
1194     /* The distribution counts are first used to generate the code values
1195      * without bit reversal.
1196      */
1197     for (bits = 1; bits <= MAX_BITS; bits++) {
1198         next_code[bits] = code = (code + bl_count[bits - 1]) << 1;
1199     }
1200     /* Check that the bit counts in bl_count are consistent. The last code
1201      * must be all ones.
1202      */
1203     Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
1204             "inconsistent bit counts");
1205 
1206     for (n = 0;  n <= max_code; n++) {
1207         int len = tree[n].Len;
1208         if (len == 0) {
1209             continue;
1210         }
1211         /* Now reverse the bits */
1212         tree[n].Code = bi_reverse(next_code[len]++, len);
1213     }
1214 }
1215 
1216 local void ct_static_init(void)
1217 {
1218     int n;        /* iterates over tree elements */
1219     int bits;     /* bit counter */
1220     int length;   /* length value */
1221     int code;     /* code value */
1222     int dist;     /* distance index */
1223     ush bl_count[MAX_BITS+1];
1224     /* number of codes at each bit length for an optimal tree */
1225 
1226     /* Initialize the mapping length (0..255) -> length code (0..28) */
1227     length = 0;
1228     for (code = 0; code < LENGTH_CODES-1; code++) {
1229         base_length[code] = length;
1230         for (n = 0; n < (1 << extra_lbits[code]); n++) {
1231             length_code[length++] = (uch)code;
1232         }
1233     }
1234     Assert (length == 256, "ct_static_init: length != 256");
1235     /* Note that the length 255 (match length 258) can be represented
1236      * in two different ways: code 284 + 5 bits or code 285, so we
1237      * overwrite length_code[255] to use the best encoding:
1238      */
1239     length_code[length-1] = (uch)code;
1240 
1241     /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
1242     dist = 0;
1243     for (code = 0 ; code < 16; code++) { // 16:byte alignment
1244         base_dist[code] = dist;
1245         for (n = 0; n < (1 << extra_dbits[code]); n++) {
1246             dist_code[dist++] = (uch)code;
1247         }
1248     }
1249     Assert (dist == 256, "ct_static_init: dist != 256");
1250     dist >>= 7; /* from now on, all distances are divided by 128 */ // 7:byte alignment
1251     for (; code < D_CODES; code++) {
1252         base_dist[code] = dist << 7; // 7:byte alignment
1253         for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { // 7:byte alignment
1254             dist_code[256 + dist++] = (uch)code; // 256:byte alignment
1255         }
1256     }
1257     Assert (dist == 256, "ct_static_init: 256+dist != 512"); // 256:byte alignment
1258 
1259     /* Construct the codes of the static literal tree */
1260     for (bits = 0; bits <= MAX_BITS; bits++) {
1261         bl_count[bits] = 0;
1262     }
1263     n = 0;
1264     while (n <= 143) { // 143:byte alignment
1265         static_ltree[n++].Len = 8, bl_count[8]++; // 8:byte alignment
1266     }
1267     while (n <= 255) { // 255:byte alignment
1268         static_ltree[n++].Len = 9, bl_count[9]++; // 9:byte alignment
1269     }
1270     while (n <= 279) { // 279:byte alignment
1271         static_ltree[n++].Len = 7, bl_count[7]++; // 7:byte alignment
1272     }
1273     while (n <= 287) { // 287:byte alignment
1274         static_ltree[n++].Len = 8, bl_count[8]++; // 8:byte alignment
1275     }
1276     /* Codes 286 and 287 do not exist, but we must include them in the
1277      * tree construction to get a canonical Huffman tree (longest code
1278      * all ones)
1279      */
1280     gen_codes((ct_data *)static_ltree, L_CODES + 1, bl_count);
1281 
1282     /* The static distance tree is trivial: */
1283     for (n = 0; n < D_CODES; n++) {
1284         static_dtree[n].Len = 5; // 5:byte alignment
1285         static_dtree[n].Code = bi_reverse(n, 5); // 5:byte alignment
1286     }
1287 }
1288 
1289 local void init_block(s)
1290     deflate_state *s;
1291 {
1292     int n; /* iterates over tree elements */
1293 
1294     /* Initialize the trees. */
1295     for (n = 0; n < L_CODES; n++) {
1296         s->dyn_ltree[n].Freq = 0;
1297     }
1298     for (n = 0; n < D_CODES; n++) {
1299         s->dyn_dtree[n].Freq = 0;
1300     }
1301     for (n = 0; n < BL_CODES;n++) {
1302         s->bl_tree[n].Freq = 0;
1303     }
1304 
1305     s->dyn_ltree[END_BLOCK].Freq = 1;
1306     s->opt_len = s->static_len = 0L;
1307     s->last_lit = s->matches = 0;
1308 }
1309 
1310 local void ct_init(s)
1311     deflate_state *s;
1312 {
1313     if (static_dtree[0].Len == 0) {
1314         ct_static_init();              /* To do: at compile time */
1315     }
1316 
1317     s->compressed_len = 0L;
1318 
1319     s->l_desc.dyn_tree = s->dyn_ltree;
1320     s->l_desc.stat_desc = &static_l_desc;
1321 
1322     s->d_desc.dyn_tree = s->dyn_dtree;
1323     s->d_desc.stat_desc = &static_d_desc;
1324 
1325     s->bl_desc.dyn_tree = s->bl_tree;
1326     s->bl_desc.stat_desc = &static_bl_desc;
1327 
1328     s->bi_buf = 0;
1329     s->bi_valid = 0;
1330 #ifdef DEBUG
1331     s->bits_sent = 0L;
1332 #endif
1333 
1334     /* Initialize the first block of the first file: */
1335     init_block(s);
1336 }
1337 
1338 local void lm_init (s)
1339     deflate_state *s;
1340 {
1341     register unsigned j;
1342 
1343     s->window_size = (ulg)2L*s->w_size;
1344 
1345     /* Initialize the hash table (avoiding 64K overflow for 16 bit systems).
1346      * prev[] will be initialized on the fly.
1347      */
1348     s->head[s->hash_size-1] = NIL;
1349     zmemzero((unsigned char*)s->head, (unsigned int)(s->hash_size-1)*sizeof(*s->head));
1350 
1351     /* Set the default configuration parameters:
1352      */
1353     s->max_lazy_match   = configuration_table[s->level].max_lazy;
1354     s->good_match       = configuration_table[s->level].good_length;
1355     s->nice_match       = configuration_table[s->level].nice_length;
1356     s->max_chain_length = configuration_table[s->level].max_chain;
1357 
1358     s->strstart = 0;
1359     s->block_start = 0L;
1360     s->lookahead = 0;
1361     s->match_length = MIN_MATCH-1;
1362     s->match_available = 0;
1363 #ifdef ASMV
1364     match_init(); /* initialize the asm code */
1365 #endif
1366 
1367     s->ins_h = 0;
1368     for (j=0; j<MIN_MATCH-1; j++) {
1369         UPDATE_HASH(s, s->ins_h, s->window[j]);
1370     }
1371     /* If lookahead < MIN_MATCH, ins_h is garbage, but this is
1372      * not important since only literal bytes will be emitted.
1373      */
1374 }
1375 
1376 local int deflateReset (strm)
1377     z_stream *strm;
1378 {
1379     deflate_state *s;
1380 
1381     if (strm == Z_NULL || strm->state == Z_NULL ||
1382         strm->zalloc == Z_NULL || strm->zfree == Z_NULL) {
1383         return Z_STREAM_ERROR;
1384     }
1385 
1386     strm->total_in = strm->total_out = 0;
1387     strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
1388     strm->data_type = Z_UNKNOWN;
1389 
1390     s = (deflate_state *)strm->state;
1391     s->pending = 0;
1392     s->pending_out = s->pending_buf;
1393 
1394     s->status = s->noheader ? BUSY_STATE : INIT_STATE;
1395     s->adler = 1;
1396 
1397     ct_init(s);
1398     lm_init(s);
1399 
1400     return Z_OK;
1401 }
1402 
1403 local int deflateInit2 (strm, level, method, windowBits, memLevel, strategy)
1404     z_stream *strm;
1405     int  level;
1406     int  method;
1407     int  windowBits;
1408     int  memLevel;
1409     int  strategy;
1410 {
1411     deflate_state *s;
1412     int noheader = 0;
1413 
1414     if (strm == Z_NULL) {
1415         return Z_STREAM_ERROR;
1416     }
1417 
1418     strm->msg = Z_NULL;
1419     if (strm->zalloc == Z_NULL) {
1420         strm->zalloc = zcalloc;
1421     }
1422     if (strm->zfree == Z_NULL) {
1423         strm->zfree = zcfree;
1424     }
1425 
1426     if (level == Z_DEFAULT_COMPRESSION) {
1427         level = 6;
1428     }
1429 
1430     if (windowBits < 0) { /* undocumented feature: suppress zlib header */
1431         noheader = 1;
1432         windowBits = -windowBits;
1433     }
1434     if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != DEFLATED ||
1435         windowBits < 8 || windowBits > 15 || // 8:byte alignment, 15:byte alignment
1436         level < 1 || level > 9) { // 9:byte alignment
1437         return Z_STREAM_ERROR;
1438     }
1439     s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
1440     if (s == Z_NULL) {
1441         return Z_MEM_ERROR;
1442     }
1443     strm->state = (struct internal_state *)s;
1444     s->strm = strm;
1445 
1446     s->noheader = noheader;
1447     s->w_bits = windowBits;
1448     s->w_size = 1 << s->w_bits;
1449     s->w_mask = s->w_size - 1;
1450 
1451     s->hash_bits = memLevel + 7; // 7:byte alignment
1452     s->hash_size = 1 << s->hash_bits;
1453     s->hash_mask = s->hash_size - 1;
1454     s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
1455 
1456     s->window = (Byte*) ZALLOC(strm, s->w_size, 2 * sizeof(Byte)); // 2:byte alignment
1457     s->prev   = (Pos*)  ZALLOC(strm, s->w_size, sizeof(Pos));
1458     s->head   = (Pos*)  ZALLOC(strm, s->hash_size, sizeof(Pos));
1459 
1460     s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ // 6:byte alignment
1461 
1462     s->pending_buf = (uch*) ZALLOC(strm, s->lit_bufsize, 2 * sizeof(ush)); // 2:byte alignment
1463 
1464     if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) {
1465     strm->msg = z_errmsg[1 - Z_MEM_ERROR];
1466     deflateEnd (strm);
1467     return Z_MEM_ERROR;
1468     }
1469     s->d_buf = (ush*) &(s->pending_buf[s->lit_bufsize]);
1470     s->l_buf = (uch*) &(s->pending_buf[3 * s->lit_bufsize]); // 3:byte alignment
1471     /* We overlay pending_buf and d_buf+l_buf. This works since the average
1472      * output size for (length,distance) codes is <= 32 bits (worst case
1473      * is 15+15+13=33).
1474      */
1475 
1476     s->level = level;
1477     s->strategy = strategy;
1478     s->method = (Byte)method;
1479 
1480     return deflateReset(strm);
1481 }
1482 
1483 local int inflateInit2(z, w)
1484 z_stream *z;
1485 int w;
1486 {
1487     /* initialize state */
1488     if (z == Z_NULL) {
1489         return Z_STREAM_ERROR;
1490     }
1491     if (z->zalloc == Z_NULL) {
1492         z->zalloc = zcalloc;
1493     }
1494     if (z->zfree == Z_NULL) {
1495         z->zfree = zcfree;
1496     }
1497     z->total_in = z->total_out = 0;
1498     z->msg = Z_NULL;
1499     if ((z->state = (struct internal_state *)
1500         ZALLOC(z, 1, sizeof(struct internal_state))) == Z_NULL) {
1501         return Z_MEM_ERROR;
1502     }
1503     z->state->mode = METHOD;
1504 
1505     /* handle undocumented nowrap option (no zlib header or check) */
1506     z->state->nowrap = 0;
1507     if (w < 0) {
1508         w = - w;
1509         z->state->nowrap = 1;
1510         z->state->mode = START;
1511     }
1512 
1513     /* set window size */
1514     if (w < 8 || w > 15) { // 8:window size, 15:window size
1515         inflateEnd(z);
1516         return Z_STREAM_ERROR;
1517     }
1518     z->state->wbits = w;
1519     return Z_OK;
1520 }
1521 
1522 local void putShortMSB (s, b)
1523     deflate_state *s;
1524     uInt b;
1525 {
1526     put_byte(s, (Byte)(b >> 8)); // 8:byte alignment
1527     put_byte(s, (Byte)(b & 0xff));
1528 }
1529 
1530 local void flush_pending(strm)
1531     z_stream *strm;
1532 {
1533     unsigned len = strm->state->pending;
1534 
1535     if (len > strm->avail_out) {
1536         len = strm->avail_out;
1537     }
1538     if (len == 0) {
1539         return;
1540     }
1541 
1542     zmemcpy(strm->next_out, strm->state->pending_out, len);
1543     strm->next_out  += len;
1544     strm->state->pending_out  += len;
1545     strm->total_out += len;
1546     strm->avail_out  -= len;
1547     strm->state->pending -= len;
1548     if (strm->state->pending == 0) {
1549     strm->state->pending_out = strm->state->pending_buf;
1550     }
1551 }
1552 
1553 local void fill_window(s)
1554     deflate_state *s;
1555 {
1556     register unsigned n, m;
1557     unsigned more;    /* Amount of free space at the end of the window. */
1558 
1559     do {
1560         more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
1561 
1562         /* Deal with !@#$% 64K limit: */
1563         if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
1564             more = s->w_size;
1565         } else if (more == (unsigned)(-1)) {
1566             /* Very unlikely, but possible on 16 bit machine if strstart == 0
1567              * and lookahead == 1 (input done one byte at time)
1568              */
1569             more--;
1570 
1571         /* If the window is almost full and there is insufficient lookahead,
1572          * move the upper half to the lower one to make room in the upper half.
1573          */
1574         } else if (s->strstart >= s->w_size+MAX_DIST(s)) {
1575             /* By the IN assertion, the window is not empty so we can't confuse
1576              * more == 0 with more == 64K on a 16 bit machine.
1577              */
1578             memcpy((char*)s->window, (char*)s->window+s->w_size,
1579                    (unsigned)s->w_size);
1580             s->match_start -= s->w_size;
1581             s->strstart    -= s->w_size; /* we now have strstart >= MAX_DIST */
1582 
1583             s->block_start -= (long) s->w_size;
1584 
1585             for (n = 0; n < s->hash_size; n++) {
1586                 m = s->head[n];
1587                 s->head[n] = (Pos)(m >= s->w_size ? m-s->w_size : NIL);
1588             }
1589             for (n = 0; n < s->w_size; n++) {
1590                 m = s->prev[n];
1591                 s->prev[n] = (Pos)(m >= s->w_size ? m-s->w_size : NIL);
1592                 /* If n is not on any hash chain, prev[n] is garbage but
1593                  * its value will never be used.
1594                  */
1595             }
1596             more += s->w_size;
1597         }
1598         if (s->strm->avail_in == 0) {
1599             return;
1600         }
1601 
1602         /* If there was no sliding:
1603          *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
1604          *    more == window_size - lookahead - strstart
1605          * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
1606          * => more >= window_size - 2*WSIZE + 2
1607          * In the BIG_MEM or MMAP case (not yet supported),
1608          *   window_size == input_size + MIN_LOOKAHEAD  &&
1609          *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
1610          * Otherwise, window_size == 2*WSIZE so more >= 2.
1611          * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
1612          */
1613         Assert(more >= 2, "more < 2"); // 2:byte alignment
1614 
1615         n = read_buf(s->strm, (char*)s->window + s->strstart + s->lookahead,
1616                      more);
1617         s->lookahead += n;
1618     } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
1619 }
1620 
1621 /* For 80x86 and 680x0, an optimized version will be provided in match.asm or
1622  * match.S. The code will be functionally equivalent.
1623  */
1624 local int longest_match(s, cur_match)
1625     deflate_state *s;
1626     IPos cur_match;                             /* current match */
1627 {
1628     unsigned chain_length = s->max_chain_length; /* max hash chain length */
1629     register Byte *scan = s->window + s->strstart; /* current string */
1630     register Byte *match;                       /* matched string */
1631     register int len;                           /* length of current match */
1632     int best_len = s->prev_length;              /* best match length so far */
1633     IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
1634         s->strstart - (IPos)MAX_DIST(s) : NIL;
1635     /* Stop when cur_match becomes <= limit. To simplify the code,
1636      * we prevent matches with the string of window index 0.
1637      */
1638 
1639 #ifdef UNALIGNED_OK
1640     /* Compare two bytes at a time. Note: this is not always beneficial.
1641      * Try with and without -DUNALIGNED_OK to check.
1642      */
1643     register Byte *strend = s->window + s->strstart + MAX_MATCH - 1;
1644     register ush scan_start = *(ush*)scan;
1645     register ush scan_end   = *(ush*)(scan + best_len-1);
1646 #else
1647     register Byte *strend = s->window + s->strstart + MAX_MATCH;
1648     register Byte scan_end1  = scan[best_len - 1];
1649     register Byte scan_end   = scan[best_len];
1650 #endif
1651 
1652     /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
1653      * It is easy to get rid of this optimization if necessary.
1654      */
1655     Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
1656 
1657     /* Do not waste too much time if we already have a good match: */
1658     if (s->prev_length >= s->good_match) {
1659         chain_length >>= 2; // 2:byte alignment
1660     }
1661     Assert(s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
1662 
1663     do {
1664         Assert(cur_match < s->strstart, "no future");
1665         match = s->window + cur_match;
1666 
1667         /* Skip to next match if the match length cannot increase
1668          * or if the match length is less than 2:
1669          */
1670 #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) // 258:byte alignment
1671         /* This code assumes sizeof(unsigned short) == 2. Do not use
1672          * UNALIGNED_OK if your compiler uses a different size.
1673          */
1674         if (*(ush*)(match+best_len - 1) != scan_end ||
1675             *(ush*)match != scan_start) continue;
1676 
1677         /* It is not necessary to compare scan[2] and match[2] since they are
1678          * always equal when the other bytes match, given that the hash keys
1679          * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
1680          * strstart+3, +5, ... up to strstart+257. We check for insufficient
1681          * lookahead only every 4th comparison; the 128th check will be made
1682          * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
1683          * necessary to put more guard bytes at the end of the window, or
1684          * to check more often for insufficient lookahead.
1685          */
1686         scan++, match++;
1687         do {
1688         } while (*(ush*)(scan+=2) == *(ush*)(match+=2) && // 2:byte alignment
1689                  *(ush*)(scan+=2) == *(ush*)(match+=2) && // 2:byte alignment
1690                  *(ush*)(scan+=2) == *(ush*)(match+=2) && // 2:byte alignment
1691                  *(ush*)(scan+=2) == *(ush*)(match+=2) && // 2:byte alignment
1692                  scan < strend);
1693         /* The funny "do {}" generates better code on most compilers */
1694 
1695         /* Here, scan <= window+strstart+257 */
1696         Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan");
1697         if (*scan == *match) scan++;
1698 
1699         len = (MAX_MATCH - 1) - (int)(strend-scan);
1700         scan = strend - (MAX_MATCH-1);
1701 
1702 #else /* UNALIGNED_OK */
1703 
1704         if (match[best_len]   != scan_end  ||
1705             match[best_len-1] != scan_end1 ||
1706             *match            != *scan     ||
1707             *++match          != scan[1]) {
1708                 continue;
1709         }
1710 
1711         /* The check at best_len-1 can be removed because it will be made
1712          * again later. (This heuristic is not always a win.)
1713          * It is not necessary to compare scan[2] and match[2] since they
1714          * are always equal when the other bytes match, given that
1715          * the hash keys are equal and that HASH_BITS >= 8.
1716          */
1717         scan += 2, match++; // 2:byte alignment
1718 
1719         /* We check for insufficient lookahead only every 8th comparison;
1720          * the 256th check will be made at strstart+258.
1721          */
1722         do {
1723         } while (*++scan == *++match && *++scan == *++match &&
1724                  *++scan == *++match && *++scan == *++match &&
1725                  *++scan == *++match && *++scan == *++match &&
1726                  *++scan == *++match && *++scan == *++match &&
1727                  scan < strend);
1728 
1729         Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan");
1730 
1731         len = MAX_MATCH - (int)(strend - scan);
1732         scan = strend - MAX_MATCH;
1733 
1734 #endif /* UNALIGNED_OK */
1735 
1736         if (len > best_len) {
1737             s->match_start = cur_match;
1738             best_len = len;
1739             if (len >= s->nice_match) {
1740                 break;
1741             }
1742 #ifdef UNALIGNED_OK
1743             scan_end = *(ush*)(scan+best_len-1);
1744 #else
1745             scan_end1  = scan[best_len-1];
1746             scan_end   = scan[best_len];
1747 #endif
1748         }
1749     } while ((cur_match = s->prev[cur_match & s->w_mask]) > limit
1750              && --chain_length != 0);
1751 
1752     return best_len;
1753 }
1754 
1755 local int ct_tally (s, dist, lc)
1756     deflate_state *s;
1757     int dist;  /* distance of matched string */
1758     int lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
1759 {
1760     s->d_buf[s->last_lit] = (ush)dist;
1761     s->l_buf[s->last_lit++] = (uch)lc;
1762     if (dist == 0) {
1763         /* lc is the unmatched char */
1764         s->dyn_ltree[lc].Freq++;
1765     } else {
1766         s->matches++;
1767         /* Here, lc is the match length - MIN_MATCH */
1768         dist--;             /* dist = match distance - 1 */
1769         Assert((ush)dist < (ush)MAX_DIST(s) &&
1770                (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
1771                (ush)d_code(dist) < (ush)D_CODES,  "ct_tally: bad match");
1772 
1773         s->dyn_ltree[length_code[lc] + LITERALS + 1].Freq++;
1774         s->dyn_dtree[d_code(dist)].Freq++;
1775     }
1776 
1777     /* Try to guess if it is profitable to stop the current block here */
1778     if (s->level > 2 && (s->last_lit & 0xfff) == 0) { // 2:byte alignment
1779         /* Compute an upper bound for the compressed length */
1780         ulg out_length = (ulg)s->last_lit * 8L;
1781         ulg in_length = (ulg)s->strstart - s->block_start;
1782         int dcode;
1783         for (dcode = 0; dcode < D_CODES; dcode++) {
1784             out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]);
1785         }
1786         out_length >>= 3; // 3:byte alignment
1787 
1788         if (s->matches < s->last_lit / 2 && out_length < in_length / 2) { // 2:byte alignment
1789             return 1;
1790         }
1791     }
1792     return (s->last_lit == s->lit_bufsize - 1);
1793     /* We avoid equality with lit_bufsize because of wraparound at 64K
1794      * on 16 bit machines and because stored fblocks are restricted to
1795      * 64K-1 bytes.
1796      */
1797 }
1798 
1799 local void set_data_type(s)
1800     deflate_state *s;
1801 {
1802     int n = 0;
1803     unsigned ascii_freq = 0;
1804     unsigned bin_freq = 0;
1805     while (n < 7) { // 7:byte alignment
1806         bin_freq += s->dyn_ltree[n++].Freq;
1807     }
1808     while (n < 128) { // 128:byte alignment
1809         ascii_freq += s->dyn_ltree[n++].Freq;
1810     }
1811     while (n < LITERALS) {
1812         bin_freq += s->dyn_ltree[n++].Freq;
1813     }
1814     s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII); // 2:byte alignment
1815 }
1816 
1817 local void pqdownheap(s, tree, k)
1818     deflate_state *s;
1819     ct_data *tree;  /* the tree to restore */
1820     int k;               /* node to move down */
1821 {
1822     int v = s->heap[k];
1823     int j = k << 1;  /* left son of k */
1824     while (j <= s->heap_len) {
1825         /* Set j to the smallest of the two sons: */
1826         if (j < s->heap_len &&
1827             smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) {
1828             j++;
1829         }
1830         /* Exit if v is smaller than both sons */
1831         if (smaller(tree, v, s->heap[j], s->depth)) {
1832             break;
1833         }
1834 
1835         /* Exchange v with the smallest son */
1836         s->heap[k] = s->heap[j];
1837         k = j;
1838 
1839         /* And continue down the tree, setting j to the left son of k */
1840         j <<= 1;
1841     }
1842     s->heap[k] = v;
1843 }
1844 
1845 local void gen_bitlen(s, desc)
1846     deflate_state *s;
1847     tree_desc *desc;    /* the tree descriptor */
1848 {
1849     ct_data *tree  = desc->dyn_tree;
1850     int max_code   = desc->max_code;
1851     ct_data *stree = desc->stat_desc->static_tree;
1852     int *extra     = desc->stat_desc->extra_bits;
1853     int base       = desc->stat_desc->extra_base;
1854     int max_length = desc->stat_desc->max_length;
1855     int h;              /* heap index */
1856     int n, m;           /* iterate over the tree elements */
1857     int bits;           /* bit length */
1858     int xbits;          /* extra bits */
1859     ush f;              /* frequency */
1860     int overflow = 0;   /* number of elements with bit length too large */
1861 
1862     for (bits = 0; bits <= MAX_BITS; bits++) {
1863         s->bl_count[bits] = 0;
1864     }
1865 
1866     /* In a first pass, compute the optimal bit lengths (which may
1867      * overflow in the case of the bit length tree).
1868      */
1869     tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
1870 
1871     for (h = s->heap_max + 1; h < HEAP_SIZE; h++) {
1872         n = s->heap[h];
1873         bits = tree[tree[n].Dad].Len + 1;
1874         if (bits > max_length) {
1875             bits = max_length, overflow++;
1876         }
1877         tree[n].Len = (ush)bits;
1878         /* We overwrite tree[n].Dad which is no longer needed */
1879 
1880         if (n > max_code) {
1881             continue; /* not a leaf node */
1882         }
1883 
1884         s->bl_count[bits]++;
1885         xbits = 0;
1886         if (n >= base) {
1887             xbits = extra[n - base];
1888         }
1889         f = tree[n].Freq;
1890         s->opt_len += (ulg)f * (bits + xbits);
1891         if (stree) {
1892             s->static_len += (ulg)f * (stree[n].Len + xbits);
1893         }
1894     }
1895     if (overflow == 0) {
1896         return;
1897     }
1898 
1899     /* This happens for example on obj2 and pic of the Calgary corpus */
1900 
1901     /* Find the first bit length which could increase: */
1902     do {
1903         bits = max_length-1;
1904         while (s->bl_count[bits] == 0) {
1905             bits--;
1906         }
1907         s->bl_count[bits]--;      /* move one leaf down the tree */
1908         s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ // 2:byte alignment
1909         s->bl_count[max_length]--;
1910         /* The brother of the overflow item also moves one step up,
1911          * but this does not affect bl_count[max_length]
1912          */
1913         overflow -= 2; // 2:byte alignment
1914     } while (overflow > 0);
1915 
1916     /* Now recompute all bit lengths, scanning in increasing frequency.
1917      * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
1918      * lengths instead of fixing only the wrong ones. This idea is taken
1919      * from 'ar' written by Haruhiko Okumura.)
1920      */
1921     for (bits = max_length; bits != 0; bits--) {
1922         n = s->bl_count[bits];
1923         while (n != 0) {
1924             m = s->heap[--h];
1925             if (m > max_code) {
1926                 continue;
1927             }
1928             if (tree[m].Len != (unsigned) bits) {
1929                 s->opt_len += ((long)bits - (long)tree[m].Len)
1930                               *(long)tree[m].Freq;
1931                 tree[m].Len = (ush)bits;
1932             }
1933             n--;
1934         }
1935     }
1936 }
1937 
1938 local void build_tree(s, desc)
1939     deflate_state *s;
1940     tree_desc *desc; /* the tree descriptor */
1941 {
1942     ct_data *tree   = desc->dyn_tree;
1943     ct_data *stree  = desc->stat_desc->static_tree;
1944     int elems       = desc->stat_desc->elems;
1945     int n, m;          /* iterate over heap elements */
1946     int max_code = -1; /* largest code with non zero frequency */
1947     int node = elems;  /* next internal node of the tree */
1948     int new;           /* new node being created */
1949 
1950     /* Construct the initial heap, with least frequent element in
1951      * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
1952      * heap[0] is not used.
1953      */
1954     s->heap_len = 0, s->heap_max = HEAP_SIZE;
1955 
1956     for (n = 0; n < elems; n++) {
1957         if (tree[n].Freq != 0) {
1958             s->heap[++(s->heap_len)] = max_code = n;
1959             s->depth[n] = 0;
1960         } else {
1961             tree[n].Len = 0;
1962         }
1963     }
1964 
1965     /* The pkzip format requires that at least one distance code exists,
1966      * and that at least one bit should be sent even if there is only one
1967      * possible code. So to avoid special checks later on we force at least
1968      * two codes of non zero frequency.
1969      */
1970     while (s->heap_len < 2) { // 2:byte alignment
1971         new = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); // 2:byte alignment
1972         tree[new].Freq = 1;
1973         s->depth[new] = 0;
1974         s->opt_len--;
1975         if (stree) {
1976             s->static_len -= stree[new].Len;
1977         }
1978         /* new is 0 or 1 so it does not have extra bits */
1979     }
1980     desc->max_code = max_code;
1981 
1982     /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
1983      * establish sub-heaps of increasing lengths:
1984      */
1985     for (n = s->heap_len / 2; n >= 1; n--) { // 2:byte alignment
1986         pqdownheap(s, tree, n);
1987     }
1988 
1989     /* Construct the Huffman tree by repeatedly combining the least two
1990      * frequent nodes.
1991      */
1992     do {
1993         pqremove(s, tree, n);  /* n = node of least frequency */
1994         m = s->heap[SMALLEST]; /* m = node of next least frequency */
1995 
1996         s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
1997         s->heap[--(s->heap_max)] = m;
1998 
1999         /* Create a new node father of n and m */
2000         tree[node].Freq = tree[n].Freq + tree[m].Freq;
2001         s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
2002         tree[n].Dad = tree[m].Dad = (ush)node;
2003 #ifdef DUMP_BL_TREE
2004         if (tree == s->bl_tree) {
2005             fprintf(stderr, "\nnode %d(%d), sons %d(%d) %d(%d)",
2006                     node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
2007         }
2008 #endif
2009         /* and insert the new node in the heap */
2010         s->heap[SMALLEST] = node++;
2011         pqdownheap(s, tree, SMALLEST);
2012     } while (s->heap_len >= 2); // 2:byte alignment
2013 
2014     s->heap[--(s->heap_max)] = s->heap[SMALLEST];
2015 
2016     /* At this point, the fields freq and dad are set. We can now
2017      * generate the bit lengths.
2018      */
2019     gen_bitlen(s, (tree_desc *)desc);
2020 
2021     /* The field len is now set, we can generate the bit codes */
2022     gen_codes ((ct_data *)tree, max_code, s->bl_count);
2023 }
2024 
2025 local void scan_tree (s, tree, max_code)
2026     deflate_state *s;
2027     ct_data *tree;   /* the tree to be scanned */
2028     int max_code;    /* and its largest code of non zero frequency */
2029 {
2030     int n;                     /* iterates over all tree elements */
2031     int prevlen = -1;          /* last emitted length */
2032     int curlen;                /* length of current code */
2033     int nextlen = tree[0].Len; /* length of next code */
2034     int count = 0;             /* repeat count of the current code */
2035     int max_count = 7;         /* max repeat count */
2036     int min_count = 4;         /* min repeat count */
2037 
2038     if (nextlen == 0) {
2039         max_count = 138, min_count = 3; // 3:byte alignment, 138:byte alignment
2040     }
2041     tree[max_code + 1].Len = (ush)0xffff; /* guard */
2042 
2043     for (n = 0; n <= max_code; n++) {
2044         curlen = nextlen;
2045         nextlen = tree[n+1].Len;
2046         if (++count < max_count && curlen == nextlen) {
2047             continue;
2048         } else if (count < min_count) {
2049             s->bl_tree[curlen].Freq += count;
2050         } else if (curlen != 0) {
2051             if (curlen != prevlen) {
2052                 s->bl_tree[curlen].Freq++;
2053             }
2054             s->bl_tree[REP_3_6].Freq++;
2055         } else if (count <= 10) { // 10:byte alignment
2056             s->bl_tree[REPZ_3_10].Freq++;
2057         } else {
2058             s->bl_tree[REPZ_11_138].Freq++;
2059         }
2060         count = 0;
2061         prevlen = curlen;
2062         if (nextlen == 0) {
2063             max_count = 138, min_count = 3; // 3:byte alignment, 138:byte alignment
2064         } else if (curlen == nextlen) {
2065             max_count = 6, min_count = 3; // 3:byte alignment, 6:byte alignment
2066         } else {
2067             max_count = 7, min_count = 4; // 7:byte alignment, 4:byte alignment
2068         }
2069     }
2070 }
2071 
2072 local int build_bl_tree(s)
2073     deflate_state *s;
2074 {
2075     int max_blindex;  /* index of last bit length code of non zero freq */
2076 
2077     /* Determine the bit length frequencies for literal and distance trees */
2078     scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
2079     scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
2080 
2081     /* Build the bit length tree: */
2082     build_tree(s, (tree_desc *)(&(s->bl_desc)));
2083     /* opt_len now includes the length of the tree representations, except
2084      * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
2085      */
2086 
2087     /* Determine the number of bit length codes to send. The pkzip format
2088      * requires that at least 4 bit length codes be sent. (appnote.txt says
2089      * 3 but the actual value used is 4.)
2090      */
2091     for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { // 3:byte alignment
2092         if (s->bl_tree[bl_order[max_blindex]].Len != 0) {
2093             break;
2094         }
2095     }
2096     /* Update opt_len to include the bit length tree and counts */
2097     s->opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; // 3:byte alignment, 4:byte alignment, 5:byte alignment
2098 
2099     return max_blindex;
2100 }
2101 
2102 local void send_bits(s, value, length)
2103     deflate_state *s;
2104     int value;  /* value to send */
2105     int length; /* number of bits */
2106 {
2107 #ifdef DEBUG
2108     Assert(length > 0 && length <= 15, "invalid length"); // 15:byte alignment
2109     s->bits_sent += (ulg)length;
2110 #endif
2111     /* If not enough room in bi_buf, use (valid) bits from bi_buf and
2112      * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
2113      * unused bits in value.
2114      */
2115     if (s->bi_valid > (int)Buf_size - length) {
2116         s->bi_buf |= (value << s->bi_valid);
2117         put_short(s, s->bi_buf);
2118         s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
2119         s->bi_valid += length - Buf_size;
2120     } else {
2121         s->bi_buf |= value << s->bi_valid;
2122         s->bi_valid += length;
2123     }
2124 }
2125 
2126 local void bi_windup(s)
2127     deflate_state *s;
2128 {
2129     if (s->bi_valid > 8) { // 8:byte alignment
2130         put_short(s, s->bi_buf);
2131     } else if (s->bi_valid > 0) {
2132         put_byte(s, (Byte)s->bi_buf);
2133     }
2134     s->bi_buf = 0;
2135     s->bi_valid = 0;
2136 #ifdef DEBUG
2137     s->bits_sent = (s->bits_sent + 7) & ~7; // 7:byte alignment
2138 #endif
2139 }
2140 
2141 local void copy_block(s, buf, len, header)
2142     deflate_state *s;
2143     char     *buf;    /* the input data */
2144     unsigned len;     /* its length */
2145     int      header;  /* true if block header must be written */
2146 {
2147     bi_windup(s);              /* align on byte boundary */
2148 
2149     if (header) {
2150         put_short(s, (ush)len);
2151         put_short(s, (ush)~len);
2152 #ifdef DEBUG
2153         s->bits_sent += 2 * 16; // 2:byte alignment, 16:byte alignment
2154 #endif
2155     }
2156 #ifdef DEBUG
2157     s->bits_sent += (ulg)len << 3; // 3:byte alignment
2158 #endif
2159     while (len--) {
2160         put_byte(s, *buf++);
2161     }
2162 }
2163 
2164 local void compress_block(s, ltree, dtree)
2165     deflate_state *s;
2166     ct_data *ltree; /* literal tree */
2167     ct_data *dtree; /* distance tree */
2168 {
2169     unsigned dist;      /* distance of matched string */
2170     int lc;             /* match length or unmatched char (if dist == 0) */
2171     unsigned lx = 0;    /* running index in l_buf */
2172     unsigned code;      /* the code to send */
2173     int extra;          /* number of extra bits to send */
2174 
2175     if (s->last_lit != 0) {
2176         do {
2177             dist = s->d_buf[lx];
2178             lc = s->l_buf[lx++];
2179             if (dist == 0) {
2180                 send_code(s, lc, ltree); /* send a literal byte */
2181             } else {
2182                 /* Here, lc is the match length - MIN_MATCH */
2183                 code = length_code[lc];
2184                 send_code(s, code+LITERALS + 1, ltree); /* send the length code */
2185                 extra = extra_lbits[code];
2186                 if (extra != 0) {
2187                     lc -= base_length[code];
2188                     send_bits(s, lc, extra);       /* send the extra length bits */
2189                 }
2190                 dist--; /* dist is now the match distance - 1 */
2191                 code = d_code(dist);
2192                 Assert (code < D_CODES, "bad d_code");
2193 
2194                 send_code(s, code, dtree);       /* send the distance code */
2195                 extra = extra_dbits[code];
2196                 if (extra != 0) {
2197                     dist -= base_dist[code];
2198                     send_bits(s, dist, extra);   /* send the extra distance bits */
2199                 }
2200             } /* literal or match pair ? */
2201 
2202             /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
2203             Assert(s->pending < s->lit_bufsize + 2 * lx, "pendingBuf overflow");
2204         } while (lx < s->last_lit);
2205     }
2206     send_code(s, END_BLOCK, ltree);
2207 }
2208 
2209 local void send_tree (s, tree, max_code)
2210     deflate_state *s;
2211     ct_data *tree; /* the tree to be scanned */
2212     int max_code;       /* and its largest code of non zero frequency */
2213 {
2214     int n;                     /* iterates over all tree elements */
2215     int prevlen = -1;          /* last emitted length */
2216     int curlen;                /* length of current code */
2217     int nextlen = tree[0].Len; /* length of next code */
2218     int count = 0;             /* repeat count of the current code */
2219     int max_count = 7;         /* max repeat count */
2220     int min_count = 4;         /* min repeat count */
2221 
2222     if (nextlen == 0) {
2223         max_count = 138, min_count = 3; // 138:byte alignment, 3:byte alignment
2224     }
2225 
2226     for (n = 0; n <= max_code; n++) {
2227         curlen = nextlen;
2228         nextlen = tree[n + 1].Len;
2229         if (++count < max_count && curlen == nextlen) {
2230             continue;
2231         } else if (count < min_count) {
2232             do {
2233                 send_code(s, curlen, s->bl_tree);
2234             } while (--count != 0);
2235         } else if (curlen != 0) {
2236             if (curlen != prevlen) {
2237                 send_code(s, curlen, s->bl_tree);
2238                 count--;
2239             }
2240             Assert(count >= 3 && count <= 6, " 3_6?"); // 3:byte alignment, 6:byte alignment
2241             send_code(s, REP_3_6, s->bl_tree);
2242             send_bits(s, count - 3, 2); // 3:byte alignment, 2:byte alignment
2243         } else if (count <= 10) { // 10:byte alignment
2244             send_code(s, REPZ_3_10, s->bl_tree);
2245             send_bits(s, count - 3, 3); // 3:byte alignment
2246         } else {
2247             send_code(s, REPZ_11_138, s->bl_tree);
2248             send_bits(s, count - 11, 7); // 11:byte alignment, 7:byte alignment
2249         }
2250         count = 0;
2251         prevlen = curlen;
2252         if (nextlen == 0) {
2253             max_count = 138, min_count = 3; // 138:byte alignment, 3:byte alignment
2254         } else if (curlen == nextlen) {
2255             max_count = 6, min_count = 3; // 6:byte alignment, 3:byte alignment
2256         } else {
2257             max_count = 7, min_count = 4; // 7:byte alignment, 4:byte alignment
2258         }
2259     }
2260 }
2261 
2262 local void send_all_trees(s, lcodes, dcodes, blcodes)
2263     deflate_state *s;
2264     int lcodes, dcodes, blcodes; /* number of codes for each tree */
2265 {
2266     int rank;                    /* index in bl_order */
2267 
2268     Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); // 257:byte alignment, 4:byte alignment
2269     Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
2270             "too many codes");
2271     send_bits(s, lcodes - 257, 5); // 257:byte alignment, 5:byte alignment
2272     send_bits(s, dcodes-1,   5); // 5:byte alignment
2273     send_bits(s, blcodes - 4,  4); // 4:byte alignment
2274     for (rank = 0; rank < blcodes; rank++) {
2275         send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); // 3:byte alignment
2276     }
2277 
2278     send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */
2279 
2280     send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */
2281 }
2282 
2283 ulg ct_flush_block(s, buf, stored_len, eof)
2284     deflate_state *s;
2285     char *buf;        /* input block, or NULL if too old */
2286     ulg stored_len;   /* length of input block */
2287     int eof;          /* true if this is the last block for a file */
2288 {
2289     ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
2290     int max_blindex;  /* index of last bit length code of non zero freq */
2291 
2292      /* Check if the file is ascii or binary */
2293     if (s->data_type == UNKNOWN) {
2294         set_data_type(s);
2295     }
2296 
2297     /* Construct the literal and distance trees */
2298     build_tree(s, (tree_desc *)(&(s->l_desc)));
2299 
2300     build_tree(s, (tree_desc *)(&(s->d_desc)));
2301 
2302     /* At this point, opt_len and static_len are the total bit lengths of
2303      * the compressed block data, excluding the tree representations.
2304      */
2305 
2306     /* Build the bit length tree for the above two trees, and get the index
2307      * in bl_order of the last bit length code to send.
2308      */
2309     max_blindex = build_bl_tree(s);
2310 
2311     /* Determine the best encoding. Compute first the block length in bytes */
2312     opt_lenb = (s->opt_len + 3 + 7) >> 3; // 7:byte alignment, 3:byte alignment
2313     static_lenb = (s->static_len + 3 + 7) >> 3; // 3:byte alignment, 7:byte alignment
2314 
2315     if (static_lenb <= opt_lenb) {
2316         opt_lenb = static_lenb;
2317     }
2318 
2319     /* If compression failed and this is the first and last block,
2320      * and if the .zip file can be seeked (to rewrite the local header),
2321      * the whole file is transformed into a stored file:
2322      */
2323 
2324     if (stored_len+4 <= opt_lenb && buf != (char*)0) {
2325         /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
2326          * Otherwise we can't have processed more than WSIZE input bytes since
2327          * the last block flush, because compression would have been
2328          * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
2329          * transform a block into a stored block.
2330          */
2331         send_bits(s, (STORED_BLOCK << 1) + eof, 3);  // 3:byte alignment /* send block type */
2332         s->compressed_len = (s->compressed_len + 3 + 7) & ~7L; // 7:byte alignment, 3:byte alignment
2333         s->compressed_len += (stored_len + 4) << 3; // 3:byte alignment, 4:byte alignment
2334 
2335         copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
2336     } else if (static_lenb == opt_lenb) {
2337         send_bits(s, (STATIC_TREES << 1) + eof, 3); // 3:byte alignment
2338         compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
2339         s->compressed_len += 3 + s->static_len; // 3:byte alignment
2340     } else {
2341         send_bits(s, (DYN_TREES << 1) + eof, 3); // 3:byte alignment
2342         send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code + 1,
2343                        max_blindex+1);
2344         compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
2345         s->compressed_len += 3 + s->opt_len; // 3:byte alignment
2346     }
2347     Assert (s->compressed_len == s->bits_sent, "bad compressed size");
2348     init_block(s);
2349 
2350     if (eof) {
2351         bi_windup(s);
2352         s->compressed_len += 7;  /* align on byte boundary */
2353     }
2354 
2355     return s->compressed_len >> 3; // 3:byte alignment
2356 }
2357 
2358 local int deflate_fast(s, flush)
2359     deflate_state *s;
2360     int flush;
2361 {
2362     IPos hash_head; /* head of the hash chain */
2363     int bflush;     /* set if current block must be flushed */
2364 
2365     s->prev_length = MIN_MATCH - 1;
2366 
2367     for (;;) {
2368         /* Make sure that we always have enough lookahead, except
2369          * at the end of the input file. We need MAX_MATCH bytes
2370          * for the next match, plus MIN_MATCH bytes to insert the
2371          * string following the next match.
2372          */
2373         if (s->lookahead < MIN_LOOKAHEAD) {
2374             fill_window(s);
2375             if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
2376                 return 1;
2377             }
2378 
2379             if (s->lookahead == 0) {
2380                 break; /* flush the current block */
2381             }
2382         }
2383 
2384         /* Insert the string window[strstart .. strstart+2] in the
2385          * dictionary, and set hash_head to the head of the hash chain:
2386          */
2387         INSERT_STRING(s, s->strstart, hash_head);
2388 
2389         /* Find the longest match, discarding those <= prev_length.
2390          * At this point we have always match_length < MIN_MATCH
2391          */
2392         if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
2393             /* To simplify the code, we prevent matches with the string
2394              * of window index 0 (in particular we have to avoid a match
2395              * of the string with itself at the start of the input file).
2396              */
2397             if (s->strategy != Z_HUFFMAN_ONLY) {
2398             s->match_length = longest_match(s, hash_head);
2399             }
2400             /* longest_match() sets match_start */
2401 
2402             if (s->match_length > s->lookahead) {
2403                 s->match_length = s->lookahead;
2404             }
2405         }
2406         if (s->match_length >= MIN_MATCH) {
2407             check_match(s, s->strstart, s->match_start, s->match_length);
2408 
2409             bflush = ct_tally(s, s->strstart - s->match_start,
2410                               s->match_length - MIN_MATCH);
2411 
2412             s->lookahead -= s->match_length;
2413 
2414             /* Insert new strings in the hash table only if the match length
2415              * is not too large. This saves time but degrades compression.
2416              */
2417             if (s->match_length <= s->max_insert_length) {
2418                 s->match_length--; /* string at strstart already in hash table */
2419                 do {
2420                     s->strstart++;
2421                     INSERT_STRING(s, s->strstart, hash_head);
2422                     /* strstart never exceeds WSIZE-MAX_MATCH, so there are
2423                      * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
2424                      * these bytes are garbage, but it does not matter since
2425                      * the next lookahead bytes will be emitted as literals.
2426                      */
2427                 } while (--s->match_length != 0);
2428                 s->strstart++;
2429             } else {
2430                 s->strstart += s->match_length;
2431                 s->match_length = 0;
2432                 s->ins_h = s->window[s->strstart];
2433                 UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]);
2434 #if MIN_MATCH != 3
2435                 Call UPDATE_HASH() MIN_MATCH-3 more times
2436 #endif
2437             }
2438         } else {
2439             /* No match, output a literal byte */
2440             bflush = ct_tally (s, 0, s->window[s->strstart]);
2441             s->lookahead--;
2442             s->strstart++;
2443         }
2444         if (bflush) {
2445             FLUSH_BLOCK(s, 0);
2446         }
2447     }
2448     FLUSH_BLOCK(s, flush == Z_FINISH);
2449     return 0; /* normal exit */
2450 }
2451 
2452 local int deflate_slow(s, flush)
2453     deflate_state *s;
2454     int flush;
2455 {
2456     IPos hash_head;          /* head of hash chain */
2457     int bflush;              /* set if current block must be flushed */
2458 
2459     /* Process the input block. */
2460     for (;;) {
2461         /* Make sure that we always have enough lookahead, except
2462          * at the end of the input file. We need MAX_MATCH bytes
2463          * for the next match, plus MIN_MATCH bytes to insert the
2464          * string following the next match.
2465          */
2466         if (s->lookahead < MIN_LOOKAHEAD) {
2467             fill_window(s);
2468             if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
2469                 return 1;
2470             }
2471 
2472             if (s->lookahead == 0) {
2473                 break; /* flush the current block */
2474             }
2475         }
2476 
2477         /* Insert the string window[strstart .. strstart+2] in the
2478          * dictionary, and set hash_head to the head of the hash chain:
2479          */
2480         INSERT_STRING(s, s->strstart, hash_head);
2481 
2482         /* Find the longest match, discarding those <= prev_length.
2483          */
2484         s->prev_length = s->match_length, s->prev_match = s->match_start;
2485         s->match_length = MIN_MATCH-1;
2486 
2487         if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
2488             s->strstart - hash_head <= MAX_DIST(s)) {
2489             /* To simplify the code, we prevent matches with the string
2490              * of window index 0 (in particular we have to avoid a match
2491              * of the string with itself at the start of the input file).
2492              */
2493             if (s->strategy != Z_HUFFMAN_ONLY) {
2494             s->match_length = longest_match (s, hash_head);
2495             }
2496             /* longest_match() sets match_start */
2497             if (s->match_length > s->lookahead) {
2498                 s->match_length = s->lookahead;
2499             }
2500 
2501             if (s->match_length <= 5 && (s->strategy == Z_FILTERED || // 5:byte alignment
2502                  (s->match_length == MIN_MATCH &&
2503                   s->strstart - s->match_start > TOO_FAR))) {
2504                 /* If prev_match is also MIN_MATCH, match_start is garbage
2505                  * but we will ignore the current match anyway.
2506                  */
2507                 s->match_length = MIN_MATCH - 1;
2508             }
2509         }
2510         /* If there was a match at the previous step and the current
2511          * match is not better, output the previous match:
2512          */
2513         if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
2514             check_match(s, s->strstart - 1, s->prev_match, s->prev_length);
2515 
2516             bflush = ct_tally(s, s->strstart -1 - s->prev_match,
2517                               s->prev_length - MIN_MATCH);
2518 
2519             /* Insert in hash table all strings up to the end of the match.
2520              * strstart-1 and strstart are already inserted.
2521              */
2522             s->lookahead -= s->prev_length - 1;
2523             s->prev_length -= 2;
2524             do {
2525                 s->strstart++;
2526                 INSERT_STRING(s, s->strstart, hash_head);
2527                 /* strstart never exceeds WSIZE-MAX_MATCH, so there are
2528                  * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH
2529                  * these bytes are garbage, but it does not matter since the
2530                  * next lookahead bytes will always be emitted as literals.
2531                  */
2532             } while (--s->prev_length != 0);
2533             s->match_available = 0;
2534             s->match_length = MIN_MATCH - 1;
2535             s->strstart++;
2536 
2537             if (bflush) {
2538                 FLUSH_BLOCK(s, 0);
2539             }
2540         } else if (s->match_available) {
2541             /* If there was no match at the previous position, output a
2542              * single literal. If there was a match but the current match
2543              * is longer, truncate the previous match to a single literal.
2544              */
2545             if (ct_tally (s, 0, s->window[s->strstart - 1])) {
2546                 FLUSH_BLOCK_ONLY(s, 0);
2547             }
2548             s->strstart++;
2549             s->lookahead--;
2550             if (s->strm->avail_out == 0) {
2551                 return 1;
2552             }
2553         } else {
2554             /* There is no previous match to compare with, wait for
2555              * the next step to decide.
2556              */
2557             s->match_available = 1;
2558             s->strstart++;
2559             s->lookahead--;
2560         }
2561     }
2562     if (s->match_available) {
2563         ct_tally (s, 0, s->window[s->strstart - 1]);
2564     }
2565 
2566     FLUSH_BLOCK(s, flush == Z_FINISH);
2567     return 0;
2568 }
2569 
2570 local int deflate (strm, flush)
2571     z_stream *strm;
2572     int flush;
2573 {
2574     if (strm == Z_NULL || strm->state == Z_NULL) {
2575         return Z_STREAM_ERROR;
2576     }
2577 
2578     if (strm->next_out == Z_NULL || strm->next_in == Z_NULL) {
2579         ERR_RETURN(strm, Z_STREAM_ERROR);
2580     }
2581     if (strm->avail_out == 0) {
2582         ERR_RETURN(strm, Z_BUF_ERROR);
2583     }
2584 
2585     strm->state->strm = strm; /* just in case */
2586 
2587     /* Write the zlib header */
2588     if (strm->state->status == INIT_STATE) {
2589         uInt header = (DEFLATED + ((strm->state->w_bits - 8) << 4)) << 8; // 4:byte alignment, 8:byte alignment
2590         uInt level_flags = (strm->state->level - 1) >> 1;
2591 
2592         if (level_flags > 3) { // 3:byte alignment
2593             level_flags = 3; // 3:byte alignment
2594         }
2595         header |= (level_flags << 6); // 3:byte alignment
2596         header += 31 - (header % 31); // 31:byte alignment
2597 
2598         strm->state->status = BUSY_STATE;
2599         putShortMSB(strm->state, header);
2600     }
2601 
2602     /* Flush as much pending output as possible */
2603     if (strm->state->pending != 0) {
2604         flush_pending(strm);
2605         if (strm->avail_out == 0) {
2606             return Z_OK;
2607         }
2608     }
2609 
2610     /* User must not provide more input after the first FINISH: */
2611     if (strm->state->status == FINISH_STATE && strm->avail_in != 0) {
2612         ERR_RETURN(strm, Z_BUF_ERROR);
2613     }
2614 
2615     /* Start a new block or continue the current one.
2616      */
2617     if (strm->avail_in != 0 ||
2618         (flush == Z_FINISH && strm->state->status != FINISH_STATE)) {
2619         if (flush == Z_FINISH) {
2620             strm->state->status = FINISH_STATE;
2621         }
2622         if (strm->state->level <= 3) { // 3:byte alignment
2623             if (deflate_fast(strm->state, flush)) {
2624                 return Z_OK;
2625             }
2626         } else {
2627             if (deflate_slow(strm->state, flush)) {
2628                 return Z_OK;
2629             }
2630         }
2631     }
2632     Assert(strm->avail_out > 0, "bug2");
2633 
2634     if (flush != Z_FINISH) {
2635         return Z_OK;
2636     }
2637     if (strm->state->noheader) {
2638         return Z_STREAM_END;
2639     }
2640 
2641     /* Write the zlib trailer (adler32) */
2642     putShortMSB(strm->state, (uInt)(strm->state->adler >> 16)); // 16:byte alignment
2643     putShortMSB(strm->state, (uInt)(strm->state->adler & 0xffff));
2644     flush_pending(strm);
2645     /* If avail_out is zero, the application will call deflate again
2646      * to flush the rest.
2647      */
2648     strm->state->noheader = 1; /* write the trailer only once! */
2649     return strm->state->pending != 0 ? Z_OK : Z_STREAM_END;
2650 }
2651 
2652 local int gzflush (file, flush)
2653     gzFile file;
2654     int flush;
2655 {
2656     uInt len;
2657     int done = 0;
2658     gz_stream *s = (gz_stream*)file;
2659 
2660     if (s == NULL || s->mode != 'w') {
2661         return Z_STREAM_ERROR;
2662     }
2663 
2664     s->stream.avail_in = 0; /* should be zero already anyway */
2665 
2666     for (;;) {
2667         len = Z_BUFSIZE - s->stream.avail_out;
2668 
2669         if (len != 0) {
2670             if (fwrite(s->outbuf, 1, len, s->file) != len) {
2671             s->z_err = Z_ERRNO;
2672             return Z_ERRNO;
2673             }
2674             s->stream.next_out = s->outbuf;
2675             s->stream.avail_out = Z_BUFSIZE;
2676         }
2677         if (done) {
2678             break;
2679         }
2680         s->z_err = deflate(&(s->stream), flush);
2681 
2682         /* deflate has finished flushing only when it hasn't used up
2683          * all the available space in the output buffer:
2684          */
2685         done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
2686 
2687         if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) {
2688             break;
2689         }
2690     }
2691     return  s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
2692 }
2693 
2694 local gzFile gz_open (path, mode, fd)
2695     char *path;
2696     char *mode;
2697     int  fd;
2698 {
2699     int err;
2700     char *p = mode;
2701     gz_stream *s = (gz_stream *)ALLOC(sizeof(gz_stream));
2702 
2703     if (!s) {
2704         return Z_NULL;
2705     }
2706 
2707     s->stream.zalloc = (alloc_func)0;
2708     s->stream.zfree = (free_func)0;
2709     s->stream.next_in = s->inbuf = Z_NULL;
2710     s->stream.next_out = s->outbuf = Z_NULL;
2711     s->stream.avail_in = s->stream.avail_out = 0;
2712     s->file = NULL;
2713     s->z_err = Z_OK;
2714     s->z_eof = 0;
2715     s->crc = crc32(0L, Z_NULL, 0);
2716     s->msg = NULL;
2717     s->transparent = 0;
2718 
2719     s->path = (char*)ALLOC(strlen(path)+1);
2720     if (s->path == NULL) {
2721         return destroy(s), (gzFile)Z_NULL;
2722     }
2723     strcpy(s->path, path); /* do this early for debugging */
2724 
2725     s->mode = '\0';
2726     do {
2727         if (*p == 'r') {
2728             s->mode = 'r';
2729         }
2730         if (*p == 'w') {
2731             s->mode = 'w';
2732         }
2733     } while (*p++);
2734     if (s->mode == '\0') {
2735         return destroy(s), (gzFile)Z_NULL;
2736     }
2737 
2738     if (s->mode == 'w') {
2739         err = deflateInit2(&(s->stream), Z_BEST_COMPRESSION,
2740                            DEFLATED, -WBITS, MEM_LEVEL, 0);
2741         /* windowBits is passed < 0 to suppress zlib header */
2742 
2743         s->stream.next_out = s->outbuf = ALLOC(Z_BUFSIZE);
2744 
2745         if (err != Z_OK || s->outbuf == Z_NULL) {
2746             return destroy(s), (gzFile)Z_NULL;
2747         }
2748     } else {
2749         err = inflateInit2(&(s->stream), -WBITS);
2750         s->stream.next_in  = s->inbuf = ALLOC(Z_BUFSIZE);
2751 
2752         if (err != Z_OK || s->inbuf == Z_NULL) {
2753             return destroy(s), (gzFile)Z_NULL;
2754         }
2755     }
2756     s->stream.avail_out = Z_BUFSIZE;
2757 
2758     errno = 0;
2759     s->file = fd < 0 ? fopen(path, mode) : fdopen(fd, mode);
2760 
2761     if (s->file == NULL) {
2762         return destroy(s), (gzFile)Z_NULL;
2763     }
2764     if (s->mode == 'w') {
2765         /* Write a very simple .gz header:
2766          */
2767         fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", GZ_MAGIC_1, GZ_MAGIC_2,
2768                 DEFLATED, 0, 0, 0, 0, 0, 0, OS_CODE);
2769     } else {
2770         /* Check and skip the header:
2771          */
2772         Byte c1 = 0, c2 = 0;
2773         Byte method = 0;
2774         Byte flags = 0;
2775         Byte xflags = 0;
2776         Byte time[4];
2777         Byte osCode;
2778         int c;
2779 
2780         s->stream.avail_in = fread(s->inbuf, 1, 2, s->file); // 2:size
2781         if (s->stream.avail_in != 2 || s->inbuf[0] != GZ_MAGIC_1 // 2:byte alignment
2782             || s->inbuf[1] != GZ_MAGIC_2) {
2783             s->transparent = 1;
2784             return (gzFile)s;
2785         }
2786         s->stream.avail_in = 0;
2787         err = fscanf(s->file, "%c%c%4c%c%c", &method, &flags, time, &xflags, &osCode);
2788 
2789         if (method != DEFLATED || feof(s->file) || (flags & RESERVED) != 0) {
2790             s->z_err = Z_DATA_ERROR;
2791             return (gzFile)s;
2792         }
2793         if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
2794             long len;
2795             err = fscanf(s->file, "%c%c", &c1, &c2);
2796             len = c1 + ((long)c2 << 8); // 8:byte alignment
2797             fseek(s->file, len, SEEK_CUR);
2798         }
2799         if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
2800             while ((c = getc(s->file)) != 0 && c != EOF) {
2801             }
2802         }
2803         if ((flags & COMMENT) != 0) {   /* skip the .gz file comment */
2804             while ((c = getc(s->file)) != 0 && c != EOF) {
2805             }
2806         }
2807         if ((flags & HEAD_CRC) != 0) {  /* skip the header crc */
2808             err = fscanf(s->file, "%c%c", &c1, &c2);
2809         }
2810         if (feof(s->file)) {
2811             s->z_err = Z_DATA_ERROR;
2812         }
2813     }
2814     return (gzFile)s;
2815 }
2816 
2817 local gzFile gzopen (path, mode)
2818     char *path;
2819     char *mode;
2820 {
2821     return gz_open (path, mode, -1);
2822 }
2823 
2824 local int gzwrite (file, buf, len)
2825     gzFile file;
2826     voidp buf;
2827     unsigned len;
2828 {
2829     gz_stream *s = (gz_stream*)file;
2830 
2831     if (s == NULL || s->mode != 'w') {
2832         return Z_STREAM_ERROR;
2833     }
2834 
2835     s->stream.next_in = buf;
2836     s->stream.avail_in = len;
2837 
2838     while (s->stream.avail_in != 0) {
2839         if (s->stream.avail_out == 0) {
2840             s->stream.next_out = s->outbuf;
2841             if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
2842                 s->z_err = Z_ERRNO;
2843                 break;
2844             }
2845             s->stream.avail_out = Z_BUFSIZE;
2846         }
2847         s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
2848 
2849         if (s->z_err != Z_OK) {
2850             break;
2851         }
2852     }
2853     s->crc = crc32(s->crc, buf, len);
2854 
2855     return len - s->stream.avail_in;
2856 }
2857 
2858 local int gzclose (file)
2859     gzFile file;
2860 {
2861     uInt n;
2862     int err;
2863     gz_stream *s = (gz_stream*)file;
2864 
2865     if (s == NULL) {
2866         return Z_STREAM_ERROR;
2867     }
2868 
2869     if (s->mode == 'w') {
2870         err = gzflush(file, Z_FINISH);
2871         if (err != Z_OK) {
2872             return destroy((gz_stream *)file);
2873         }
2874 
2875         putLong (s->file, s->crc);
2876         putLong (s->file, s->stream.total_in);
2877     } else if (s->mode == 'r' && s->z_err == Z_STREAM_END) {
2878         /* slide CRC and original size if they are at the end of inbuf */
2879         if ((n = s->stream.avail_in) < 8  && !s->z_eof) { // 8:byte alignment
2880             Byte *p = s->inbuf;
2881             Byte *q = s->stream.next_in;
2882             while (n--) {
2883                 *p++ = *q++;
2884             }
2885 
2886             n = s->stream.avail_in;
2887             n += fread(p, 1, 8, s->file); // 8:size
2888             s->stream.next_in = s->inbuf;
2889         }
2890         /* check CRC and original size */
2891         if (n < 8 ||
2892             getLong(s->stream.next_in) != s->crc ||
2893             getLong(s->stream.next_in + 4) != s->stream.total_out) { // 4:byte alignment
2894             s->z_err = Z_DATA_ERROR;
2895         }
2896     }
2897     return destroy((gz_stream *)file);
2898 }
2899 
2900 /* ========================================================================= */
2901 
2902 static int wm_tool_printf(const char *format, ...)
2903 {
2904     int ret;
2905     va_list ap;
2906 
2907         va_start(ap, format);
2908         ret = vprintf(format, ap);
2909         va_end(ap);
2910 
2911         fflush(stdout);
2912 
2913         return ret;
2914 }
2915 
2916 static unsigned long long wm_tool_crc32_reflect(unsigned long long ref, unsigned char ch)
2917 {
2918     int i;
2919     unsigned long long value = 0;
2920 
2921     for (i = 1; i < (ch + 1); i++) {
2922         if (ref & 1) {
2923             value |= 1 << (ch - i);
2924         }
2925         ref >>= 1;
2926     }
2927 
2928     return value;
2929 }
2930 
2931 static unsigned int wm_tool_crc32(unsigned int crc, unsigned char *buffer, int size, wm_tool_crc32_reflect_e mode)
2932 {
2933     int i;
2934     unsigned char temp;
2935 
2936     for (i = 0; i < size; i++) {
2937         if (mode & WM_TOOL_CRC32_REFLECT_INPUT) {
2938             temp = wm_tool_crc32_reflect(buffer[i], 8); // 8:ch
2939         } else {
2940             temp = buffer[i];
2941         }
2942         crc = wm_tool_crc32_tab[(crc ^ temp) & 0xff] ^ (crc >> 8); // 8:byte alignment
2943     }
2944 
2945     return crc ;
2946 }
2947 
2948 static unsigned int wm_tool_get_crc32(unsigned char *buffer, int size, wm_tool_crc32_reflect_e mode)
2949 {
2950     wm_tool_file_crc = wm_tool_crc32(wm_tool_file_crc, buffer, size, mode);
2951     if (mode & WM_TOOL_CRC32_REFLECT_OUTPUT) {
2952         wm_tool_file_crc = wm_tool_crc32_reflect(wm_tool_file_crc, 32); // 32:size
2953     }
2954     return wm_tool_file_crc;
2955 }
2956 
2957 static unsigned short wm_tool_get_crc16(unsigned char *ptr, unsigned short count)
2958 {
2959     unsigned short crc, i;
2960 
2961     crc = 0;
2962 
2963     while (count--) {
2964         crc = crc ^ (int) *ptr++ << 8; // 8:byte alignment
2965 
2966         for (i = 0; i < 8; i++) { // 8:loop cap
2967             if (crc & 0x8000)
2968                 crc = crc << 1 ^ 0x1021;
2969             else
2970                 crc = crc << 1;
2971         }
2972     }
2973 
2974     return (crc & 0xFFFF);
2975 }
2976 
2977 static int wm_tool_char_to_hex(char ch)
2978 {
2979     int hex;
2980 
2981     hex = -1;
2982 
2983     if ((ch >= '0') && (ch <= '9')) {
2984         hex = ch - '0';
2985     } else if ((ch >= 'a') && (ch <= 'f')) {
2986         hex = ch - 'a' + 0xa;
2987     } else if ((ch >= 'A') && (ch <= 'F')) {
2988         hex = ch - 'A' + 0xa;
2989     }
2990 
2991     return hex;
2992 }
2993 
2994 static int wm_tool_str_to_hex_array(char *str, int cnt, unsigned char array[])
2995 {
2996     int hex;
2997     unsigned char tmp;
2998     unsigned char *des;
2999 
3000     des = array;
3001 
3002     while (cnt-- > 0) {
3003         hex = wm_tool_char_to_hex(*str++);
3004         if (hex < 0) {
3005             return -1;
3006         } else {
3007             tmp = (hex << 4) & 0xf0;
3008         }
3009 
3010         hex = wm_tool_char_to_hex(*str++);
3011         if (hex < 0) {
3012             return -1;
3013         } else {
3014             tmp = tmp | (hex & 0x0f);
3015         }
3016 
3017         *des++ = (unsigned char) tmp;
3018     }
3019 
3020     return ((*str == 0) ? 0 : -1);
3021 }
3022 
3023 static char *wm_tool_strcasestr(const char *str1, const char *str2)
3024 {
3025     char *cp = (char *) str1;
3026     char *s1, *s2;
3027 
3028     if (!*str2) {
3029         return (char *) str1;
3030     }
3031 
3032     while (*cp) {
3033         s1 = cp;
3034         s2 = (char *) str2;
3035 
3036         while (*s1 && *s2 && !(tolower((int)*s1) - tolower((int)*s2))) {
3037             s1++, s2++;
3038         }
3039         if (!*s2) {
3040             return cp;
3041         }
3042         cp++;
3043     }
3044 
3045     return NULL;
3046 }
3047 
3048 static int wm_tool_get_file_size(const char* filename)
3049 {
3050     FILE *fp = fopen(filename, "r");
3051     if (!fp) {
3052         return -1;
3053     }
3054     fseek(fp, 0L, SEEK_END);
3055     int size = ftell(fp);
3056     fclose(fp);
3057     return size;
3058 }
3059 
3060 static char *wm_tool_get_name(const char *name)
3061 {
3062     static char sz_name[WM_TOOL_PATH_MAX] = {0};
3063     char *p = (char *)name;
3064     char *q = (char *)name;
3065 
3066     do {
3067 #ifdef __MINGW32__
3068         p = strchr(p, '\\');
3069 #else
3070         p = strchr(p, '/');
3071 #endif
3072         if (p) {
3073             p++;
3074             q = p;
3075         }
3076     } while (p);
3077 
3078     strncpy(sz_name, q, WM_TOOL_PATH_MAX - 1);
3079 
3080 #ifdef __MINGW32__
3081     p = wm_tool_strcasestr(sz_name, ".exe");
3082     if (p)
3083         *p = '\0';
3084 #endif
3085 
3086     return sz_name;
3087 }
3088 
3089 static void wm_tool_print_usage(const char *name)
3090 {
3091     wm_tool_printf("Usage: %s [-h] [-v] [-b] [-o] [-sb] [-ct] [-it]"
3092                    " [-ua] [-ra] [-ih] [-nh] [-un] [-df] [-vs]"
3093                    " [-l] [-c] [-ws] [-ds] [-rs] [-eo] [-dl] [-sl]"
3094                    "\r\n"
3095                    "\r\n"
3096                    "WinnerMicro firmware packaging "
3097                    "and programming "
3098                    "tool\r\n\r\n"
3099                    "options:\r\n\r\n"
3100                    "  -h                    , show usage\r\n"
3101                    "  -v                    , show version\r\n"
3102                    "\r\n"
3103                    "  -b  binary            , original binary file\r\n"
3104                    "  -o  output_name       , output firmware file\r\n"
3105                    "                          the default is the same as the original binary file name\r\n"
3106                    "  -sb second_boot       , second boot file, used to generate fls file\r\n"
3107                    "  -fc compress_type     , whether the firmware is compressed, default is compressed\r\n"
3108                    "                          <0 | 1> or <uncompress | compress>\r\n"
3109                    "  -it image_type        , firmware image layout type, default is 0\r\n"
3110                    "                          <0 | 1>\r\n"
3111                    "  -ua update_address    , upgrade storage location (hexadecimal)\r\n"
3112                    "                          the default is 8090000\r\n"
3113                    "  -ra run_address       , runtime position (hexadecimal)\r\n"
3114                    "                          the default is 8002400\r\n"
3115                    "  -ih image_header      , image header storage location (hexadecimal)\r\n"
3116                    "                          the default is 8002000\r\n"
3117                    "  -nh next_image_header , next image header storage location (hexadecimal)\r\n"
3118                    "                          the default is 0\r\n"
3119                    "  -un upd_no            , upd no version number (hexadecimal)\r\n"
3120                    "                          the default is 0\r\n"
3121                    "  -df                   , generate debug firmware for openocd\r\n"
3122                    "  -vs version_string    , firmware version string, cannot exceed 16 bytes\r\n"
3123                    "\r\n"
3124                    "  -l                    , list the local serial port\r\n"
3125                    "  -c  serial_name       , connect a serial port\r\n"
3126 #if defined(__APPLE__) && defined(__MACH__)
3127                    "                          e.g: tty.usbserial0 tty.usbserial3 tty.usbserial7\r\n"
3128 #elif defined(__MINGW32__) || defined(__CYGWIN__)
3129                    "                          e.g: COM0 COM3 COM7\r\n"
3130 #elif defined(__linux__)
3131                    "                          e.g: ttyUSB0 ttyUSB3 ttyUSB7\r\n"
3132 #endif
3133                    "  -ws baud_rate         , set the serial port speed during normal work, default is 115200\r\n"
3134                    "                          <1200 - 2000000> or <1M | 2M>\r\n"
3135                    "  -ds baud_rate         , set the serial port speed when downloading, default is 115200\r\n"
3136                    "                          <115200 | 460800 | 921600 | 1000000 | 2000000> or <1M | 2M>\r\n"
3137                    "  -rs reset_action      , set device reset method, default is manual control\r\n"
3138                    "                          <none | at | rts>\r\n"
3139                    "                           none - manual control device reset\r\n"
3140                    "                           at   - use the at command to control the device reset\r\n"
3141                    "                           rts  - use the serial port rts pin to control the device reset\r\n"
3142                    "  -eo erase_option      , firmware area erase option\r\n"
3143                    "                          <all>\r\n"
3144                    "                           all  - erase all areas\r\n"
3145                    "  -dl download_firmware , firmware file to be downloaded, default download compressed image\r\n"
3146                    "  -sl display_format    , display the log information output from the serial port\r\n"
3147                    "                          <0 | 1> or <str | hex>\r\n"
3148                    "                           str - string mode display\r\n"
3149                    "                           hex - hexadecimal format\r\n",
3150                    wm_tool_get_name(name));
3151 
3152     return;
3153 }
3154 
3155 static void wm_tool_print_version(const char *name)
3156 {
3157     wm_tool_printf("%s %s for w800\r\nCopyright (C) 2013 - 2020 WinnerMicro, Inc.\r\n", \
3158                    wm_tool_get_name(name), wm_tool_version);
3159 
3160     return;
3161 }
3162 
3163 static int wm_tool_parse_arv(int argc, char *argv[])
3164 {
3165     int opt;
3166     int option_index = 0;
3167     char *opt_string = "hvlc:b:o:";
3168     int cnt = 0;
3169 
3170     opterr = 1; /* show err info */
3171 
3172     struct option long_options[] = {
3173         {"dl", required_argument, NULL, 'd'},
3174         {"ws", required_argument, NULL, 'w'},
3175         {"ds", required_argument, NULL, 's'},
3176         {"sb", required_argument, NULL, 'S'},
3177         {"it", required_argument, NULL, 'i'},
3178         {"fc", required_argument, NULL, 'C'},
3179         {"ua", required_argument, NULL, 'u'},
3180         {"ra", required_argument, NULL, 'r'},
3181         {"ih", required_argument, NULL, 'H'},
3182         {"nh", required_argument, NULL, 'n'},
3183         {"un", required_argument, NULL, 'U'},
3184         {"df", no_argument,       NULL, 'D'},
3185         {"vs", required_argument, NULL, 'V'},
3186         {"rs", required_argument, NULL, 'a'},
3187         {"eo", required_argument, NULL, 'e'},
3188         {"sl", required_argument, NULL, 'g'},
3189         {0,    0,                 NULL, 0}
3190     };
3191 
3192     while ((opt = getopt_long_only(argc, argv, opt_string, long_options, &option_index)) != -1) {
3193         WM_TOOL_DBG_PRINT("%c-%s\r\n", opt, optarg);
3194 
3195         switch (opt) {
3196             case '?':
3197             case 'h':
3198                 {
3199                     wm_tool_show_usage = 1;
3200                     break;
3201                 }
3202             case 'v':
3203                 {
3204                     wm_tool_show_ver = 1;
3205                     break;
3206                 }
3207             case 'l':
3208                 {
3209                     wm_tool_list_com = 1;
3210                     break;
3211                 }
3212             case 'c':
3213                 {
3214 #if defined(__MINGW32__)
3215                     strcpy(wm_tool_serial_path, optarg);
3216 #elif defined(__CYGWIN__)
3217                     sprintf(wm_tool_serial_path, "/dev/ttyS%d", atoi(optarg + strlen("COM")) - 1);
3218 #else
3219                     sprintf(wm_tool_serial_path, "/dev/%s", optarg);
3220 #endif
3221                     break;
3222                 }
3223             case 'w':
3224                 {
3225                     if (optarg[1] == 'M') {
3226                         wm_tool_normal_serial_rate = (optarg[0] - 0x30) * 1000000; // 1000000:byte alignment
3227                     } else {
3228                         wm_tool_normal_serial_rate = strtol(optarg, NULL, 10);
3229                     }
3230                     break;
3231                 }
3232             case 's':
3233                 {
3234                     if (optarg[1] == 'M') {
3235                         wm_tool_download_serial_rate = (optarg[0] - 0x30) * 1000000; // 1000000:byte alignment
3236                     } else {
3237                         wm_tool_download_serial_rate = strtol(optarg, NULL, 10); // 10:base
3238                     }
3239                     break;
3240                 }
3241             case 'a':
3242                 {
3243                     if (strncmp(optarg, "none", strlen("none")) == 0) {
3244                         wm_tool_dl_action = WM_TOOL_DL_ACTION_NONE;
3245                     } else if (strncmp(optarg, "at", strlen("at")) == 0) {
3246                         wm_tool_dl_action = WM_TOOL_DL_ACTION_AT;
3247                     } else if (strncmp(optarg, "rts", strlen("rts")) == 0) {
3248                         wm_tool_dl_action = WM_TOOL_DL_ACTION_RTS;
3249                     } else {
3250                         wm_tool_show_usage = 1;
3251                     }
3252                     break;
3253                 }
3254             case 'e':
3255                 {
3256                     if (strncmp(optarg, "all", strlen("all")) == 0) {
3257                         wm_tool_dl_erase = WM_TOOL_DL_ERASE_ALL;
3258                     } else {
3259                         wm_tool_show_usage = 1;
3260                     }
3261                     break;
3262                 }
3263             case 'd':
3264                 {
3265                     wm_tool_download_image = strdup(optarg);
3266                     if (wm_tool_strcasestr(wm_tool_download_image, ".fls")) {
3267                         wm_tool_dl_type = WM_TOOL_DL_TYPE_FLS;
3268                     }
3269                     break;
3270                 }
3271             case 'o':
3272                 {
3273                     wm_tool_output_image = strdup(optarg);
3274                     break;
3275                 }
3276             case 'b':
3277                 {
3278                     wm_tool_input_binary = strdup(optarg);
3279                     break;
3280                 }
3281             case 'S':
3282                 {
3283                     wm_tool_secboot_image = strdup(optarg);
3284                     break;
3285                 }
3286             case 'i':
3287                 {
3288                     {
3289                         if (isdigit((int)optarg[0])) {
3290                             wm_tool_image_type = atoi(optarg); // optarg[0] - 0x30;
3291                         } else {
3292                             wm_tool_show_usage = 1;
3293                         }
3294                     }
3295                     break;
3296                 }
3297             case 'C':
3298                 {
3299                     if (optarg[0] == '0') {
3300                         wm_tool_zip_type = WM_TOOL_ZIP_TYPE_UNCOMPRESS;
3301                     } else if (optarg[0] == '1') {
3302                         wm_tool_zip_type = WM_TOOL_ZIP_TYPE_COMPRESS;
3303                     } else if (strncmp(optarg, "compress", strlen("compress")) == 0) {
3304                         wm_tool_zip_type = WM_TOOL_ZIP_TYPE_COMPRESS;
3305                     } else if (strncmp(optarg, "uncompress", strlen("uncompress")) == 0) {
3306                         wm_tool_zip_type = WM_TOOL_ZIP_TYPE_UNCOMPRESS;
3307                     } else {
3308                         wm_tool_show_usage = 1;
3309                     }
3310                     break;
3311                 }
3312             case 'u':
3313                 {
3314                     wm_tool_upd_addr = strtol(optarg, NULL, 16); // 16:value of base
3315                     break;
3316                 }
3317             case 'r':
3318                 {
3319                     wm_tool_run_addr = strtol(optarg, NULL, 16); // 16:value of base
3320                     break;
3321                 }
3322             case 'D':
3323                 {
3324                     wm_tool_is_debug = 1;
3325                     break;
3326                 }
3327             case 'V':
3328                 {
3329                     strncpy(wm_tool_image_version, optarg, WM_TOOL_IMAGE_VERSION_LEN);
3330                     wm_tool_image_version[WM_TOOL_IMAGE_VERSION_LEN - 1] = '\0';
3331                     break;
3332                 }
3333             case 'g':
3334                 {
3335                     if (optarg[0] == '0') {
3336                         wm_tool_show_log_type = WM_TOOL_SHOW_LOG_STR;
3337                     } else if (optarg[0] == '1') {
3338                         wm_tool_show_log_type = WM_TOOL_SHOW_LOG_HEX;
3339                     } else if (strncmp(optarg, "str", strlen("str")) == 0) {
3340                         wm_tool_show_log_type = WM_TOOL_SHOW_LOG_STR;
3341                     } else if (strncmp(optarg, "hex", strlen("hex")) == 0) {
3342                         wm_tool_show_log_type = WM_TOOL_SHOW_LOG_HEX;
3343                     } else {
3344                         wm_tool_show_usage = 1;
3345                     }
3346                     break;
3347                 }
3348             case 'H':
3349                 {
3350                     wm_tool_image_header = strtol(optarg, NULL, 16); // 16:value of base
3351                     break;
3352                 }
3353             case 'n':
3354                 {
3355                     wm_tool_next_image_header = strtol(optarg, NULL, 16); // 16:value of base
3356                     break;
3357                 }
3358             case 'U':
3359                 {
3360                     wm_tool_image_upd_no = strtol(optarg, NULL, 16); // 16:value of base
3361                     break;
3362                 }
3363             default:
3364                 {
3365                     wm_tool_show_usage = 1;
3366                     break;
3367                 }
3368         }
3369 
3370         cnt++;
3371     }
3372 
3373     return cnt;
3374 }
3375 
3376 static int wm_tool_pack_image(const char *outfile)
3377 {
3378     FILE *fpbin;
3379     FILE *fpimg;
3380     int readlen = 0;
3381     int filelen = 0;
3382     int patch = 0;
3383     wm_tool_firmware_booter_t fbooter;
3384     unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1];
3385 
3386     fpbin = fopen(wm_tool_input_binary, "rb");
3387     if (fpbin == NULL) {
3388         wm_tool_printf("can not open input file [%s].\r\n", wm_tool_input_binary);
3389         return -2;
3390     }
3391 
3392     fpimg = fopen(outfile, "wb+");
3393     if (fpimg == NULL) {
3394         wm_tool_printf("open img file error: [%s].\r\n", outfile);
3395         fclose(fpbin);
3396         return -3;
3397     }
3398 
3399     /* --------deal with upgrade image's CRC begin---- */
3400     wm_tool_file_crc = 0xFFFFFFFF;
3401     while (!feof(fpbin)) {
3402         memset(buf, 0, sizeof(buf));
3403         readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpbin);
3404         if (readlen % WM_TOOL_ONCE_READ_LEN != 0) {
3405             patch = WM_TOOL_ONCE_READ_LEN - readlen%WM_TOOL_ONCE_READ_LEN;
3406             readlen += patch;
3407         }
3408         filelen += readlen;
3409         wm_tool_get_crc32((unsigned char*)buf, readlen, 0);
3410     }
3411     /* --------deal with upgrade image's CRC end---- */
3412 
3413     wm_tool_src_binary_len = filelen;
3414     wm_tool_src_binary_crc = wm_tool_file_crc;
3415 
3416     memset(&fbooter, 0, sizeof(wm_tool_firmware_booter_t));
3417     strcpy((char *)fbooter.ver, wm_tool_image_version);
3418     fbooter.magic_no = WM_TOOL_IMG_HEAD_MAGIC_NO;
3419 
3420     fbooter.run_org_checksum = wm_tool_file_crc;
3421     fbooter.img_type         = wm_tool_image_type;
3422     fbooter.run_img_len      = filelen;
3423     fbooter.run_img_addr     = wm_tool_run_addr;
3424     fbooter.zip_type         = WM_TOOL_ZIP_TYPE_UNCOMPRESS;
3425     fbooter.img_header_addr  = wm_tool_image_header;
3426     fbooter.upgrade_img_addr = wm_tool_upd_addr;
3427     fbooter.upd_no           = wm_tool_image_upd_no;
3428     fbooter.next_boot        = wm_tool_next_image_header;
3429 
3430     /* calculate image's header's CRC */
3431     wm_tool_file_crc = 0xFFFFFFFF;
3432     wm_tool_get_crc32((unsigned char *)&fbooter, sizeof(wm_tool_firmware_booter_t) - 4, 0); // 4:byte alignment
3433     fbooter.hd_checksum = wm_tool_file_crc;
3434 
3435     /* write image's header to output file */
3436     fwrite(&fbooter, 1, sizeof(wm_tool_firmware_booter_t), fpimg);
3437 
3438     /* write image to output file */
3439     fseek(fpbin, 0, SEEK_SET);
3440     while (!feof(fpbin)) {
3441         readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpbin);
3442         fwrite(buf, 1, readlen, fpimg);
3443     }
3444 
3445     /* write dummy data to pad 4byte-aligned */
3446     if (patch > 0) {
3447         memset(buf, 0, patch);
3448         fwrite(buf, 1, patch, fpimg);
3449     }
3450 
3451     if (fpbin) {
3452         fclose(fpbin);
3453     }
3454 
3455     if (fpimg) {
3456         fclose(fpimg);
3457     }
3458 
3459     wm_tool_printf("generate normal image completed.\r\n");
3460 
3461     return 0;
3462 }
3463 
3464 static int wm_tool_pack_gz_image(const char *gzbin, const char *outfile)
3465 {
3466     FILE *fpbin;
3467     FILE *fpimg;
3468     int readlen = 0;
3469     int filelen = 0;
3470     int patch = 0;
3471     wm_tool_firmware_booter_t fbooter;
3472     unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1];
3473 
3474     fpbin = fopen(gzbin, "rb");
3475     if (fpbin == NULL) {
3476         wm_tool_printf("can not open input file [%s].\r\n", gzbin);
3477         return -2; // -2:byte alignment
3478     }
3479 
3480     fpimg = fopen(outfile, "wb+");
3481     if (fpimg == NULL) {
3482         wm_tool_printf("create img file error: [%s].\r\n", outfile);
3483         fclose(fpbin);
3484         return -3; // -3:byte alignment
3485     }
3486 
3487     /* --------deal with upgrade image's CRC begin---- */
3488     wm_tool_file_crc = 0xFFFFFFFF;
3489     while (!feof(fpbin)) {
3490         memset(buf, 0, sizeof(buf));
3491         readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpbin);
3492         if (readlen % 4 != 0) { // 4:byte alignment
3493             patch = 4 - readlen % 4; // 4:byte alignment
3494             readlen += patch;
3495         }
3496         filelen += readlen;
3497         wm_tool_get_crc32((unsigned char*)buf, readlen, 0);
3498     }
3499     /* --------deal with upgrade image's CRC end---- */
3500 
3501     memset(&fbooter, 0, sizeof(wm_tool_firmware_booter_t));
3502     strcpy((char *)fbooter.ver, wm_tool_image_version);
3503     fbooter.magic_no = WM_TOOL_IMG_HEAD_MAGIC_NO;
3504 
3505     fbooter.run_org_checksum = wm_tool_file_crc;
3506     fbooter.img_type         = wm_tool_image_type;
3507     fbooter.run_img_len      = filelen;
3508     fbooter.run_img_addr     = wm_tool_run_addr;
3509     fbooter.zip_type         = wm_tool_zip_type;
3510     fbooter.img_header_addr  = wm_tool_image_header;
3511     fbooter.upgrade_img_addr = wm_tool_upd_addr;
3512     fbooter.upd_no           = wm_tool_image_upd_no;
3513     fbooter.next_boot        = wm_tool_next_image_header;
3514 
3515     /* calculate image's header's CRC */
3516     wm_tool_file_crc = 0xFFFFFFFF;
3517     wm_tool_get_crc32((unsigned char *)&fbooter, sizeof(wm_tool_firmware_booter_t) - 4, 0);
3518     fbooter.hd_checksum = wm_tool_file_crc;
3519 
3520     /* write image's header to output file */
3521     fwrite(&fbooter, 1, sizeof(wm_tool_firmware_booter_t), fpimg);
3522 
3523     /* write image to output file */
3524     fseek(fpbin, 0, SEEK_SET);
3525     while (!feof(fpbin)) {
3526         readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpbin);
3527         fwrite(buf, 1, readlen, fpimg);
3528     }
3529 
3530     /* write dummy data to pad 4byte-aligned */
3531     if (patch > 0) {
3532         memset(buf, 0, patch);
3533         fwrite(buf, 1, patch, fpimg);
3534     }
3535 
3536     if (fpbin) {
3537         fclose(fpbin);
3538     }
3539 
3540     if (fpimg) {
3541         fclose(fpimg);
3542     }
3543 
3544     wm_tool_printf("generate compressed image completed.\r\n");
3545 
3546     return 0;
3547 }
3548 
3549 static int wm_tool_pack_dbg_image(const char *image, const char *outfile)
3550 {
3551     FILE *fpimg;
3552     FILE *fout;
3553     unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1];
3554     int readlen = 0;
3555     int i;
3556     wm_tool_firmware_booter_t fbooter;
3557     int appimg_len = 0;
3558     int final_len = 0;
3559     int magic_word = 0;
3560 
3561     fpimg = fopen(image, "rb");
3562     if (fpimg == NULL) {
3563         wm_tool_printf("open img file error: [%s].\r\n", image);
3564         return -4; // -4:byte alignment
3565     }
3566 
3567     magic_word = 0;
3568     readlen = fread(&magic_word, 1, 4, fpimg); // 4:size
3569     if (magic_word != WM_TOOL_IMG_HEAD_MAGIC_NO) {
3570         wm_tool_printf("input [%s] file magic error.\n", image);
3571         fclose(fpimg);
3572         return -5; // -5:byte alignment
3573     }
3574 
3575     fout = fopen(outfile, "wb+");
3576     if (fout == NULL) {
3577         wm_tool_printf("create img file error [%s].\r\n", outfile);
3578         fclose(fpimg);
3579         return -6; // -6:byte alignment
3580     }
3581 
3582     appimg_len = wm_tool_get_file_size(image);
3583 
3584     /* write 0xFF to output file */
3585     final_len = WM_TOOL_RUN_IMG_HEADER_LEN + (appimg_len - sizeof(wm_tool_firmware_booter_t));
3586     for (i = 0; i < (final_len /WM_TOOL_ONCE_READ_LEN); i++) {
3587         memset(buf, 0xff, WM_TOOL_ONCE_READ_LEN);
3588         fwrite(buf, 1, WM_TOOL_ONCE_READ_LEN, fout);
3589     }
3590     memset(buf, 0xff, final_len % WM_TOOL_ONCE_READ_LEN);
3591     fwrite(buf, 1, final_len % WM_TOOL_ONCE_READ_LEN, fout);
3592 
3593     memset(&fbooter, 0, sizeof(wm_tool_firmware_booter_t));
3594 
3595     /* write sec img to output file */
3596     fseek(fpimg, 0, SEEK_SET);
3597     readlen = fread((unsigned char *)&fbooter, 1, sizeof(wm_tool_firmware_booter_t), fpimg);
3598 
3599     fseek(fout, 0, SEEK_SET);
3600     fwrite(&fbooter, 1, sizeof(wm_tool_firmware_booter_t), fout);
3601     fseek(fout, WM_TOOL_RUN_IMG_HEADER_LEN, SEEK_SET);
3602 
3603     while (!feof(fpimg)) {
3604         readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpimg);
3605         fwrite(buf, 1, readlen, fout);
3606     }
3607 
3608     if (fpimg) {
3609         fclose(fpimg);
3610     }
3611 
3612     if (fout) {
3613         fclose(fout);
3614     }
3615 
3616     wm_tool_printf("generate debug image completed.\r\n");
3617 
3618     return 0;
3619 }
3620 
3621 static int wm_tool_pack_fls(const char *image, const char *outfile)
3622 {
3623     FILE *fpsec;
3624     FILE *fpimg;
3625     FILE *fout;
3626     unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1];
3627     int readlen = 0;
3628     int magic_word = 0;
3629 
3630     fpsec = fopen(wm_tool_secboot_image, "rb");
3631     if (fpsec == NULL) {
3632         wm_tool_printf("can not open input file [%s].\r\n", wm_tool_secboot_image);
3633         return -2; // -2:byte alignment
3634     }
3635 
3636     magic_word = 0;
3637     readlen = fread(&magic_word, 1, 4, fpsec);
3638     if (magic_word != WM_TOOL_IMG_HEAD_MAGIC_NO) {
3639         wm_tool_printf("input [%s] file magic error.\r\n", wm_tool_secboot_image);
3640         fclose(fpsec);
3641         return -3; // -3:byte alignment
3642     }
3643 
3644     fpimg = fopen(image, "rb");
3645     if (fpimg == NULL) {
3646         wm_tool_printf("open img file error [%s].\r\n", image);
3647         fclose(fpsec);
3648         return -4; // -4:byte alignment
3649     }
3650 
3651     magic_word = 0;
3652     readlen = fread(&magic_word, 1, 4, fpimg);
3653     if (magic_word != WM_TOOL_IMG_HEAD_MAGIC_NO) {
3654         wm_tool_printf("input [%s] file magic error.\r\n", image);
3655         fclose(fpsec);
3656         fclose(fpimg);
3657         return -5; // -5:byte alignment
3658     }
3659 
3660     fout = fopen(outfile, "wb+");
3661     if (fout == NULL) {
3662         wm_tool_printf("create img file error [%s].\r\n", outfile);
3663         fclose(fpsec);
3664         fclose(fpimg);
3665         return -6; // -6:byte alignment
3666     }
3667 
3668     fseek(fpsec, 0, SEEK_SET);
3669 
3670     while (!feof(fpsec)) {
3671         readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpsec);
3672         fwrite(buf, 1, readlen, fout);
3673     }
3674 
3675     fseek(fpimg, 0, SEEK_SET);
3676 
3677     while (!feof(fpimg)) {
3678         readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpimg);
3679         fwrite(buf, 1, readlen, fout);
3680     }
3681 
3682     if (fpsec) {
3683         fclose(fpsec);
3684     }
3685 
3686     if (fpimg) {
3687         fclose(fpimg);
3688     }
3689 
3690     if (fout) {
3691         fclose(fout);
3692     }
3693 
3694     wm_tool_printf("generate flash file completed.\r\n");
3695 
3696     return 0;
3697 }
3698 
3699 static int wm_tool_gzip_bin(const char *binary, const char *gzbin)
3700 {
3701     FILE *bfp;
3702     gzFile gzfp;
3703     int ret;
3704     char buf[1024];
3705 
3706     bfp = fopen(binary, "rb");
3707     if (!bfp) {
3708         wm_tool_printf("can not open binary.\r\n");
3709         return -1;
3710     }
3711 
3712     gzfp = gzopen((char *)gzbin, "wb+");
3713     if (!gzfp) {
3714         wm_tool_printf("can not gzip binary.\r\n");
3715         fclose(bfp);
3716         return -1;
3717     }
3718 
3719     do {
3720         ret = fread(buf, 1, sizeof(buf), bfp);
3721         if (ret > 0) {
3722             ret = gzwrite(gzfp, (voidp)buf, ret);
3723             if (ret <= 0) {
3724                 wm_tool_printf("can not write gzip binary.\r\n");
3725                 return -2;
3726             }
3727         }
3728     } while (ret > 0);
3729 
3730     gzclose(gzfp);
3731     fclose(bfp);
3732 
3733     wm_tool_printf("compress binary completed.\r\n");
3734 
3735     return 0;
3736 }
3737 
3738 static int wm_tool_pack_firmware(void)
3739 {
3740     int ret;
3741     char *path;
3742     char *name;
3743     char *image;
3744     char *gzbin;
3745     char *gzimg;
3746     char *dbgimg;
3747     char *fls;
3748 
3749     if (!wm_tool_input_binary) {
3750         return 1;
3751     }
3752 
3753     if (!wm_tool_output_image) {
3754         char *r = wm_tool_input_binary;
3755         char *t = wm_tool_input_binary;
3756         do {
3757             r = strchr(r, '.');
3758             if (r) {
3759                 t = r;
3760                 r++;
3761             }
3762         } while (r);
3763         wm_tool_output_image = malloc(t - wm_tool_input_binary + 1);
3764         if (!wm_tool_output_image) {
3765             return -1;
3766         }
3767         memcpy(wm_tool_output_image, wm_tool_input_binary, t - wm_tool_input_binary);
3768         wm_tool_output_image[t - wm_tool_input_binary] = '\0';
3769     }
3770 
3771     char *p = wm_tool_output_image;
3772     char *q = wm_tool_output_image;
3773 
3774     do {
3775         p = strchr(p, '/');
3776         if (p) {
3777             p++;
3778             q = p;
3779         }
3780     } while (p);
3781 
3782     /* output file */
3783     name = strdup(q);
3784     *q = '\0';
3785     path = strdup(wm_tool_output_image);
3786 
3787     image = malloc(strlen(path) + strlen(name) + strlen(".img") + 1);
3788     if (!image) {
3789         return -1;
3790     }
3791     sprintf(image, "%s%s.img", path, name);
3792     if (WM_TOOL_ZIP_TYPE_UNCOMPRESS == wm_tool_zip_type) {
3793         ret = wm_tool_pack_image(image);
3794         if (ret) {
3795             return ret;
3796         }
3797     }
3798 
3799     if (WM_TOOL_ZIP_TYPE_COMPRESS == wm_tool_zip_type) {
3800         gzbin = malloc(strlen(path) + strlen(name) + strlen("_gz.bin") + 1);
3801         gzimg = malloc(strlen(path) + strlen(name) + strlen("_gz.img") + 1);
3802         if (!gzbin || !gzimg) {
3803             return -1;
3804         }
3805         sprintf(gzbin, "%s%s.bin.gz", path, name);
3806         sprintf(gzimg, "%s%s_gz.img", path, name);
3807 
3808         ret = wm_tool_gzip_bin(wm_tool_input_binary, gzbin);
3809         if (ret) {
3810             free(gzbin);
3811             free(gzimg);
3812             return ret;
3813         }
3814 
3815         ret = wm_tool_pack_gz_image(gzbin, gzimg);
3816         free(gzbin);
3817         free(gzimg);
3818         if (ret)
3819             return ret;
3820     }
3821 
3822     if (wm_tool_is_debug) {
3823         dbgimg = malloc(strlen(path) + strlen(name) + strlen("_dbg.img") + 1);
3824         if (!dbgimg) {
3825             return -1;
3826         }
3827         sprintf(dbgimg, "%s%s_dbg.img", path, name);
3828 
3829         ret = wm_tool_pack_dbg_image(image, dbgimg);
3830         free(dbgimg);
3831         if (ret) {
3832             return ret;
3833         }
3834     }
3835 
3836     if (wm_tool_secboot_image) {
3837         fls = malloc(strlen(path) + strlen(name) + strlen(".fls") + 1);
3838         if (!fls) {
3839             return -1;
3840         }
3841         sprintf(fls, "%s%s.fls", path, name);
3842 
3843         ret = wm_tool_pack_fls(image, fls);
3844 
3845         free(fls);
3846     }
3847 
3848     free(image);
3849 
3850     return ret;
3851 }
3852 
3853 #ifdef __MINGW32__
3854 static BOOL wm_tool_signal_proc(DWORD no)
3855 {
3856     switch (no) {
3857         case CTRL_C_EVENT:
3858             wm_tool_signal_proc_entry();
3859             return(FALSE);
3860         default:
3861             return FALSE;
3862     }
3863 }
3864 
3865 static void wm_tool_signal_init(void)
3866 {
3867     SetConsoleCtrlHandler((PHANDLER_ROUTINE)wm_tool_signal_proc, TRUE);
3868 }
3869 
3870 static void wm_tool_delay_ms(int ms)
3871 {
3872     Sleep(ms);
3873 
3874     return;
3875 }
3876 
3877 static int wm_tool_uart_set_rts(int boolflag)
3878 {
3879     return EscapeCommFunction(wm_tool_uart_handle, ((boolflag) ? SETRTS : CLRRTS)) ? 0 : -1;
3880 }
3881 
3882 static int wm_tool_uart_set_dtr(int boolflag)
3883 {
3884     return EscapeCommFunction(wm_tool_uart_handle, ((boolflag) ? SETDTR : CLRDTR)) ? 0 : -1;
3885 }
3886 
3887 static int wm_tool_uart_set_timeout(void)
3888 {
3889     BOOL ret;
3890     COMMTIMEOUTS timeout;
3891 
3892     timeout.ReadIntervalTimeout         = MAXDWORD;
3893     timeout.ReadTotalTimeoutConstant    = 0;
3894     timeout.ReadTotalTimeoutMultiplier  = 0;
3895     timeout.WriteTotalTimeoutConstant   = 0;
3896     timeout.WriteTotalTimeoutMultiplier = 0;
3897 
3898     ret = SetCommTimeouts(wm_tool_uart_handle, &timeout);
3899     if (ret)
3900         ret = SetCommMask(wm_tool_uart_handle, EV_TXEMPTY);
3901 
3902     return ret ? 0 : -1;
3903 }
3904 
3905 static void wm_tool_uart_set_block(int bolck)
3906 {
3907     if (bolck)
3908         wm_tool_uart_block = INFINITE;
3909     else
3910         wm_tool_uart_block = 0;
3911 
3912     return;
3913 }
3914 
3915 static int wm_tool_uart_set_speed(int speed)
3916 {
3917     int i;
3918     int size;
3919     DCB cfg;
3920 
3921     size = sizeof(wm_tool_uart_speed_array) / sizeof(int);
3922 
3923     for (i= 0; i < size; i++) {
3924         if (speed == wm_tool_uart_name_array[i]) {
3925             if (GetCommState(wm_tool_uart_handle, &cfg)) {
3926                 cfg.DCBlength       = sizeof(DCB);
3927                 cfg.BaudRate        = wm_tool_uart_speed_array[i];
3928                 cfg.fBinary         = TRUE;
3929                 cfg.fParity         = FALSE;
3930                 cfg.fDtrControl     = DTR_CONTROL_DISABLE;
3931                 cfg.fDsrSensitivity = FALSE;
3932                 cfg.fRtsControl        = RTS_CONTROL_DISABLE;
3933                 cfg.ByteSize        = 8;
3934                 cfg.StopBits        = ONESTOPBIT;
3935                 cfg.fAbortOnError   = FALSE;
3936                 cfg.fOutX            = FALSE;
3937                 cfg.fInX            = FALSE;
3938                 cfg.fErrorChar      = FALSE;
3939                 cfg.fNull           = FALSE;
3940                 cfg.fOutxCtsFlow    = FALSE;
3941                 cfg.fOutxDsrFlow    = FALSE;
3942                 cfg.Parity          = NOPARITY;
3943                 cfg.fTXContinueOnXoff = FALSE;
3944 
3945                 return SetCommState(wm_tool_uart_handle, &cfg) ? 0 : -1;
3946             } else {
3947                 return -3; // -4:byte alignment
3948             }
3949         }
3950     }
3951 
3952     return -2; // -2:byte alignment
3953 }
3954 
3955 static void wm_tool_uart_clear(void)
3956 {
3957     PurgeComm(wm_tool_uart_handle, PURGE_RXCLEAR);
3958 
3959     return;
3960 }
3961 
3962 static int wm_tool_uart_open(const char *device)
3963 {
3964     BOOL ret;
3965     char name[40];
3966 
3967     sprintf(name, "\\\\.\\%s", device);
3968 
3969     wm_tool_uart_handle = CreateFile(name, GENERIC_WRITE | GENERIC_READ,
3970                                      0, NULL, OPEN_EXISTING,
3971                                      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
3972                                      NULL);
3973     if (wm_tool_uart_handle == INVALID_HANDLE_VALUE) {
3974         return -1;
3975     }
3976 
3977     ret = SetupComm(wm_tool_uart_handle, 4096, 4096);
3978     if (ret) {
3979         ret  = wm_tool_uart_set_speed(WM_TOOL_DEFAULT_BAUD_RATE);
3980         ret |= wm_tool_uart_set_timeout();
3981     } else {
3982         ret = -1;
3983     }
3984 
3985     return ret;
3986 }
3987 
3988 static int wm_tool_uart_read(void *data, unsigned int size)
3989 {
3990     BOOL ret;
3991     DWORD wait;
3992     unsigned long len = 0;
3993     COMSTAT state;
3994     DWORD error;
3995     OVERLAPPED event;
3996 
3997     do {
3998         memset(&event, 0, sizeof(OVERLAPPED));
3999 
4000         event.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
4001 
4002         ClearCommError(wm_tool_uart_handle, &error, &state);
4003 
4004         ret = ReadFile(wm_tool_uart_handle, data, size, &len, &event);
4005         if (!ret) {
4006             if (ERROR_IO_PENDING == GetLastError()) {
4007                 wait = WaitForSingleObject(event.hEvent, wm_tool_uart_block);
4008                 if (WAIT_OBJECT_0 == wait)
4009                     ret = TRUE;
4010             }
4011         }
4012     } while (wm_tool_uart_block && !len);
4013 
4014     if (ret) {
4015         if (len > 0)
4016             return (int)len;
4017     }
4018 
4019     return -1;
4020 }
4021 
4022 static int wm_tool_uart_write(const void *data, unsigned int size)
4023 {
4024     BOOL ret;
4025     DWORD wait;
4026     OVERLAPPED event;
4027     COMSTAT state;
4028     DWORD error;
4029     unsigned int snd = 0;
4030     unsigned long len = 0;
4031 
4032     memset(&event, 0, sizeof(OVERLAPPED));
4033 
4034     event.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
4035 
4036     do {
4037         ClearCommError(wm_tool_uart_handle, &error, &state);
4038 
4039         ret = WriteFile(wm_tool_uart_handle, data + snd, size - snd, &len, &event);
4040         if (!ret) {
4041             if (ERROR_IO_PENDING == GetLastError()) {
4042                 wait = WaitForSingleObject(event.hEvent, INFINITE);
4043                 if (WAIT_OBJECT_0 == wait)
4044                     ret = TRUE;
4045             }
4046         }
4047 
4048         if (ret) {
4049             if ((len > 0) && (snd != size)) {
4050                 snd += len;
4051             } else {
4052                 return size;
4053             }
4054         } else {
4055             break;
4056         }
4057     } while (1);
4058 
4059     return -1;
4060 }
4061 
4062 static void wm_tool_uart_close(void)
4063 {
4064     FlushFileBuffers(wm_tool_uart_handle);
4065     CloseHandle(wm_tool_uart_handle);
4066     wm_tool_uart_handle = NULL;
4067 
4068     return;
4069 }
4070 
4071 static DWORD WINAPI wm_tool_uart_tx_thread(LPVOID arg)
4072 {
4073     wm_tool_stdin_to_uart();
4074 
4075     return 0;
4076 }
4077 
4078 static int wm_tool_create_thread(void)
4079 {
4080     HANDLE thread_handle;
4081     thread_handle = CreateThread(0, 0, wm_tool_uart_tx_thread, NULL, 0, NULL);
4082     CloseHandle(thread_handle);
4083     return 0;
4084 }
4085 
4086 #else
4087 
4088 static void wm_tool_signal_proc(int no)
4089 {
4090     wm_tool_signal_proc_entry();
4091 }
4092 
4093 static void wm_tool_signal_init(void)
4094 {
4095     signal(SIGINT, wm_tool_signal_proc);
4096 }
4097 
4098 static void wm_tool_delay_ms(int ms)
4099 {
4100     usleep(ms * 1000);
4101 
4102     return;
4103 }
4104 
4105 static int wm_tool_uart_set_rts(int boolflag)
4106 {
4107     int ret;
4108     int controlbits;
4109 
4110     ret = ioctl(wm_tool_uart_fd, TIOCMGET, &controlbits);
4111     if (ret < 0) {
4112         WM_TOOL_DBG_PRINT("TIOCMGET failed!\r\n");
4113         return ret;
4114     }
4115 
4116     if (controlbits & TIOCM_RTS) {
4117         WM_TOOL_DBG_PRINT("TIOCM_RTS!, %d!\r\n", boolflag);
4118     } else {
4119         WM_TOOL_DBG_PRINT("~TIOCM_RTS!, %d!\r\n", boolflag);
4120     }
4121 
4122     if (boolflag) {
4123         controlbits |= TIOCM_RTS;
4124     } else {
4125         controlbits &= ~TIOCM_RTS;
4126     }
4127 
4128     ret = ioctl(wm_tool_uart_fd, TIOCMSET, &controlbits);
4129     if (ret < 0) {
4130         WM_TOOL_DBG_PRINT("TIOCMSET failed!\r\n");
4131     }
4132 
4133     if (ret >= 0)
4134         ret = 0;
4135 
4136     return ret;
4137 }
4138 
4139 static int wm_tool_uart_set_dtr(int boolflag)
4140 {
4141     int ret;
4142     int controlbits;
4143 
4144     ret = ioctl(wm_tool_uart_fd, TIOCMGET, &controlbits);
4145     if (ret < 0) {
4146         WM_TOOL_DBG_PRINT("TIOCMGET failed!\r\n");
4147         return ret;
4148     }
4149 
4150     if (controlbits & TIOCM_DTR) {
4151         WM_TOOL_DBG_PRINT("TIOCM_DTR, %d!\r\n", boolflag);
4152     } else {
4153         WM_TOOL_DBG_PRINT("~TIOCM_DTR, %d!\r\n", boolflag);
4154     }
4155 
4156     if (boolflag) {
4157         controlbits |= TIOCM_DTR;
4158     } else {
4159         controlbits &= ~TIOCM_DTR;
4160     }
4161 
4162     ret = ioctl(wm_tool_uart_fd, TIOCMSET, &controlbits);
4163     if (ret < 0) {
4164         WM_TOOL_DBG_PRINT("TIOCMSET failed!\r\n");
4165     }
4166 
4167     if (ret >= 0) {
4168         ret = 0;
4169     }
4170 
4171     return ret;
4172 }
4173 
4174 static void wm_tool_uart_set_block(int bolck)
4175 {
4176     int comopt;
4177 
4178     comopt = fcntl(wm_tool_uart_fd, F_GETFL, 0);
4179 
4180     if (bolck) {
4181         fcntl(wm_tool_uart_fd, F_SETFL, comopt & ~O_NDELAY);
4182     } else {
4183         fcntl(wm_tool_uart_fd, F_SETFL, comopt | O_NDELAY);
4184     }
4185 
4186     return;
4187 }
4188 
4189 static int wm_tool_uart_set_speed(int speed)
4190 {
4191     int i;
4192     int size;
4193     int status = -1;
4194     struct termios opt;
4195 
4196     tcgetattr(wm_tool_uart_fd, &opt);
4197 
4198     size = sizeof(wm_tool_uart_speed_array) / sizeof(int);
4199 
4200     for (i= 0; i < size; i++) {
4201         if (speed == wm_tool_uart_name_array[i]) {
4202             cfsetispeed(&opt, wm_tool_uart_speed_array[i]);
4203             cfsetospeed(&opt, wm_tool_uart_speed_array[i]);
4204 
4205             status = tcsetattr(wm_tool_uart_fd, TCSANOW, &opt);
4206 
4207             break;
4208         }
4209     }
4210 
4211     return status;
4212 }
4213 
4214 static void wm_tool_uart_clear(void)
4215 {
4216     tcflush(wm_tool_uart_fd, TCIFLUSH);
4217 
4218     return;
4219 }
4220 
4221 static int wm_tool_uart_open(const char *device)
4222 {
4223     struct termios tty;
4224 
4225     wm_tool_uart_fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
4226     if (-1 == wm_tool_uart_fd) {
4227         return -1;
4228     }
4229 
4230     tcgetattr(wm_tool_uart_fd, &wm_tool_saved_serial_cfg);
4231 
4232     wm_tool_uart_set_dtr(0);
4233 
4234     tcgetattr(wm_tool_uart_fd, &tty);
4235 
4236     /* databit 8bit */
4237     tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
4238 
4239     /* set into raw, no echo mode */
4240     tty.c_iflag =  IGNBRK;
4241     tty.c_lflag = 0;
4242     tty.c_oflag = 0;
4243     tty.c_cflag |= CLOCAL | CREAD;
4244     tty.c_cflag &= ~CRTSCTS;
4245     tty.c_cc[VMIN] = 1;
4246     tty.c_cc[VTIME] = 5; // 5:byte alignment
4247 
4248     /* have no software flow control */
4249     tty.c_iflag &= ~(IXON|IXOFF|IXANY);
4250 
4251     /* parity none */
4252     tty.c_cflag &= ~(PARENB | PARODD);
4253 
4254     /* stopbit 1bit */
4255     tty.c_cflag &= ~CSTOPB;
4256 
4257     tcsetattr(wm_tool_uart_fd, TCSANOW, &tty);
4258 
4259     return wm_tool_uart_set_speed(WM_TOOL_DEFAULT_BAUD_RATE);
4260 }
4261 
4262 static int wm_tool_uart_read(void *data, unsigned int size)
4263 {
4264     return read(wm_tool_uart_fd, data, size);
4265 }
4266 
4267 static int wm_tool_uart_write(const void *data, unsigned int size)
4268 {
4269     int snd = 0;
4270     int ret = 0;
4271 
4272     do {
4273         ret = write(wm_tool_uart_fd, data + snd, size - snd);
4274         if (ret > 0) {
4275             snd += ret;
4276 
4277             if (snd == size) {
4278                 return size;
4279             }
4280         } else {
4281             break;
4282         }
4283     } while (1);
4284 
4285     return -1;
4286 }
4287 
4288 static void wm_tool_uart_close(void)
4289 {
4290     tcsetattr(wm_tool_uart_fd, TCSANOW, &wm_tool_saved_serial_cfg);
4291 
4292     tcdrain(wm_tool_uart_fd);
4293     tcflush(wm_tool_uart_fd, TCIOFLUSH);
4294 
4295     close(wm_tool_uart_fd);
4296     wm_tool_uart_fd = -1;
4297 
4298     return;
4299 }
4300 
4301 static void *wm_tool_uart_tx_thread(void *arg)
4302 {
4303     wm_tool_stdin_to_uart();
4304 
4305     return NULL;
4306 }
4307 
4308 static int wm_tool_create_thread(void)
4309 {
4310     return 0;
4311 }
4312 #endif
4313 
4314 static void wm_tool_signal_proc_entry(void)
4315 {
4316     WM_TOOL_DBG_PRINT("signal exit.\r\n");
4317     exit(0);
4318 }
4319 
4320 static void wm_tool_stdin_to_uart(void)
4321 {
4322     int ret;
4323     char buf[WM_TOOL_ONCE_READ_LEN];
4324 
4325     while (1) {
4326         if (fgets(buf, WM_TOOL_ONCE_READ_LEN, stdin)) {
4327             ret = wm_tool_uart_write(buf, strlen(buf));
4328             if (ret <= 0) {
4329                 WM_TOOL_DBG_PRINT("failed to write [%s].\r\n", buf);
4330             }
4331         }
4332     }
4333 
4334     return;
4335 }
4336 
4337 static int wm_tool_show_log_from_serial(void)
4338 {
4339     int i;
4340     int ret;
4341     unsigned int j = 0;
4342     unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1];
4343 
4344     ret = wm_tool_uart_open(wm_tool_serial_path);
4345     if (ret) {
4346         wm_tool_printf("can not open serial\r\n");
4347         return ret;
4348     }
4349 
4350     if (wm_tool_normal_serial_rate != WM_TOOL_DEFAULT_BAUD_RATE) {
4351         ret = wm_tool_uart_set_speed(wm_tool_normal_serial_rate);
4352         if (ret) {
4353             wm_tool_printf("can not set serial baud rate.\r\n");
4354             wm_tool_uart_close();
4355             return ret;
4356         }
4357     }
4358 
4359     ret = wm_tool_create_thread();
4360     if (ret) {
4361         wm_tool_printf("can not create thread.\r\n");
4362         wm_tool_uart_close();
4363         return ret;
4364     }
4365 
4366     wm_tool_uart_set_block(0);
4367 
4368     wm_tool_signal_init();
4369 
4370     while (1) {
4371         ret = wm_tool_uart_read(buf, WM_TOOL_ONCE_READ_LEN);
4372         if (ret > 0) {
4373             if (WM_TOOL_SHOW_LOG_STR == wm_tool_show_log_type) {
4374                 buf[ret] = '\0';
4375                 wm_tool_printf("%s", (char *)buf);
4376             } else if (WM_TOOL_SHOW_LOG_HEX == wm_tool_show_log_type) {
4377                 for (i = 0; i < ret; i++, j++) {
4378                     wm_tool_printf("%02X ", buf[i]);
4379                     if ((j + 1) % 16 == 0) { // 16:byte alignment
4380                         wm_tool_printf("\r\n");
4381                     }
4382                 }
4383             } else {
4384                 break;
4385             }
4386         } else {
4387             wm_tool_delay_ms(1);
4388         }
4389     }
4390 
4391     wm_tool_uart_close();
4392 
4393     return ret;
4394 }
4395 
4396 static int wm_tool_set_wifi_chip_speed(int speed)
4397 {
4398     int ret;
4399 
4400     if (speed == 2000000) { // 2000000:value of speed
4401         ret = wm_tool_uart_write(wm_tool_chip_cmd_b2000000, sizeof(wm_tool_chip_cmd_b2000000));
4402     } else if (speed == 1000000) { // 1000000:value of speed
4403         ret = wm_tool_uart_write(wm_tool_chip_cmd_b1000000, sizeof(wm_tool_chip_cmd_b1000000));
4404     } else if (speed == 921600) { // 921600:value of speed
4405         ret = wm_tool_uart_write(wm_tool_chip_cmd_b921600, sizeof(wm_tool_chip_cmd_b921600));
4406     } else if (speed == 460800) { // 460800:value of speed
4407         ret = wm_tool_uart_write(wm_tool_chip_cmd_b460800, sizeof(wm_tool_chip_cmd_b460800));
4408     } else {
4409         ret = wm_tool_uart_write(wm_tool_chip_cmd_b115200, sizeof(wm_tool_chip_cmd_b115200));
4410     }
4411 
4412     return ret;
4413 }
4414 
4415 static int wm_tool_send_esc2uart(int ms)
4416 {
4417     int i;
4418     int err = 0;
4419     unsigned char esc_key = 27;
4420 
4421     for (i = 0; i < (ms / 10); i++) { // 10:byte alignment
4422         err = wm_tool_uart_write(&esc_key, 1);
4423         wm_tool_delay_ms(10); // 10:10ms
4424     }
4425 
4426     return err;
4427 }
4428 
4429 static int wm_tool_erase_image(wm_tool_dl_erase_e type)
4430 {
4431     int cnt = 0;
4432     int ret = -1;
4433     unsigned char ch;
4434     /* 2M-8k */
4435     unsigned char rom_cmd[] = {0x21, 0x0a, 0x00, 0xc3, 0x35, 0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0xfe, 0x01};
4436 
4437     WM_TOOL_DBG_PRINT("start erase.\r\n");
4438 
4439     if (WM_TOOL_DL_ERASE_ALL == type) {
4440         wm_tool_printf("erase flash...\r\n");
4441         ret = wm_tool_uart_write(rom_cmd, sizeof(rom_cmd));
4442     }
4443     if (ret <= 0) {
4444         return -1;
4445     }
4446 
4447     wm_tool_uart_clear();
4448 
4449     wm_tool_uart_set_block(1);
4450 
4451     do {
4452         ret = wm_tool_uart_read(&ch, 1);
4453         if (ret > 0) {
4454             if ((ch == 'C') || (ch == 'P')) {
4455                 cnt++;
4456             } else {
4457                 cnt = 0;
4458             }
4459         } else {
4460             wm_tool_printf("erase error, errno = %d.\r\n", errno);
4461             return -2; // -2:byte alignment
4462         }
4463     } while (cnt < 3); // 3:loop condition
4464 
4465     wm_tool_uart_set_block(0);
4466 
4467     wm_tool_printf("erase finish.\r\n");
4468 
4469     return 0;
4470 }
4471 
4472 static int wm_tool_query_mac(void)
4473 {
4474     int ret = -1;
4475     int err;
4476     int offset = 0;
4477     char macstr[32] = {0};
4478     int len = strlen("MAC:AABBCCDDEEFF\n"); /* resp format, ROM "Mac:AABBCCDDEEFF\n", SECBOOT "MAC:AABBCCDDEEFF\n" */
4479     unsigned char macaddr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
4480 
4481     wm_tool_uart_clear();
4482 
4483     wm_tool_uart_set_block(1);
4484 
4485     err = wm_tool_uart_write(wm_tool_chip_cmd_get_mac, sizeof(wm_tool_chip_cmd_get_mac));
4486     if (err > 0) {
4487         do {
4488             err = wm_tool_uart_read((unsigned char *)(macstr + offset), sizeof(macstr) - 1 - offset);
4489             if (err > 0) {
4490                 offset += err;
4491                 if (offset >= len) {
4492                     macstr[len - 1] = '\0'; /* \n -> 0 */
4493                     if (strstr(macstr, "Mac:")) {
4494                         err = wm_tool_str_to_hex_array(macstr + strlen("MAC:"), 6, macaddr); // 6:cnt
4495                     } else {
4496                         err = 0;
4497                     }
4498 
4499                     if (!err) {
4500                         wm_tool_printf("mac %02X-%02X-%02X-%02X-%02X-%02X.\r\n", macaddr[0],
4501                                        macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
4502 
4503                         if (!strncmp(macstr, "Mac:", strlen("Mac:")) && \
4504                             (WM_TOOL_DL_TYPE_FLS != wm_tool_dl_type) && \
4505                             !wm_tool_dl_erase) {
4506                             wm_tool_printf("please download the firmware in .fls format.\r\n");
4507                         } else {
4508                             ret = 0;
4509                         }
4510                     }
4511                     break;
4512                 }
4513             }
4514         } while (err > 0);
4515     }
4516 
4517     wm_tool_uart_set_block(0);
4518 
4519     return ret;
4520 }
4521 
4522 static int wm_tool_xmodem_download(const char *image)
4523 {
4524     FILE *imgfp;
4525     unsigned char packet_data[XMODEM_DATA_SIZE];
4526     unsigned char frame_data[XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1];
4527     int complete, retry_num, pack_counter, read_number, write_number = 0, i;
4528     unsigned short crc_value;
4529     unsigned char ack_id;
4530     int sndlen;
4531     int total_size;
4532     int ret = -111; // -111:byte alignment
4533     int percent = 0;
4534     int curImgLen = 0;
4535     wm_tool_firmware_booter_t fbooter;
4536     int packet_data_len = 0;
4537     int packet_data_offset = 0;
4538 
4539     imgfp = fopen(image, "rb");
4540     if (!imgfp) {
4541         wm_tool_printf("can not open image to download.\r\n");
4542         return -1;
4543     }
4544     total_size=wm_tool_get_file_size(image);
4545     wm_tool_printf("file size %d\r\n", total_size);
4546     sndlen = 0;
4547     pack_counter = 0;
4548     complete = 0;
4549     retry_num = 0;
4550 
4551     wm_tool_printf("start download.\r\n");
4552     wm_tool_printf("0%% [");
4553 
4554     wm_tool_uart_clear();
4555 
4556     wm_tool_uart_set_block(1);
4557 
4558     ack_id = XMODEM_ACK;
4559 
4560     while (!complete) {
4561         WM_TOOL_DBG_PRINT("switch ack_id = %x\r\n", ack_id);
4562 
4563         switch (ack_id) {
4564             case XMODEM_ACK:
4565                 {
4566                     retry_num = 0;
4567                     if (curImgLen == -1) {
4568                         read_number = 0;
4569                         curImgLen = 0;
4570                         pack_counter = 0;
4571                     } else {
4572                         pack_counter++;
4573 
4574                         if (packet_data_offset > 0 && packet_data_len > 0) {
4575                             WM_TOOL_DBG_PRINT("packet_data_offset = %d, packet_data_len = %d\r\n", \
4576                                 packet_data_offset, packet_data_len);
4577                             WM_TOOL_DBG_PRINT("header %x %x %x %x\r\n", packet_data[packet_data_offset], \
4578                                 packet_data[packet_data_offset + 1], packet_data[packet_data_offset + 2], \
4579                                 packet_data[packet_data_offset + 3]);
4580                             memmove(packet_data, packet_data + packet_data_offset, packet_data_len);
4581                             WM_TOOL_DBG_PRINT("header %x %x %x %x\r\n", packet_data[0], packet_data[1],
4582                                 packet_data[2], packet_data[3]);
4583                             packet_data_offset = 0;
4584                         }
4585                         read_number = fread(packet_data + packet_data_len, sizeof(char), \
4586                         XMODEM_DATA_SIZE-packet_data_len, imgfp);
4587                         read_number += packet_data_len;
4588                         packet_data_len = 0;
4589 
4590                         WM_TOOL_DBG_PRINT("fread = %d\r\n", read_number);
4591                     }
4592                     if (read_number > 0) {
4593                         if (curImgLen == 0) {
4594                             memcpy(&fbooter, packet_data, sizeof(wm_tool_firmware_booter_t));
4595                             curImgLen = fbooter.run_img_len;
4596                             curImgLen += sizeof(wm_tool_firmware_booter_t);
4597                             if ((fbooter.img_type & 256) > 0) { // 256:byte alignment
4598                                 curImgLen += 128; // 128:byte alignment
4599                             }
4600                             WM_TOOL_DBG_PRINT("curImgLen %d\r\n", curImgLen);
4601                         }
4602                         if (read_number > curImgLen) {
4603                             WM_TOOL_DBG_PRINT("read_number %d, curImgLen %d\r\n", read_number, curImgLen);
4604                             packet_data_len = read_number - curImgLen;
4605                             packet_data_offset = curImgLen;
4606                             read_number = curImgLen;
4607                             curImgLen = -1;
4608                         } else {
4609                             curImgLen -= read_number;
4610                         }
4611                         sndlen += read_number;
4612 
4613                         memset(&frame_data[0], 0, sizeof(frame_data));
4614                         frame_data[0] = XMODEM_HEAD;
4615                         frame_data[1] = (char)pack_counter;
4616                         frame_data[2] = (char)(255 - frame_data[1]); // 255:byte alignment, 2:array element
4617 
4618                         for (i = 0; i < read_number; i++) {
4619                             frame_data[i + 3] = packet_data[i]; // 3:byte alignment
4620                         }
4621 
4622                         crc_value = wm_tool_get_crc16(&frame_data[3], XMODEM_DATA_SIZE);
4623 
4624                         frame_data[XMODEM_DATA_SIZE + 3] =
4625                             (unsigned char)(crc_value >> 8); // 8:byte alignment, 3:byte alignment
4626                         frame_data[XMODEM_DATA_SIZE + 4] = (unsigned char)(crc_value); // 4:byte alignment
4627 
4628                         write_number = wm_tool_uart_write(frame_data, XMODEM_DATA_SIZE + 5); // 5:byte alignment
4629                         if (write_number <= 0) {
4630                             wm_tool_printf("write serial error, errno = %d.\r\n", errno);
4631                         }
4632 
4633                         WM_TOOL_DBG_PRINT("waiting for ack, %d, %d ...\r\n", pack_counter, write_number);
4634 
4635                         if ((wm_tool_uart_read(&ack_id, 1)) <= 0) {
4636                             WM_TOOL_DBG_PRINT("waiting ack timeout\r\n");
4637                             complete = 1;
4638                         } else {
4639                             if (ack_id == XMODEM_ACK) {
4640                                 int start_percent = 0;
4641                                 int step = 10; // 10:byte alignment
4642                                 WM_TOOL_DBG_PRINT("Ok!\r\n");
4643                                 if (sndlen * step / total_size > percent) {
4644                                     percent = sndlen * step / total_size;
4645                                     wm_tool_printf("#");
4646                                 }
4647                                 if (sndlen % 10240 == 0) { // 10240:byte alignment
4648                                 }
4649                             } else {
4650                                 WM_TOOL_DBG_PRINT("error = %x!\r\n", ack_id);
4651                             }
4652                         }
4653                     } else {
4654                         ack_id = XMODEM_EOT;
4655 
4656                         WM_TOOL_DBG_PRINT("waiting for complete ack ...\r\n");
4657 
4658                         while (ack_id != XMODEM_ACK) {
4659                             ack_id = XMODEM_EOT;
4660 
4661                             write_number = wm_tool_uart_write(&ack_id, 1);
4662                             if (write_number <= 0) {
4663                                 wm_tool_printf("write serial error, errno = %d.\r\n", errno);
4664                             }
4665 
4666                             while ((wm_tool_uart_read(&ack_id, 1)) <= 0) {
4667                             }
4668                         }
4669 
4670                         if (sndlen >= total_size) {
4671                             complete = 1;
4672 
4673                             WM_TOOL_DBG_PRINT("ok\r\n");
4674 
4675                             wm_tool_printf("] 100%%\r\n");
4676 
4677                             wm_tool_printf("download completed.\r\n");
4678 
4679                             ret = 0;
4680                         } else {
4681                             wm_tool_delay_ms(100); // 100:100ms
4682                             wm_tool_uart_clear();
4683                         }
4684                     }
4685                     break;
4686                 }
4687             case XMODEM_NAK:
4688                 {
4689                     if (retry_num++ > 100) { // 100:retry_num
4690                         WM_TOOL_DBG_PRINT("retry too many times, quit!\r\n");
4691                         wm_tool_printf("download firmware timeout.\r\n");
4692 
4693                         complete = 1;
4694                     } else {
4695                         write_number = wm_tool_uart_write(frame_data, XMODEM_DATA_SIZE + 5); // 5:byte alignment
4696                         if (write_number <= 0) {
4697                             wm_tool_printf("write serial error, errno = %d.\r\n", errno);
4698                         }
4699 
4700                         WM_TOOL_DBG_PRINT("retry for ack, %d, %d ...\r\n", pack_counter, write_number);
4701                         while ((wm_tool_uart_read(&ack_id, 1)) <= 0) {
4702                         }
4703 
4704                         if (ack_id == XMODEM_ACK) {
4705                             WM_TOOL_DBG_PRINT("ok\r\n");
4706                         } else {
4707                             WM_TOOL_DBG_PRINT("error!\r\n");
4708                         }
4709                     }
4710                     break;
4711                 }
4712             default:
4713                 {
4714                     WM_TOOL_DBG_PRINT("fatal error!\r\n");
4715                     WM_TOOL_DBG_PRINT("unknown xmodem protocol [%x].\r\n", ack_id);
4716                     wm_tool_printf("\r\ndownload failed, please reset and try again.\r\n");
4717 
4718                     complete = 1;
4719                     break;
4720                 }
4721         }
4722     }
4723 
4724     wm_tool_uart_set_block(0);
4725 
4726     fclose(imgfp);
4727 
4728     return ret;
4729 }
4730 static int wm_tool_download_firmware(void)
4731 {
4732     int ret;
4733     int cnt = 0;
4734     int note = 1;
4735     int timeout = 0;
4736     float timeuse;
4737     time_t start, end;
4738     unsigned char ch;
4739 
4740     wm_tool_printf("connecting serial...\r\n");
4741 
4742     ret = wm_tool_uart_open(wm_tool_serial_path);
4743     if (ret) {
4744         wm_tool_printf("can not open serial\r\n");
4745         return ret;
4746     }
4747 
4748     /* In some cases, setting the serial port initialization setting requires a delay. */
4749     wm_tool_delay_ms(500); // 500:500ms
4750 
4751     wm_tool_printf("serial connected.\r\n");
4752 
4753     if (wm_tool_dl_action == WM_TOOL_DL_ACTION_AT) {
4754         if (wm_tool_normal_serial_rate != WM_TOOL_DEFAULT_BAUD_RATE) {
4755             wm_tool_uart_set_speed(wm_tool_normal_serial_rate);
4756         }
4757 
4758         ret = wm_tool_uart_write("AT+Z\r\n", strlen("AT+Z\r\n"));
4759         if (ret <= 0) {
4760             wm_tool_printf("reset error.\r\n");
4761             wm_tool_uart_close();
4762             return -4; // -4:byte alignment
4763         }
4764 
4765         if (wm_tool_normal_serial_rate != WM_TOOL_DEFAULT_BAUD_RATE) {
4766             wm_tool_uart_set_speed(WM_TOOL_DEFAULT_BAUD_RATE);
4767         }
4768     } else if (WM_TOOL_DL_ACTION_RTS == wm_tool_dl_action) {
4769         ret  = wm_tool_uart_set_dtr(0);
4770         ret |= wm_tool_uart_set_rts(1);
4771         wm_tool_delay_ms(50); // 50:50ms
4772         ret |= wm_tool_uart_set_dtr(1);
4773         ret |= wm_tool_uart_set_rts(0);
4774         wm_tool_delay_ms(50); // 50:50ms
4775         ret |= wm_tool_uart_set_dtr(0);
4776         if (ret < 0) {
4777             wm_tool_printf("set rts to reboot error.\r\n");
4778             wm_tool_uart_close();
4779             return -5; // -5:byte alignment
4780         }
4781     }
4782 
4783     wm_tool_printf("wait serial sync...");
4784 
4785     wm_tool_send_esc2uart(500); // 500:used for delay
4786 
4787     start = time(NULL);
4788 
4789     do {
4790         ret = wm_tool_uart_read(&ch, 1);
4791 
4792         WM_TOOL_DBG_PRINT("ret=%d, %x-%c\r\n", ret, ch, ch);
4793 
4794         if (ret > 0) {
4795             if ((ch == 'C') || (ch == 'P')) {
4796                 cnt++;
4797             } else {
4798                 cnt = 0;
4799             }
4800         } else {
4801             wm_tool_send_esc2uart(30); // 30:30ms
4802         }
4803 
4804         end = time(NULL);
4805         timeuse = difftime(end, start);
4806         if (timeuse >= 1) {
4807             wm_tool_printf(".");
4808 
4809             timeout++;
4810             if ((timeout >= (WM_TOOL_DOWNLOAD_TIMEOUT_SEC / 10)) && note) { // 10:byte alignment
4811                 wm_tool_printf("\r\nplease manually reset the device.\r\n");
4812                 note = 0;
4813             } else if (timeout > WM_TOOL_DOWNLOAD_TIMEOUT_SEC) {
4814                 wm_tool_uart_close();
4815                 wm_tool_printf("\r\nserial sync timeout.\r\n");
4816                 return -6; // -6:byte alignment
4817             }
4818 
4819             start = time(NULL);
4820         }
4821     } while (cnt < 3); // 3:loop condition
4822 
4823     wm_tool_printf("\r\nserial sync sucess.\r\n");
4824 
4825     ret = wm_tool_query_mac();
4826     if (ret) {
4827         wm_tool_uart_close();
4828         wm_tool_printf("download failed.\r\n");
4829         return ret;
4830     }
4831 
4832     if (WM_TOOL_DL_ERASE_ALL == wm_tool_dl_erase) {
4833         ret = wm_tool_erase_image(WM_TOOL_DL_ERASE_ALL);
4834         if (ret) {
4835             wm_tool_uart_close();
4836             wm_tool_printf("failed to erase.\r\n");
4837             return ret;
4838         }
4839     }
4840 
4841     if (!wm_tool_download_image && wm_tool_dl_erase) {
4842         return 0;
4843     }
4844 
4845     if (wm_tool_download_serial_rate != WM_TOOL_DEFAULT_BAUD_RATE) {
4846         ret = wm_tool_set_wifi_chip_speed(wm_tool_download_serial_rate);
4847         if (ret > 0) {
4848             wm_tool_delay_ms(1 * 1000); // 1000:ms
4849             wm_tool_uart_set_speed(wm_tool_download_serial_rate);
4850         }
4851     }
4852 
4853     ret = wm_tool_xmodem_download(wm_tool_download_image);
4854 
4855     if (wm_tool_download_serial_rate != WM_TOOL_DEFAULT_BAUD_RATE) {
4856         wm_tool_delay_ms(1 * 1000); // 1000:ms
4857         wm_tool_set_wifi_chip_speed(WM_TOOL_DEFAULT_BAUD_RATE);
4858         wm_tool_delay_ms(1 * 1000); // 1000:ms
4859     }
4860 
4861     if (!ret) {
4862         if (WM_TOOL_DL_TYPE_FLS == wm_tool_dl_type) {
4863             if (WM_TOOL_DL_ACTION_RTS == wm_tool_dl_action) { /* auto reset */
4864                 wm_tool_uart_set_dtr(0);
4865                 wm_tool_uart_set_rts(1);
4866                 wm_tool_delay_ms(50); // 50:ms
4867                 wm_tool_uart_set_dtr(1);
4868                 wm_tool_uart_set_rts(0);
4869                 wm_tool_delay_ms(50); // 50:ms
4870                 wm_tool_uart_set_dtr(0);
4871             } else {
4872                 wm_tool_printf("please manually reset the device.\r\n");
4873             }
4874         }
4875     }
4876 
4877     wm_tool_uart_close();
4878 
4879     return ret;
4880 }
4881 
4882 static void wm_tool_show_local_com(void)
4883 {
4884 #if defined(__APPLE__) && defined(__MACH__)
4885     char *comstr = "tty.usbserial";
4886 #elif defined(__CYGWIN__)
4887     int num;
4888     char *comstr = "ttyS";
4889 #elif defined(__linux__)
4890     char *comstr = "ttyUSB";
4891 #endif
4892 
4893 #if defined(__APPLE__) || defined(__MACH__) || defined(__CYGWIN__) || defined(__linux__)
4894 
4895     DIR *dir;
4896     struct dirent *file;
4897 
4898     dir = opendir("/dev");
4899     if (dir) {
4900         while ((file = readdir(dir)) != NULL) {
4901             if ((strncmp(file->d_name, comstr, strlen(comstr)) == 0) && (file->d_type == DT_CHR)) {
4902 #if defined(__CYGWIN__)
4903                 num = atoi(file->d_name + strlen(comstr));
4904                 wm_tool_printf("COM%d ", num + 1);
4905 #else
4906                 wm_tool_printf("%s ", file->d_name);
4907 #endif
4908             }
4909         }
4910         closedir(dir);
4911         wm_tool_printf("\r\n");
4912     }
4913 
4914 #elif defined(__MINGW32__)
4915 
4916     LONG ret;
4917     HKEY key;
4918     DWORD i = 0;
4919     DWORD knlen;
4920     char kname[WM_TOOL_PATH_MAX] = {0};
4921     DWORD kvlen;
4922     char kvalue[WM_TOOL_PATH_MAX] = {0};
4923     REGSAM kmask = KEY_READ;
4924 
4925 #if defined(KEY_WOW64_64KEY)
4926     BOOL is_64;
4927 
4928     if (IsWow64Process(GetCurrentProcess(), &is_64)) {
4929         if (is_64)
4930             kmask |= KEY_WOW64_64KEY;
4931     }
4932 #endif
4933 
4934     ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), \
4935                          0, NULL, 0, kmask, NULL, &key, NULL);
4936     if (ret != ERROR_SUCCESS) {
4937         return;
4938     }
4939 
4940     do {
4941         knlen = sizeof(kname);
4942         kvlen = sizeof(kvalue);
4943         ret = RegEnumValue(key, i, kname, &knlen, 0, NULL, (LPBYTE)kvalue, &kvlen);
4944         if (ret == ERROR_SUCCESS) {
4945             if (strcmp(kvalue, "") != 0) {
4946                 wm_tool_printf("%s ", kvalue);
4947             }
4948         }
4949 
4950         i++;
4951     } while (ret != ERROR_NO_MORE_ITEMS);
4952 
4953     RegCloseKey(key);
4954 
4955     wm_tool_printf("\r\n");
4956 
4957 #else
4958 
4959     wm_tool_printf("\r\nunsupported system.\r\n");
4960 
4961 #endif
4962 
4963     return;
4964 }
4965 static void wm_tool_free_res(void)
4966 {
4967     if (wm_tool_download_image) {
4968         free(wm_tool_download_image);
4969     }
4970 
4971     if (wm_tool_output_image) {
4972         free(wm_tool_output_image);
4973     }
4974 
4975     if (wm_tool_input_binary) {
4976         free(wm_tool_input_binary);
4977     }
4978 
4979     if (wm_tool_secboot_image) {
4980         free(wm_tool_secboot_image);
4981     }
4982 
4983     return;
4984 }
4985 
4986 int main(int argc, char *argv[])
4987 {
4988     int ret = 0;
4989 
4990     if (!wm_tool_parse_arv(argc, argv)) {
4991         wm_tool_print_usage(argv[0]);
4992         wm_tool_free_res();
4993         return 0;
4994     }
4995 
4996     if (wm_tool_show_usage) {
4997         wm_tool_print_usage(argv[0]);
4998         wm_tool_free_res();
4999         return 0;
5000     }
5001 
5002     if (wm_tool_show_ver) {
5003         wm_tool_print_version(argv[0]);
5004         wm_tool_free_res();
5005         return 0;
5006     }
5007 
5008     if (wm_tool_list_com) {
5009         wm_tool_show_local_com();
5010         wm_tool_free_res();
5011         return 0;
5012     }
5013 
5014     if (wm_tool_input_binary) {
5015         ret = wm_tool_pack_firmware();
5016     }
5017 
5018     if (wm_tool_download_image || wm_tool_dl_erase) {
5019         ret = wm_tool_download_firmware();
5020     }
5021 
5022     if (wm_tool_show_log_type) {
5023     }
5024 
5025     if (ret > 0) {
5026         wm_tool_print_usage(argv[0]);
5027     }
5028 
5029     wm_tool_free_res();
5030 
5031     return ret;
5032 }