From: TJ Date: Fri, 8 Apr 2016 19:52:11 +0000 (+0100) Subject: Import FFMPEG LZW code and CMS header from Broadcom/Zyxel source-code X-Git-Tag: v1.00~9 X-Git-Url: https://iam.tj/gitweb/gitweb.cgi?p=firmware_extractor.git;a=commitdiff_plain;h=1693f804f61fb9856114c39185ea3eb46e3f93e5 Import FFMPEG LZW code and CMS header from Broadcom/Zyxel source-code --- diff --git a/cms.h b/cms.h new file mode 100644 index 0000000..d650c46 --- /dev/null +++ b/cms.h @@ -0,0 +1,532 @@ +/*********************************************************************** + * + * Copyright (c) 2006-2007 Broadcom Corporation + * All Rights Reserved + * + * <:label-BRCM:2011:DUAL/GPL:standard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as published by + * the Free Software Foundation (the "GPL"). + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php, or by + * writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * +:> + * + ************************************************************************/ + +#ifndef __CMS_H__ +#define __CMS_H__ + +/*!\file cms.h + * \brief Header file containing common and constant definitions for + * the CPE Management System (CMS). Parameters which may change + * depending on vendor preference or board configuration are located + * in cms_params.h (which is included by this file at the bottom.) + */ + +#include "os_defs.h" +#include "cms_version.h" + + + +/*!\enum CmsRet + * \brief Return codes for all external functions, and some internal functions too. + * + * Codes from 9000-9799 are reserved for TR69C return values. + * All Broadcom return codes should start at 9800. + */ +typedef enum +{ + CMSRET_SUCCESS = 0, /**= 9000) && ((r) < 9800))) + + + +#ifndef TRUE +/** TRUE = 1 + */ +#define TRUE 1 +#endif + +#ifndef FALSE +/** FALSE = 0 + */ +#define FALSE 0 +#endif + +/** Maximum value for a UINT64 */ +#define MAX_UINT64 18446744073709551615ULL + +/** Maximum value for a SINT64 */ +#define MAX_SINT64 9223372036854775807LL + +/** Minimum value for a SINT64 */ +#define MIN_SINT64 (-1 * MAX_SINT64 - 1) + +/** Maximum value for a UINT32 */ +#define MAX_UINT32 4294967295U + +/** Maximum value for a SINT32 */ +#define MAX_SINT32 2147483647 + +/** Minimum value for a SINT32 */ +#define MIN_SINT32 (-2147483648) + +/** Maximum value for a UINT16 */ +#define MAX_UINT16 65535 + +/** Maximum value for a SINT16 */ +#define MAX_SINT16 32767 + +/** Minimum value for a SINT16 */ +#define MIN_SINT16 (-32768) + + +/** + * This is common used string length types. + */ +#define BUFLEN_4 4 //!< buffer length 4 +#define BUFLEN_8 8 //!< buffer length 8 +#define BUFLEN_16 16 //!< buffer length 16 +#define BUFLEN_18 18 //!< buffer length 18 -- for ppp session id +#define BUFLEN_24 24 //!< buffer length 24 -- mostly for password +#define BUFLEN_32 32 //!< buffer length 32 +#define BUFLEN_40 40 //!< buffer length 40 +#define BUFLEN_48 48 //!< buffer length 48 +#define BUFLEN_64 64 //!< buffer length 64 +#define BUFLEN_80 80 //!< buffer length 80 +#define BUFLEN_128 128 //!< buffer length 128 +#define BUFLEN_256 256 //!< buffer length 256 +#define BUFLEN_264 264 //!< buffer length 264 +#define BUFLEN_512 512 //!< buffer length 512 +#define BUFLEN_1024 1024 //!< buffer length 1024 +#define BUFLEN_4096 4096 //!< buffer length 4096 + +#if 1 //__MSTC__, Dennis, 3 group privilege size +#define PRIVILEGE_BUFLEN (512 * 3) +#endif + +#define IIDSTACK_BUF_LEN 40 //!< good length to use for mdm_dumpIidStack +#define MAC_ADDR_LEN 6 //!< Mac address len in an array of 6 bytes +#define MAC_STR_LEN 17 //!< Mac String len with ":". eg: xx:xx:xx:xx:xx:xx +#define VPI_MIN 0 //!< VPI min +#define VPI_MAX 255 //!< VPI max +#define VCI_MIN 32 //!< VCI min +#define VCI_MAX 65535 //!< VCI max + +#define PPP_CONNECT_ERROR_REASON_LEN 48 + +#define CMS_IFNAME_LENGTH BUFLEN_32 //!< broadcom interface name length +#define CMS_MAX_ACS_URL_LENGTH 260 //!< max acs url from dhcp server, specified in TR-181 as max length 256 +#define CMS_MAX_ACS_PROVISIONING_CODE_LENGTH 68 //!< max acs provisioning code, TR-181 max length is 64 + +#define CMS_AFTR_NAME_LENGTH 256 //!< max aftr name from dhcpv6 server + +#ifdef DMP_X_5067F0_IPV6_1 /* aka SUPPORT_IPV6 */ +#define CMS_IPADDR_LENGTH 46 //!< IP address length to hold IPv6 in CIDR notation (match INET6_ADDRSTRLEN) +#else +#define CMS_IPADDR_LENGTH BUFLEN_16 //!< IP address length to hold IPv4 in ASCII +#endif /* DMP_X_5067F0_IPV6_1 */ +# +#define CMS_MAX_DEFAULT_GATEWAY 8 //!< max default gateways allowed in L3 X_5067F0_DefaultConnectionServices +#define CMS_MAX_DNSIFNAME 8 //!< max dns wan interface names in X_BROADCOM_Networking.DNSIfName +#define CMS_MAX_ACTIVE_DNS_IP 4 //!< max active dns ip (in resolv.conf) + +#ifdef DMP_X_5067F0_GPONRG_OMCI_LIGHT_1 +#define CMS_MAX_GPONWAN_INTF 4 //!< max gpon wan layer 2 interfaces for light omci GponRg +#else +#ifdef DMP_X_5067F0_GPONRG_OMCI_FULL_1 +#define CMS_MAX_GPONWAN_INTF 1 //!< max gpon wan layer 2 interfaces for full omci GponRg +#else +#define CMS_MAX_GPONWAN_INTF 0 //!< No gpon at all, so no GPONWAN intf +#endif +#endif + +/** + * Values for network protocol + */ +#define PROTO_PPPOE 0 //!< PPPoE protocol +#define PROTO_PPPOA 1 //!< PPPoA protocol +#define PROTO_MER 2 //!< MER protocol +#define PROTO_BRIDGE 3 //!< bridge protocol +#define PROTO_PPPOE_RELA 4 //!< PPPoE relay protocol +#define PROTO_IPOA 5 //!< ip over atm protocol +#define PROTO_IPOWAN 6 //!< ip over wan protocol +#define PROTO_NONE 10 //!< invalid protocol + +#define IFC_WAN_MAX 16 //!< Max WAN Connection in the system. +#define IFC_VLAN_MAX 8 //!< Max VLAN on single PVC +#define ATM_QUEUE_MAX 8 //!< Max ATM queues + +/*!\enum WanIfcType + * \brief Enumerated values of WAN interface types. + */ +typedef enum { + WAN_IFC_ATM=0, /**< ATM */ + WAN_IFC_PPPOA=1, /**< PPPoA */ + WAN_IFC_IPOA=2, /**< IPoA */ + WAN_IFC_ETH=3, /**< Eth */ + WAN_IFC_PTM=4, /**< Ptm */ + WAN_IFC_NONE=10 /**< undefined/invalid */ +} WanIfcType; + +#ifdef NOT_USED_AND_USE_CMSWANCONNECTIONTYPE_BELOW +/******************* NOTE: DO NOT USE WanProtocal. USE CmsWanConnetctionType Below !!!!! *********** + * !\enum WanProtocol + * \brief Enumerated values of WAN connection protocols. + * This should be used to replace the same set of defines in cms.h + */ +typedef enum { + WAN_PROTO_PPPOE=0, /**< PPPoE */ + WAN_PROTO_PPPOA=1, /** < PPPoA */ + WAN_PROTO_MER=2, /**< static or dynamic mer */ + WAN_PROTO_BRIDGE=3, /**< bridge */ + WAN_PROTO_PPPOE_RELAY=4, /**< pppoe relay */ + WAN_PROTO_IPOA=5, /**< IPoA */ + WAN_PROTO_IPOWAN=6, /**< IP over Wan only when SUPPORT ETHWAN */ + WAN_PROTO_NONE=10 /**< no proto found/defined/invalid */ +} WanProtocol; +#endif + +/* try to match with the above old defines PROTO_PPPOE=0 PPPOA=1, MER=2, BRIDGE=3 thing + * so that no html changes need */ +typedef enum + +{ + CMS_WAN_TYPE_PPPOE = 0, + CMS_WAN_TYPE_PPPOA = 1, + CMS_WAN_TYPE_DYNAMIC_IPOE = 2, + CMS_WAN_TYPE_BRIDGE = 3, + CMS_WAN_TYPE_PPPOE_RELAY = 4, + CMS_WAN_TYPE_IPOA = 5, + CMS_WAN_TYPE_STATIC_IPOE = 6, + + CMS_WAN_TYPE_STATIC_ETHERNET_IP = 10, + CMS_WAN_TYPE_DYNAMIC_ETHERNET_IP = 11, + CMS_WAN_TYPE_ETHERNET_PPPOE = 12, + CMS_WAN_TYPE_ETHERNET_BRIDGE = 13, + CMS_WAN_TYPE_UNDEFINED = 99 +} CmsWanConnectionType; + + + +#define BRIDGE_PROTO_STR "Bridge" +#define IPOA_PROTO_STR "IPoA" +#define IPOE_PROTO_STR "IPoE" +#define PPPOE_PROTO_STR "PPPoE" +#define PPPOA_PROTO_STR "PPPoA" +#define IPOW_PROTO_STR "IPoW" +#ifdef DMP_X_5067F0_MSTC_WWAN_1 // __MSTC__, Richard Huang, +#define PPP_PROTO_STR "PPP" +#endif + +#define ETH_IFC_STR "eth" +#define USB_IFC_STR "usb" +#define WLAN_IFC_STR "wl" +#define MOCA_IFC_STR "moca" +#define GPON_IFC_STR "veip" +#define EPON_IFC_STR "epon" +#define ATM_IFC_STR "atm" +#define PTM_IFC_STR "ptm" +#define BRIDGE_IFC_STR "br" +#define IPOA_IFC_STR "ipoa" +#define IPOE_IFC_STR "ipoe" +#define PPP_IFC_STR "ppp" +#define PPPOE_IFC_STR "pppoe" +#define PPPOA_IFC_STR "pppoa" +#define IPA_IFC_STR "ipa" +#define BRIDGE_SMUX_STR "bridge" +#ifdef DMP_X_5067F0_MSTC_WWAN_1 // __MSTC__, Richard Huang, For Telefonica 3G WAN backup, __TELEFONICA__, MitraStar Chehuai, 20110617 */ +#define PPPO3G_IFC_STR "pppo3G" +#endif + +/* for interface group with routed pvc */ +#define RT_TABLES_BASE 200 + +typedef enum +{ + ATM=0, /**< WanDev is used for DSL ATM */ + PTM=1, /**< WanDev is used for DSL PTM */ + Ethernet=2 /**< WanDev is used for Ethernet */ +}WanLinkType; + + +typedef enum +{ + CMS_CONNECTION_MODE_DEFAULT=0, /**< Default connection mdoe - single wan service over 1 connection */ + CMS_CONNECTION_MODE_VLANMUX=1, /**< Vlan mux connection mdoe - multiple vlan service over 1 connection */ + CMS_CONNECTION_MODE_MSC=2, /**< MSC connection mdoe - multiple wan service over 1 connection */ +} ConnectionModeType; + + +typedef enum +{ + ATM_EOA=0, /**< WanDev is used for DSL ATM */ + ATM_IPOA=1, /**< WanDev is used for DSL ATM IPOA */ + ATM_PPPOA=2, /**< WanDev is used for DSL ATM PPPoA */ + PTM_EOA=3 /**< WanDev is used for DSL PTM */ + +}Layer2IfNameType; + + +typedef enum +{ + ENBL_IPV4_ONLY=0, /**< Wan Connection is IPv4 only */ + ENBL_IPV4_IPV6=1, /**< Wan Connection is dual stack */ + ENBL_IPV6_ONLY=2 /**< Wan Connection is IPv6 only */ +}WanConnL3Type; + + +/* RAM size defines */ +#define SZ_8MB 0x800000 +#define SZ_16MB 0x1000000 + +/*filter*/ +#define CFG_FILTER_CMD_SIZE 256 + +#define MAX_PERSISTENT_WAN_PORT 39 /**< Max Ethernet ports can be configured as WAN ports */ +#define MAX_GMAC_ETH_PORT 5 /**< Max GMAC Ethernet ports in the system */ + +#define DNSINFO_CONF "/var/dnsinfo.conf" /**< This file is created by cms when there is a WAN connection status change and is used + * by dnsproxy and can be used by other applications for the finding the WAN dns info. + * and has the following fields, WAN Interface; Subnet/Mask; dns1, dns2..; app1, app2.. : + * eg. atm1;172.0.0.1/32;10.7.2.8,20.1.2.5;tr69c -- WAN service for TR69 + * 1). WAN interface name. eg. ppp0, atm0, etc. + * 2) subnet/mask in cidr format (bind to this WAN) + * 3) dns list for this WAN + * 4) process name list uses this WAN + */ + +/* include cms_params.h after we have defined all other constants. */ +#include "cms_params.h" + +/* for Gpon */ +typedef enum +{ + OMCI_FLOW_NONE = 0, + OMCI_FLOW_UPSTREAM, + OMCI_FLOW_DOWNSTREAM, + OMCI_FLOW_BOTH, +} OmciFLowDirection; + + +typedef enum +{ + LOGIN_INVALID=0, /**< This is for httpd login */ + LOGIN_USER=1, /**< user login */ + LOGIN_SUPPORT=2, /**< support login */ + LOGIN_ADMIN=10, /**< admin login */ +} HttpLoginType; + +#if 1 //__MSTC__, DingRuei, Run time chage Web UI +/*Web UI Style Type*/ +#define WEBUI_BRICK 1 +#define WEBUI_BRCM 2 +#define WEBUI_BRICK_ODM 3 +#define UNKNOWN_TYPE 1025 +#endif //__MSTC__, DingRuei, Run time chage Web UI + +#ifdef SUPPORT_MSTC_WEB_REDIRECT // __MSTC__, for web redirect +#define WAN_REDIRECT_STATUS_FILE "/var/redirect_status" +#endif + +#endif /* __CMS_H__ */ diff --git a/cms_lzw.h b/cms_lzw.h new file mode 100644 index 0000000..9dd8d4d --- /dev/null +++ b/cms_lzw.h @@ -0,0 +1,179 @@ +/* + * LZW decoder + * Copyright (c) 2003 Fabrice Bellard. + * Copyright (c) 2006 Konstantin Shishkov. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __CMS_LZW_H__ +#define __CMS_LZW_H__ + +/*!\file cms_lzw.h + * \brief Header file for LZW Encoder/Decoder functions. + * + * These functions were taken from the ffmpeg library. + */ + + +#define LZW_MAXBITS 12 +#define LZW_SIZTABLE (1<bbits < s->cursize) { + s->bbuf = (s->bbuf << 8) | (*s->pbuf++); + s->bbits += 8; + } + // printf("TIFF: bbuf=0x%08x bbits=%d cursize=%d\n", s->bbuf, s->bbits, s->cursize); + c = s->bbuf >> (s->bbits - s->cursize); + + s->bbits -= s->cursize; + + // printf("bbits=%d c=0x%08x curmask=0x%08x\n", s->bbits, c, s->curmask); + return c & s->curmask; +} + + +void ff_lzw_decode_tail(LZWDecoderState *s) +{ + /* always use TIFF mode */ + s->pbuf= s->ebuf; +} + + +CmsRet cmsLzw_initDecoder(LZWDecoderState **p, UINT8 *inbuf, UINT32 inbuf_size) +{ + LZWDecoderState *s; + int mode = FF_LZW_TIFF; /* always use TIFF mode */ + int csize = 8; /* the encoder side has this hardcoded, so hardcode here too */ + + *p = (LZWDecoderState *) cmsMem_alloc(sizeof(LZWDecoderState), ALLOC_ZEROIZE); + if (*p == NULL) + { + cmsLog_error("could not allocate %d bytes for decoder state", sizeof(LZWDecoderState)); + return CMSRET_RESOURCE_EXCEEDED; + } + else + { + cmsLog_debug("%d bytes allocated for decoder state", sizeof(LZWDecoderState)); + } + + s = *p; + + /* read buffer */ + s->pbuf = inbuf; + s->ebuf = s->pbuf + inbuf_size; + s->bbuf = 0; + s->bbits = 0; + s->bs = 0; + + /* decoder */ + s->codesize = csize; + s->cursize = s->codesize + 1; + s->curmask = mask[s->cursize]; + s->top_slot = 1 << s->cursize; + s->clear_code = 1 << s->codesize; + s->end_code = s->clear_code + 1; + s->slot = s->newcodes = s->clear_code + 2; + s->oc = s->fc = -1; + s->sp = s->stack; + + s->mode = mode; + s->extra_slot = (s->mode == FF_LZW_TIFF); + + return CMSRET_SUCCESS; +} + + +SINT32 cmsLzw_decode(LZWDecoderState *s, UINT8 *outbuf, UINT32 outlen) +{ + UINT32 l; + int c, code, oc, fc; + uint8_t *sp; + + if (s->end_code < 0) + return -1; + + l = outlen; + sp = s->sp; + oc = s->oc; + fc = s->fc; + + for (;;) { + + while (sp > s->stack) { + // printf("transfer stack to buf, sp=0x%02x buf=%p\n", *sp, outbuf); + *outbuf++ = *(--sp); + if ((--l) == 0) + goto the_end; + } + + c = lzw_get_code(s); + if (c == s->end_code) { + cmsLog_debug("got end code %d", c); + break; + } else if (c == s->clear_code) { + cmsLog_debug("got clear code %d", c); + s->cursize = s->codesize + 1; + s->curmask = mask[s->cursize]; + s->slot = s->newcodes; + s->top_slot = 1 << s->cursize; + fc= oc= -1; + } else { + code = c; + // printf("got valid code %d (0x%02x)\n", c, c); + + if (code == s->slot && fc>=0) { + *sp++ = fc; + code = oc; + }else if(code >= s->slot) { + cmsLog_error("code %d greater than slot %d", code, s->slot); + break; + } + + while (code >= s->newcodes) { + // printf("transfer suffix to to sp \n"); + *sp++ = s->suffix[code]; + code = s->prefix[code]; + } + + // printf("sp=%p gets code %d\n", sp, code); + *sp++ = code; + + + if (s->slot < s->top_slot && oc>=0) { + // printf("suffix[%d]=%d prefix[%d]=%d\n", s->slot, code, s->slot, oc); + s->suffix[s->slot] = code; + s->prefix[s->slot++] = oc; + } + fc = code; + oc = c; + + if (s->slot >= s->top_slot - s->extra_slot) { + if (s->cursize < LZW_MAXBITS) { + s->top_slot <<= 1; + s->curmask = mask[++s->cursize]; + // printf("new top_slot=0x%x curmask=0x%x\n", s->top_slot, s->curmask); + } + } + } + } // end of for loop + + + s->end_code = -1; + the_end: + s->sp = sp; + s->oc = oc; + s->fc = fc; + + cmsLog_debug("about to return, outlen=%d l=%d\n", outlen, l); + return outlen - l; +} + + + +void cmsLzw_cleanupDecoder(LZWDecoderState **s) +{ + cmsMem_free(*s); + *s = NULL; +} + + + +#endif /* COMPRESSED_CONFIG_FILE */ diff --git a/lzw_encode.c b/lzw_encode.c new file mode 100644 index 0000000..714e70f --- /dev/null +++ b/lzw_encode.c @@ -0,0 +1,344 @@ +/* + * LZW encoder + * Copyright (c) 2007 Bartlomiej Wolowiec + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef COMPRESSED_CONFIG_FILE + +#include "cms_lzw.h" + + +#ifdef DESKTOP_LINUX + +/* + * We are on Intel. Intel is LE. + */ +#define be2me_16(x) ntohs(x) +#define be2me_32(x) ntohl(x) + +#else + +/* + * We are on the MIPS. MIPS is in BE mode. + */ +#define be2me_16(x) (x) +#define be2me_32(x) (x) + +#define UNALIGNED_STORES_ARE_BAD +#endif + + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) + + +/** + * Hash function adding character + * @param head LZW code for prefix + * @param add Character to add + * @return New hash value + */ +static inline int hash(int head, const int add) +{ + head ^= (add << LZW_HASH_SHIFT); + if (head >= LZW_HASH_SIZE) + head -= LZW_HASH_SIZE; + cmsAst_assert(head >= 0 && head < LZW_HASH_SIZE); + return head; +} + +/** + * Hash function calculates next hash value + * @param head Actual hash code + * @param offset Offset calculated by hashOffset + * @return New hash value + */ +static inline int hashNext(int head, const int offset) +{ + head -= offset; + if(head < 0) + head += LZW_HASH_SIZE; + return head; +} + +/** + * Hash function calculates hash offset + * @param head Actual hash code + * @return Hash offset + */ +static inline int hashOffset(const int head) +{ + return head ? LZW_HASH_SIZE - head : 1; +} + + +static void init_put_bits(PutBitContext *s, uint8_t *buffer, int buffer_size) +{ + if(buffer_size < 0) { + buffer_size = 0; + buffer = NULL; + } + + s->buf = buffer; + s->buf_end = s->buf + buffer_size; + + s->buf_ptr = s->buf; + s->bit_left=32; + s->bit_buf=0; +} + + +void put_bits(PutBitContext *s, int n, unsigned int value) +{ + unsigned int bit_buf; + int bit_left; + + // printf("put_bits=%d %c (0x%x)\n", n, value, value); + cmsAst_assert(n == 32 || value < (1U << n)); + + bit_buf = s->bit_buf; + bit_left = s->bit_left; + + // printf("n=%d value=%x cnt=%d buf=%x\n", n, value, bit_cnt, bit_buf); + /* XXX: optimize */ + if (n < bit_left) { + bit_buf = (bit_buf<> (n - bit_left); +#ifdef UNALIGNED_STORES_ARE_BAD + if (3 & (intptr_t) s->buf_ptr) { + s->buf_ptr[0] = bit_buf >> 24; + s->buf_ptr[1] = bit_buf >> 16; + s->buf_ptr[2] = bit_buf >> 8; + s->buf_ptr[3] = bit_buf ; + } else +#endif + *(uint32_t *)s->buf_ptr = be2me_32(bit_buf); + // printf("STORING: buf=%p be bitbuf = %08x me=%08x (bit_left=%d)\n", + // s->buf_ptr, bit_buf, *(uint32_t *)s->buf_ptr, bit_left); + s->buf_ptr+=4; + bit_left+=32 - n; + bit_buf = value; + } + + s->bit_buf = bit_buf; + s->bit_left = bit_left; +} + +/* pad the end of the output stream with zeros */ +static inline void flush_put_bits(PutBitContext *s) +{ + s->bit_buf<<= s->bit_left; + while (s->bit_left < 32) { + /* XXX: should test end of buffer */ + *s->buf_ptr++=s->bit_buf >> 24; + s->bit_buf<<=8; + s->bit_left+=8; + } + s->bit_left=32; + s->bit_buf=0; +} + + +/* return the number of bits output */ +static inline int put_bits_count(PutBitContext *s) +{ + return (s->buf_ptr - s->buf) * 8 + 32 - s->bit_left; +} + + + +/** + * Write one code to stream + * @param s LZW state + * @param c code to write + */ +static inline void writeCode(LZWEncoderState * s, int c) +{ + cmsAst_assert(0 <= c && c < 1 << s->bits); + put_bits(&s->pb, s->bits, c); +} + + +/** + * Find LZW code for block + * @param s LZW state + * @param c Last character in block + * @param hash_prefix LZW code for prefix + * @return LZW code for block or -1 if not found in table + */ +static inline int findCode(LZWEncoderState * s, uint8_t c, int hash_prefix) +{ + int h = hash(FFMAX(hash_prefix, 0), c); + int hash_offset = hashOffset(h); + + while (s->tab[h].hash_prefix != LZW_PREFIX_FREE) { + if ((s->tab[h].suffix == c) + && (s->tab[h].hash_prefix == hash_prefix)) + return h; + h = hashNext(h, hash_offset); + } + + return h; +} + +/** + * Add block to LZW code table + * @param s LZW state + * @param c Last character in block + * @param hash_prefix LZW code for prefix + * @param hash_code LZW code for bytes block + */ +static inline void addCode(LZWEncoderState * s, uint8_t c, int hash_prefix, int hash_code) +{ + s->tab[hash_code].code = s->tabsize; + s->tab[hash_code].suffix = c; + s->tab[hash_code].hash_prefix = hash_prefix; + + s->tabsize++; + + if (s->tabsize >= 1 << s->bits) + s->bits++; +} + +/** + * Clear LZW code table + * @param s LZW state + */ +static void clearTable(LZWEncoderState * s) +{ + int i, h; + // printf("clearTable called\n"); + writeCode(s, s->clear_code); + s->bits = 9; + for (i = 0; i < LZW_HASH_SIZE; i++) { + s->tab[i].hash_prefix = LZW_PREFIX_FREE; + } + for (i = 0; i < 256; i++) { + h = hash(0, i); + s->tab[h].code = i; + s->tab[h].suffix = i; + s->tab[h].hash_prefix = LZW_PREFIX_EMPTY; + } + s->tabsize = 258; +} + +/** + * Calculate number of bytes written + * @param s LZW encode state + * @return Number of bytes written + */ +static SINT32 writtenBytes(LZWEncoderState *s){ + int ret = put_bits_count(&s->pb) >> 3; + ret -= s->output_bytes; + s->output_bytes += ret; + return ret; +} + + +CmsRet cmsLzw_initEncoder(LZWEncoderState **p, UINT8 *outbuf, UINT32 outsize) +{ + LZWEncoderState *s; + + *p = (LZWEncoderState *) cmsMem_alloc(sizeof(LZWEncoderState), ALLOC_ZEROIZE); + if (*p == NULL) + { + cmsLog_error("could not allocate %d bytes for encoder state", sizeof(LZWEncoderState)); + return CMSRET_RESOURCE_EXCEEDED; + } + else + { + cmsLog_debug("%d bytes allocated for encoder state", sizeof(LZWEncoderState)); + } + + s = *p; + + s->clear_code = 256; + s->end_code = 257; + s->maxbits = LZW_MAXBITS; + init_put_bits(&s->pb, outbuf, outsize); + s->bufsize = outsize; + cmsAst_assert(9 <= s->maxbits && s->maxbits <= s->maxbits); + s->maxcode = 1 << s->maxbits; + s->output_bytes = 0; + s->last_code = LZW_PREFIX_EMPTY; + s->bits = 9; + + return CMSRET_SUCCESS; +} + + +int cmsLzw_encode(LZWEncoderState *s, const UINT8 *inbuf, UINT32 insize) +{ + UINT32 i; + UINT32 round_error=5; + + // printf("size check, insize*3=%d outbuf*2=%d\n", insize * 3, s->bufsize * 2); + if(insize * 3 > (UINT32) (s->bufsize - s->output_bytes) * 2 + round_error){ + cmsLog_error("size check failed, insize=%d (*3) outsize=%d (*2)", insize, (s->bufsize - s->output_bytes)); + return -1; + } + + if (s->last_code == LZW_PREFIX_EMPTY) + clearTable(s); + + for (i = 0; i < insize; i++) { + uint8_t c = *inbuf++; + int code = findCode(s, c, s->last_code); + + // printf("\n\n[%d] c=%c code=%d\n", i, c, code); + if (s->tab[code].hash_prefix == LZW_PREFIX_FREE) { + writeCode(s, s->last_code); + addCode(s, c, s->last_code, code); + code= hash(0, c); + } + s->last_code = s->tab[code].code; + if (s->tabsize >= s->maxcode - 1) { + clearTable(s); + } + } + + return writtenBytes(s); +} + + +SINT32 cmsLzw_flushEncoder(LZWEncoderState * s) +{ + if (s->last_code != -1) + writeCode(s, s->last_code); + + writeCode(s, s->end_code); + flush_put_bits(&s->pb); + s->last_code = -1; + + return writtenBytes(s); +} + + +void cmsLzw_cleanupEncoder(LZWEncoderState **s) +{ + cmsMem_free(*s); + *s = NULL; +} + + +#endif /* COMPRESSED_CONFIG_FILE */ +