#include #include #include #include #include #include #include #include #include #include #include #ifdef __MINGW32__ #include #else #include #include #include #include #endif #define WM_TOOL_PATH_MAX 256 #define WM_TOOL_ONCE_READ_LEN 1024 #define WM_TOOL_RUN_IMG_HEADER_LEN 0x100 #define WM_TOOL_SECBOOT_IMG_ADDR (0x2100) #define WM_TOOL_SECBOOT_HEADER_LEN (0x100) #define WM_TOOL_SECBOOT_HEADER_POS (WM_TOOL_SECBOOT_IMG_ADDR - WM_TOOL_SECBOOT_HEADER_LEN) //#define WM_TOOL_SECBOOT_IMG_AREA_TOTAL_LEN 9216//(56 * 1024) #define WM_TOOL_IMG_HEAD_MAGIC_NO (0xA0FFFF9F) #define WM_TOOL_DEFAULT_BAUD_RATE 115200 #define WM_TOOL_DOWNLOAD_TIMEOUT_SEC (60 * 1) #define WM_TOOL_USE_1K_XMODEM 1 /* 1 for use 1k_xmodem 0 for xmodem */ #define WM_TOOL_IMAGE_VERSION_LEN 16 /* Xmodem Frame form: <255-blk #><--128 data bytes--> */ #define XMODEM_SOH 0x01 #define XMODEM_STX 0x02 #define XMODEM_EOT 0x04 #define XMODEM_ACK 0x06 #define XMODEM_NAK 0x15 #define XMODEM_CAN 0x18 #define XMODEM_CRC_CHR 'C' #define XMODEM_CRC_SIZE 2 /* Crc_High Byte + Crc_Low Byte */ #define XMODEM_FRAME_ID_SIZE 2 /* Frame_Id + 255-Frame_Id */ #define XMODEM_DATA_SIZE_SOH 128 /* for Xmodem protocol */ #define XMODEM_DATA_SIZE_STX 1024 /* for 1K xmodem protocol */ #if (WM_TOOL_USE_1K_XMODEM) #define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_STX #define XMODEM_HEAD XMODEM_STX #else #define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_SOH #define XMODEM_HEAD XMODEM_SOH #endif #ifdef WM_DEBUG #define WM_TOOL_DBG_PRINT wm_tool_printf #else #define WM_TOOL_DBG_PRINT(...) #endif typedef enum { WM_TOOL_DL_ACTION_NONE = 0, WM_TOOL_DL_ACTION_AT, WM_TOOL_DL_ACTION_RTS } wm_tool_dl_action_e; typedef enum { WM_TOOL_DL_ERASE_NONE = 0, WM_TOOL_DL_ERASE_ALL } wm_tool_dl_erase_e; typedef enum { WM_TOOL_DL_TYPE_IMAGE = 0, WM_TOOL_DL_TYPE_FLS } wm_tool_dl_type_e; typedef enum { WM_TOOL_LAYOUT_TYPE_1M = 0, WM_TOOL_LAYOUT_TYPE_2M = 3 } wm_tool_layout_type_e; typedef enum { WM_TOOL_ZIP_TYPE_UNCOMPRESS = 0, WM_TOOL_ZIP_TYPE_COMPRESS } wm_tool_zip_type_e; typedef enum { WM_TOOL_CRC32_REFLECT_OUTPUT = 1, WM_TOOL_CRC32_REFLECT_INPUT = 2 } wm_tool_crc32_reflect_e; typedef enum { WM_TOOL_SHOW_LOG_NONE = 0, WM_TOOL_SHOW_LOG_STR, WM_TOOL_SHOW_LOG_HEX } wm_tool_show_log_e; typedef struct { unsigned int magic_no; unsigned short img_type; unsigned short zip_type; unsigned int run_img_addr; unsigned int run_img_len; unsigned int img_header_addr; unsigned int upgrade_img_addr; unsigned int run_org_checksum; unsigned int upd_no; unsigned char ver[WM_TOOL_IMAGE_VERSION_LEN]; unsigned int reserved0; unsigned int reserved1; unsigned int next_boot; unsigned int hd_checksum; } wm_tool_firmware_booter_t; const static char *wm_tool_version = "1.0.4"; static int wm_tool_show_usage = 0; static int wm_tool_list_com = 0; static int wm_tool_show_ver = 0; static char wm_tool_serial_path[WM_TOOL_PATH_MAX] = "/dev/ttyS0"; static unsigned int wm_tool_download_serial_rate = WM_TOOL_DEFAULT_BAUD_RATE; static unsigned int wm_tool_normal_serial_rate = WM_TOOL_DEFAULT_BAUD_RATE; static wm_tool_dl_action_e wm_tool_dl_action = WM_TOOL_DL_ACTION_NONE; static wm_tool_dl_erase_e wm_tool_dl_erase = WM_TOOL_DL_ERASE_NONE; static wm_tool_dl_type_e wm_tool_dl_type = WM_TOOL_DL_TYPE_IMAGE; static char *wm_tool_download_image = NULL; static char *wm_tool_input_binary = NULL; static char *wm_tool_output_image = NULL; static char *wm_tool_secboot_image = NULL; static unsigned int wm_tool_src_binary_len = 0; static unsigned int wm_tool_src_binary_crc = 0; static int wm_tool_is_debug = 0; static char wm_tool_image_version[WM_TOOL_IMAGE_VERSION_LEN]; static wm_tool_layout_type_e wm_tool_image_type = WM_TOOL_LAYOUT_TYPE_1M; static wm_tool_zip_type_e wm_tool_zip_type = WM_TOOL_ZIP_TYPE_COMPRESS; static unsigned int wm_tool_upd_addr = 0x8090000; static unsigned int wm_tool_run_addr = 0x8002400; static unsigned int wm_tool_image_header = 0x8002000; static unsigned int wm_tool_next_image_header = 0x0; static unsigned int wm_tool_image_upd_no = 0x0; static unsigned int wm_tool_file_crc = 0xFFFFFFFF; static wm_tool_show_log_e wm_tool_show_log_type = WM_TOOL_SHOW_LOG_NONE; #ifdef __MINGW32__ #ifndef CBR_2000000 #define CBR_2000000 2000000 #endif #ifndef CBR_1000000 #define CBR_1000000 1000000 #endif #ifndef CBR_921600 #define CBR_921600 921600 #endif #ifndef CBR_460800 #define CBR_460800 460800 #endif static DWORD wm_tool_uart_block = 0; static HANDLE wm_tool_uart_handle = NULL; const static int wm_tool_uart_speed_array[] = {CBR_2000000, CBR_1000000, CBR_921600, CBR_460800, CBR_115200, CBR_38400, CBR_19200, CBR_9600, CBR_4800, CBR_2400, CBR_1200}; #else /* __MINGW32__ */ #ifndef B2000000 #define B2000000 2000000 #endif #ifndef B1000000 #define B1000000 1000000 #endif #ifndef B921600 #define B921600 921600 #endif #ifndef B460800 #define B460800 460800 #endif static int wm_tool_uart_fd = -1; static struct termios wm_tool_saved_serial_cfg; const static int wm_tool_uart_speed_array[] = {B2000000, B1000000, B921600, B460800, B115200, B38400, B19200, B9600, B4800, B2400, B1200}; #endif /* __MINGW32__ */ const static int wm_tool_uart_name_array[] = {2000000, 1000000, 921600, 460800, 115200, 38400, 19200, 9600, 4800, 2400, 1200}; const static unsigned char wm_tool_chip_cmd_b115200[] = {0x21, 0x0a, 0x00, 0x97, 0x4b, 0x31, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00}; const static unsigned char wm_tool_chip_cmd_b460800[] = {0x21, 0x0a, 0x00, 0x07, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x00}; const static unsigned char wm_tool_chip_cmd_b921600[] = {0x21, 0x0a, 0x00, 0x5d, 0x50, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00}; const static unsigned char wm_tool_chip_cmd_b1000000[] = {0x21, 0x0a, 0x00, 0x5e, 0x3d, 0x31, 0x00, 0x00, 0x00, 0x40, 0x42, 0x0f, 0x00}; const static unsigned char wm_tool_chip_cmd_b2000000[] = {0x21, 0x0a, 0x00, 0xef, 0x2a, 0x31, 0x00, 0x00, 0x00, 0x80, 0x84, 0x1e, 0x00}; const static unsigned char wm_tool_chip_cmd_get_mac[] = {0x21, 0x06, 0x00, 0xea, 0x2d, 0x38, 0x00, 0x00, 0x00}; static const unsigned int wm_tool_crc32_tab[] = {0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL}; static void wm_tool_signal_proc_entry(void); static void wm_tool_stdin_to_uart(void); /* ============================ zlib gzip ================================== */ #define ALLOC(size) zcalloc((voidp)0, 1, size) #define TRYFREE(p) {if (p) zcfree((voidp)0, p);} #define BINARY 0 #define ASCII 1 #define UNKNOWN 2 #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 #define REP_3_6 16 #define REPZ_3_10 17 #define REPZ_11_138 18 #define MAX_BL_BITS 7 #define BASE 65521 /* largest prime smaller than 65536 */ #define NMAX 5552 #define DO1(buf) {s1 += *buf++; s2 += s1;} #define DO2(buf) DO1(buf); DO1(buf); #define DO4(buf) DO2(buf); DO2(buf); #define DO8(buf) DO4(buf); DO4(buf); #define DO16(buf) DO8(buf); DO8(buf); #define Z_OK 0 #define Z_STREAM_END 1 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) #define DEFLATED 8 #ifndef WBITS # define WBITS 15 /* 32K window */ #endif #ifndef MEM_LEVEL # define MEM_LEVEL 8 #endif #define Z_BUFSIZE 4096 #define GZ_MAGIC_1 0x1f #define GZ_MAGIC_2 0x8b #ifndef OS_CODE # define OS_CODE 0x03 /* assume Unix */ #endif #ifndef TOO_FAR # define TOO_FAR 4096 #endif #define Z_NO_FLUSH 0 #define Z_FINISH 4 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define RESERVED 0xE0 /* bits 5..7: reserved */ #define LENGTH_CODES 29/* number of length codes, not counting the special END_BLOCK code */ #define LITERALS 256/* number of literal bytes 0..255 */ #define L_CODES (LITERALS+1+LENGTH_CODES)/* number of Literal or Length codes, including the END_BLOCK code */ #define D_CODES 30/* number of distance codes */ #define BL_CODES 19/* number of codes used to transfer the bit lengths */ #define HEAP_SIZE (2*L_CODES+1)/* maximum heap size */ #define END_BLOCK 256 #define MAX_BITS 15 #define MAX_MEM_LEVEL 9 #define MIN_MATCH 3 #define MAX_MATCH 258 #define Z_UNKNOWN 2 #define INIT_STATE 42 #define BUSY_STATE 113 #define FINISH_STATE 666 #define NIL 0 #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_DEFAULT_STRATEGY 0 #define SMALLEST 1 #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) #define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) #define ERR_RETURN(strm,err) return (strm->msg=z_errmsg[1-err], err) #define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} #define put_short(s, w) { \ put_byte(s, (uch)((w) & 0xff)); \ put_byte(s, (uch)((ush)(w) >> 8)); \ } #define INSERT_STRING(s, str, match_head) \ (UPDATE_HASH(s, s->ins_h, s->window[(str) + MIN_MATCH-1]), \ s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ s->head[s->ins_h] = (str)) #define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) #define check_match(s, start, match, length) #define d_code(dist) \ ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) #define FLUSH_BLOCK_ONLY(s, eof) { \ ct_flush_block(s, (s->block_start >= 0L ? \ (char*)&s->window[(unsigned)s->block_start] : \ (char*)Z_NULL), (long)s->strstart - s->block_start, (eof)); \ s->block_start = s->strstart; \ flush_pending(s->strm); \ } #define FLUSH_BLOCK(s, eof) { \ FLUSH_BLOCK_ONLY(s, eof); \ if (s->strm->avail_out == 0) return 1; \ } #define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) #define MAX(a,b) (a >= b ? a : b) #define Buf_size (8 * 2*sizeof(char)) #define smaller(tree, n, m, depth) \ (tree[n].Freq < tree[m].Freq || \ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) #define pqremove(s, tree, top) \ {\ top = s->heap[SMALLEST]; \ s->heap[SMALLEST] = s->heap[s->heap_len--]; \ pqdownheap(s, tree, SMALLEST); \ } #ifndef local # define local static #endif #ifndef __P #define __P(args) args #endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} #define Assert(cond,msg) #ifndef Byte typedef unsigned char Byte; /* 8 bits */ #endif #ifndef uInt typedef unsigned int uInt; /* may be 16 or 32 bits */ #endif #ifndef uLong typedef unsigned long uLong; /* 32 bits or more */ #endif typedef Byte *voidp; typedef voidp gzFile; typedef unsigned char uch; typedef unsigned long ulg; typedef unsigned short ush; typedef ush Pos; typedef unsigned IPos; typedef voidp (*alloc_func) __P((voidp opaque, uInt items, uInt size)); typedef void (*free_func) __P((voidp opaque, voidp address)); typedef uLong (*check_func) __P((uLong check, Byte *buf, uInt len)); typedef struct z_stream_s { Byte *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total nb of input bytes read so far */ Byte *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total nb of bytes output so far */ char *msg; /* last error message, NULL if no error */ struct internal_state *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidp opaque; /* private data object passed to zalloc and zfree */ Byte data_type; /* best guess about the data type: ascii or binary */ } z_stream; typedef struct gz_stream { z_stream stream; int z_err; /* error code for last stream operation */ int z_eof; /* set if end of input file */ FILE *file; /* .gz file */ Byte *inbuf; /* input buffer */ Byte *outbuf; /* output buffer */ uLong crc; /* crc32 of uncompressed data */ char *msg; /* error message */ char *path; /* path name for debugging only */ int transparent; /* 1 if input file is not a .gz file */ char mode; /* 'w' or 'r' */ } gz_stream; /* Data structure describing a single value and its code string. */ typedef struct ct_data_s { union { ush freq; /* frequency count */ ush code; /* bit string */ } fc; union { ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; } ct_data; struct static_tree_desc_s { ct_data *static_tree; /* static tree or NULL */ int *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ static_tree_desc *stat_desc; /* the corresponding static tree */ } tree_desc; typedef struct inflate_huft_s inflate_huft; struct inflate_huft_s { union { struct { char Exop; /* number of extra bits or operation */ char Bits; /* number of bits in this code or subcode */ } what; Byte *pad; /* pad structure to a power of 2 (4 bytes for */ } word; /* 16-bit, 8 bytes for 32-bit machines) */ union { uInt Base; /* literal, length base, or distance base */ inflate_huft *Next; /* pointer to next level of table */ } more; }; /* inflate codes private state */ struct inflate_codes_state { /* mode */ enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ START, /* x: set up for LEN */ LEN, /* i: get length/literal/eob next */ LENEXT, /* i: getting length extra (have base) */ DIST, /* i: get distance next */ DISTEXT, /* i: getting distance extra */ COPY, /* o: copying bytes in window, waiting for space */ LIT, /* o: got literal, waiting for output space */ WASH, /* o: got eob, possibly still output waiting */ END, /* x: got eob and all data flushed */ BAD} /* x: got error */ mode; /* current inflate_codes mode */ /* mode dependent information */ uInt len; union { struct { inflate_huft *tree; /* pointer into tree */ uInt need; /* bits needed */ } code; /* if LEN or DIST, where in tree */ uInt lit; /* if LIT, literal */ struct { uInt get; /* bits to get for extra */ uInt dist; /* distance back to copy from */ } copy; /* if EXT or COPY, where and how much */ } sub; /* submode */ /* mode independent information */ Byte lbits; /* ltree bits decoded per branch */ Byte dbits; /* dtree bits decoder per branch */ inflate_huft *ltree; /* literal/length/eob tree */ inflate_huft *dtree; /* distance tree */ }; /* inflate blocks semi-private state */ struct inflate_blocks_state { /* mode */ enum { TYPE, /* get type bits (3, including end bit) */ LENS, /* get lengths for stored */ STORED, /* processing stored block */ TABLE, /* get table lengths */ BTREE, /* get bit lengths tree for a dynamic block */ DTREE, /* get length, distance trees for a dynamic block */ CODES, /* processing fixed or dynamic block */ DRY, /* output remaining window bytes */ DONE, /* finished last block, done */ INF_ERROR}/* got a data error--stuck here */ mode; /* current inflate_block mode */ /* mode dependent information */ union { uInt left; /* if STORED, bytes left to copy */ struct { uInt table; /* table lengths (14 bits) */ uInt index; /* index into blens (or border) */ uInt *blens; /* bit lengths of codes */ uInt bb; /* bit length tree depth */ inflate_huft *tb; /* bit length decoding tree */ } trees; /* if DTREE, decoding info for trees */ struct inflate_codes_state *codes; /* if CODES, current state */ } sub; /* submode */ uInt last; /* true if this block is the last block */ /* mode independent information */ uInt bitk; /* bits in bit buffer */ uLong bitb; /* bit buffer */ Byte *window; /* sliding window */ Byte *end; /* one byte after sliding window */ Byte *read; /* window read pointer */ Byte *write; /* window write pointer */ check_func checkfn; /* check function */ uLong check; /* check on output */ }; typedef struct internal_state { z_stream *strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ Byte *pending_buf; /* output still pending */ Byte *pending_out; /* next pending byte to output to the stream */ int pending; /* nb of bytes in the pending buffer */ uLong adler; /* adler32 of uncompressed data */ int noheader; /* suppress zlib header and adler32 */ Byte data_type; /* UNKNOWN, BINARY or ASCII */ Byte method; /* STORED (for zip only) or DEFLATED */ /* used by deflate.c: */ uInt w_size; /* LZ77 window size (32K by default) */ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ Byte *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of * wSize-MAX_MATCH bytes, but this ensures that IO is always * performed with a length multiple of the block size. Also, it limits * the window size to 64K, which is quite useful on MSDOS. * To do: use the user input buffer as sliding window. */ ulg window_size; /* Actual size of window: 2*wSize, except when the user input buffer * is directly used as sliding window. */ Pos *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ Pos *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ uInt hash_bits; /* log2(hash_size) */ uInt hash_mask; /* hash_size-1 */ uInt hash_shift; /* Number of bits by which ins_h must be shifted at each input * step. It must be such that after MIN_MATCH steps, the oldest * byte no longer takes part in the hash key, that is: * hash_shift * MIN_MATCH >= hash_bits */ long block_start; /* Window position at the beginning of the current output block. Gets * negative when the window is moved backwards. */ uInt match_length; /* length of best match */ IPos prev_match; /* previous match */ int match_available; /* set if previous match exists */ uInt strstart; /* start of string to insert */ uInt match_start; /* start of matching string */ uInt lookahead; /* number of valid bytes ahead in window */ uInt prev_length; /* Length of the best match at previous step. Matches not greater than this * are discarded. This is used in the lazy match evaluation. */ uInt max_chain_length; /* To speed up deflation, hash chains are never searched beyond this * length. A higher limit improves compression ratio but degrades the * speed. */ uInt max_lazy_match; /* Attempt to find a better match only when the current match is strictly * smaller than this value. This mechanism is used only for compression * levels >= 4. */ # define max_insert_length max_lazy_match /* Insert new strings in the hash table only if the match length is not * greater than this length. This saves time but degrades compression. * max_insert_length is used only for compression levels <= 3. */ int level; /* compression level (1..9) */ int strategy; /* favor or force Huffman coding*/ uInt good_match; /* Use a faster search when the previous match is longer than this */ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */ ct_data dyn_ltree[HEAP_SIZE]; /* literal and length tree */ ct_data dyn_dtree[2*D_CODES+1]; /* distance tree */ ct_data bl_tree[2*BL_CODES+1]; /* Huffman tree for the bit lengths */ tree_desc l_desc; /* descriptor for literal tree */ tree_desc d_desc; /* descriptor for distance tree */ tree_desc bl_desc; /* descriptor for bit length tree */ ush bl_count[MAX_BITS+1]; /* number of codes at each bit length for an optimal tree */ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ int heap_len; /* number of elements in the heap */ int heap_max; /* element of largest frequency */ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. * The same heap array is used to build all trees. */ uch depth[2*L_CODES+1]; /* Depth of each subtree used as tie breaker for trees of equal frequency */ uch *l_buf; /* buffer for literals or lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for * limiting lit_bufsize to 64K: * - frequencies can be kept in 16 bit counters * - if compression is not successful for the first block, all input * data is still in the window so we can still emit a stored block even * when input comes from standard input. (This can also be done for * all blocks if lit_bufsize is not greater than 32K.) * - if compression is not successful for a file smaller than 64K, we can * even emit a stored file instead of a stored block (saving 5 bytes). * This is applicable only for zip (not gzip or zlib). * - creating new Huffman trees less frequently may not provide fast * adaptation to changes in the input data statistics. (Take for * example a binary file with poorly compressible code followed by * a highly compressible string table.) Smaller buffer sizes give * fast adaptation but have of course the overhead of transmitting * trees more frequently. * - I can't count above 4 */ uInt last_lit; /* running index in l_buf */ ush *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ ulg compressed_len; /* total bit length of compressed file */ uInt matches; /* number of string matches in current block */ #ifdef DEBUG ulg bits_sent; /* bit length of the compressed data */ #endif ush bi_buf; /* Output buffer. bits are inserted starting at the bottom (least * significant bits). */ int bi_valid; /* Number of valid bits in bi_buf. All bits above the last valid bit * are always zero. */ /* mode */ enum { METHOD, /* waiting for method byte */ FLAG, /* waiting for flag byte */ //START, /* make new blocks state */ BLOCKS, /* decompressing blocks */ CHECK4, /* four check bytes to go */ CHECK3, /* three check bytes to go */ CHECK2, /* two check bytes to go */ CHECK1, /* one check byte to go */ //DONE, /* finished check, done */ //INF_ERROR/* got an error--stay here */ } mode; /* current inflate mode */ /* mode dependent information */ union { uInt method; /* if FLAGS, method byte */ struct inflate_blocks_state *blocks; /* if BLOCKS, current state */ struct { uLong was; /* computed check value */ uLong need; /* stream check value */ } check; /* if CHECK, check values to compare */ } sub; /* submode */ /* mode independent information */ int nowrap; /* flag for no wrapper */ uInt wbits; /* log2(window size) (8..15, defaults to 15) */ } deflate_state; typedef struct config_s { ush good_length; /* reduce lazy search above this match length */ ush max_lazy; /* do not perform lazy search above this match length */ ush nice_length; /* quit search above this match length */ ush max_chain; } config; char *z_errmsg[] = { "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */ "file error", /* Z_ERRNO (-1) */ "stream error", /* Z_STREAM_ERROR (-2) */ "data error", /* Z_DATA_ERROR (-3) */ "insufficient memory", /* Z_MEM_ERROR (-4) */ "buffer error", /* Z_BUF_ERROR (-5) */ ""}; local int base_length[LENGTH_CODES]; local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {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}; local uch length_code[MAX_MATCH-MIN_MATCH+1]; local int base_dist[D_CODES]; local int extra_dbits[D_CODES] /* extra bits for each distance code */ = {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}; local ct_data static_ltree[L_CODES+2]; local uch dist_code[512]; local int base_dist[D_CODES]; local ct_data static_dtree[D_CODES]; local static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; local static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; local int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; local static_tree_desc static_bl_desc = {(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; local uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; local config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0}, /* store only */ /* 1 */ {4, 4, 8, 4}, /* maximum speed, no lazy matches */ /* 2 */ {4, 5, 16, 8}, /* 3 */ {4, 6, 32, 32}, /* 4 */ {4, 4, 16, 16}, /* lazy matches */ /* 5 */ {8, 16, 32, 32}, /* 6 */ {8, 16, 128, 128}, /* 7 */ {8, 32, 128, 256}, /* 8 */ {32, 128, 258, 1024}, /* 9 */ {32, 258, 258, 4096}}; /* maximum compression */ #define FIXEDH 530 /* number of hufts used by fixed tables */ local inflate_huft fixed_mem[FIXEDH]; #define next more.Next #define Freq fc.freq #define Code fc.code #define Dad dl.dad #define Len dl.len local voidp zcalloc (opaque, items, size) voidp opaque; unsigned items; unsigned size; { return calloc(items, size); } local void zcfree (opaque, ptr) voidp opaque; voidp ptr; { free(ptr); } local uLong crc32(crc, buf, len) uLong crc; Byte *buf; uInt len; { if (buf == Z_NULL) return 0L; crc = crc ^ 0xffffffffL; if (len) do { crc = wm_tool_crc32_tab[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); } while (--len); return crc ^ 0xffffffffL; } local void zmemcpy(dest, source, len) Byte* dest; Byte* source; uInt len; { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } local void zmemzero(dest, len) Byte* dest; uInt len; { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ } while (--len != 0); } local uLong adler32(adler, buf, len) uLong adler; Byte *buf; uInt len; { unsigned long s1 = adler & 0xffff; unsigned long s2 = (adler >> 16) & 0xffff; int k; if (buf == Z_NULL) return 1L; while (len > 0) { k = len < NMAX ? len : NMAX; len -= k; while (k >= 16) { DO16(buf); k -= 16; } if (k != 0) do { DO1(buf); } while (--k); s1 %= BASE; s2 %= BASE; } return (s2 << 16) | s1; } local int read_buf(strm, buf, size) z_stream *strm; char *buf; unsigned size; { unsigned len = strm->avail_in; if (len > size) len = size; if (len == 0) return 0; strm->avail_in -= len; if (!strm->state->noheader) { strm->state->adler = adler32(strm->state->adler, strm->next_in, len); } zmemcpy((Byte *)buf, strm->next_in, len); strm->next_in += len; strm->total_in += len; return (int)len; } local int inflate_trees_free(t, z) inflate_huft *t; /* table to free */ z_stream *z; /* for zfree function */ /* Free the malloc'ed tables built by huft_build(), which makes a linked list of the tables it made, with the links in a dummy first entry of each table. */ { register inflate_huft *p, *q; /* Don't free fixed trees */ if (t >= fixed_mem && t <= fixed_mem + FIXEDH) return Z_OK; /* Go through linked list, freeing from the malloced (t[-1]) address. */ p = t; while (p != Z_NULL) { q = (--p)->next; ZFREE(z,p); p = q; } return Z_OK; } local void inflate_codes_free(c, z) struct inflate_codes_state *c; z_stream *z; { inflate_trees_free(c->dtree, z); inflate_trees_free(c->ltree, z); ZFREE(z, c); } local int inflate_blocks_free(s, z, c) struct inflate_blocks_state *s; z_stream *z; uLong *c; { if (s->checkfn != Z_NULL) *c = s->check; if (s->mode == BTREE || s->mode == DTREE) ZFREE(z, s->sub.trees.blens); if (s->mode == CODES) inflate_codes_free(s->sub.codes, z); ZFREE(z, s->window); ZFREE(z, s); return Z_OK; } local int deflateEnd (strm) z_stream *strm; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; TRY_FREE(strm, strm->state->window); TRY_FREE(strm, strm->state->prev); TRY_FREE(strm, strm->state->head); TRY_FREE(strm, strm->state->pending_buf); ZFREE(strm, strm->state); strm->state = Z_NULL; return Z_OK; } local int inflateEnd(z) z_stream *z; { uLong c; if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) return Z_STREAM_ERROR; if (z->state->mode == BLOCKS) inflate_blocks_free(z->state->sub.blocks, z, &c); ZFREE(z, z->state); z->state = Z_NULL; return Z_OK; } local int destroy (s) gz_stream *s; { int err = Z_OK; if (!s) return Z_STREAM_ERROR; TRYFREE(s->inbuf); TRYFREE(s->outbuf); TRYFREE((voidp)s->path); TRYFREE((voidp)s->msg); if (s->stream.state != NULL) { if (s->mode == 'w') { err = deflateEnd(&(s->stream)); } else if (s->mode == 'r') { err = inflateEnd(&(s->stream)); } } if (s->file != NULL && fclose(s->file)) { err = Z_ERRNO; } if (s->z_err < 0) err = s->z_err; zcfree((voidp)0, (voidp)s); return err; } local void putLong (file, x) FILE *file; uLong x; { int n; for (n = 0; n < 4; n++) { fputc((int)(x & 0xff), file); x >>= 8; } } local uLong getLong (buf) Byte *buf; { uLong x = 0; Byte *p = buf+4; do { x <<= 8; x |= *--p; } while (p != buf); return x; } local unsigned bi_reverse(code, len) unsigned code; /* the value to invert */ int len; /* its bit length */ { register unsigned res = 0; do { res |= code & 1; code >>= 1, res <<= 1; } while (--len > 0); return res >> 1; } local void gen_codes (tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ush bl_count[]; /* number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ ush code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ /* The distribution counts are first used to generate the code values * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { next_code[bits] = code = (code + bl_count[bits-1]) << 1; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ Assert (code + bl_count[MAX_BITS]-1 == (1< length code (0..28) */ length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { dist_code[256 + dist++] = (uch)code; } } Assert (dist == 256, "ct_static_init: 256+dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; n = 0; while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; /* Codes 286 and 287 do not exist, but we must include them in the * tree construction to get a canonical Huffman tree (longest code * all ones) */ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; static_dtree[n].Code = bi_reverse(n, 5); } } local void init_block(s) deflate_state *s; { int n; /* iterates over tree elements */ /* Initialize the trees. */ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; s->last_lit = s->matches = 0; } local void ct_init(s) deflate_state *s; { if (static_dtree[0].Len == 0) { ct_static_init(); /* To do: at compile time */ } s->compressed_len = 0L; s->l_desc.dyn_tree = s->dyn_ltree; s->l_desc.stat_desc = &static_l_desc; s->d_desc.dyn_tree = s->dyn_dtree; s->d_desc.stat_desc = &static_d_desc; s->bl_desc.dyn_tree = s->bl_tree; s->bl_desc.stat_desc = &static_bl_desc; s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->bits_sent = 0L; #endif /* Initialize the first block of the first file: */ init_block(s); } local void lm_init (s) deflate_state *s; { register unsigned j; s->window_size = (ulg)2L*s->w_size; /* Initialize the hash table (avoiding 64K overflow for 16 bit systems). * prev[] will be initialized on the fly. */ s->head[s->hash_size-1] = NIL; zmemzero((unsigned char*)s->head, (unsigned int)(s->hash_size-1)*sizeof(*s->head)); /* Set the default configuration parameters: */ s->max_lazy_match = configuration_table[s->level].max_lazy; s->good_match = configuration_table[s->level].good_length; s->nice_match = configuration_table[s->level].nice_length; s->max_chain_length = configuration_table[s->level].max_chain; s->strstart = 0; s->block_start = 0L; s->lookahead = 0; s->match_length = MIN_MATCH-1; s->match_available = 0; #ifdef ASMV match_init(); /* initialize the asm code */ #endif s->ins_h = 0; for (j=0; jins_h, s->window[j]); /* If lookahead < MIN_MATCH, ins_h is garbage, but this is * not important since only literal bytes will be emitted. */ } local int deflateReset (strm) z_stream *strm; { deflate_state *s; if (strm == Z_NULL || strm->state == Z_NULL || strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; strm->total_in = strm->total_out = 0; strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; s->pending = 0; s->pending_out = s->pending_buf; s->status = s->noheader ? BUSY_STATE : INIT_STATE; s->adler = 1; ct_init(s); lm_init(s); return Z_OK; } local int deflateInit2 (strm, level, method, windowBits, memLevel, strategy) z_stream *strm; int level; int method; int windowBits; int memLevel; int strategy; { deflate_state *s; int noheader = 0; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; if (strm->zalloc == Z_NULL) strm->zalloc = zcalloc; if (strm->zfree == Z_NULL) strm->zfree = zcfree; if (level == Z_DEFAULT_COMPRESSION) level = 6; if (windowBits < 0) { /* undocumented feature: suppress zlib header */ noheader = 1; windowBits = -windowBits; } if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != DEFLATED || windowBits < 8 || windowBits > 15 || level < 1 || level > 9) { return Z_STREAM_ERROR; } s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state *)s; s->strm = strm; s->noheader = noheader; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; s->hash_bits = memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); s->window = (Byte*) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Pos*) ZALLOC(strm, s->w_size, sizeof(Pos)); s->head = (Pos*) ZALLOC(strm, s->hash_size, sizeof(Pos)); s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ s->pending_buf = (uch*) ZALLOC(strm, s->lit_bufsize, 2*sizeof(ush)); if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { strm->msg = z_errmsg[1-Z_MEM_ERROR]; deflateEnd (strm); return Z_MEM_ERROR; } s->d_buf = (ush*) &(s->pending_buf[s->lit_bufsize]); s->l_buf = (uch*) &(s->pending_buf[3*s->lit_bufsize]); /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 32 bits (worst case * is 15+15+13=33). */ s->level = level; s->strategy = strategy; s->method = (Byte)method; return deflateReset(strm); } local int inflateInit2(z, w) z_stream *z; int w; { /* initialize state */ if (z == Z_NULL) return Z_STREAM_ERROR; if (z->zalloc == Z_NULL) z->zalloc = zcalloc; if (z->zfree == Z_NULL) z->zfree = zcfree; z->total_in = z->total_out = 0; z->msg = Z_NULL; if ((z->state = (struct internal_state *) ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) return Z_MEM_ERROR; z->state->mode = METHOD; /* handle undocumented nowrap option (no zlib header or check) */ z->state->nowrap = 0; if (w < 0) { w = - w; z->state->nowrap = 1; z->state->mode = START; } /* set window size */ if (w < 8 || w > 15) { inflateEnd(z); return Z_STREAM_ERROR; } z->state->wbits = w; return Z_OK; } local void putShortMSB (s, b) deflate_state *s; uInt b; { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); } local void flush_pending(strm) z_stream *strm; { unsigned len = strm->state->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; zmemcpy(strm->next_out, strm->state->pending_out, len); strm->next_out += len; strm->state->pending_out += len; strm->total_out += len; strm->avail_out -= len; strm->state->pending -= len; if (strm->state->pending == 0) { strm->state->pending_out = strm->state->pending_buf; } } local void fill_window(s) deflate_state *s; { register unsigned n, m; unsigned more; /* Amount of free space at the end of the window. */ do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); /* Deal with !@#$% 64K limit: */ if (more == 0 && s->strstart == 0 && s->lookahead == 0) { more = s->w_size; } else if (more == (unsigned)(-1)) { /* Very unlikely, but possible on 16 bit machine if strstart == 0 * and lookahead == 1 (input done one byte at time) */ more--; /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ } else if (s->strstart >= s->w_size+MAX_DIST(s)) { /* By the IN assertion, the window is not empty so we can't confuse * more == 0 with more == 64K on a 16 bit machine. */ memcpy((char*)s->window, (char*)s->window+s->w_size, (unsigned)s->w_size); s->match_start -= s->w_size; s->strstart -= s->w_size; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) s->w_size; for (n = 0; n < s->hash_size; n++) { m = s->head[n]; s->head[n] = (Pos)(m >= s->w_size ? m-s->w_size : NIL); } for (n = 0; n < s->w_size; n++) { m = s->prev[n]; s->prev[n] = (Pos)(m >= s->w_size ? m-s->w_size : NIL); /* If n is not on any hash chain, prev[n] is garbage but * its value will never be used. */ } more += s->w_size; } if (s->strm->avail_in == 0) return; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. */ Assert(more >= 2, "more < 2"); n = read_buf(s->strm, (char*)s->window + s->strstart + s->lookahead, more); s->lookahead += n; } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); } /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ local int longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Byte *scan = s->window + s->strstart; /* current string */ register Byte *match; /* matched string */ register int len; /* length of current match */ int best_len = s->prev_length; /* best match length so far */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ register Byte *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ush*)scan; register ush scan_end = *(ush*)(scan+best_len-1); #else register Byte *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len-1]; register Byte scan_end = scan[best_len]; #endif /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. * It is easy to get rid of this optimization if necessary. */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); /* Do not waste too much time if we already have a good match: */ if (s->prev_length >= s->good_match) { chain_length >>= 2; } Assert(s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); match = s->window + cur_match; /* Skip to next match if the match length cannot increase * or if the match length is less than 2: */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ if (*(ush*)(match+best_len-1) != scan_end || *(ush*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at * strstart+3, +5, ... up to strstart+257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ scan++, match++; do { } while (*(ush*)(scan+=2) == *(ush*)(match+=2) && *(ush*)(scan+=2) == *(ush*)(match+=2) && *(ush*)(scan+=2) == *(ush*)(match+=2) && *(ush*)(scan+=2) == *(ush*)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ /* Here, scan <= window+strstart+257 */ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); if (*scan == *match) scan++; len = (MAX_MATCH - 1) - (int)(strend-scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ if (match[best_len] != scan_end || match[best_len-1] != scan_end1 || *match != *scan || *++match != scan[1]) continue; /* The check at best_len-1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that * the hash keys are equal and that HASH_BITS >= 8. */ scan += 2, match++; /* We check for insufficient lookahead only every 8th comparison; * the 256th check will be made at strstart+258. */ do { } while (*++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && *++scan == *++match && scan < strend); Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; #endif /* UNALIGNED_OK */ if (len > best_len) { s->match_start = cur_match; best_len = len; if (len >= s->nice_match) break; #ifdef UNALIGNED_OK scan_end = *(ush*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; #endif } } while ((cur_match = s->prev[cur_match & s->w_mask]) > limit && --chain_length != 0); return best_len; } local int ct_tally (s, dist, lc) deflate_state *s; int dist; /* distance of matched string */ int lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ { s->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; } else { s->matches++; /* Here, lc is the match length - MIN_MATCH */ dist--; /* dist = match distance - 1 */ Assert((ush)dist < (ush)MAX_DIST(s) && (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "ct_tally: bad match"); s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } /* Try to guess if it is profitable to stop the current block here */ if (s->level > 2 && (s->last_lit & 0xfff) == 0) { /* Compute an upper bound for the compressed length */ ulg out_length = (ulg)s->last_lit*8L; ulg in_length = (ulg)s->strstart - s->block_start; int dcode; for (dcode = 0; dcode < D_CODES; dcode++) { out_length += (ulg)s->dyn_dtree[dcode].Freq * (5L+extra_dbits[dcode]); } out_length >>= 3; if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; } return (s->last_lit == s->lit_bufsize-1); /* We avoid equality with lit_bufsize because of wraparound at 64K * on 16 bit machines and because stored blocks are restricted to * 64K-1 bytes. */ } local void set_data_type(s) deflate_state *s; { int n = 0; unsigned ascii_freq = 0; unsigned bin_freq = 0; while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? BINARY : ASCII); } local void pqdownheap(s, tree, k) deflate_state *s; ct_data *tree; /* the tree to restore */ int k; /* node to move down */ { int v = s->heap[k]; int j = k << 1; /* left son of k */ while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ if (smaller(tree, v, s->heap[j], s->depth)) break; /* Exchange v with the smallest son */ s->heap[k] = s->heap[j]; k = j; /* And continue down the tree, setting j to the left son of k */ j <<= 1; } s->heap[k] = v; } local void gen_bitlen(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; ct_data *stree = desc->stat_desc->static_tree; int *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ int n, m; /* iterate over the tree elements */ int bits; /* bit length */ int xbits; /* extra bits */ ush f; /* frequency */ int overflow = 0; /* number of elements with bit length too large */ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; /* In a first pass, compute the optimal bit lengths (which may * overflow in the case of the bit length tree). */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ for (h = s->heap_max+1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; tree[n].Len = (ush)bits; /* We overwrite tree[n].Dad which is no longer needed */ if (n > max_code) continue; /* not a leaf node */ s->bl_count[bits]++; xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; s->opt_len += (ulg)f * (bits + xbits); if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); } if (overflow == 0) return; /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ do { bits = max_length-1; while (s->bl_count[bits] == 0) bits--; s->bl_count[bits]--; /* move one leaf down the tree */ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] */ overflow -= 2; } while (overflow > 0); /* Now recompute all bit lengths, scanning in increasing frequency. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all * lengths instead of fixing only the wrong ones. This idea is taken * from 'ar' written by Haruhiko Okumura.) */ for (bits = max_length; bits != 0; bits--) { n = s->bl_count[bits]; while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; if (tree[m].Len != (unsigned) bits) { s->opt_len += ((long)bits - (long)tree[m].Len) *(long)tree[m].Freq; tree[m].Len = (ush)bits; } n--; } } } local void build_tree(s, desc) deflate_state *s; tree_desc *desc; /* the tree descriptor */ { ct_data *tree = desc->dyn_tree; ct_data *stree = desc->stat_desc->static_tree; int elems = desc->stat_desc->elems; int n, m; /* iterate over heap elements */ int max_code = -1; /* largest code with non zero frequency */ int node = elems; /* next internal node of the tree */ int new; /* new node being created */ /* Construct the initial heap, with least frequent element in * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. * heap[0] is not used. */ s->heap_len = 0, s->heap_max = HEAP_SIZE; for (n = 0; n < elems; n++) { if (tree[n].Freq != 0) { s->heap[++(s->heap_len)] = max_code = n; s->depth[n] = 0; } else { tree[n].Len = 0; } } /* The pkzip format requires that at least one distance code exists, * and that at least one bit should be sent even if there is only one * possible code. So to avoid special checks later on we force at least * two codes of non zero frequency. */ while (s->heap_len < 2) { new = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); tree[new].Freq = 1; s->depth[new] = 0; s->opt_len--; if (stree) s->static_len -= stree[new].Len; /* new is 0 or 1 so it does not have extra bits */ } desc->max_code = max_code; /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); /* Construct the Huffman tree by repeatedly combining the least two * frequent nodes. */ do { pqremove(s, tree, n); /* n = node of least frequency */ m = s->heap[SMALLEST]; /* m = node of next least frequency */ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ s->heap[--(s->heap_max)] = m; /* Create a new node father of n and m */ tree[node].Freq = tree[n].Freq + tree[m].Freq; s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); tree[n].Dad = tree[m].Dad = (ush)node; #ifdef DUMP_BL_TREE if (tree == s->bl_tree) { fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); } #endif /* and insert the new node in the heap */ s->heap[SMALLEST] = node++; pqdownheap(s, tree, SMALLEST); } while (s->heap_len >= 2); s->heap[--(s->heap_max)] = s->heap[SMALLEST]; /* At this point, the fields freq and dad are set. We can now * generate the bit lengths. */ gen_bitlen(s, (tree_desc *)desc); /* The field len is now set, we can generate the bit codes */ gen_codes ((ct_data *)tree, max_code, s->bl_count); } local void scan_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; tree[max_code+1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { s->bl_tree[curlen].Freq += count; } else if (curlen != 0) { if (curlen != prevlen) s->bl_tree[curlen].Freq++; s->bl_tree[REP_3_6].Freq++; } else if (count <= 10) { s->bl_tree[REPZ_3_10].Freq++; } else { s->bl_tree[REPZ_11_138].Freq++; } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } local int build_bl_tree(s) deflate_state *s; { int max_blindex; /* index of last bit length code of non zero freq */ /* Determine the bit length frequencies for literal and distance trees */ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); /* opt_len now includes the length of the tree representations, except * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format * requires that at least 4 bit length codes be sent. (appnote.txt says * 3 but the actual value used is 4.) */ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ s->opt_len += 3*(max_blindex+1) + 5+5+4; return max_blindex; } local void send_bits(s, value, length) deflate_state *s; int value; /* value to send */ int length; /* number of bits */ { #ifdef DEBUG Assert(length > 0 && length <= 15, "invalid length"); s->bits_sent += (ulg)length; #endif /* If not enough room in bi_buf, use (valid) bits from bi_buf and * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { s->bi_buf |= (value << s->bi_valid); put_short(s, s->bi_buf); s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); s->bi_valid += length - Buf_size; } else { s->bi_buf |= value << s->bi_valid; s->bi_valid += length; } } local void bi_windup(s) deflate_state *s; { if (s->bi_valid > 8) { put_short(s, s->bi_buf); } else if (s->bi_valid > 0) { put_byte(s, (Byte)s->bi_buf); } s->bi_buf = 0; s->bi_valid = 0; #ifdef DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } local void copy_block(s, buf, len, header) deflate_state *s; char *buf; /* the input data */ unsigned len; /* its length */ int header; /* true if block header must be written */ { bi_windup(s); /* align on byte boundary */ if (header) { put_short(s, (ush)len); put_short(s, (ush)~len); #ifdef DEBUG s->bits_sent += 2*16; #endif } #ifdef DEBUG s->bits_sent += (ulg)len<<3; #endif while (len--) { put_byte(s, *buf++); } } local void compress_block(s, ltree, dtree) deflate_state *s; ct_data *ltree; /* literal tree */ ct_data *dtree; /* distance tree */ { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ unsigned lx = 0; /* running index in l_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ if (s->last_lit != 0) do { dist = s->d_buf[lx]; lc = s->l_buf[lx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ } else { /* Here, lc is the match length - MIN_MATCH */ code = length_code[lc]; send_code(s, code+LITERALS+1, ltree); /* send the length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; send_bits(s, lc, extra); /* send the extra length bits */ } dist--; /* dist is now the match distance - 1 */ code = d_code(dist); Assert (code < D_CODES, "bad d_code"); send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { dist -= base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree); } local void send_tree (s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ int curlen; /* length of current code */ int nextlen = tree[0].Len; /* length of next code */ int count = 0; /* repeat count of the current code */ int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ /* tree[max_code+1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { curlen = nextlen; nextlen = tree[n+1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { do { send_code(s, curlen, s->bl_tree); } while (--count != 0); } else if (curlen != 0) { if (curlen != prevlen) { send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); } else if (count <= 10) { send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); } else { send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { max_count = 138, min_count = 3; } else if (curlen == nextlen) { max_count = 6, min_count = 3; } else { max_count = 7, min_count = 4; } } } local void send_all_trees(s, lcodes, dcodes, blcodes) deflate_state *s; int lcodes, dcodes, blcodes; /* number of codes for each tree */ { int rank; /* index in bl_order */ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ send_bits(s, dcodes-1, 5); send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ } ulg ct_flush_block(s, buf, stored_len, eof) deflate_state *s; char *buf; /* input block, or NULL if too old */ ulg stored_len; /* length of input block */ int eof; /* true if this is the last block for a file */ { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex; /* index of last bit length code of non zero freq */ /* Check if the file is ascii or binary */ if (s->data_type == UNKNOWN) set_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); build_tree(s, (tree_desc *)(&(s->d_desc))); /* At this point, opt_len and static_len are the total bit lengths of * the compressed block data, excluding the tree representations. */ /* Build the bit length tree for the above two trees, and get the index * in bl_order of the last bit length code to send. */ max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute first the block length in bytes */ opt_lenb = (s->opt_len+3+7)>>3; static_lenb = (s->static_len+3+7)>>3; if (static_lenb <= opt_lenb) opt_lenb = static_lenb; /* If compression failed and this is the first and last block, * and if the .zip file can be seeked (to rewrite the local header), * the whole file is transformed into a stored file: */ if (stored_len+4 <= opt_lenb && buf != (char*)0) { /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. * Otherwise we can't have processed more than WSIZE input bytes since * the last block flush, because compression would have been * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to * transform a block into a stored block. */ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ s->compressed_len = (s->compressed_len + 3 + 7) & ~7L; s->compressed_len += (stored_len + 4) << 3; copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } else if (static_lenb == opt_lenb) { send_bits(s, (STATIC_TREES<<1)+eof, 3); compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); s->compressed_len += 3 + s->static_len; } else { send_bits(s, (DYN_TREES<<1)+eof, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1); compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); s->compressed_len += 3 + s->opt_len; } Assert (s->compressed_len == s->bits_sent, "bad compressed size"); init_block(s); if (eof) { bi_windup(s); s->compressed_len += 7; /* align on byte boundary */ } return s->compressed_len >> 3; } local int deflate_fast(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ s->prev_length = MIN_MATCH-1; for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) return 1; if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ INSERT_STRING(s, s->strstart, hash_head); /* Find the longest match, discarding those <= prev_length. * At this point we have always match_length < MIN_MATCH */ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ if (s->strategy != Z_HUFFMAN_ONLY) { s->match_length = longest_match (s, hash_head); } /* longest_match() sets match_start */ if (s->match_length > s->lookahead) s->match_length = s->lookahead; } if (s->match_length >= MIN_MATCH) { check_match(s, s->strstart, s->match_start, s->match_length); bflush = ct_tally(s, s->strstart - s->match_start, s->match_length - MIN_MATCH); s->lookahead -= s->match_length; /* Insert new strings in the hash table only if the match length * is not too large. This saves time but degrades compression. */ if (s->match_length <= s->max_insert_length) { s->match_length--; /* string at strstart already in hash table */ do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH * these bytes are garbage, but it does not matter since * the next lookahead bytes will be emitted as literals. */ } while (--s->match_length != 0); s->strstart++; } else { s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif } } else { /* No match, output a literal byte */ bflush = ct_tally (s, 0, s->window[s->strstart]); s->lookahead--; s->strstart++; } if (bflush) FLUSH_BLOCK(s, 0); } FLUSH_BLOCK(s, flush == Z_FINISH); return 0; /* normal exit */ } local int deflate_slow(s, flush) deflate_state *s; int flush; { IPos hash_head; /* head of hash chain */ int bflush; /* set if current block must be flushed */ /* Process the input block. */ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes * for the next match, plus MIN_MATCH bytes to insert the * string following the next match. */ if (s->lookahead < MIN_LOOKAHEAD) { fill_window(s); if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) return 1; if (s->lookahead == 0) break; /* flush the current block */ } /* Insert the string window[strstart .. strstart+2] in the * dictionary, and set hash_head to the head of the hash chain: */ INSERT_STRING(s, s->strstart, hash_head); /* Find the longest match, discarding those <= prev_length. */ s->prev_length = s->match_length, s->prev_match = s->match_start; s->match_length = MIN_MATCH-1; if (hash_head != NIL && s->prev_length < s->max_lazy_match && s->strstart - hash_head <= MAX_DIST(s)) { /* To simplify the code, we prevent matches with the string * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ if (s->strategy != Z_HUFFMAN_ONLY) { s->match_length = longest_match (s, hash_head); } /* longest_match() sets match_start */ if (s->match_length > s->lookahead) s->match_length = s->lookahead; if (s->match_length <= 5 && (s->strategy == Z_FILTERED || (s->match_length == MIN_MATCH && s->strstart - s->match_start > TOO_FAR))) { /* If prev_match is also MIN_MATCH, match_start is garbage * but we will ignore the current match anyway. */ s->match_length = MIN_MATCH-1; } } /* If there was a match at the previous step and the current * match is not better, output the previous match: */ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { check_match(s, s->strstart-1, s->prev_match, s->prev_length); bflush = ct_tally(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH); /* Insert in hash table all strings up to the end of the match. * strstart-1 and strstart are already inserted. */ s->lookahead -= s->prev_length-1; s->prev_length -= 2; do { s->strstart++; INSERT_STRING(s, s->strstart, hash_head); /* strstart never exceeds WSIZE-MAX_MATCH, so there are * always MIN_MATCH bytes ahead. If lookahead < MIN_MATCH * these bytes are garbage, but it does not matter since the * next lookahead bytes will always be emitted as literals. */ } while (--s->prev_length != 0); s->match_available = 0; s->match_length = MIN_MATCH-1; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); } else if (s->match_available) { /* If there was no match at the previous position, output a * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ if (ct_tally (s, 0, s->window[s->strstart-1])) { FLUSH_BLOCK_ONLY(s, 0); } s->strstart++; s->lookahead--; if (s->strm->avail_out == 0) return 1; } else { /* There is no previous match to compare with, wait for * the next step to decide. */ s->match_available = 1; s->strstart++; s->lookahead--; } } if (s->match_available) ct_tally (s, 0, s->window[s->strstart-1]); FLUSH_BLOCK(s, flush == Z_FINISH); return 0; } local int deflate (strm, flush) z_stream *strm; int flush; { if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; if (strm->next_out == Z_NULL || strm->next_in == Z_NULL) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); strm->state->strm = strm; /* just in case */ /* Write the zlib header */ if (strm->state->status == INIT_STATE) { uInt header = (DEFLATED + ((strm->state->w_bits-8)<<4)) << 8; uInt level_flags = (strm->state->level-1) >> 1; if (level_flags > 3) level_flags = 3; header |= (level_flags << 6); header += 31 - (header % 31); strm->state->status = BUSY_STATE; putShortMSB(strm->state, header); } /* Flush as much pending output as possible */ if (strm->state->pending != 0) { flush_pending(strm); if (strm->avail_out == 0) return Z_OK; } /* User must not provide more input after the first FINISH: */ if (strm->state->status == FINISH_STATE && strm->avail_in != 0) { ERR_RETURN(strm, Z_BUF_ERROR); } /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || (flush == Z_FINISH && strm->state->status != FINISH_STATE)) { if (flush == Z_FINISH) { strm->state->status = FINISH_STATE; } if (strm->state->level <= 3) { if (deflate_fast(strm->state, flush)) return Z_OK; } else { if (deflate_slow(strm->state, flush)) return Z_OK; } } Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; if (strm->state->noheader) return Z_STREAM_END; /* Write the zlib trailer (adler32) */ putShortMSB(strm->state, (uInt)(strm->state->adler >> 16)); putShortMSB(strm->state, (uInt)(strm->state->adler & 0xffff)); flush_pending(strm); /* If avail_out is zero, the application will call deflate again * to flush the rest. */ strm->state->noheader = 1; /* write the trailer only once! */ return strm->state->pending != 0 ? Z_OK : Z_STREAM_END; } local int gzflush (file, flush) gzFile file; int flush; { uInt len; int done = 0; gz_stream *s = (gz_stream*)file; if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; s->stream.avail_in = 0; /* should be zero already anyway */ for (;;) { len = Z_BUFSIZE - s->stream.avail_out; if (len != 0) { if (fwrite(s->outbuf, 1, len, s->file) != len) { s->z_err = Z_ERRNO; return Z_ERRNO; } s->stream.next_out = s->outbuf; s->stream.avail_out = Z_BUFSIZE; } if (done) break; s->z_err = deflate(&(s->stream), flush); /* deflate has finished flushing only when it hasn't used up * all the available space in the output buffer: */ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; } return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; } local gzFile gz_open (path, mode, fd) char *path; char *mode; int fd; { int err; char *p = mode; gz_stream *s = (gz_stream *)ALLOC(sizeof(gz_stream)); if (!s) return Z_NULL; s->stream.zalloc = (alloc_func)0; s->stream.zfree = (free_func)0; s->stream.next_in = s->inbuf = Z_NULL; s->stream.next_out = s->outbuf = Z_NULL; s->stream.avail_in = s->stream.avail_out = 0; s->file = NULL; s->z_err = Z_OK; s->z_eof = 0; s->crc = crc32(0L, Z_NULL, 0); s->msg = NULL; s->transparent = 0; s->path = (char*)ALLOC(strlen(path)+1); if (s->path == NULL) { return destroy(s), (gzFile)Z_NULL; } strcpy(s->path, path); /* do this early for debugging */ s->mode = '\0'; do { if (*p == 'r') s->mode = 'r'; if (*p == 'w') s->mode = 'w'; } while (*p++); if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; if (s->mode == 'w') { err = deflateInit2(&(s->stream), Z_BEST_COMPRESSION, DEFLATED, -WBITS, MEM_LEVEL, 0); /* windowBits is passed < 0 to suppress zlib header */ s->stream.next_out = s->outbuf = ALLOC(Z_BUFSIZE); if (err != Z_OK || s->outbuf == Z_NULL) { return destroy(s), (gzFile)Z_NULL; } } else { err = inflateInit2(&(s->stream), -WBITS); s->stream.next_in = s->inbuf = ALLOC(Z_BUFSIZE); if (err != Z_OK || s->inbuf == Z_NULL) { return destroy(s), (gzFile)Z_NULL; } } s->stream.avail_out = Z_BUFSIZE; errno = 0; s->file = fd < 0 ? fopen(path, mode) : fdopen(fd, mode); if (s->file == NULL) { return destroy(s), (gzFile)Z_NULL; } if (s->mode == 'w') { /* Write a very simple .gz header: */ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", GZ_MAGIC_1, GZ_MAGIC_2, DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); } else { /* Check and skip the header: */ Byte c1 = 0, c2 = 0; Byte method = 0; Byte flags = 0; Byte xflags = 0; Byte time[4]; Byte osCode; int c; s->stream.avail_in = fread(s->inbuf, 1, 2, s->file); if (s->stream.avail_in != 2 || s->inbuf[0] != GZ_MAGIC_1 || s->inbuf[1] != GZ_MAGIC_2) { s->transparent = 1; return (gzFile)s; } s->stream.avail_in = 0; err = fscanf(s->file,"%c%c%4c%c%c", &method, &flags, time, &xflags, &osCode); if (method != DEFLATED || feof(s->file) || (flags & RESERVED) != 0) { s->z_err = Z_DATA_ERROR; return (gzFile)s; } if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ long len; err = fscanf(s->file, "%c%c", &c1, &c2); len = c1 + ((long)c2<<8); fseek(s->file, len, SEEK_CUR); } if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ while ((c = getc(s->file)) != 0 && c != EOF) ; } if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ while ((c = getc(s->file)) != 0 && c != EOF) ; } if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ err = fscanf(s->file, "%c%c", &c1, &c2); } if (feof(s->file)) { s->z_err = Z_DATA_ERROR; } } return (gzFile)s; } local gzFile gzopen (path, mode) char *path; char *mode; { return gz_open (path, mode, -1); } local int gzwrite (file, buf, len) gzFile file; voidp buf; unsigned len; { gz_stream *s = (gz_stream*)file; if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; s->stream.next_in = buf; s->stream.avail_in = len; while (s->stream.avail_in != 0) { if (s->stream.avail_out == 0) { s->stream.next_out = s->outbuf; if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { s->z_err = Z_ERRNO; break; } s->stream.avail_out = Z_BUFSIZE; } s->z_err = deflate(&(s->stream), Z_NO_FLUSH); if (s->z_err != Z_OK) break; } s->crc = crc32(s->crc, buf, len); return len - s->stream.avail_in; } local int gzclose (file) gzFile file; { uInt n; int err; gz_stream *s = (gz_stream*)file; if (s == NULL) return Z_STREAM_ERROR; if (s->mode == 'w') { err = gzflush (file, Z_FINISH); if (err != Z_OK) return destroy((gz_stream *)file); putLong (s->file, s->crc); putLong (s->file, s->stream.total_in); } else if (s->mode == 'r' && s->z_err == Z_STREAM_END) { /* slide CRC and original size if they are at the end of inbuf */ if ((n = s->stream.avail_in) < 8 && !s->z_eof) { Byte *p = s->inbuf; Byte *q = s->stream.next_in; while (n--) { *p++ = *q++; }; n = s->stream.avail_in; n += fread(p, 1, 8, s->file); s->stream.next_in = s->inbuf; } /* check CRC and original size */ if (n < 8 || getLong(s->stream.next_in) != s->crc || getLong(s->stream.next_in + 4) != s->stream.total_out) { s->z_err = Z_DATA_ERROR; } } return destroy((gz_stream *)file); } /* ========================================================================= */ static int wm_tool_printf(const char *format, ...) { int ret; va_list ap; va_start(ap, format); ret = vprintf(format, ap); va_end(ap); fflush(stdout); return ret; } static unsigned long long wm_tool_crc32_reflect(unsigned long long ref, unsigned char ch) { int i; unsigned long long value = 0; for ( i = 1; i < ( ch + 1 ); i++ ) { if( ref & 1 ) value |= 1 << ( ch - i ); ref >>= 1; } return value; } static unsigned int wm_tool_crc32(unsigned int crc, unsigned char *buffer, int size, wm_tool_crc32_reflect_e mode) { int i; unsigned char temp; for (i = 0; i < size; i++) { if (mode & WM_TOOL_CRC32_REFLECT_INPUT) { temp = wm_tool_crc32_reflect(buffer[i], 8); } else { temp = buffer[i]; } crc = wm_tool_crc32_tab[(crc ^ temp) & 0xff] ^ (crc >> 8); } return crc ; } static unsigned int wm_tool_get_crc32(unsigned char *buffer, int size, wm_tool_crc32_reflect_e mode) { wm_tool_file_crc = wm_tool_crc32(wm_tool_file_crc, buffer, size, mode); if (mode & WM_TOOL_CRC32_REFLECT_OUTPUT) { wm_tool_file_crc = wm_tool_crc32_reflect(wm_tool_file_crc, 32); } return wm_tool_file_crc; } static unsigned short wm_tool_get_crc16(unsigned char *ptr, unsigned short count) { unsigned short crc, i; crc = 0; while (count--) { crc = crc ^ (int) *ptr++ << 8; for (i = 0; i < 8; i++) { if (crc & 0x8000) crc = crc << 1 ^ 0x1021; else crc = crc << 1; } } return (crc & 0xFFFF); } static int wm_tool_char_to_hex(char ch) { int hex; hex = -1; if ((ch >= '0') && (ch <= '9')) { hex = ch - '0'; } else if ((ch >= 'a') && (ch <= 'f')) { hex = ch - 'a' + 0xa; } else if ((ch >= 'A') && (ch <= 'F')) { hex = ch - 'A' + 0xa; } return hex; } static int wm_tool_str_to_hex_array(char *str, int cnt, unsigned char array[]) { int hex; unsigned char tmp; unsigned char *des; des = array; while (cnt-- > 0) { hex = wm_tool_char_to_hex(*str++); if (hex < 0) { return -1; } else { tmp = (hex << 4) & 0xf0; } hex = wm_tool_char_to_hex(*str++); if (hex < 0) { return -1; } else { tmp = tmp | (hex & 0x0f); } *des++ = (unsigned char) tmp; } return ((*str == 0) ? 0 : -1); } static char *wm_tool_strcasestr(const char *str1, const char *str2) { char *cp = (char *) str1; char *s1, *s2; if (!*str2) return (char *) str1; while (*cp) { s1 = cp; s2 = (char *) str2; while (*s1 && *s2 && !(tolower((int)*s1) - tolower((int)*s2))) s1++, s2++; if (!*s2) return cp; cp++; } return NULL; } static int wm_tool_get_file_size(const char* filename) { FILE *fp = fopen(filename, "r"); if(!fp) return -1; fseek(fp,0L,SEEK_END); int size = ftell(fp); fclose(fp); return size; } static char *wm_tool_get_name(const char *name) { static char sz_name[WM_TOOL_PATH_MAX] = {0}; char *p = (char *)name; char *q = (char *)name; do { #ifdef __MINGW32__ p = strchr(p, '\\'); #else p = strchr(p, '/'); #endif if (p) { p++; q = p; } } while (p); strncpy(sz_name, q, WM_TOOL_PATH_MAX - 1); #ifdef __MINGW32__ p = wm_tool_strcasestr(sz_name, ".exe"); if (p) *p = '\0'; #endif return sz_name; } static void wm_tool_print_usage(const char *name) { wm_tool_printf("Usage: %s [-h] [-v] [-b] [-o] [-sb] [-ct] [-it]" " [-ua] [-ra] [-ih] [-nh] [-un] [-df] [-vs]" " [-l] [-c] [-ws] [-ds] [-rs] [-eo] [-dl] [-sl]" "\r\n" "\r\n" "WinnerMicro firmware packaging " "and programming " "tool\r\n\r\n" "options:\r\n\r\n" " -h , show usage\r\n" " -v , show version\r\n" "\r\n" " -b binary , original binary file\r\n" " -o output_name , output firmware file\r\n" " the default is the same as the original binary file name\r\n" " -sb second_boot , second boot file, used to generate fls file\r\n" " -fc compress_type , whether the firmware is compressed, default is compressed\r\n" " <0 | 1> or \r\n" " -it image_type , firmware image layout type, default is 0\r\n" " <0 | 1>\r\n" " -ua update_address , upgrade storage location (hexadecimal)\r\n" " the default is 8090000\r\n" " -ra run_address , runtime position (hexadecimal)\r\n" " the default is 8002400\r\n" " -ih image_header , image header storage location (hexadecimal)\r\n" " the default is 8002000\r\n" " -nh next_image_header , next image header storage location (hexadecimal)\r\n" " the default is 0\r\n" " -un upd_no , upd no version number (hexadecimal)\r\n" " the default is 0\r\n" " -df , generate debug firmware for openocd\r\n" " -vs version_string , firmware version string, cannot exceed 16 bytes\r\n" "\r\n" " -l , list the local serial port\r\n" " -c serial_name , connect a serial port\r\n" #if defined(__APPLE__) && defined(__MACH__) " e.g: tty.usbserial0 tty.usbserial3 tty.usbserial7\r\n" #elif defined(__MINGW32__) || defined(__CYGWIN__) " e.g: COM0 COM3 COM7\r\n" #elif defined(__linux__) " e.g: ttyUSB0 ttyUSB3 ttyUSB7\r\n" #endif " -ws baud_rate , set the serial port speed during normal work, default is 115200\r\n" " <1200 - 2000000> or <1M | 2M>\r\n" " -ds baud_rate , set the serial port speed when downloading, default is 115200\r\n" " <115200 | 460800 | 921600 | 1000000 | 2000000> or <1M | 2M>\r\n" " -rs reset_action , set device reset method, default is manual control\r\n" " \r\n" " none - manual control device reset\r\n" " at - use the at command to control the device reset\r\n" " rts - use the serial port rts pin to control the device reset\r\n" " -eo erase_option , firmware area erase option\r\n" " \r\n" " all - erase all areas\r\n" " -dl download_firmware , firmware file to be downloaded, default download compressed image\r\n" " -sl display_format , display the log information output from the serial port\r\n" " <0 | 1> or \r\n" " str - string mode display\r\n" " hex - hexadecimal format\r\n" , wm_tool_get_name(name)); return; } static void wm_tool_print_version(const char *name) { wm_tool_printf("%s %s for W806\r\nCopyright (C) 2013 - 2020 WinnerMicro, Inc.\r\n", wm_tool_get_name(name), wm_tool_version); return; } static int wm_tool_parse_arv(int argc, char *argv[]) { int opt; int option_index = 0; char *opt_string = "hvlc:b:o:"; int cnt = 0; opterr = 1;/* show err info */ struct option long_options[] = { {"dl", required_argument, NULL, 'd'}, {"ws", required_argument, NULL, 'w'}, {"ds", required_argument, NULL, 's'}, {"sb", required_argument, NULL, 'S'}, {"it", required_argument, NULL, 'i'}, {"fc", required_argument, NULL, 'C'}, {"ua", required_argument, NULL, 'u'}, {"ra", required_argument, NULL, 'r'}, {"ih", required_argument, NULL, 'H'}, {"nh", required_argument, NULL, 'n'}, {"un", required_argument, NULL, 'U'}, {"df", no_argument, NULL, 'D'}, {"vs", required_argument, NULL, 'V'}, {"rs", required_argument, NULL, 'a'}, {"eo", required_argument, NULL, 'e'}, {"sl", required_argument, NULL, 'g'}, {0, 0, NULL, 0} }; while ( (opt = getopt_long_only(argc, argv, opt_string, long_options, &option_index)) != -1) { WM_TOOL_DBG_PRINT("%c-%s\r\n", opt, optarg); switch (opt) { case '?': case 'h': { wm_tool_show_usage = 1; break; } case 'v': { wm_tool_show_ver = 1; break; } case 'l': { wm_tool_list_com = 1; break; } case 'c': { #if defined(__MINGW32__) strcpy(wm_tool_serial_path, optarg); #elif defined(__CYGWIN__) sprintf(wm_tool_serial_path, "/dev/ttyS%d", atoi(optarg + strlen("COM")) - 1); #else sprintf(wm_tool_serial_path, "/dev/%s", optarg); #endif break; } case 'w': { if ('M' == optarg[1]) wm_tool_normal_serial_rate = (optarg[0] - 0x30) * 1000000; else wm_tool_normal_serial_rate = strtol(optarg, NULL, 10); break; } case 's': { if ('M' == optarg[1]) wm_tool_download_serial_rate = (optarg[0] - 0x30) * 1000000; else wm_tool_download_serial_rate = strtol(optarg, NULL, 10); break; } case 'a': { if (0 == strncmp(optarg, "none", strlen("none"))) wm_tool_dl_action = WM_TOOL_DL_ACTION_NONE; else if (0 == strncmp(optarg, "at", strlen("at"))) wm_tool_dl_action = WM_TOOL_DL_ACTION_AT; else if (0 == strncmp(optarg, "rts", strlen("rts"))) wm_tool_dl_action = WM_TOOL_DL_ACTION_RTS; else wm_tool_show_usage = 1; break; } case 'e': { if (0 == strncmp(optarg, "all", strlen("all"))) wm_tool_dl_erase = WM_TOOL_DL_ERASE_ALL; else wm_tool_show_usage = 1; break; } case 'd': { wm_tool_download_image = strdup(optarg); if (wm_tool_strcasestr(wm_tool_download_image, ".fls")) wm_tool_dl_type = WM_TOOL_DL_TYPE_FLS; break; } case 'o': { wm_tool_output_image = strdup(optarg); break; } case 'b': { wm_tool_input_binary = strdup(optarg); break; } case 'S': { wm_tool_secboot_image = strdup(optarg); break; } case 'i': { #if 0 if ('0' == optarg[0]) wm_tool_image_type = WM_TOOL_LAYOUT_TYPE_1M; else if ('3' == optarg[0]) wm_tool_image_type = WM_TOOL_LAYOUT_TYPE_2M; else if (0 == strncmp(optarg, "1M", strlen("1M"))) wm_tool_image_type = WM_TOOL_LAYOUT_TYPE_1M; else if (0 == strncmp(optarg, "2M", strlen("2M"))) wm_tool_image_type = WM_TOOL_LAYOUT_TYPE_2M; else #endif { if (isdigit((int)optarg[0])) wm_tool_image_type = atoi(optarg);//optarg[0] - 0x30; else wm_tool_show_usage = 1; } break; } case 'C': { if ('0' == optarg[0]) wm_tool_zip_type = WM_TOOL_ZIP_TYPE_UNCOMPRESS; else if ('1' == optarg[0]) wm_tool_zip_type = WM_TOOL_ZIP_TYPE_COMPRESS; else if (0 == strncmp(optarg, "compress", strlen("compress"))) wm_tool_zip_type = WM_TOOL_ZIP_TYPE_COMPRESS; else if (0 == strncmp(optarg, "uncompress", strlen("uncompress"))) wm_tool_zip_type = WM_TOOL_ZIP_TYPE_UNCOMPRESS; else wm_tool_show_usage = 1; break; } case 'u': { wm_tool_upd_addr = strtol(optarg, NULL, 16); break; } case 'r': { wm_tool_run_addr = strtol(optarg, NULL, 16); break; } case 'D': { wm_tool_is_debug = 1; break; } case 'V': { strncpy(wm_tool_image_version, optarg, WM_TOOL_IMAGE_VERSION_LEN); wm_tool_image_version[WM_TOOL_IMAGE_VERSION_LEN - 1] = '\0'; break; } case 'g': { if ('0' == optarg[0]) wm_tool_show_log_type = WM_TOOL_SHOW_LOG_STR; else if ('1' == optarg[0]) wm_tool_show_log_type = WM_TOOL_SHOW_LOG_HEX; else if (0 == strncmp(optarg, "str", strlen("str"))) wm_tool_show_log_type = WM_TOOL_SHOW_LOG_STR; else if (0 == strncmp(optarg, "hex", strlen("hex"))) wm_tool_show_log_type = WM_TOOL_SHOW_LOG_HEX; else wm_tool_show_usage = 1; break; break; } case 'H': { wm_tool_image_header = strtol(optarg, NULL, 16); break; } case 'n': { wm_tool_next_image_header = strtol(optarg, NULL, 16); break; } case 'U': { wm_tool_image_upd_no = strtol(optarg, NULL, 16); break; } default: { wm_tool_show_usage = 1; break; } } cnt++; } return cnt; } static int wm_tool_pack_image(const char *outfile) { FILE *fpbin = NULL; FILE *fpimg = NULL; int readlen = 0; int filelen = 0; int patch = 0; wm_tool_firmware_booter_t fbooter; unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1]; fpbin = fopen(wm_tool_input_binary, "rb"); if (NULL == fpbin) { wm_tool_printf("can not open input file [%s].\r\n", wm_tool_input_binary); return -2; } fpimg = fopen(outfile, "wb+"); if (NULL == fpimg) { wm_tool_printf("open img file error: [%s].\r\n", outfile); fclose(fpbin); return -3; } /* --------deal with upgrade image's CRC begin---- */ wm_tool_file_crc = 0xFFFFFFFF; while (!feof(fpbin)) { memset(buf, 0, sizeof(buf)); readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpbin); if(readlen % 4 != 0) { patch = 4 - readlen%4; readlen += patch; } filelen += readlen; wm_tool_get_crc32((unsigned char*)buf, readlen, 0); } /* --------deal with upgrade image's CRC end---- */ wm_tool_src_binary_len = filelen; wm_tool_src_binary_crc = wm_tool_file_crc; memset(&fbooter, 0, sizeof(wm_tool_firmware_booter_t)); strcpy((char *)fbooter.ver, wm_tool_image_version); fbooter.magic_no = WM_TOOL_IMG_HEAD_MAGIC_NO; fbooter.run_org_checksum = wm_tool_file_crc; fbooter.img_type = wm_tool_image_type; fbooter.run_img_len = filelen; fbooter.run_img_addr = wm_tool_run_addr; fbooter.zip_type = WM_TOOL_ZIP_TYPE_UNCOMPRESS; fbooter.img_header_addr = wm_tool_image_header; fbooter.upgrade_img_addr = wm_tool_upd_addr; fbooter.upd_no = wm_tool_image_upd_no; fbooter.next_boot = wm_tool_next_image_header; /* calculate image's header's CRC */ wm_tool_file_crc = 0xFFFFFFFF; wm_tool_get_crc32((unsigned char *)&fbooter, sizeof(wm_tool_firmware_booter_t) - 4, 0); fbooter.hd_checksum = wm_tool_file_crc; /* write image's header to output file */ fwrite(&fbooter, 1, sizeof(wm_tool_firmware_booter_t), fpimg); /* write image to output file */ fseek(fpbin, 0, SEEK_SET); while (!feof(fpbin)) { readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpbin); fwrite(buf, 1, readlen, fpimg); } /* write dummy data to pad 4byte-aligned */ if (patch > 0) { memset(buf, 0, patch); fwrite(buf, 1, patch, fpimg); } if (fpbin) { fclose(fpbin); } if (fpimg) { fclose(fpimg); } wm_tool_printf("generate normal image completed.\r\n"); return 0; } static int wm_tool_pack_gz_image(const char *gzbin, const char *outfile) { FILE *fpbin = NULL; FILE *fpimg = NULL; int readlen = 0; int filelen = 0; int patch = 0; wm_tool_firmware_booter_t fbooter; unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1]; fpbin = fopen(gzbin, "rb"); if (NULL == fpbin) { wm_tool_printf("can not open input file [%s].\r\n", gzbin); return -2; } fpimg = fopen(outfile, "wb+"); if (NULL == fpimg) { wm_tool_printf("create img file error: [%s].\r\n", outfile); fclose(fpbin); return -3; } /* --------deal with upgrade image's CRC begin---- */ wm_tool_file_crc = 0xFFFFFFFF; while (!feof(fpbin)) { memset(buf, 0, sizeof(buf)); readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpbin); if(readlen % 4 != 0) { patch = 4 - readlen%4; readlen += patch; } filelen += readlen; wm_tool_get_crc32((unsigned char*)buf, readlen, 0); } /* --------deal with upgrade image's CRC end---- */ memset(&fbooter, 0, sizeof(wm_tool_firmware_booter_t)); strcpy((char *)fbooter.ver, wm_tool_image_version); fbooter.magic_no = WM_TOOL_IMG_HEAD_MAGIC_NO; fbooter.run_org_checksum = wm_tool_file_crc; fbooter.img_type = wm_tool_image_type; fbooter.run_img_len = filelen; fbooter.run_img_addr = wm_tool_run_addr; fbooter.zip_type = wm_tool_zip_type; fbooter.img_header_addr = wm_tool_image_header; fbooter.upgrade_img_addr = wm_tool_upd_addr; fbooter.upd_no = wm_tool_image_upd_no; fbooter.next_boot = wm_tool_next_image_header; /* calculate image's header's CRC */ wm_tool_file_crc = 0xFFFFFFFF; wm_tool_get_crc32((unsigned char *)&fbooter, sizeof(wm_tool_firmware_booter_t) - 4, 0); fbooter.hd_checksum = wm_tool_file_crc; /* write image's header to output file */ fwrite(&fbooter, 1, sizeof(wm_tool_firmware_booter_t), fpimg); /* write image to output file */ fseek(fpbin, 0, SEEK_SET); while (!feof(fpbin)) { readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpbin); fwrite(buf, 1, readlen, fpimg); } /* write dummy data to pad 4byte-aligned */ if (patch > 0) { memset(buf, 0, patch); fwrite(buf, 1, patch, fpimg); } if (fpbin) { fclose(fpbin); } if (fpimg) { fclose(fpimg); } wm_tool_printf("generate compressed image completed.\r\n"); return 0; } static int wm_tool_pack_dbg_image(const char *image, const char *outfile) { FILE *fpimg = NULL; FILE *fout = NULL; unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1]; int readlen = 0; int i; wm_tool_firmware_booter_t fbooter; int appimg_len = 0; int final_len = 0; int magic_word = 0; fpimg = fopen(image, "rb"); if (NULL == fpimg) { wm_tool_printf("open img file error: [%s].\r\n", image); return -4; } magic_word = 0; readlen = fread(&magic_word, 1, 4, fpimg); if (magic_word != WM_TOOL_IMG_HEAD_MAGIC_NO) { wm_tool_printf("input [%s] file magic error.\n", image); fclose(fpimg); return -5; } fout = fopen(outfile, "wb+"); if (NULL == fout) { wm_tool_printf("create img file error [%s].\r\n", outfile); fclose(fpimg); return -6; } appimg_len = wm_tool_get_file_size(image); /* write 0xFF to output file */ final_len = WM_TOOL_RUN_IMG_HEADER_LEN + (appimg_len - sizeof(wm_tool_firmware_booter_t)); for (i = 0; i < (final_len /WM_TOOL_ONCE_READ_LEN); i++) { memset(buf, 0xff, WM_TOOL_ONCE_READ_LEN); fwrite(buf, 1, WM_TOOL_ONCE_READ_LEN, fout); } memset(buf, 0xff, final_len % WM_TOOL_ONCE_READ_LEN); fwrite(buf, 1, final_len % WM_TOOL_ONCE_READ_LEN, fout); memset(&fbooter, 0, sizeof(wm_tool_firmware_booter_t)); /* write sec img to output file */ fseek(fpimg, 0, SEEK_SET); readlen = fread((unsigned char *)&fbooter, 1, sizeof(wm_tool_firmware_booter_t), fpimg); fseek(fout, 0, SEEK_SET); fwrite(&fbooter, 1, sizeof(wm_tool_firmware_booter_t), fout); fseek(fout, WM_TOOL_RUN_IMG_HEADER_LEN, SEEK_SET); while (!feof(fpimg)) { readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpimg); fwrite(buf, 1, readlen, fout); } if (fpimg) { fclose(fpimg); } if (fout) { fclose(fout); } wm_tool_printf("generate debug image completed.\r\n"); return 0; } static int wm_tool_pack_fls(const char *image, const char *outfile) { FILE *fpsec = NULL; FILE *fpimg = NULL; FILE *fout = NULL; unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1]; int readlen = 0; int magic_word = 0; fpsec = fopen(wm_tool_secboot_image,"rb"); if (NULL == fpsec) { wm_tool_printf("can not open input file [%s].\r\n", wm_tool_secboot_image); return -2; } magic_word = 0; readlen = fread(&magic_word, 1, 4, fpsec); if (magic_word != WM_TOOL_IMG_HEAD_MAGIC_NO) { wm_tool_printf("input [%s] file magic error.\r\n", wm_tool_secboot_image); fclose(fpsec); return -3; } fpimg = fopen(image, "rb"); if (NULL == fpimg) { wm_tool_printf("open img file error [%s].\r\n", image); fclose(fpsec); return -4; } magic_word = 0; readlen = fread(&magic_word, 1, 4, fpimg); if (magic_word != WM_TOOL_IMG_HEAD_MAGIC_NO) { wm_tool_printf("input [%s] file magic error.\r\n", image); fclose(fpsec); fclose(fpimg); return -5; } fout = fopen(outfile, "wb+"); if (NULL == fout) { wm_tool_printf("create img file error [%s].\r\n", outfile); fclose(fpsec); fclose(fpimg); return -6; } fseek(fpsec, 0, SEEK_SET); while (!feof(fpsec)) { readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpsec); fwrite(buf, 1, readlen, fout); } fseek(fpimg, 0, SEEK_SET); while (!feof(fpimg)) { readlen = fread(buf, 1, WM_TOOL_ONCE_READ_LEN, fpimg); fwrite(buf, 1, readlen, fout); } if (fpsec) { fclose(fpsec); } if (fpimg) { fclose(fpimg); } if (fout) { fclose(fout); } wm_tool_printf("generate flash file completed.\r\n"); return 0; } static int wm_tool_gzip_bin(const char *binary, const char *gzbin) { FILE *bfp; gzFile gzfp; int ret; char buf[1024]; bfp = fopen(binary, "rb"); gzfp = gzopen((char *)gzbin, "wb+"); if (!bfp || !gzfp) { wm_tool_printf("can not gzip binary.\r\n"); return -1; } do { ret = fread(buf, 1, sizeof(buf), bfp); if (ret > 0) { ret = gzwrite(gzfp, (voidp)buf, ret); if (ret <= 0) { wm_tool_printf("can not write gzip binary.\r\n"); return -2; } } } while (ret > 0); gzclose(gzfp); fclose(bfp); wm_tool_printf("compress binary completed.\r\n"); return 0; } static int wm_tool_pack_firmware(void) { int ret; char *path; char *name; char *image; char *gzbin; char *gzimg; char *dbgimg; char *fls; if (!wm_tool_input_binary) return 1; if (!wm_tool_output_image) { char *r = wm_tool_input_binary; char *t = wm_tool_input_binary; do { r = strchr(r, '.'); if (r) { t = r; r++; } } while (r); wm_tool_output_image = malloc(t - wm_tool_input_binary + 1); if (!wm_tool_output_image) return -1; memcpy(wm_tool_output_image, wm_tool_input_binary, t - wm_tool_input_binary); wm_tool_output_image[t - wm_tool_input_binary] = '\0'; } char *p = wm_tool_output_image; char *q = wm_tool_output_image; do { p = strchr(p, '/'); if (p) { p++; q = p; } } while (p); /* output file */ name = strdup(q); *q = '\0'; path = strdup(wm_tool_output_image); image = malloc(strlen(path) + strlen(name) + strlen(".img") + 1); if (!image) return -1; sprintf(image, "%s%s.img", path, name); if (WM_TOOL_ZIP_TYPE_UNCOMPRESS == wm_tool_zip_type) { ret = wm_tool_pack_image(image); if (ret) return ret; } if (WM_TOOL_ZIP_TYPE_COMPRESS == wm_tool_zip_type) { gzbin = malloc(strlen(path) + strlen(name) + strlen("_gz.bin") + 1); gzimg = malloc(strlen(path) + strlen(name) + strlen("_gz.img") + 1); if (!gzbin || !gzimg) return -1; sprintf(gzbin, "%s%s.bin.gz", path, name); sprintf(gzimg, "%s%s_gz.img", path, name); ret = wm_tool_gzip_bin(wm_tool_input_binary, gzbin); if (ret) return ret; ret = wm_tool_pack_gz_image(gzbin, gzimg); free(gzbin); free(gzimg); if (ret) return ret; } if (wm_tool_is_debug) { dbgimg = malloc(strlen(path) + strlen(name) + strlen("_dbg.img") + 1); if (!dbgimg) return -1; sprintf(dbgimg, "%s%s_dbg.img", path, name); ret = wm_tool_pack_dbg_image(image, dbgimg); free(dbgimg); if (ret) return ret; } if (wm_tool_secboot_image) { fls = malloc(strlen(path) + strlen(name) + strlen(".fls") + 1); if (!fls) return -1; sprintf(fls, "%s%s.fls", path, name); ret = wm_tool_pack_fls(image, fls); free(fls); } free(image); return ret; } #ifdef __MINGW32__ static BOOL wm_tool_signal_proc(DWORD no) { switch (no) { case CTRL_C_EVENT: wm_tool_signal_proc_entry(); return(FALSE); default: return FALSE; } } static void wm_tool_signal_init(void) { SetConsoleCtrlHandler((PHANDLER_ROUTINE)wm_tool_signal_proc, TRUE); } static void wm_tool_delay_ms(int ms) { Sleep(ms); return; } static int wm_tool_uart_set_rts(int boolflag) { return EscapeCommFunction(wm_tool_uart_handle,((boolflag) ? SETRTS : CLRRTS)) ? 0 : -1; } static int wm_tool_uart_set_dtr(int boolflag) { return EscapeCommFunction(wm_tool_uart_handle,((boolflag) ? SETDTR : CLRDTR)) ? 0 : -1; } static int wm_tool_uart_set_timeout(void) { BOOL ret; COMMTIMEOUTS timeout; timeout.ReadIntervalTimeout = MAXDWORD; timeout.ReadTotalTimeoutConstant = 0; timeout.ReadTotalTimeoutMultiplier = 0; timeout.WriteTotalTimeoutConstant = 0; timeout.WriteTotalTimeoutMultiplier = 0; ret = SetCommTimeouts(wm_tool_uart_handle, &timeout); if (ret) ret = SetCommMask(wm_tool_uart_handle, EV_TXEMPTY); return ret ? 0 : -1; } static void wm_tool_uart_set_block(int bolck) { if (bolck) wm_tool_uart_block = INFINITE; else wm_tool_uart_block = 0; return; } static int wm_tool_uart_set_speed(int speed) { int i; int size; DCB cfg; size = sizeof(wm_tool_uart_speed_array) / sizeof(int); for (i= 0; i < size; i++) { if (speed == wm_tool_uart_name_array[i]) { if (GetCommState(wm_tool_uart_handle, &cfg)) { cfg.DCBlength = sizeof(DCB); cfg.BaudRate = wm_tool_uart_speed_array[i]; cfg.fBinary = TRUE; cfg.fParity = FALSE; cfg.fDtrControl = DTR_CONTROL_DISABLE; cfg.fDsrSensitivity = FALSE; cfg.fRtsControl = RTS_CONTROL_DISABLE; cfg.ByteSize = 8; cfg.StopBits = ONESTOPBIT; cfg.fAbortOnError = FALSE; cfg.fOutX = FALSE; cfg.fInX = FALSE; cfg.fErrorChar = FALSE; cfg.fNull = FALSE; cfg.fOutxCtsFlow = FALSE; cfg.fOutxDsrFlow = FALSE; cfg.Parity = NOPARITY; cfg.fTXContinueOnXoff = FALSE; return SetCommState(wm_tool_uart_handle, &cfg) ? 0 : -1; } else { return -3; } } } return -2; } static void wm_tool_uart_clear(void) { PurgeComm(wm_tool_uart_handle, PURGE_RXCLEAR); return; } static int wm_tool_uart_open(const char *device) { BOOL ret; char name[40]; sprintf(name,"\\\\.\\%s", device); wm_tool_uart_handle = CreateFile(name, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (wm_tool_uart_handle == INVALID_HANDLE_VALUE) { return -1; } ret = SetupComm(wm_tool_uart_handle, 4096, 4096); if (ret) { ret = wm_tool_uart_set_speed(WM_TOOL_DEFAULT_BAUD_RATE); ret |= wm_tool_uart_set_timeout(); } else { ret = -1; } return ret; } static int wm_tool_uart_read(void *data, unsigned int size) { BOOL ret; DWORD wait; unsigned long len = 0; COMSTAT state; DWORD error; OVERLAPPED event; do { memset(&event, 0, sizeof(OVERLAPPED)); event.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); ClearCommError(wm_tool_uart_handle, &error, &state); ret = ReadFile(wm_tool_uart_handle, data, size, &len, &event); if (!ret) { if (ERROR_IO_PENDING == GetLastError()) { wait = WaitForSingleObject(event.hEvent, wm_tool_uart_block); if (WAIT_OBJECT_0 == wait) ret = TRUE; } } } while (wm_tool_uart_block && !len); if (ret) { if (len > 0) return (int)len; } return -1; } static int wm_tool_uart_write(const void *data, unsigned int size) { BOOL ret; DWORD wait; OVERLAPPED event; COMSTAT state; DWORD error; unsigned int snd = 0; unsigned long len = 0; memset(&event, 0, sizeof(OVERLAPPED)); event.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); do { ClearCommError(wm_tool_uart_handle, &error, &state); ret = WriteFile(wm_tool_uart_handle, data + snd, size - snd, &len, &event); if (!ret) { if (ERROR_IO_PENDING == GetLastError()) { wait = WaitForSingleObject(event.hEvent, INFINITE); if (WAIT_OBJECT_0 == wait) ret = TRUE; } } if (ret) { if ((len > 0) && (snd != size)) { snd += len; } else { return size; } } else { break; } } while (1); return -1; } static void wm_tool_uart_close(void) { FlushFileBuffers(wm_tool_uart_handle); CloseHandle(wm_tool_uart_handle); wm_tool_uart_handle = NULL; return; } static DWORD WINAPI wm_tool_uart_tx_thread(LPVOID arg) { wm_tool_stdin_to_uart(); return 0; } static int wm_tool_create_thread(void) { HANDLE thread_handle; thread_handle = CreateThread(0, 0, wm_tool_uart_tx_thread, NULL, 0, NULL); CloseHandle(thread_handle); return 0; } #else static void wm_tool_signal_proc(int no) { wm_tool_signal_proc_entry(); } static void wm_tool_signal_init(void) { signal(SIGINT, wm_tool_signal_proc); } static void wm_tool_delay_ms(int ms) { usleep(ms * 1000); return; } static int wm_tool_uart_set_rts(int boolflag) { int ret; int controlbits; ret = ioctl(wm_tool_uart_fd, TIOCMGET, &controlbits); if (ret < 0) { WM_TOOL_DBG_PRINT("TIOCMGET failed!\r\n"); return ret; } if (controlbits & TIOCM_RTS) { WM_TOOL_DBG_PRINT("TIOCM_RTS!, %d!\r\n", boolflag); } else { WM_TOOL_DBG_PRINT("~TIOCM_RTS!, %d!\r\n", boolflag); } if (boolflag) controlbits |= TIOCM_RTS; else controlbits &= ~TIOCM_RTS; ret = ioctl(wm_tool_uart_fd, TIOCMSET, &controlbits); if (ret < 0) { WM_TOOL_DBG_PRINT("TIOCMSET failed!\r\n"); } if (ret >= 0) ret = 0; return ret; } static int wm_tool_uart_set_dtr(int boolflag) { int ret; int controlbits; ret = ioctl(wm_tool_uart_fd, TIOCMGET, &controlbits); if (ret < 0) { WM_TOOL_DBG_PRINT("TIOCMGET failed!\r\n"); return ret; } if (controlbits & TIOCM_DTR) { WM_TOOL_DBG_PRINT("TIOCM_DTR, %d!\r\n", boolflag); } else { WM_TOOL_DBG_PRINT("~TIOCM_DTR, %d!\r\n", boolflag); } if (boolflag) controlbits |= TIOCM_DTR; else controlbits &= ~TIOCM_DTR; ret = ioctl(wm_tool_uart_fd, TIOCMSET, &controlbits); if (ret < 0) { WM_TOOL_DBG_PRINT("TIOCMSET failed!\r\n"); } if (ret >= 0) ret = 0; return ret; } static void wm_tool_uart_set_block(int bolck) { int comopt; comopt = fcntl(wm_tool_uart_fd, F_GETFL, 0); if (bolck) fcntl(wm_tool_uart_fd, F_SETFL, comopt & ~O_NDELAY); else fcntl(wm_tool_uart_fd, F_SETFL, comopt | O_NDELAY); return; } static int wm_tool_uart_set_speed(int speed) { int i; int size; int status = -1; struct termios opt; tcgetattr(wm_tool_uart_fd, &opt); size = sizeof(wm_tool_uart_speed_array) / sizeof(int); for (i= 0; i < size; i++) { if (speed == wm_tool_uart_name_array[i]) { cfsetispeed(&opt, wm_tool_uart_speed_array[i]); cfsetospeed(&opt, wm_tool_uart_speed_array[i]); status = tcsetattr(wm_tool_uart_fd, TCSANOW, &opt); break; } } return status; } static void wm_tool_uart_clear(void) { tcflush(wm_tool_uart_fd, TCIFLUSH); return; } static int wm_tool_uart_open(const char *device) { struct termios tty; wm_tool_uart_fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); if (-1 == wm_tool_uart_fd) { return -1; } tcgetattr(wm_tool_uart_fd, &wm_tool_saved_serial_cfg); wm_tool_uart_set_dtr(0); tcgetattr(wm_tool_uart_fd, &tty); /* databit 8bit */ tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; /* set into raw, no echo mode */ tty.c_iflag = IGNBRK; tty.c_lflag = 0; tty.c_oflag = 0; tty.c_cflag |= CLOCAL | CREAD; tty.c_cflag &= ~CRTSCTS; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 5; /* have no software flow control */ tty.c_iflag &= ~(IXON|IXOFF|IXANY); /* parity none */ tty.c_cflag &= ~(PARENB | PARODD); /* stopbit 1bit */ tty.c_cflag &= ~CSTOPB; tcsetattr(wm_tool_uart_fd, TCSANOW, &tty); return wm_tool_uart_set_speed(WM_TOOL_DEFAULT_BAUD_RATE); } static int wm_tool_uart_read(void *data, unsigned int size) { return read(wm_tool_uart_fd, data, size); } static int wm_tool_uart_write(const void *data, unsigned int size) { int snd = 0; int ret = 0; do { ret = write(wm_tool_uart_fd, data + snd, size - snd); if (ret > 0) { snd += ret; if (snd == size) { return size; } } else { break; } } while (1); return -1; } static void wm_tool_uart_close(void) { tcsetattr(wm_tool_uart_fd, TCSANOW, &wm_tool_saved_serial_cfg); tcdrain(wm_tool_uart_fd); tcflush(wm_tool_uart_fd, TCIOFLUSH); close(wm_tool_uart_fd); wm_tool_uart_fd = -1; return; } static void *wm_tool_uart_tx_thread(void *arg) { wm_tool_stdin_to_uart(); return NULL; } static int wm_tool_create_thread(void) { pthread_t thread_id; return pthread_create(&thread_id, NULL, wm_tool_uart_tx_thread, NULL); } #endif static void wm_tool_signal_proc_entry(void) { WM_TOOL_DBG_PRINT("signal exit.\r\n"); exit(0); } static void wm_tool_stdin_to_uart(void) { int ret; char buf[WM_TOOL_ONCE_READ_LEN]; while (1) { if (fgets(buf, WM_TOOL_ONCE_READ_LEN, stdin)) { ret = wm_tool_uart_write(buf, strlen(buf)); if (ret <= 0) { WM_TOOL_DBG_PRINT("failed to write [%s].\r\n", buf); } } } return; } static int wm_tool_show_log_from_serial(void) { int i; int ret; unsigned int j = 0; unsigned char buf[WM_TOOL_ONCE_READ_LEN + 1]; ret = wm_tool_uart_open(wm_tool_serial_path); if (ret) { wm_tool_printf("can not open serial\r\n"); return ret; } if (WM_TOOL_DEFAULT_BAUD_RATE != wm_tool_normal_serial_rate) { ret = wm_tool_uart_set_speed(wm_tool_normal_serial_rate); if (ret) { wm_tool_printf("can not set serial baud rate.\r\n"); wm_tool_uart_close(); return ret; } } ret = wm_tool_create_thread(); if (ret) { wm_tool_printf("can not create thread.\r\n"); wm_tool_uart_close(); return ret; } wm_tool_uart_set_block(0); wm_tool_signal_init(); while (1) { ret = wm_tool_uart_read(buf, WM_TOOL_ONCE_READ_LEN); if (ret > 0) { if (WM_TOOL_SHOW_LOG_STR == wm_tool_show_log_type) { buf[ret] = '\0'; wm_tool_printf("%s", (char *)buf); } else if (WM_TOOL_SHOW_LOG_HEX == wm_tool_show_log_type) { for (i = 0; i < ret; i++, j++) { wm_tool_printf("%02X ", buf[i]); if ((j + 1) % 16 == 0) { wm_tool_printf("\r\n"); } } } else { break; } } else { wm_tool_delay_ms(1); } } wm_tool_uart_close(); return ret; } static int wm_tool_set_wifi_chip_speed(int speed) { int ret; if (2000000 == speed) { ret = wm_tool_uart_write(wm_tool_chip_cmd_b2000000, sizeof(wm_tool_chip_cmd_b2000000)); } else if (1000000 == speed) { ret = wm_tool_uart_write(wm_tool_chip_cmd_b1000000, sizeof(wm_tool_chip_cmd_b1000000)); } else if (921600 == speed) { ret = wm_tool_uart_write(wm_tool_chip_cmd_b921600, sizeof(wm_tool_chip_cmd_b921600)); } else if (460800 == speed) { ret = wm_tool_uart_write(wm_tool_chip_cmd_b460800, sizeof(wm_tool_chip_cmd_b460800)); } else { ret = wm_tool_uart_write(wm_tool_chip_cmd_b115200, sizeof(wm_tool_chip_cmd_b115200)); } return ret; } static int wm_tool_send_esc2uart(int ms) { int i; int err = 0; unsigned char esc_key = 27; for (i = 0; i < (ms / 10); i++) { err = wm_tool_uart_write(&esc_key, 1); wm_tool_delay_ms(10);/* 10-50ms */ } return err; } static int wm_tool_erase_image(wm_tool_dl_erase_e type) { int cnt = 0; int ret = -1; unsigned char ch; unsigned char rom_cmd[] = {0x21, 0x0a, 0x00, 0xc3, 0x35, 0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0xfe, 0x01}; /*2M-8k*/ WM_TOOL_DBG_PRINT("start erase.\r\n"); if (WM_TOOL_DL_ERASE_ALL == type) { wm_tool_printf("erase flash...\r\n"); ret = wm_tool_uart_write(rom_cmd, sizeof(rom_cmd)); } if (ret <= 0) return -1; wm_tool_uart_clear(); wm_tool_uart_set_block(1); do { ret = wm_tool_uart_read(&ch, 1); if (ret > 0) { if (('C' == ch) || ('P' == ch)) cnt++; else cnt = 0; } else { wm_tool_printf("erase error, errno = %d.\r\n", errno); return -2; } } while (cnt < 3); wm_tool_uart_set_block(0); wm_tool_printf("erase finish.\r\n"); return 0; } static int wm_tool_query_mac(void) { int ret = -1; int err; int offset = 0; char macstr[32] = {0}; int len = strlen("MAC:AABBCCDDEEFF\n");/* resp format, ROM "Mac:AABBCCDDEEFF\n", SECBOOT "MAC:AABBCCDDEEFF\n" */ unsigned char macaddr[6] = {0}; wm_tool_uart_clear(); wm_tool_uart_set_block(1); err = wm_tool_uart_write(wm_tool_chip_cmd_get_mac, sizeof(wm_tool_chip_cmd_get_mac)); if (err > 0) { do { err = wm_tool_uart_read((unsigned char *)(macstr + offset), sizeof(macstr) - 1 - offset); if (err > 0) { offset += err; if (offset >= len) { macstr[len - 1] = '\0';/* \n -> 0 */ err = wm_tool_str_to_hex_array(macstr + strlen("MAC:"), 6, macaddr); if (!err) { wm_tool_printf("mac %02X-%02X-%02X-%02X-%02X-%02X.\r\n", macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]); if (!strncmp(macstr, "Mac:", strlen("Mac:")) && (WM_TOOL_DL_TYPE_FLS != wm_tool_dl_type) && !wm_tool_dl_erase) { wm_tool_printf("please download the firmware in .fls format.\r\n"); } else { ret = 0; } } break; } } } while (err > 0); } wm_tool_uart_set_block(0); return ret; } static int wm_tool_xmodem_download(const char *image) { FILE *imgfp; unsigned char packet_data[XMODEM_DATA_SIZE]; unsigned char frame_data[XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1]; int complete, retry_num, pack_counter, read_number, write_number = 0, i; unsigned short crc_value; unsigned char ack_id; int sndlen; int ret = -111; imgfp = fopen(image, "rb"); if (!imgfp) { wm_tool_printf("can not open image to download.\r\n"); return -1; } sndlen = 0; pack_counter = 0; complete = 0; retry_num = 0; wm_tool_printf("start download.\r\n"); wm_tool_printf("0%% ["); wm_tool_uart_clear(); wm_tool_uart_set_block(1); ack_id = XMODEM_ACK; while (!complete) { WM_TOOL_DBG_PRINT("switch ack_id = %x\r\n", ack_id); switch(ack_id) { case XMODEM_ACK: { retry_num = 0; pack_counter++; read_number = fread(packet_data, sizeof(char), XMODEM_DATA_SIZE, imgfp); WM_TOOL_DBG_PRINT("fread = %d\r\n", read_number); if (read_number > 0) { sndlen += read_number; if (read_number < XMODEM_DATA_SIZE) { WM_TOOL_DBG_PRINT("start filling the last frame!\r\n"); for ( ; read_number < XMODEM_DATA_SIZE; read_number++) packet_data[read_number] = 0x0; } frame_data[0] = XMODEM_HEAD; frame_data[1] = (char)pack_counter; frame_data[2] = (char)(255 - frame_data[1]); for (i = 0; i < XMODEM_DATA_SIZE; i++) frame_data[i + 3] = packet_data[i]; crc_value = wm_tool_get_crc16(packet_data, XMODEM_DATA_SIZE); frame_data[XMODEM_DATA_SIZE + 3]=(unsigned char)(crc_value >> 8); frame_data[XMODEM_DATA_SIZE + 4]=(unsigned char)(crc_value); write_number = wm_tool_uart_write(frame_data, XMODEM_DATA_SIZE + 5); if (write_number <= 0) wm_tool_printf("write serial error, errno = %d.\r\n", errno); WM_TOOL_DBG_PRINT("waiting for ack, %d, %d ...\r\n", pack_counter, write_number); while ((wm_tool_uart_read(&ack_id, 1)) <= 0); if (ack_id == XMODEM_ACK) { WM_TOOL_DBG_PRINT("Ok!\r\n"); if (sndlen % 10240 == 0) { wm_tool_printf("#"); } } else { WM_TOOL_DBG_PRINT("error = %x!\r\n", ack_id); } } else { ack_id = XMODEM_EOT; complete = 1; WM_TOOL_DBG_PRINT("waiting for complete ack ...\r\n"); while (ack_id != XMODEM_ACK) { ack_id = XMODEM_EOT; write_number = wm_tool_uart_write(&ack_id, 1); if (write_number <= 0) wm_tool_printf("write serial error, errno = %d.\r\n", errno); while ((wm_tool_uart_read(&ack_id, 1)) <= 0); } WM_TOOL_DBG_PRINT("ok\r\n"); wm_tool_printf("] 100%%\r\n"); wm_tool_printf("download completed.\r\n"); ret = 0; } break; } case XMODEM_NAK: { if ( retry_num++ > 100) { WM_TOOL_DBG_PRINT("retry too many times, quit!\r\n"); wm_tool_printf("download firmware timeout.\r\n"); complete = 1; } else { write_number = wm_tool_uart_write(frame_data, XMODEM_DATA_SIZE + 5); if (write_number <= 0) wm_tool_printf("write serial error, errno = %d.\r\n", errno); WM_TOOL_DBG_PRINT("retry for ack, %d, %d ...\r\n", pack_counter, write_number); while ((wm_tool_uart_read(&ack_id, 1)) <= 0); if (ack_id == XMODEM_ACK) { WM_TOOL_DBG_PRINT("ok\r\n"); } else { WM_TOOL_DBG_PRINT("error!\r\n"); } } break; } default: { WM_TOOL_DBG_PRINT("fatal error!\r\n"); WM_TOOL_DBG_PRINT("unknown xmodem protocal [%x].\r\n", ack_id); wm_tool_printf("\r\ndownload failed, please reset and try again.\r\n"); complete = 1; break; } } } wm_tool_uart_set_block(0); fclose(imgfp); return ret; } static int wm_tool_download_firmware(void) { int ret; int cnt = 0; int note = 1; int timeout = 0; float timeuse; time_t start, end; unsigned char ch; wm_tool_printf("connecting serial...\r\n"); ret = wm_tool_uart_open(wm_tool_serial_path); if (ret) { wm_tool_printf("can not open serial\r\n"); return ret; } /* In some cases, setting the serial port initialization setting requires a delay. */ wm_tool_delay_ms(500); wm_tool_printf("serial connected.\r\n"); if (WM_TOOL_DL_ACTION_AT == wm_tool_dl_action) { if (WM_TOOL_DEFAULT_BAUD_RATE != wm_tool_normal_serial_rate) wm_tool_uart_set_speed(wm_tool_normal_serial_rate); #if 0 /* use erase option */ if (WM_TOOL_DL_TYPE_FLS == wm_tool_dl_type) { ret = wm_tool_uart_write("AT+&FLSW=8002000,0\r\n", strlen("AT+&FLSW=8002000,0\r\n")); if (ret <= 0) { wm_tool_printf("destroy secboot failed.\r\n"); wm_tool_uart_close(); return -3; } wm_tool_delay_ms(300); } #endif ret = wm_tool_uart_write("AT+Z\r\n", strlen("AT+Z\r\n")); if (ret <= 0) { wm_tool_printf("reset error.\r\n"); wm_tool_uart_close(); return -4; } if (WM_TOOL_DEFAULT_BAUD_RATE != wm_tool_normal_serial_rate) wm_tool_uart_set_speed(WM_TOOL_DEFAULT_BAUD_RATE); } else if (WM_TOOL_DL_ACTION_RTS == wm_tool_dl_action) { ret = wm_tool_uart_set_dtr(0); ret |= wm_tool_uart_set_rts(1); wm_tool_delay_ms(50); ret |= wm_tool_uart_set_dtr(1); ret |= wm_tool_uart_set_rts(0); wm_tool_delay_ms(50); ret |= wm_tool_uart_set_dtr(0); if (ret < 0) { wm_tool_printf("set rts to reboot error.\r\n"); wm_tool_uart_close(); return -5; } } wm_tool_printf("wait serial sync..."); wm_tool_send_esc2uart(500);/* used for delay */ start = time(NULL); do { ret = wm_tool_uart_read(&ch, 1); WM_TOOL_DBG_PRINT("ret=%d, %x-%c\r\n", ret, ch, ch); if (ret > 0) { if (('C' == ch) || ('P' == ch)) cnt++; else cnt = 0; } else { wm_tool_send_esc2uart(30); } end = time(NULL); timeuse = difftime(end, start); if (timeuse >= 1) { wm_tool_printf("."); timeout++; if ((timeout >= (WM_TOOL_DOWNLOAD_TIMEOUT_SEC / 10)) && note) { wm_tool_printf("\r\nplease manually reset the device.\r\n"); note = 0; } else if (timeout > WM_TOOL_DOWNLOAD_TIMEOUT_SEC) { wm_tool_uart_close(); wm_tool_printf("\r\nserial sync timeout.\r\n"); return -6; } start = time(NULL); } } while (cnt < 3); wm_tool_printf("\r\nserial sync sucess.\r\n"); ret = wm_tool_query_mac(); if (ret) { wm_tool_uart_close(); wm_tool_printf("download failed.\r\n"); return ret; } if (WM_TOOL_DL_ERASE_ALL == wm_tool_dl_erase) { ret = wm_tool_erase_image(WM_TOOL_DL_ERASE_ALL); if (ret) { wm_tool_uart_close(); wm_tool_printf("failed to erase.\r\n"); return ret; } } if (!wm_tool_download_image && wm_tool_dl_erase) { return 0; } if (WM_TOOL_DEFAULT_BAUD_RATE != wm_tool_download_serial_rate) { ret = wm_tool_set_wifi_chip_speed(wm_tool_download_serial_rate); if (ret > 0) { wm_tool_delay_ms(1 * 1000); wm_tool_uart_set_speed(wm_tool_download_serial_rate); } } ret = wm_tool_xmodem_download(wm_tool_download_image); if (WM_TOOL_DEFAULT_BAUD_RATE != wm_tool_download_serial_rate) { wm_tool_delay_ms(1 * 1000); wm_tool_set_wifi_chip_speed(WM_TOOL_DEFAULT_BAUD_RATE); wm_tool_delay_ms(1 * 1000); } if (!ret) { if (WM_TOOL_DL_TYPE_FLS == wm_tool_dl_type) { if (WM_TOOL_DL_ACTION_RTS == wm_tool_dl_action)/* auto reset */ { wm_tool_uart_set_dtr(0); wm_tool_uart_set_rts(1); wm_tool_delay_ms(50); wm_tool_uart_set_dtr(1); wm_tool_uart_set_rts(0); wm_tool_delay_ms(50); wm_tool_uart_set_dtr(0); } else { wm_tool_printf("please manually reset the device.\r\n"); } } } wm_tool_uart_close(); return ret; } static void wm_tool_show_local_com(void) { #if defined(__APPLE__) && defined(__MACH__) char *comstr = "tty.usbserial"; #elif defined(__CYGWIN__) int num; char *comstr = "ttyS"; #elif defined(__linux__) char *comstr = "ttyUSB"; #endif #if defined(__APPLE__) || defined(__MACH__) || defined(__CYGWIN__) || defined(__linux__) DIR *dir; struct dirent *file; dir = opendir("/dev"); if (dir) { while (NULL != (file = readdir(dir))) { if ((0 == strncmp(file->d_name, comstr, strlen(comstr))) && (DT_CHR == file->d_type)) { #if defined(__CYGWIN__) num = atoi(file->d_name + strlen(comstr)); wm_tool_printf("COM%d ", num + 1); #else wm_tool_printf("%s ", file->d_name); #endif } } closedir(dir); wm_tool_printf("\r\n"); } #elif defined(__MINGW32__) LONG ret; HKEY key; DWORD i = 0; DWORD knlen; char kname[WM_TOOL_PATH_MAX] = {0}; DWORD kvlen; char kvalue[WM_TOOL_PATH_MAX] = {0}; REGSAM kmask = KEY_READ; #if defined(KEY_WOW64_64KEY) BOOL is_64; if (IsWow64Process(GetCurrentProcess(), &is_64)) { if (is_64) kmask |= KEY_WOW64_64KEY; } #endif ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DEVICEMAP\\SERIALCOMM"), 0, NULL, 0, kmask, NULL, &key, NULL); if (ret != ERROR_SUCCESS) { return; } do{ knlen = sizeof(kname); kvlen = sizeof(kvalue); ret = RegEnumValue(key, i, kname, &knlen, 0, NULL, (LPBYTE)kvalue, &kvlen); if (ret == ERROR_SUCCESS) { if (strcmp(kvalue, "") != 0) { wm_tool_printf("%s ", kvalue); } } i++; } while (ret != ERROR_NO_MORE_ITEMS); RegCloseKey(key); wm_tool_printf("\r\n"); #else wm_tool_printf("\r\nunsupported system.\r\n"); #endif return; } static void wm_tool_free_res(void) { if (wm_tool_download_image) free(wm_tool_download_image); if (wm_tool_output_image) free(wm_tool_output_image); if (wm_tool_input_binary) free(wm_tool_input_binary); if (wm_tool_secboot_image) free(wm_tool_secboot_image); return; } int main(int argc, char *argv[]) { int ret = 0; if (!wm_tool_parse_arv(argc, argv)) { wm_tool_print_usage(argv[0]); wm_tool_free_res(); return 0; } if (wm_tool_show_usage) { wm_tool_print_usage(argv[0]); wm_tool_free_res(); return 0; } if (wm_tool_show_ver) { wm_tool_print_version(argv[0]); wm_tool_free_res(); return 0; } if (wm_tool_list_com) { wm_tool_show_local_com(); wm_tool_free_res(); return 0; } if (wm_tool_input_binary) { ret = wm_tool_pack_firmware(); } if (wm_tool_download_image || wm_tool_dl_erase) { ret = wm_tool_download_firmware(); } if (wm_tool_show_log_type) { ret = wm_tool_show_log_from_serial(); } if (ret > 0) wm_tool_print_usage(argv[0]); wm_tool_free_res(); return ret; }