[Feature][task-view-564][FOTA] add full fota from ftp for zhenkang

Only Configure: No
Affected branch: ZK-first-oem-release
Affected module: FOTA
Is it affected on both ZXIC and MTK: only MTK
Self-test: Yes
Doc Update: No

Change-Id: I94df8adf40986cb761f182862c502a024955f707
diff --git a/LYNQ_PUBLIC/IC_meta/mtk/2735/liblynq-ftp-fota/liblynq-ftp-fota.bb b/LYNQ_PUBLIC/IC_meta/mtk/2735/liblynq-ftp-fota/liblynq-ftp-fota.bb
new file mode 100755
index 0000000..37e4e31
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_meta/mtk/2735/liblynq-ftp-fota/liblynq-ftp-fota.bb
@@ -0,0 +1,66 @@
+inherit externalsrc package
+
+DESCRIPTION = "lynq-fota.so demo"
+SECTION = "base"
+#LICENSE = "MediaTekProprietary"
+LICENSE = "CLOSED"
+LIC_FILES_CHKSUM = "file://LICENSE;md5=e1696b147d49d491bcb4da1a57173fff"
+
+DEPENDS += "bootctrl nandapi liblynq-protcl liblynq-log liblynq-uci zlib"
+
+inherit workonsrc
+WORKONSRC = "${TOPDIR}/../LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota"
+
+TARGET_CC_ARCH += "${LDFLAGS}"
+BB_INCLUDE_ADD = "--sysroot=${STAGING_DIR_HOST}"
+BB_LDFLAGS_ADD = "--sysroot=${STAGING_DIR_HOST} -Wl,--hash-style=gnu"
+#Parameters passed to do_compile()
+EXTRA_OEMAKE = "'RAT_CONFIG_C2K_SUPPORT = ${RAT_CONFIG_C2K_SUPPORT}'\
+                'MTK_MULTI_SIM_SUPPORT = ${MTK_MULTI_SIM_SUPPORT}'\
+                'TARGET_PLATFORM = ${TARGET_PLATFORM}'"
+
+
+FILES_${PN} = "${base_libdir}/*.so \
+               ${base_bindir}\
+               ${base_sbindir}"
+
+
+FILES_${PN}-dev = "/test \
+                   ${includedir}"
+
+FILES_${PN}-doc = "/doc"
+
+FILES_${PN}-dbg ="${base_bindir}/.debug \
+                  ${base_libdir}/.debug \
+                  ${base_sbindir}/.debug"
+
+INSANE_SKIP_${PN} += "already-stripped"
+INSANE_SKIP_${PN} += "installed-vs-shipped"
+
+
+#INHIBIT_PACKAGE_STRIP = "1"
+do_compile () {
+	if [ "${PACKAGE_ARCH}" = "cortexa7hf-vfp-vfpv4-neon" ]; then
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -Os -mhard-float -Wl,--hash-style=gnu -DTELEPHONYWARE"
+	elif [ "${PACKAGE_ARCH}" = "cortexa7hf-neon-vfpv4" ]; then
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -Os -mhard-float -Wl,--hash-style=gnu -DTELEPHONYWARE"
+	elif [ "${PACKAGE_ARCH}" = "cortexa53hf-neon-fp-armv8" ]; then
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -Os -mhard-float -Wl,--hash-style=gnu -DTELEPHONYWARE -mhard-float -mfpu=neon-fp-armv8 -mfloat-abi=hard -mcpu=cortex-a53 -mtune=cortex-a53"
+	else
+		oe_runmake all ROOT=${STAGING_DIR_HOST} OFLAGS="--sysroot=${STAGING_DIR_HOST} -Os -Wl,--hash-style=gnu -DTELEPHONYWARE"
+	fi
+}
+
+do_install () {
+    oe_runmake install ROOT=${D}
+
+    if [ -d "${WORKONSRC}" ] ; then
+        install -d ${D}${includedir}/
+        cp -af ${S}/include/ ${D}${includedir}/
+      fi
+}
+
+addtask bachclean
+do_bachclean () {
+    oe_runmake clean
+}
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/MD5/base64.c b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/MD5/base64.c
new file mode 100644
index 0000000..16db0fd
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/MD5/base64.c
@@ -0,0 +1,132 @@
+// SPDX-License-Identifier: BSD-2-Clause
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ */
+#include "base64.h"
+
+static const char base64_table[] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+size_t base64_enc_len(size_t size)
+{
+	return 4 * ((size + 2) / 3) + 1;
+}
+
+bool base64_enc(const void *data, size_t dlen, char *buf, size_t *blen)
+{
+	size_t n;
+	size_t boffs = 0;
+	const char *d = data;
+
+	n = base64_enc_len(dlen);
+	if (*blen < n) {
+		*blen = n;
+		return false;
+	}
+
+	for (n = 0; n < dlen; n += 3) {
+		uint32_t igrp;
+
+		igrp = d[n];
+		igrp <<= 8;
+
+		if ((n + 1) < dlen)
+			igrp |= d[n + 1];
+		igrp <<= 8;
+
+		if ((n + 2) < dlen)
+			igrp |= d[n + 2];
+
+		buf[boffs] = base64_table[(igrp >> 18) & 0x3f];
+		buf[boffs + 1] = base64_table[(igrp >> 12) & 0x3f];
+		if ((n + 1) < dlen)
+			buf[boffs + 2] = base64_table[(igrp >> 6) & 0x3f];
+		else
+			buf[boffs + 2] = '=';
+		if ((n + 2) < dlen)
+			buf[boffs + 3] = base64_table[igrp & 0x3f];
+		else
+			buf[boffs + 3] = '=';
+
+		boffs += 4;
+	}
+	buf[boffs++] = '\0';
+
+	*blen = boffs;
+	return true;
+}
+
+static bool get_idx(char ch, uint8_t *idx)
+{
+	size_t n;
+
+	for (n = 0; base64_table[n] != '\0'; n++) {
+		if (ch == base64_table[n]) {
+			*idx = n;
+			return true;
+		}
+	}
+	return false;
+}
+
+bool base64_dec(const char *data, size_t size, void *buf, size_t *blen)
+{
+	size_t n;
+	uint8_t idx;
+	uint8_t *b = buf;
+	size_t m = 0;
+	size_t s = 0;
+
+	for (n = 0; n < size && data[n] != '\0'; n++) {
+		if (data[n] == '=')
+			break;	/* Reached pad characters, we're done */
+
+		if (!get_idx(data[n], &idx))
+			continue;
+
+		if (m > *blen)
+			b = NULL;
+
+		switch (s) {
+		case 0:
+			if (b)
+				b[m] = idx << 2;
+			s++;
+			break;
+		case 1:
+			if (b)
+				b[m] |= idx >> 4;
+			m++;
+			if (m > *blen)
+				b = NULL;
+			if (b)
+				b[m] = (idx & 0xf) << 4;
+			s++;
+			break;
+		case 2:
+			if (b)
+				b[m] |= idx >> 2;
+			m++;
+			if (m > *blen)
+				b = NULL;
+			if (b)
+				b[m] = (idx & 0x3) << 6;
+			s++;
+			break;
+		case 3:
+			if (b)
+				b[m] |= idx;
+			m++;
+			s = 0;
+			break;
+		default:
+			return false;	/* "Can't happen" */
+		}
+	}
+	/* We don't detect if input was bad, but that's OK with the spec. */
+	*blen = m;
+	if (b)
+		return true;
+	else
+		return false;
+}
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/MD5/md5.c b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/MD5/md5.c
new file mode 100755
index 0000000..5dd9ff3
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/MD5/md5.c
@@ -0,0 +1,161 @@
+#include "string.h"
+#include "md5.h"
+
+unsigned char PADDING[]={0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+void MD5Init(MD5_CTX *context)
+{
+	context->count[0] = 0;
+	context->count[1] = 0;
+	context->state[0] = 0x67452301;
+	context->state[1] = 0xEFCDAB89;
+	context->state[2] = 0x98BADCFE;
+	context->state[3] = 0x10325476;
+}
+void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen)
+{
+	unsigned int i = 0,index = 0,partlen = 0;
+	index = (context->count[0] >> 3) & 0x3F;
+	partlen = 64 - index;
+	context->count[0] += inputlen << 3;
+	if(context->count[0] < (inputlen << 3))
+		context->count[1]++;
+	context->count[1] += inputlen >> 29;
+
+	if(inputlen >= partlen)
+	{
+		memcpy(&context->buffer[index],input,partlen);
+		MD5Transform(context->state,context->buffer);
+		for(i = partlen;i+64 <= inputlen;i+=64)
+			MD5Transform(context->state,&input[i]);
+		index = 0;        
+	}  
+	else
+	{
+		i = 0;
+	}
+	memcpy(&context->buffer[index],&input[i],inputlen-i);
+}
+void MD5Final(MD5_CTX *context,unsigned char digest[16])
+{
+	unsigned int index = 0,padlen = 0;
+	unsigned char bits[8];
+	index = (context->count[0] >> 3) & 0x3F;
+	padlen = (index < 56)?(56-index):(120-index);
+	MD5Encode(bits,context->count,8);
+	MD5Update(context,PADDING,padlen);
+	MD5Update(context,bits,8);
+	MD5Encode(digest,context->state,16);
+}
+void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len)
+{
+	unsigned int i = 0,j = 0;
+	while(j < len)
+	{
+		output[j] = input[i] & 0xFF;  
+		output[j+1] = (input[i] >> 8) & 0xFF;
+		output[j+2] = (input[i] >> 16) & 0xFF;
+		output[j+3] = (input[i] >> 24) & 0xFF;
+		i++;
+		j+=4;
+	}
+}
+void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len)
+{
+	unsigned int i = 0,j = 0;
+	while(j < len)
+	{
+		output[i] = (input[j]) |
+			(input[j+1] << 8) |
+			(input[j+2] << 16) |
+			(input[j+3] << 24);
+		i++;
+		j+=4; 
+	}
+}
+void MD5Transform(unsigned int state[4],unsigned char block[64])
+{
+	unsigned int a = state[0];
+	unsigned int b = state[1];
+	unsigned int c = state[2];
+	unsigned int d = state[3];
+	unsigned int x[64];
+	MD5Decode(x,block,64);
+	FF(a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
+	FF(d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
+	FF(c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
+	FF(b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
+	FF(a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
+	FF(d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
+	FF(c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
+	FF(b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
+	FF(a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
+	FF(d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
+	FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
+	FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
+	FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
+	FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
+	FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
+	FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
+
+	/* Round 2 */
+	GG(a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
+	GG(d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
+	GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
+	GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
+	GG(a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
+	GG(d, a, b, c, x[10], 9,  0x2441453); /* 22 */
+	GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
+	GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
+	GG(a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
+	GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
+	GG(c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
+	GG(b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
+	GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
+	GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
+	GG(c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
+	GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
+
+	/* Round 3 */
+	HH(a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
+	HH(d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
+	HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
+	HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
+	HH(a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
+	HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
+	HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
+	HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
+	HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
+	HH(d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
+	HH(c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
+	HH(b, c, d, a, x[ 6], 23,  0x4881d05); /* 44 */
+	HH(a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
+	HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
+	HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
+	HH(b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
+
+	/* Round 4 */
+	II(a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
+	II(d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
+	II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
+	II(b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
+	II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
+	II(d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
+	II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
+	II(b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
+	II(a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
+	II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
+	II(c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
+	II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
+	II(a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
+	II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
+	II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
+	II(b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+}
\ No newline at end of file
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/MD5/md5_encode.c b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/MD5/md5_encode.c
new file mode 100755
index 0000000..918d634
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/MD5/md5_encode.c
@@ -0,0 +1,264 @@
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <log/log.h>
+//xf.li@20230822 add for ab recover start
+#include <errno.h>
+//xf.li@20230822 add for ab recover end
+#include "md5.h"
+#include "mtk_device_wrap.h"
+#include "liblog/lynq_deflog.h"
+#define LOG_TAG "LYNQ_FOTA"
+
+int ota_file_open(char* path, char* flag)
+{
+#if 1
+	if(strcmp(flag, "r") == 0 || strcmp(flag, "rb") == 0)
+		return mtk_device_wrap_open(path, O_RDONLY);
+	else if(strcmp(flag, "r+") == 0 || strcmp(flag, "rb+") == 0)
+		return mtk_device_wrap_open(path, O_RDWR | O_CREAT);
+	else if(strcmp(flag, "w+") == 0 ||strcmp(flag, "wb+") == 0 || strcmp(flag, "w") == 0  || strcmp(flag, "wb") == 0 )	
+		return mtk_device_wrap_open(path, O_RDWR | O_CREAT | O_TRUNC);
+	else if(strcmp(flag, "a+") == 0 ||strcmp(flag, "ab+") == 0 || strcmp(flag, "a") == 0  || strcmp(flag, "ab") == 0 )	
+		return mtk_device_wrap_open(path, O_RDWR | O_CREAT | O_APPEND);	
+#endif
+}
+
+
+int ota_file_seek(int handle, int offset,  int flag)
+{
+	return mtk_device_wrap_seek(handle,offset,flag);
+}
+
+
+
+int ota_file_read(char* buffer, size_t count, int file)
+{
+	return mtk_device_wrap_read(file,buffer,count);
+}
+
+
+
+void ota_file_close(int handle)
+{
+	mtk_device_wrap_close(handle);
+}
+
+#define MD5_READ_BUFFER_LEN 4*1024
+int lynq_md5_file_verfy(char* filePath, char* file_md5)
+{
+	int ret = -1;
+	int handle;
+
+	LYVERBLOG("[+MD5]:calc file md5: %s\n", filePath);
+	handle = open(filePath, O_RDONLY);	
+	LYVERBLOG("[+MD5]:handle:%d\n",handle);
+	if(handle >= 0){
+		{
+			int read_len = 0; 
+			unsigned char buffer[MD5_READ_BUFFER_LEN] = {0};
+			unsigned char decrypt[16];
+			int i;
+			MD5_CTX md5;  
+			MD5Init(&md5);
+			//strcpy(buffer,"12345");
+			while ((read_len = read(handle,buffer, MD5_READ_BUFFER_LEN)) > 0)
+			{   
+				//printf("readlen:%d\n",read_len);
+				MD5Update(&md5, (unsigned char*)buffer, read_len); 				
+				memset(buffer,0,sizeof(buffer));
+			}
+			MD5Final(&md5, (unsigned char*)decrypt);
+			memset(buffer, 0, MD5_READ_BUFFER_LEN);
+			for(i = 0; i < 16; i++)  
+			{  
+				sprintf((char*)(buffer + i * 2), "%02x",decrypt[i]);  
+			}
+			LYVERBLOG("[+MD5]:md5:%s\n", buffer);
+			LYVERBLOG("[+MD5]:md5:%s\n", file_md5);
+			
+			ret = strncmp((const char*)buffer, (const char*)file_md5,32);
+			LYVERBLOG("[+MD5]:ret:%d\n", ret);
+		}
+		close(handle);
+	}
+	return ret;
+}
+//xf.li@20230822 add for ab recover start
+#define MD5_VERFY_ERROR 5
+int lynq_md5_file_verfy_ab(char* filePath, char* file_md5)
+{
+	int ret = -1;
+	int handle;
+
+	RLOGD("[+MD5]:calc file md5: %s\n", filePath);
+	handle = open(filePath, O_RDONLY);	
+	RLOGD("[+MD5]:handle:%d\n",handle);
+	if(handle == -1)
+	{
+		RLOGD("[+MD5]: can't open the file, errno is %d\n",errno);
+	}
+	if(handle >= 0)
+	{
+		int read_len = 0; 
+		unsigned char buffer[MD5_READ_BUFFER_LEN] = {0};
+		unsigned char decrypt[16];
+		int i;
+		MD5_CTX md5;  
+		MD5Init(&md5);
+		while ((read_len = read(handle,buffer, MD5_READ_BUFFER_LEN)) > 0)
+		{   
+			MD5Update(&md5, (unsigned char*)buffer, read_len); 				
+			memset(buffer,0,sizeof(buffer));
+			usleep(1000);
+		}
+		MD5Final(&md5, (unsigned char*)decrypt);
+		memset(buffer, 0, MD5_READ_BUFFER_LEN);
+		for(i = 0; i < 16; i++)  
+		{  
+			sprintf((char*)(buffer + i * 2), "%02x",decrypt[i]);  
+		}
+		RLOGD("[+MD5]:buffer md5:%s\n", buffer);
+		RLOGD("[+MD5]:file_md5 md5:%s\n", file_md5);
+		
+		ret = strncmp((const char*)buffer, (const char*)file_md5,32);
+		RLOGD("[+MD5]:ret:%d\n", ret);
+		close(handle);
+	}
+	if(ret != 0)
+	{
+		return MD5_VERFY_ERROR;
+	}
+	return ret;
+}
+int calculate_file_md5_value(char* filePath, unsigned char buffer_out[])
+{
+	//int ret = -1;
+	int handle;
+
+	RLOGD("[+MD5]:calc file md5: %s\n", filePath);
+	handle = open(filePath, O_RDONLY);
+	RLOGD("[+MD5]:handle:%d\n",handle);
+	if(handle == -1)
+	{
+		RLOGD("[+MD5]: can't open the file, errno is %d\n",errno);
+	}
+	if(handle >= 0)
+	{
+		int read_len = 0; 
+		unsigned char buffer[MD5_READ_BUFFER_LEN] = {0};
+		unsigned char decrypt[16];
+		int i;
+		MD5_CTX md5;  
+		MD5Init(&md5);
+		while ((read_len = read(handle,buffer, MD5_READ_BUFFER_LEN)) > 0)
+		{   
+			MD5Update(&md5, (unsigned char*)buffer, read_len); 				
+			memset(buffer,0,sizeof(buffer));
+			usleep(1000);
+		}
+		MD5Final(&md5, (unsigned char*)decrypt);
+		memset(buffer, 0, MD5_READ_BUFFER_LEN);
+		for(i = 0; i < 16; i++)  
+		{  
+			sprintf((char*)(buffer + i * 2), "%02x",decrypt[i]);  
+		}
+		RLOGD("[+MD5]: md5 of %s : %s\n", filePath, buffer);
+		memcpy(buffer_out, buffer, MD5_READ_BUFFER_LEN);
+		close(handle);
+	}
+	else
+	{
+		return -1;
+	}
+	return 0;
+}
+
+int lynq_md5_two_file_verfy(char* filePath_1, char* filePath_2)
+{
+	int ret = -1;
+	int handle_1, handle_2;
+	unsigned char buffer_1[MD5_READ_BUFFER_LEN] = {0};
+	unsigned char buffer_2[MD5_READ_BUFFER_LEN] = {0};
+	
+	ret = calculate_file_md5_value(filePath_1, buffer_1);
+	if(ret < 0)
+	{
+		RLOGD("[+MD5]:calculate file1 md5 value ERROE!!!\n");
+		return ret;
+	}
+	ret = calculate_file_md5_value(filePath_2, buffer_2);
+	if(ret < 0)
+	{
+		RLOGD("[+MD5]:calculate file2 md5 value ERROE!!!\n");
+		return ret;
+	}
+	RLOGD("buffer_1 is %s, buffer_2 is %s\n", buffer_1, buffer_2);
+	ret = strncmp((const char*)buffer_1, (const char*)buffer_2, 32);
+	RLOGD("[+MD5]:strncmp ret:%d\n", ret);
+
+	if(ret != 0)
+	{
+		return MD5_VERFY_ERROR;
+	}
+	return 0;
+}
+//xf.li@20230822 add for ab recover end
+#if 0
+int md5_file_verfy_new(char* filePath, char* file_md5,int packe_len)
+{
+	int ret = -1;
+	int handle;
+	int tatal_packe_len = 0;
+
+	LYVERBLOG("[+MD5]:calc file md5: %s\n", filePath);
+	handle = mtk_device_wrap_open(filePath, O_RDONLY);	
+	LYVERBLOG("[+MD5]:handle:%d\n",handle);
+	if(handle >= 0){
+		{
+			int read_len = 0; 
+			unsigned char buffer[MD5_READ_BUFFER_LEN] = {0};
+			unsigned char decrypt[16];
+			int i;
+			MD5_CTX md5;  
+			MD5Init(&md5);
+			//strcpy(buffer,"12345");
+			tatal_packe_len = packe_len;
+			LYVERBLOG("[+MD5]:tatal_packe_len:%d\n", tatal_packe_len);
+			while ((read_len = mtk_device_wrap_read(handle,buffer, MD5_READ_BUFFER_LEN)) > 0)
+			{   
+				//printf("readlen:%d\n",read_len);
+				if(tatal_packe_len >= read_len)
+				{
+					MD5Update(&md5, (unsigned char*)buffer, read_len); 
+					tatal_packe_len -= read_len;
+				}
+				else if(tatal_packe_len > 0)
+				{
+					LYVERBLOG("[+MD5]:tatal_packe_len:%d\n", tatal_packe_len);
+					MD5Update(&md5, (unsigned char*)buffer, tatal_packe_len); 
+					tatal_packe_len -= read_len;
+				}
+				LYVERBLOG("[+MD5]:tatal_packe_len:%d\n", tatal_packe_len);			
+				memset(buffer,0,sizeof(buffer));
+			}
+			MD5Final(&md5, (unsigned char*)decrypt);
+			memset(buffer, 0, MD5_READ_BUFFER_LEN);
+			for(i = 0; i < 16; i++)  
+			{  
+				sprintf((char*)(buffer + i * 2), "%02x",decrypt[i]);  
+			}
+			LYVERBLOG("[+MD5]:md5:%s\n", buffer);
+			LYVERBLOG("[+MD5]:md5:%s\n", file_md5);
+			
+			ret = strncmp((const char*)buffer, (const char*)file_md5,32);
+			LYVERBLOG("[+MD5]:ret:%d\n", ret);
+		}
+		mtk_device_wrap_close(handle);
+	}
+	return ret;
+}
+#endif
\ No newline at end of file
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/base64.h b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/base64.h
new file mode 100644
index 0000000..a341175
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/base64.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (c) 2014, STMicroelectronics International N.V.
+ */
+#ifndef BASE64_H
+#define BASE64_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool base64_enc(const void *data, size_t size, char *buf, size_t *blen);
+bool base64_dec(const char *data, size_t size, void *buf, size_t *blen);
+size_t base64_enc_len(size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BASE64_H */
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/iot_rock.h b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/iot_rock.h
new file mode 100755
index 0000000..37b3c3e
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/iot_rock.h
@@ -0,0 +1,114 @@
+#ifndef _IOT_ROCK_H_

+#define _IOT_ROCK_H_

+

+#include <sys/types.h>

+#include <sys/stat.h>

+#include <fcntl.h>

+#include <unistd.h>

+

+/* public */

+

+#define E_ROCK_SUCCESS (0)

+#define E_ROCK_INVALID_DELTA (-1)

+#define E_ROCK_DELTA_MISMATCH (-2)

+#define E_ROCK_DELTA_CHUNK_MISMATCH (-3)

+#define E_ROCK_READ_DELTA_ERROR (-4)

+#define E_ROCK_READ_BLOCK_ERROR (-11)

+#define E_ROCK_WRITE_BLOCK_ERROR (-12)

+#define E_ROCK_RAM_NOT_ENOUGH (-20)

+#define E_ROCK_INVALID_CTX	(-30)

+#define E_ROCK_FOTA_ADDR (-50)

+

+#define MAX_OTA_ROLE   (128) 

+#define REAL_OTA_ROLE  (32)

+

+#define MODE_NORMAL           0

+#define MODE_A2B              1

+#define MODE_B2A              2

+

+#define WAIT            0xff

+#define PASS             0

+#define ERROR           -1

+

+typedef struct {

+	void* user_context;

+	unsigned int rom_base;	// old rom start

+	unsigned char* ram_base;	// ram working buffer start

+	unsigned int ram_len; 		// ram working buffer len

+

+	unsigned int backup_base;	// ram backup storage start

+	unsigned int backup_len; 		// ram backup storage len

+

+	unsigned int update_nvram;	// nvram update flag

+

+	int read_rom_directly;

+	int first_run;

+} IOT_UPDATA_CONTEXT;

+

+

+

+

+typedef struct {

+

+    char fota_flag[32];	    //fota 标志保留 

+    int  update_result;     //升级结果

+	int  ota_run;            //  

+	char cid[32];

+	char did[32];

+} UPDATE_INFO;

+

+

+typedef struct {

+	int  need_update;

+    int  check_delta;

+    int  check_rom;

+	int  update_result;

+	

+} UPDATE_STATUS;

+

+

+typedef struct {

+	int  ota_run;

+    UPDATE_STATUS  update_status[MAX_OTA_ROLE];

+	int  update_result;

+	int  switch_slot;

+	

+} OTA_STATUS;

+

+

+

+

+

+//#define DELTA_HEARD_SIZE	(4*5)

+

+//#define DELTA_HEARD_SIZE	    (4*11 + 4*11)

+#define DELTA_HEARD_SIZE	    512

+#define DELTA_FULL_HEARD_SIZE   8

+

+

+

+int iot_patch(IOT_UPDATA_CONTEXT* update_ctx);

+int lynq_read_process(void);

+unsigned int iot_hash(unsigned char *buf,unsigned int len, unsigned int* value);

+int lynq_md5_file_verfy(char* filePath, char* file_md5);

+//xf.li@20230822 add for ab recover start

+int lynq_md5_file_verfy_ab(char* filePath, char* file_md5);

+int calculate_file_md5_value(char* filePath, unsigned char buffer_out[]);

+int lynq_md5_two_file_verfy(char* filePath_1, char* filePath_2);

+//xf.li@20230822 add for ab recover end

+//int md5_file_verfy_new(char* filePath, char* file_md5,int packe_len);

+int lynq_rock_main(int first_run);

+int lynq_fota_func(void);

+int lynq_nand_open(const char *pathname, int flags);

+ssize_t lynq_nand_read(int fd, void *buf, size_t count);

+ssize_t lynq_nand_write(int fd, void *buf, size_t count);

+int lynq_nand_close(int fd);

+int lynq_get_upgrade_status(void);

+void lynq_reboot_device(void);

+int lynq_fota_nrestart(void);

+int lynq_fota_set_addr_value(char *value,int size);

+int lynq_fota_get_addr_value(char *tmp);

+#endif

+

+

+

diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/iot_rock_ipl.h b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/iot_rock_ipl.h
new file mode 100755
index 0000000..77c7c2a
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/iot_rock_ipl.h
@@ -0,0 +1,22 @@
+#ifndef _IOT_ROCK_IPL_H_

+#define _IOT_ROCK_IPL_H_

+

+void rock_trace(void* ctx, const char* fmt, ...);

+void rock_progress(void* ctx, int percent);

+int rock_read_block(void* ctx, unsigned char* dest, unsigned int start, unsigned int size);

+int rock_read_delta(void* ctx, unsigned char* dest, unsigned int offset, unsigned int size);

+int rock_write_block(void* ctx, unsigned char* src, unsigned int start, unsigned int size);

+int rock_process_block(void* ctx, unsigned char* data, unsigned int start, unsigned int size);

+int rock_get_blocksize(void* ctx);

+

+int rock_read_file(void* ctx,  void* name, unsigned char* dest, unsigned int offset, unsigned int size);

+int rock_write_file(void* ctx,  void* name, unsigned char* src, unsigned int offset, unsigned int size);

+

+int rock_delete_file(void* ctx, void* name);

+

+int rock_fatal(void* ctx, int error_code);

+

+int rock_mismatch(void* ctx, unsigned char* buf, unsigned int start, unsigned int size, 

+							unsigned int source_hash,unsigned int target_hash);

+#endif

+

diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/lynq_fota_file.h b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/lynq_fota_file.h
new file mode 100755
index 0000000..0193de6
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/lynq_fota_file.h
@@ -0,0 +1,18 @@
+#ifndef LYNQ_FOTA_FILE_H
+#define LYNQ_FOTA_FILE_H
+
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int lynq_fota_open(const char * pathname,  const char * file_name, int flags);
+ssize_t lynq_fota_read(int fd, void *buf, size_t count);
+int lynq_fota_close(int fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LYNQ_FOTA_FILE_H
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/md5.h b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/md5.h
new file mode 100755
index 0000000..f0e3a1b
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/md5.h
@@ -0,0 +1,48 @@
+#ifndef MD5_H
+#define MD5_H
+
+typedef struct
+{
+	unsigned int count[2];
+	unsigned int state[4];
+	unsigned char buffer[64];   
+}MD5_CTX;
+
+
+#define F(x,y,z) ((x & y) | (~x & z))
+#define G(x,y,z) ((x & z) | (y & ~z))
+#define H(x,y,z) (x^y^z)
+#define I(x,y,z) (y ^ (x | ~z))
+#define ROTATE_LEFT(x,n) ((x << n) | (x >> (32-n)))
+#define FF(a,b,c,d,x,s,ac) \
+{ \
+	a += F(b,c,d) + x + ac; \
+	a = ROTATE_LEFT(a,s); \
+	a += b; \
+}
+#define GG(a,b,c,d,x,s,ac) \
+{ \
+	a += G(b,c,d) + x + ac; \
+	a = ROTATE_LEFT(a,s); \
+	a += b; \
+}
+#define HH(a,b,c,d,x,s,ac) \
+{ \
+	a += H(b,c,d) + x + ac; \
+	a = ROTATE_LEFT(a,s); \
+	a += b; \
+}
+#define II(a,b,c,d,x,s,ac) \
+{ \
+	a += I(b,c,d) + x + ac; \
+	a = ROTATE_LEFT(a,s); \
+	a += b; \
+}                                            
+void MD5Init(MD5_CTX *context);
+void MD5Update(MD5_CTX *context,unsigned char *input,unsigned int inputlen);
+void MD5Final(MD5_CTX *context,unsigned char digest[16]);
+void MD5Transform(unsigned int state[4],unsigned char block[64]);
+void MD5Encode(unsigned char *output,unsigned int *input,unsigned int len);
+void MD5Decode(unsigned int *output,unsigned char *input,unsigned int len);
+
+#endif
\ No newline at end of file
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/md5_encode.h b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/md5_encode.h
new file mode 100755
index 0000000..c3e5d38
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/md5_encode.h
@@ -0,0 +1,33 @@
+#ifndef MD5_ENCODE_H_
+#define MD5_ENCODE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+//打开文件
+int ota_file_open(char* path, char* flag);
+//文件偏移位置
+int ota_file_seek(int handle, int offset,  int flag);
+//读文件内容
+int ota_file_read(char* buffer, size_t count, int file);
+//关闭文件
+void ota_file_close(int handle);
+
+
+/*** 
+ * @description:                校验文件的MD5
+ * @param filePath              文件路径
+ * @param file_md5              待校验MD5值
+ * @return  		0:校验成功;  其他:校验失败 
+ */
+int md5_file_verfy(char* filePath, char* file_md5);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/sha.h b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/sha.h
new file mode 100755
index 0000000..ea0c773
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/include/sha.h
@@ -0,0 +1,78 @@
+/* sha.h
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of Google Inc. nor the names of its contributors may
+**       be used to endorse or promote products derived from this software
+**       without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _EMBEDDED_SHA_H_
+#define _EMBEDDED_SHA_H_
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct SHA_CTX {
+    uint64_t count;
+    uint32_t state[5];
+#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+    union {
+        uint8_t b[64];
+        uint32_t w[16];
+    } buf;
+#else
+    uint8_t buf[64];
+#endif
+} SHA_CTX;
+
+void SHA_init(SHA_CTX* ctx);
+void SHA_update(SHA_CTX* ctx, const void* data, int len);
+const uint8_t* SHA_final(SHA_CTX* ctx);
+
+/* Convenience method. Returns digest parameter value. */
+const uint8_t* SHA(const void* data, int len, uint8_t* digest);
+
+#define SHA_DIGEST_SIZE 20
+
+typedef enum check_status_t{
+	ERROR_SHA = -3,			// sha1输入参数错误
+	PATCH_ERR = -2,			// 检测hash既不等于source_hash也不等于target_hash, 一般错误情况
+	NOT_EXIST_FILE = -1,	// 检测文件不存在
+	SOURCE_SUCC = 0,		// 检测hash等于目标source_hash, 一般正常情况
+	PATCH_SUCC = 1,			// 检测hash等于目标target_hash, up to data
+}Check_status;
+
+int ParseSha1(const char* str, uint8_t* digest);
+
+const uint8_t* ROCK_SHA(const char *file_name, uint8_t *digest);
+const uint8_t* ROCK_SHA_FILE(int fd_sha, int offset,int totle_size, uint8_t *digest);
+const uint8_t* ROCK_SHA_FILE_COMMON(int fd_sha, int offset,int totle_size, uint8_t *digest);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/makefile b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/makefile
new file mode 100755
index 0000000..767c3f9
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/makefile
@@ -0,0 +1,85 @@
+SHELL = /bin/sh
+RM = rm -f
+
+LOCAL_CFLAGS := -Wall \
+                -g -Os \
+                -flto \
+                -fpermissive \
+                -DRIL_SHLIB \
+                -DATCI_PARSE \
+                -DKEEP_ALIVE \
+                -D__LINUX_OS__ \
+                -DECALL_SUPPORT
+
+CFLAGS += -fPIC -O2 $(INCLUDE) -D_LARGEFILE64_SOURCE
+
+$(warning ################# rock ROOT: $(ROOT),includedir:$(includedir))
+LOCAL_PATH   = .
+
+LOCAL_C_INCLUDES = \
+  -I. \
+  -I./include \
+  -I$(LOCAL_PATH)/../include \
+  -I$(ROOT)$(includedir)/logger \
+  -I$(ROOT)$(includedir)/liblog \
+  -I$(ROOT)$(includedir)/ftp \
+  -I$(ROOT)$(includedir)/glib-2.0 \
+  -I$(ROOT)$(libdir)/glib-2.0/include \
+
+
+
+LOCAL_LIBS := \
+    -L. \
+    -L./lib \
+    -ldl \
+    -lpthread \
+    -llog \
+    -lstdc++ \
+    -lnandapi  \
+    -lbootctrl  \
+    -llynq-log \
+    -llynq-protcl \
+    -llynq-uci \
+    -lz
+
+SOURCES = $(wildcard *.c wildcard *.h rock_ua/*.c  MD5/*c rock_ua/*.cpp)
+
+EXECUTABLE = liblynq-ftp-fota.so
+
+OBJECTS=$(SOURCES:.c=.o)
+
+CPP_SOURCES = $(wildcard rock_ua/*.cpp)
+
+
+CPP_OBJECTS=$(CPP_SOURCES:.cpp=.o)
+
+.PHONY: build clean install pack_rootfs 
+
+all: build
+$(EXECUTABLE): $(OBJECTS) $(CPP_OBJECTS)
+	$(CXX) -shared -Wl,--no-undefined $(OBJECTS) $(LOCAL_LIBS) $(CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_C_INCLUDES) -o $@
+
+%.o : %.c
+	$(CC) $(LOCAL_C_INCLUDES) $(CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_LIBS) -o $@ -c $< 
+
+%.o : %.cpp
+	$(CXX) $(LOCAL_C_INCLUDES) $(CFLAGS) $(LOCAL_CFLAGS) $(LOCAL_LIBS) -o $@ -c $<
+
+build:  $(EXECUTABLE)
+	$(warning ########## build $(EXECUTABLE)  ##########)
+
+install:
+	mkdir -p $(ROOT)$(base_libdir)/
+	install $(EXECUTABLE) $(ROOT)$(base_libdir)/
+	mkdir -p $(ROOT)$(includedir)/$(NAME)/sdk
+
+pack_rootfs:
+	mkdir -p $(PACK_INITRAMFS_TO)$(base_libdir)/
+	cp -af $(EXECUTABLE) $(PACK_INITRAMFS_TO)$(base_libdir)/
+	$(CROSS)strip $(PACK_INITRAMFS_TO)$(base_libdir)/$(EXECUTABLE)
+	mkdir -p $(PACK_TO)$(base_libdir)/
+	cp -af $(EXECUTABLE) $(PACK_TO)$(base_libdir)/
+	$(CROSS)strip $(PACK_TO)$(base_libdir)/$(EXECUTABLE)
+.PHONY: clean
+clean:
+	$(RM) $(OBJECTS) $(EXECUTABLE)
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/ioapi.c b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/ioapi.c
new file mode 100755
index 0000000..782d324
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/ioapi.c
@@ -0,0 +1,231 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+         Modifications for Zip64 support
+         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+         For more info read MiniZip_info.txt
+
+*/
+
+#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS)))
+        #define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#if defined(__APPLE__) || defined(IOAPI_NO_64) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64)
+// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
+#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
+#define FTELLO_FUNC(stream) ftello(stream)
+#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
+#else
+#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
+#define FTELLO_FUNC(stream) ftello64(stream)
+#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
+#endif
+
+
+#include "ioapi.h"
+
+voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc, const void*filename, int mode) {
+    if (pfilefunc->zfile_func64.zopen64_file != NULL)
+        return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
+    else
+    {
+        return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
+    }
+}
+
+long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) {
+    if (pfilefunc->zfile_func64.zseek64_file != NULL)
+        return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+    else
+    {
+        uLong offsetTruncated = (uLong)offset;
+        if (offsetTruncated != offset)
+            return -1;
+        else
+            return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
+    }
+}
+
+ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc, voidpf filestream) {
+    if (pfilefunc->zfile_func64.zseek64_file != NULL)
+        return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
+    else
+    {
+        uLong tell_uLong = (uLong)(*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
+        if ((tell_uLong) == MAXU32)
+            return (ZPOS64_T)-1;
+        else
+            return tell_uLong;
+    }
+}
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32, const zlib_filefunc_def* p_filefunc32) {
+    p_filefunc64_32->zfile_func64.zopen64_file = NULL;
+    p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
+    p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
+    p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
+    p_filefunc64_32->zfile_func64.ztell64_file = NULL;
+    p_filefunc64_32->zfile_func64.zseek64_file = NULL;
+    p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
+    p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+    p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
+    p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
+    p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+}
+
+
+
+static voidpf ZCALLBACK fopen_file_func(voidpf opaque, const char* filename, int mode) {
+    FILE* file = NULL;
+    const char* mode_fopen = NULL;
+    (void)opaque;
+    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+        mode_fopen = "rb";
+    else
+    if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+        mode_fopen = "r+b";
+    else
+    if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+        mode_fopen = "wb";
+
+    if ((filename!=NULL) && (mode_fopen != NULL))
+        file = fopen(filename, mode_fopen);
+    return file;
+}
+
+static voidpf ZCALLBACK fopen64_file_func(voidpf opaque, const void* filename, int mode) {
+    FILE* file = NULL;
+    const char* mode_fopen = NULL;
+    (void)opaque;
+    if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+        mode_fopen = "rb";
+    else
+    if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+        mode_fopen = "r+b";
+    else
+    if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+        mode_fopen = "wb";
+
+    if ((filename!=NULL) && (mode_fopen != NULL))
+        file = FOPEN_FUNC((const char*)filename, mode_fopen);
+    return file;
+}
+
+
+static uLong ZCALLBACK fread_file_func(voidpf opaque, voidpf stream, void* buf, uLong size) {
+    uLong ret;
+    (void)opaque;
+    ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
+    return ret;
+}
+
+static uLong ZCALLBACK fwrite_file_func(voidpf opaque, voidpf stream, const void* buf, uLong size) {
+    uLong ret;
+    (void)opaque;
+    ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
+    return ret;
+}
+
+static long ZCALLBACK ftell_file_func(voidpf opaque, voidpf stream) {
+    long ret;
+    (void)opaque;
+    ret = ftell((FILE *)stream);
+    return ret;
+}
+
+
+static ZPOS64_T ZCALLBACK ftell64_file_func(voidpf opaque, voidpf stream) {
+    ZPOS64_T ret;
+    (void)opaque;
+    ret = (ZPOS64_T)FTELLO_FUNC((FILE *)stream);
+    return ret;
+}
+
+static long ZCALLBACK fseek_file_func(voidpf opaque, voidpf stream, uLong offset, int origin) {
+    int fseek_origin=0;
+    long ret;
+    (void)opaque;
+    switch (origin)
+    {
+    case ZLIB_FILEFUNC_SEEK_CUR :
+        fseek_origin = SEEK_CUR;
+        break;
+    case ZLIB_FILEFUNC_SEEK_END :
+        fseek_origin = SEEK_END;
+        break;
+    case ZLIB_FILEFUNC_SEEK_SET :
+        fseek_origin = SEEK_SET;
+        break;
+    default: return -1;
+    }
+    ret = 0;
+    if (fseek((FILE *)stream, (long)offset, fseek_origin) != 0)
+        ret = -1;
+    return ret;
+}
+
+static long ZCALLBACK fseek64_file_func(voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) {
+    int fseek_origin=0;
+    long ret;
+    (void)opaque;
+    switch (origin)
+    {
+    case ZLIB_FILEFUNC_SEEK_CUR :
+        fseek_origin = SEEK_CUR;
+        break;
+    case ZLIB_FILEFUNC_SEEK_END :
+        fseek_origin = SEEK_END;
+        break;
+    case ZLIB_FILEFUNC_SEEK_SET :
+        fseek_origin = SEEK_SET;
+        break;
+    default: return -1;
+    }
+    ret = 0;
+
+    if(FSEEKO_FUNC((FILE *)stream, (z_off64_t)offset, fseek_origin) != 0)
+                        ret = -1;
+
+    return ret;
+}
+
+
+static int ZCALLBACK fclose_file_func(voidpf opaque, voidpf stream) {
+    int ret;
+    (void)opaque;
+    ret = fclose((FILE *)stream);
+    return ret;
+}
+
+static int ZCALLBACK ferror_file_func(voidpf opaque, voidpf stream) {
+    int ret;
+    (void)opaque;
+    ret = ferror((FILE *)stream);
+    return ret;
+}
+
+void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def) {
+    pzlib_filefunc_def->zopen_file = fopen_file_func;
+    pzlib_filefunc_def->zread_file = fread_file_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+    pzlib_filefunc_def->ztell_file = ftell_file_func;
+    pzlib_filefunc_def->zseek_file = fseek_file_func;
+    pzlib_filefunc_def->zclose_file = fclose_file_func;
+    pzlib_filefunc_def->zerror_file = ferror_file_func;
+    pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def) {
+    pzlib_filefunc_def->zopen64_file = fopen64_file_func;
+    pzlib_filefunc_def->zread_file = fread_file_func;
+    pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+    pzlib_filefunc_def->ztell64_file = ftell64_file_func;
+    pzlib_filefunc_def->zseek64_file = fseek64_file_func;
+    pzlib_filefunc_def->zclose_file = fclose_file_func;
+    pzlib_filefunc_def->zerror_file = ferror_file_func;
+    pzlib_filefunc_def->opaque = NULL;
+}
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/ioapi.h b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/ioapi.h
new file mode 100755
index 0000000..c588a18
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/ioapi.h
@@ -0,0 +1,210 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+         Modifications for Zip64 support
+         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+         For more info read MiniZip_info.txt
+
+         Changes
+
+    Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
+    Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
+               More if/def section may be needed to support other platforms
+    Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
+                          (but you should use iowin32.c for windows instead)
+
+*/
+
+#ifndef _ZLIBIOAPI64_H
+#define _ZLIBIOAPI64_H
+
+#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
+
+  // Linux needs this to support file operation on files larger then 4+GB
+  // But might need better if/def to select just the platforms that needs them.
+
+        #ifndef __USE_FILE_OFFSET64
+                #define __USE_FILE_OFFSET64
+        #endif
+        #ifndef __USE_LARGEFILE64
+                #define __USE_LARGEFILE64
+        #endif
+        #ifndef _LARGEFILE64_SOURCE
+                #define _LARGEFILE64_SOURCE
+        #endif
+        #ifndef _FILE_OFFSET_BIT
+                #define _FILE_OFFSET_BIT 64
+        #endif
+
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "zlib.h"
+
+#if defined(USE_FILE32API)
+#define fopen64 fopen
+#define ftello64 ftell
+#define fseeko64 fseek
+#else
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__HAIKU__) || defined(MINIZIP_FOPEN_NO_64)
+#define fopen64 fopen
+#define ftello64 ftello
+#define fseeko64 fseeko
+#endif
+#ifdef _MSC_VER
+ #define fopen64 fopen
+ #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
+  #define ftello64 _ftelli64
+  #define fseeko64 _fseeki64
+ #else // old MSC
+  #define ftello64 ftell
+  #define fseeko64 fseek
+ #endif
+#endif
+#endif
+
+/*
+#ifndef ZPOS64_T
+  #ifdef _WIN32
+                #define ZPOS64_T fpos_t
+  #else
+    #include <stdint.h>
+    #define ZPOS64_T uint64_t
+  #endif
+#endif
+*/
+
+#ifdef HAVE_MINIZIP64_CONF_H
+#include "mz64conf.h"
+#endif
+
+/* a type chosen by DEFINE */
+#ifdef HAVE_64BIT_INT_CUSTOM
+typedef  64BIT_INT_CUSTOM_TYPE ZPOS64_T;
+#else
+#ifdef HAS_STDINT_H
+#include "stdint.h"
+typedef uint64_t ZPOS64_T;
+#else
+
+
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 ZPOS64_T;
+#else
+typedef unsigned long long int ZPOS64_T;
+#endif
+#endif
+#endif
+
+/* Maximum unsigned 32-bit value used as placeholder for zip64 */
+#ifndef MAXU32
+#define MAXU32 (0xffffffff)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ      (1)
+#define ZLIB_FILEFUNC_MODE_WRITE     (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE   (8)
+
+
+#ifndef ZCALLBACK
+ #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+   #define ZCALLBACK CALLBACK
+ #else
+   #define ZCALLBACK
+ #endif
+#endif
+
+
+
+
+typedef voidpf   (ZCALLBACK *open_file_func)      (voidpf opaque, const char* filename, int mode);
+typedef uLong    (ZCALLBACK *read_file_func)      (voidpf opaque, voidpf stream, void* buf, uLong size);
+typedef uLong    (ZCALLBACK *write_file_func)     (voidpf opaque, voidpf stream, const void* buf, uLong size);
+typedef int      (ZCALLBACK *close_file_func)     (voidpf opaque, voidpf stream);
+typedef int      (ZCALLBACK *testerror_file_func) (voidpf opaque, voidpf stream);
+
+typedef long     (ZCALLBACK *tell_file_func)      (voidpf opaque, voidpf stream);
+typedef long     (ZCALLBACK *seek_file_func)      (voidpf opaque, voidpf stream, uLong offset, int origin);
+
+
+/* here is the "old" 32 bits structure structure */
+typedef struct zlib_filefunc_def_s
+{
+    open_file_func      zopen_file;
+    read_file_func      zread_file;
+    write_file_func     zwrite_file;
+    tell_file_func      ztell_file;
+    seek_file_func      zseek_file;
+    close_file_func     zclose_file;
+    testerror_file_func zerror_file;
+    voidpf              opaque;
+} zlib_filefunc_def;
+
+typedef ZPOS64_T (ZCALLBACK *tell64_file_func)    (voidpf opaque, voidpf stream);
+typedef long     (ZCALLBACK *seek64_file_func)    (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin);
+typedef voidpf   (ZCALLBACK *open64_file_func)    (voidpf opaque, const void* filename, int mode);
+
+typedef struct zlib_filefunc64_def_s
+{
+    open64_file_func    zopen64_file;
+    read_file_func      zread_file;
+    write_file_func     zwrite_file;
+    tell64_file_func    ztell64_file;
+    seek64_file_func    zseek64_file;
+    close_file_func     zclose_file;
+    testerror_file_func zerror_file;
+    voidpf              opaque;
+} zlib_filefunc64_def;
+
+void fill_fopen64_filefunc(zlib_filefunc64_def* pzlib_filefunc_def);
+void fill_fopen_filefunc(zlib_filefunc_def* pzlib_filefunc_def);
+
+/* now internal definition, only for zip.c and unzip.h */
+typedef struct zlib_filefunc64_32_def_s
+{
+    zlib_filefunc64_def zfile_func64;
+    open_file_func      zopen32_file;
+    tell_file_func      ztell32_file;
+    seek_file_func      zseek32_file;
+} zlib_filefunc64_32_def;
+
+
+#define ZREAD64(filefunc,filestream,buf,size)     ((*((filefunc).zfile_func64.zread_file))   ((filefunc).zfile_func64.opaque,filestream,buf,size))
+#define ZWRITE64(filefunc,filestream,buf,size)    ((*((filefunc).zfile_func64.zwrite_file))  ((filefunc).zfile_func64.opaque,filestream,buf,size))
+//#define ZTELL64(filefunc,filestream)            ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
+//#define ZSEEK64(filefunc,filestream,pos,mode)   ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
+#define ZCLOSE64(filefunc,filestream)             ((*((filefunc).zfile_func64.zclose_file))  ((filefunc).zfile_func64.opaque,filestream))
+#define ZERROR64(filefunc,filestream)             ((*((filefunc).zfile_func64.zerror_file))  ((filefunc).zfile_func64.opaque,filestream))
+
+voidpf call_zopen64(const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode);
+long call_zseek64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin);
+ZPOS64_T call_ztell64(const zlib_filefunc64_32_def* pfilefunc,voidpf filestream);
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
+
+#define ZOPEN64(filefunc,filename,mode)         (call_zopen64((&(filefunc)),(filename),(mode)))
+#define ZTELL64(filefunc,filestream)            (call_ztell64((&(filefunc)),(filestream)))
+#define ZSEEK64(filefunc,filestream,pos,mode)   (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/lynq_fota_zip_file.cpp b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/lynq_fota_zip_file.cpp
new file mode 100755
index 0000000..94c3eae
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/lynq_fota_zip_file.cpp
@@ -0,0 +1,91 @@
+#include <iostream>
+#include "zlib.h"
+#include <vector>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include "unzip.h"
+#include "lynq_fota_file.h"
+
+static unzFile g_zip_file = NULL;
+static int g_org_type = 0;
+
+//curl -o test.dat ftp://cv2x:lynq@192.168.1.100:6521/T800_RTK_TMP/fota.delta -r 100-599
+
+static inline int zip_file_to_int()
+{
+    int *p = (int*)&g_zip_file;
+    return *p;
+}
+
+int lynq_fota_open(const char * pathname,  const char * file_name, int flags)
+{
+    g_org_type = 0;
+
+    printf("cy: to pen %s\n", pathname);
+    if (file_name == NULL)
+    {
+        g_org_type = 1;
+        //printf("cy: to open org type %s\n", pathname);
+        return open(pathname, flags);
+    }
+    //printf("cy: org file name %s\n", file_name);
+    g_zip_file = unzOpen(pathname);
+    if (g_zip_file == NULL)
+    {
+        printf("cy: open zip file fail\n");
+        return -1;
+    }
+    if (UNZ_OK != unzLocateFile(g_zip_file, file_name, 0))
+    {
+        //printf("goto file fail [%s]\n", file_name);
+        unzClose(g_zip_file);
+        return -1;
+    }
+    if (UNZ_OK != unzOpenCurrentFile(g_zip_file))
+    {
+        //printf("open file fail\n");
+        unzClose(g_zip_file);
+        return -1;
+    }
+    return zip_file_to_int();
+}
+
+ssize_t lynq_fota_read(int fd, void *buf, size_t count)
+{
+    //printf("cy: read file %d, %d\n", fd, count);
+    if (g_org_type)
+    {
+        return read(fd, buf, count);
+    }
+
+    //printf("cy: read file %d, %d\n", fd, count);
+
+    if (fd != zip_file_to_int())
+        return -1;
+    
+    return unzReadCurrentFile(g_zip_file, buf, count);
+}
+
+ssize_t lynq_fota_write(int fd, const void *buf, size_t count)
+{
+    if (g_org_type)
+    {
+        return write(fd, buf, count);
+    }
+    return -1;
+}
+
+int lynq_fota_close(int fd)
+{
+    //printf("cy: lynq_fota_close %d, %d\n", fd, g_org_type);
+    if (g_org_type)
+    {
+        return close(fd);
+    }
+    g_org_type = 0;
+    if (fd != zip_file_to_int())
+        return -1;
+    unzCloseCurrentFile(g_zip_file);
+    return unzClose(g_zip_file);
+}
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/rock_ua.cpp b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/rock_ua.cpp
new file mode 100755
index 0000000..5fd004f
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/rock_ua.cpp
@@ -0,0 +1,2122 @@
+// 2017-07-31 carota Rock FOTA ua porting file
+
+
+#define ROCK_FOTA_SUPPORT
+
+#ifdef ROCK_FOTA_SUPPORT
+
+
+extern "C" {
+#include "iot_rock.h"
+#include "iot_rock_ipl.h"
+#include "base64.h"
+};
+
+#include "sha.h"
+#include <log/log.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <stdint.h>
+
+
+#include <hardware/boot_control.h>
+#include <hardware/hardware.h>
+#include <sys/reboot.h>
+
+
+
+#include "liblog/lynq_deflog.h"
+#include "mtk_device_wrap.h"
+#include <include/lynq_uci.h>
+#include "lynq_fota_file.h"
+
+#define ROCK_DEFAULT_BLOCK_SIZE 0x40000
+#define ROCK_RAM_LEN  (1024*1024)
+
+#define LOG_TAG "LYNQ_FOTA"
+#define ROCK_BACKUP_LEN ROCK_DEFAULT_BLOCK_SIZE
+
+
+#define FILENAME_SIZE   50
+
+char full_partition_filename[REAL_OTA_ROLE][FILENAME_SIZE];
+
+struct fota_header{
+    unsigned int  delta_head[DELTA_HEARD_SIZE/sizeof(unsigned int)];
+    char full_type[DELTA_FULL_HEARD_SIZE];
+};
+
+struct fota_header g_header;
+
+
+#define FOTA_UCI_MODULE "lynq_fota"
+#define FOTA_UCI_FILE "lynq_uci"
+#define FOTA_UCI_ADDR "lynq_fota_addr"
+#define FOTA_UCI_STATE "lynq_fota_state"
+
+#define FILE_UPDATE_STATE  "/data/.update_status"
+#define FILE_UPDATE_FLAG   "/tmp/update_flag"
+#define FILE_FOTA_STATE    "/data/.fota_status"
+
+#define NAND_PAGE_SIZE  4096
+
+
+#define BOOTDEV_TYPE_NAND 1
+
+#define BACKUP_ADDR_FLAG    0xffffffff
+#define FILE_BACKUP      "/data/.backup"
+
+#define SLOT_A    0
+#define SLOT_B    1
+
+#define FULL_HEAD "full-zip"
+
+//xf.li@20230822 add for ab rollback start
+#define DEV_SYSTEM_A    "/dev/disk/by-partlabel/system_a"
+#define DEV_SYSTEM_B    "/dev/disk/by-partlabel/system_b"
+
+#define DEV_BOOT_A      "/dev/disk/by-partlabel/boot_a"
+#define DEV_BOOT_B      "/dev/disk/by-partlabel/boot_b"
+
+#define DEV_SPM_A      "/dev/disk/by-partlabel/spm_a"
+#define DEV_SPM_B      "/dev/disk/by-partlabel/spm_b"
+
+#define DEV_MD1IMG_A    "/dev/disk/by-partlabel/md1img_a"
+#define DEV_MD1IMG_B    "/dev/disk/by-partlabel/md1img_b"
+
+#define DEV_TEE_A       "/dev/disk/by-partlabel/tee_a"
+#define DEV_TEE_B       "/dev/disk/by-partlabel/tee_b" 
+
+#define DEV_VBMETA_A       "/dev/disk/by-partlabel/vbmeta_a"
+#define DEV_VBMETA_B       "/dev/disk/by-partlabel/vbmeta_b"
+
+#define DEV_BL2_A         "/dev/disk/by-partlabel/bl2_a"
+#define DEV_BL2_B         "/dev/disk/by-partlabel/bl2_b"
+
+#define DEV_BL33_A        "/dev/disk/by-partlabel/bl33_a"
+#define DEV_BL33_B        "/dev/disk/by-partlabel/bl33_b"
+
+#define DEV_MEDMCU_A        "/dev/disk/by-partlabel/medmcu_a"
+#define DEV_MEDMCU_B        "/dev/disk/by-partlabel/medmcu_b"
+
+#define DEV_OEMAPP_A        "/dev/disk/by-partlabel/oemapp_a"
+#define DEV_OEMAPP_B        "/dev/disk/by-partlabel/oemapp_b"
+
+#define DEV_OEMAPP2_A        "/dev/disk/by-partlabel/oemapp2_a"
+#define DEV_OEMAPP2_B        "/dev/disk/by-partlabel/oemapp2_b"
+
+
+#define DEV_MISC        "/dev/disk/by-partlabel/misc"
+
+#define BACKUP_UBI_NUM  31 //max ubi number
+#define MTD_SYSTEM_A 14
+#define MTD_SYSTEM_B 15
+#define MD5_RETRY_TIME 3
+#define MD5_VERFY_ERROR 5
+#define MD5_READ_BUFFER_LEN 4*1024
+#define FOTA_FIRST 0
+#define RECOVER_FIRST 1
+int fota_interrupt = 1;
+//xf.li@20230822 add for ab rollback end
+
+
+//int fd_system_a,fd_system_b,fd_boot_a,fd_boot_b,fd_tee_a,fd_tee_b,fd_bl2,fd_bl33,fd_curr,fd_log,fd_update_status,fd_md1img_a,fd_md1img_b,fd_fota_status,fd_md1dsp_a,fd_md1dsp_b,fd_vbmeta_a,fd_vbmeta_b,fd_oemapp_a,fd_oemapp_b,fd_oemapp2_a,fd_oemapp2_b,fd_medmcu_a,fd_medmcu_b,fd_bl33_a,fd_bl33_b;
+int fd_curr,fd_log,fd_update_status,fd_fota_status;
+int fd_write,fd_read;
+int full_partition_num;
+static unsigned int  delta_offset = 0;
+static unsigned int  now_patch = 0;
+unsigned int  current_slot = 0;
+unsigned char rock_debug_buffer[512];
+
+extern const hw_module_t HAL_MODULE_INFO_SYM;
+boot_control_module_t* module;
+
+static void lynq_init_wake_lock_func(void);
+static void lynq_fota_grab_artial_wake_lock(void);
+static void lynq_fota_release_wake_lock(void);
+int check(int sys_size);
+int check_cpu();
+
+
+#include <string>
+#include <vector>
+
+class PartitionInfo
+{
+public:
+    std::string dest_part_name;
+    std::string org_file_name;
+    unsigned int file_offset;
+    unsigned int part_org_size;
+    unsigned int part_size;
+    unsigned int zip_flag;
+    unsigned int part_index;
+    char part_sha[SHA_DIGEST_SIZE];
+    PartitionInfo(){
+        file_offset = -1;
+        part_org_size = -1;
+        part_size = -1;
+        zip_flag = -1;
+        part_index = -1;
+        dest_part_name = "";
+        org_file_name = "";
+        memset(part_sha, 0 , SHA_DIGEST_SIZE);
+    }
+    PartitionInfo(const PartitionInfo &org){
+        if (this == &org)
+            return;
+        this->file_offset = org.file_offset;
+        this->part_org_size = org.part_org_size;
+        this->part_size = org.part_size;
+        this->zip_flag = org.zip_flag;
+        this->part_index = org.part_index;
+        memcpy(this->part_sha, org.part_sha, SHA_DIGEST_SIZE);
+        this->dest_part_name = org.dest_part_name;
+        this->org_file_name = org.org_file_name;
+    }
+    PartitionInfo& operator=(const PartitionInfo& org) {
+        if (this == &org)
+            return *this;
+        this->file_offset = org.file_offset;
+        this->part_org_size = org.part_org_size;
+        this->part_size = org.part_size;
+        this->zip_flag = org.zip_flag;
+        this->part_index = org.part_index;
+        memcpy(this->part_sha, org.part_sha, SHA_DIGEST_SIZE);
+        this->dest_part_name = org.dest_part_name;
+        this->org_file_name = org.org_file_name;
+        return *this;
+    }
+};
+
+struct partition_desc
+{
+    int part_index;
+    int zip_flag;
+    int part_size;
+    int part_org_size;
+    char sha_value[SHA_DIGEST_SIZE];
+};
+
+std::vector<PartitionInfo> g_lstPartitionInfo;
+std::string g_strFtpAddress;
+
+class FotaTool {
+public:
+    FotaTool() {
+        m_bLockState = false;
+    }
+    ~FotaTool() {
+        if (m_fdFotaFlag >= 0)
+            close(m_fdFotaFlag);
+        ClosePartionFile();
+
+        system("echo fota-interface >/sys/power/wake_unlock");
+        m_bLockState = false;
+    }
+    bool Init() {
+        m_fdFotaFlag = open(FILE_UPDATE_FLAG,O_RDWR | O_CREAT,0777);
+        if (m_fdFotaFlag < 0)
+        {
+            RLOGE("+[UA]: can't open file /tmp/update_flag.\n");
+            return false;
+        }
+        m_strTempFileName = "/tmp/ftp_fota_part";
+        m_fdLocalFile =-1;
+        const hw_module_t* hw_module = &HAL_MODULE_INFO_SYM;
+
+        if (!hw_module ||
+                strcmp(BOOT_CONTROL_HARDWARE_MODULE_ID, hw_module->id) != 0) {
+            RLOGD("+[UA]: Error loading boot_control HAL implementation.\n");
+            return false;
+        }
+
+        module = (boot_control_module_t*)hw_module;
+        module->init(module);
+
+
+        if (module == NULL) {
+            RLOGD("+[UA]: Error getting bootctrl module.\n");
+            return false;
+        }
+
+        lynq_init_wake_lock_func();
+        lynq_fota_grab_artial_wake_lock();
+        /*************    Bootctrl Init  End  *************/
+
+        m_bLockState = true;
+        return m_bLockState;
+    }
+    bool PreparePartionFile(PartitionInfo * pt_info)
+    {
+        int ret, fd;
+        char digest_s[SHA_DIGEST_SIZE];
+        m_pPartitionInfo = pt_info;
+        ClosePartionFile();
+        std::string range = " -r ";
+        if (pt_info->part_size == -1)
+        {
+            range += std::to_string(pt_info->file_offset);
+        }
+        else
+        {
+            range += std::to_string(pt_info->file_offset) + "-" + std::to_string(pt_info->file_offset + pt_info->part_size - 1);
+        }
+        std::string strFtpCmd = "curl -o " + m_strTempFileName + " " + g_strFtpAddress + range;
+
+        ret = system(strFtpCmd.c_str());
+        if (ret < 0)
+        {
+            RLOGE("+[UA]: down load file fail [ %s ]\n", strFtpCmd.c_str());
+            return false;
+        }
+        if (pt_info->org_file_name != "")
+        {
+            memset(digest_s,0,SHA_DIGEST_SIZE);
+
+            fd=open(m_strTempFileName.c_str(),O_RDONLY);
+            ROCK_SHA_FILE_COMMON(fd ,0 ,pt_info->part_size, digest_s);
+            close(fd);
+            if (memcmp(digest_s, pt_info->part_sha, SHA_DIGEST_SIZE) != 0)
+            {
+                RLOGE("+[UA]: sha check fail [ %s ]\n", pt_info->org_file_name.c_str());
+                return false;
+            }
+        }
+        m_fdLocalFile = lynq_fota_open(m_strTempFileName.c_str(), pt_info->zip_flag == 0 ? NULL : pt_info->org_file_name.c_str(), O_RDONLY);
+        return m_fdLocalFile >= 0;
+    }
+    int ReadPartionFileData(void *buf, size_t count)
+    {
+        //printf("cy: to read file %d\n", count);
+        if (m_fdLocalFile < 0)
+            return -1;
+        return lynq_fota_read(m_fdLocalFile, buf, count);
+    }
+    int ClosePartionFile()
+    {
+        if (m_fdLocalFile < 0)
+            return 0;
+        int ret = lynq_fota_close(m_fdLocalFile);
+        if (access(m_strTempFileName.c_str(), F_OK) != -1)
+            remove(m_strTempFileName.c_str());
+        m_fdLocalFile = -1;
+        return ret;
+    }
+private:
+    int m_fdFotaFlag;
+    bool m_bLockState;
+    std::string m_strTempFileName;
+    int m_fdLocalFile;
+    PartitionInfo * m_pPartitionInfo;
+};
+
+OTA_STATUS  fota_status;
+UPDATE_INFO up_info;
+
+static const char hex_chars[] = "0123456789abcdef";
+
+/**
+ * @brief The following is the wake up
+ * start
+ */
+
+#define ANDROID_WAKE_LOCK_NAME "fota-interface"
+
+void *dlHandle_wakelock;
+
+enum {
+    PARTIAL_WAKE_LOCK = 1,  // the cpu stays on, but the screen is off
+    FULL_WAKE_LOCK = 2      // the screen is also on
+};
+
+// while you have a lock held, the device will stay on at least at the
+// level you request.
+
+int (*acquire_wake_lock)(int lock, const char* id);
+int (*release_wake_lock)(const char* id);
+
+void convert_hex(unsigned char *sha, unsigned char *shastr)
+{
+    int i;
+    int j = 0;
+    unsigned int c;
+
+    for (i = 0; i < 20; i++) {
+        c = (sha[i] >> 4) & 0x0f;
+        shastr[j++] = hex_chars[c];
+        shastr[j++] = hex_chars[sha[i] & 0x0f];
+    }
+    shastr[40] = '\0';
+}  
+
+
+
+
+int rock_mismatch(void* ctx, unsigned char* buf, unsigned int start, unsigned int size, 
+                  unsigned int source_hash,unsigned int target_hash) {
+
+    return 0;
+}
+
+int rock_fatal(void* ctx, int error_code) {
+    return 0;
+}
+
+void rock_trace(void* ctx, const char* fmt, ...) {
+
+    va_list     ap;
+    memset(rock_debug_buffer,0x0,sizeof(rock_debug_buffer));
+    va_start (ap, fmt);
+
+    
+    vsnprintf(rock_debug_buffer,sizeof(rock_debug_buffer),fmt,ap);
+    LYDBGLOG("+[UA]: %s",rock_debug_buffer);
+    
+
+    va_end (ap);
+
+}
+
+static int save_fota_status()
+{
+    int err;
+    fd_fota_status = open(FILE_FOTA_STATE,O_RDWR | O_CREAT,0777);
+
+    if (fd_fota_status < 0) {
+        err = errno;
+        RLOGD("+[UA]: save_fota_status: Error opening metadata file: %s\n",strerror(errno));
+        return -err;
+    }
+    
+    write(fd_fota_status, &fota_status,sizeof(fota_status));
+    sync();
+    
+    close(fd_fota_status);
+}
+
+int lynq_read_process(void)
+{
+    int err;
+    fd_fota_status = open(FILE_FOTA_STATE,O_RDWR | O_CREAT,0777);
+
+    if (fd_fota_status < 0) {
+        err = errno;
+        RLOGD("+[UA]: save_fota_status: Error opening metadata file: %s\n",strerror(errno));
+        return -err;
+    }
+    memset(&fota_status, 0 , sizeof(fota_status));
+    read(fd_fota_status, &fota_status,sizeof(fota_status));
+    sync();
+    close(fd_fota_status);
+    return fota_status.ota_run;
+}
+
+static int save_fota_info()
+{
+    int err;
+    fd_update_status = open(FILE_UPDATE_STATE,O_RDWR);
+
+    if (fd_update_status < 0) {
+        err = errno;
+        RLOGD("+[UA]: save_fota_status: Error opening metadata file: %s\n",strerror(errno));
+        return -err;
+    }
+
+    write(fd_update_status, &up_info, sizeof(fota_status));
+    sync();
+    close(fd_update_status);
+}
+
+
+
+void rock_progress(void* ctx, int percent) {
+    int i = 0;
+    static int tmp_percent = -1;
+    rock_trace(ctx, "rock update progress %d\n", percent);
+
+    if (tmp_percent != percent) {
+        tmp_percent = percent;
+        if (percent > 20) {
+            i = fota_status.ota_run;
+            if (fota_status.update_status[i-1].check_delta != PASS) {
+                fota_status.update_status[i-1].check_delta = PASS;
+                fota_status.update_status[i-1].check_rom= PASS;
+                save_fota_status();
+            }
+        }
+    }
+}
+
+int rock_process_block(void* ctx, unsigned char* data, unsigned int start, unsigned int size){
+
+    int writen = 0;
+    int ret,err;
+
+    if (start == BACKUP_ADDR_FLAG) {
+        int fd_backup = open(FILE_BACKUP,O_RDWR | O_CREAT,0777);
+        while (writen < size) {
+            write(fd_backup,data,ROCK_DEFAULT_BLOCK_SIZE);
+            sync();
+            writen += ROCK_DEFAULT_BLOCK_SIZE;
+        }
+        close(fd_backup);
+        return size;
+    }
+
+    writen = 0;
+
+    if (mtk_device_wrap_seek(fd_write, start, SEEK_SET) < 0) {
+        err = errno;
+        rock_trace(ctx, "mtk_device_wrap_seek write\n");
+        return err;
+    }
+
+    while (writen < size) {
+        ret = mtk_device_wrap_write(fd_write,data+writen, ROCK_DEFAULT_BLOCK_SIZE);
+        writen += ROCK_DEFAULT_BLOCK_SIZE;
+    }
+    
+    
+    return size;
+}
+
+int rock_write_block(void* ctx, unsigned char* src, unsigned int start, unsigned int size){
+
+#if 0
+
+    int writen = 0;
+    int ret,err;
+    
+    
+    if (start == BACKUP_ADDR_FLAG) {
+        int fd_backup = open(FILE_BACKUP,O_RDWR | O_CREAT,0777);
+        while (writen < size) {
+            write(fd_backup,src,ROCK_DEFAULT_BLOCK_SIZE);
+            sync();
+            writen += ROCK_DEFAULT_BLOCK_SIZE;
+        }
+        close(fd_backup);
+        return size;
+    }
+    
+    writen = 0;
+
+    if (mtk_device_wrap_seek(fd_curr, start, SEEK_SET) < 0) {
+        err = errno;
+        rock_trace(ctx, "mtk_device_wrap_seek write\n");
+        return err;
+    }
+
+    while (writen < size) {
+        ret = mtk_device_wrap_write(fd_curr,src+writen, ROCK_DEFAULT_BLOCK_SIZE);
+        writen += ROCK_DEFAULT_BLOCK_SIZE;
+    }
+    
+
+#endif
+
+    return size;
+
+}
+
+int rock_read_block(void* ctx, unsigned char* dest, unsigned int start, unsigned int size){
+
+
+    int ret,err;
+    
+
+    if (start == BACKUP_ADDR_FLAG) {
+        int fd_backup = open(FILE_BACKUP,O_RDONLY);
+        read(fd_backup,dest,size);
+        sync();
+        close(fd_backup);
+        return size;
+    }
+    
+
+
+    if (mtk_device_wrap_seek(fd_read, start, SEEK_SET) < 0) {
+        err = errno;
+        rock_trace(ctx, "mtk_device_wrap_seek read block err\n");
+    }
+
+    do {
+
+        ret = mtk_device_wrap_read(fd_read, dest, size);
+
+        if (ret == 0) {
+            break;
+        } else if (ret < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+            err = -errno;
+            rock_trace(ctx,"%s Error reading metadata file\n");
+
+            mtk_device_wrap_close(fd_read);
+
+            return err;
+        }
+        size -= ret;
+        dest += ret;
+    } while(size > 0);
+
+
+    return ret;
+
+    
+}
+
+
+int rock_get_blocksize(void* ctx) {
+    return ROCK_DEFAULT_BLOCK_SIZE;
+}
+
+int rock_read_file(void* ctx,  void* name, unsigned char* dest, unsigned int offset, unsigned int size){return 0;}
+int rock_write_file(void* ctx,  void* name, unsigned char* src, unsigned int offset, unsigned int size){return 0;}
+int rock_delete_file(void* ctx, void* name){return 0;}
+/* ROCK IPL end */
+
+void delete_enter(char data[])
+{
+    char *find = strchr(data, ':');
+    if(find)
+        *find = '\0';
+    return ;
+}
+
+static void func_buf(char* str) 
+{
+    char* dest = str;
+    while (*str) {
+        if (*str != '"' && *str != '\n') {
+            *dest++ = *str;
+        }
+        str++;
+    }
+    *dest = '\0';
+    return ;
+}
+
+int get_full_filename(void)
+{
+    int i;
+    int len;
+    FILE *fp;
+    char buffer[64];
+    fp = popen("cat /proc/mtd|grep _a|awk '{print $4}'","r");
+    i = 0;
+    while(fgets(buffer, 63, fp) != NULL)
+    {
+        func_buf(buffer);
+        len = strlen(buffer);
+        buffer[len -2] = '\0';
+        strcpy(full_partition_filename[i],buffer);
+        RLOGD("full_partition_filename[%d]:%s\n", i, full_partition_filename[i]);
+        i++;
+    }
+    pclose(fp);
+    full_partition_num = i;
+    return 0;
+}
+
+
+static int init_dev_fd()
+{
+
+    int err;
+    int ret;
+    int result;
+    char lynq_fota_addr[128] = {0};
+    char ftp_addr[128] = {0};
+    char fota_name[]= "fota.delta";
+    int n;
+    size_t size = 1024;
+    ret = lynq_fota_get_addr_value(lynq_fota_addr);
+    if(0 != ret)
+    {
+        RLOGE("+[UA]: lynq_fota_get_addr_value fail %d\n", ret);
+        return E_ROCK_FOTA_ADDR;
+    }
+    RLOGD("+[UA]: get fota pack addr: %s\n",lynq_fota_addr);
+    if (!base64_dec(lynq_fota_addr, strlen(lynq_fota_addr), ftp_addr, &size))
+    {
+        RLOGE("+[UA]: base64_dec fota addr fail\n");
+        return E_ROCK_FOTA_ADDR;
+    }
+    g_strFtpAddress = ftp_addr;
+    RLOGD("+[UA]: get fota pack addr: %s\n", g_strFtpAddress.c_str());
+
+    fd_update_status = open(FILE_UPDATE_STATE,O_RDWR | O_CREAT,0777);
+    if (fd_update_status < 0) {
+        err = errno;
+        RLOGD("+[UA]: Error opening metadata file: %s\n",strerror(errno));
+        return -err;
+    }
+    memset(&up_info, 0, sizeof(up_info));
+    lseek(fd_update_status,0,SEEK_SET);
+    read(fd_update_status,(unsigned char *)&up_info,sizeof(up_info));
+    close(fd_update_status);
+    return 0;
+}
+
+
+
+
+
+static int close_dev_fd(int fd)
+{
+    lynq_fota_close(fd);
+}
+
+
+
+static int reboot_device() {
+    
+    reboot(RB_AUTOBOOT);
+
+    while (1) pause();
+}
+
+
+int nand_copyto_nand(char *source, char *target)
+{
+    int fd_source,fd_target,size;
+
+    char delta_data[ROCK_DEFAULT_BLOCK_SIZE];
+
+    fd_source = mtk_device_wrap_open(source,O_RDONLY);
+
+    if (fd_source < 0) {
+        RLOGD("+[UA]: open source  error\n");
+        return 1;
+    }
+
+    fd_target = mtk_device_wrap_open(target,O_RDWR);
+
+    if (fd_target < 0) {
+        mtk_device_wrap_close(fd_target);
+        mtk_device_wrap_close(fd_source);
+        RLOGD("+[UA]: open target  error\n");
+        return 1;
+    }
+    
+    while(( size = mtk_device_wrap_read(fd_source,delta_data,ROCK_DEFAULT_BLOCK_SIZE))>0) {
+        mtk_device_wrap_write(fd_target,delta_data,ROCK_DEFAULT_BLOCK_SIZE);
+    }
+    
+    mtk_device_wrap_close(fd_target);
+    mtk_device_wrap_close(fd_source);
+    return 0;
+}
+
+int delta_copyto_nand_new(FotaTool * tool, PartitionInfo * pi, uint8_t *digest)
+{
+
+    char delta_data[NAND_PAGE_SIZE];
+    unsigned int ret = 0;
+    int err, i, to_read = 0;
+    int size = pi->part_org_size;
+
+    const uint8_t *p;
+    SHA_CTX ctx;
+    SHA_init(&ctx);
+
+    if (!tool->PreparePartionFile(pi)) {
+        LYERRLOG("+[UA]: delta_copyto_nand prepare err\n");
+        return -1;
+    }
+
+    if (mtk_device_wrap_seek(fd_curr, 0, SEEK_SET) < 0) {
+        LYERRLOG("+[UA]: delta_copyto_nand seek err\n");
+        return -1;
+    }
+
+
+    do {
+        memset(delta_data,0xff,NAND_PAGE_SIZE);
+        to_read = NAND_PAGE_SIZE;
+        if (size < to_read)
+            to_read = size;
+        ret = tool->ReadPartionFileData(delta_data, to_read);
+
+        if (ret == 0) {
+            break;
+        } else if (ret < 0) {
+            if (errno == EINTR) {
+                continue;
+            }
+            err = -errno;
+
+            return err;
+        }
+
+        SHA_update(&ctx, delta_data, ret);
+        size -= NAND_PAGE_SIZE;
+        mtk_device_wrap_write(fd_curr,delta_data,NAND_PAGE_SIZE);
+        //mtk_device_wrap_write(fd_curr,delta_data,ret);
+
+    } while(size > 0);
+
+    p = SHA_final(&ctx);
+    for (i = 0; i < SHA_DIGEST_SIZE; ++i)
+    {
+        digest[i] = *p++;
+    }
+
+    return 0;
+
+}
+
+
+unsigned char ram_buffer[ROCK_RAM_LEN];
+
+/*
+int check(int sys_size)
+{
+    int fd;
+    int i=0;
+    int j=0;
+    int num=i;
+    int n = 0;
+    const uint8_t data[] = { 0x74, 0x77, 0x6f, 0x63, 0x6f, 0x72, 0x65};
+    const char * core_flag="twocore\n";
+    
+    uint8_t buffer[16];
+
+    if(sys_size == 0)//for only upgrade oemapp and oemapp2
+    {
+        return 0;
+    }
+    n = strlen(core_flag);
+    lynq_fota_lseek(fd_delta,520,SEEK_SET);
+    lynq_fota_lseek(fd_delta,sys_size,SEEK_CUR);
+    lynq_fota_lseek(fd_delta, -1*n, SEEK_CUR);
+    lynq_fota_read(fd_delta, buffer, n);
+    lynq_fota_lseek(fd_delta,0,SEEK_SET);//file reset
+    if (memcmp(buffer, core_flag, n) == 0)
+    {
+        return 0;
+    }
+    return -1;
+
+}
+
+int check_cpu(void)
+{
+    int i=0;
+    int ret;
+    char buffer[3][64];
+    FILE *fp;
+    char num;
+    fp = popen("od -x /proc/device-tree/chosen/atag,devinfo","r");
+
+    for(i=0;i<3;i++)
+    {
+        fgets(buffer[i], 64, fp);
+    }
+
+    for(i=0;i<3;i++)
+    {
+        RLOGD("buffer[i] = %s\n",buffer[i]);
+    }
+    RLOGD("%c\n", buffer[2][14]);
+
+    num = buffer[2][14];
+
+
+    RLOGD("num=%c\n", num);
+    if(num == '0' || num == '1')
+    {
+        printf("this is four core\n");
+        return 4;
+    }
+    else if(num == '2' || num == '3')
+    {
+        printf("this is two core\n");
+        return 2;
+    }
+    else
+    {
+        RLOGD("this char is error\n");
+        return -1;
+    }
+    pclose(fp);
+
+    return -1;
+}
+*/
+static PartitionInfo * find_partition_info_by_index(int index)
+{
+    for(auto it = g_lstPartitionInfo.begin(); it != g_lstPartitionInfo.end(); ++it)
+    {
+        if (it->part_index == index)
+            return &*it;
+    }
+    return NULL;
+}
+static int prepare_header_and_check(FotaTool *pFotaTool)
+{
+    int i, size, total_read, count;
+    ssize_t file_offset = sizeof(g_header);
+    std::string left_data;
+    struct partition_desc * pDesc = NULL;
+    const char * pName = NULL;
+    const int max_partition_size = 1024*1024*250;
+    if (pFotaTool == NULL)
+        return -1;
+    for(i = MAX_OTA_ROLE/2;i<(MAX_OTA_ROLE/2+full_partition_num); i++) {
+        if (g_header.delta_head[i] > 0) {
+            fota_status.update_status[i].need_update = 1;
+
+            PartitionInfo pi;
+            pi.part_index = i-MAX_OTA_ROLE/2;
+            pi.zip_flag = 0;
+            pi.part_org_size = -1;
+            pi.org_file_name = "";
+            pi.dest_part_name = full_partition_filename[pi.part_index];
+            pi.file_offset = file_offset;
+            pi.part_size = g_header.delta_head[i];
+            file_offset += pi.part_size;
+            g_lstPartitionInfo.push_back(pi);
+            RLOGD("cy: count %d, last index %d, name %s\n",
+                  g_lstPartitionInfo.size(), g_lstPartitionInfo.rbegin()->part_index,g_lstPartitionInfo.rbegin()->dest_part_name.c_str());
+        }
+        RLOGD("+[UA]: %s,full size = %d, i=%d\n",full_partition_filename[i-MAX_OTA_ROLE/2],g_header.delta_head[i], i);
+    }
+
+    PartitionInfo pi;
+    pi.part_index = -1;
+    pi.zip_flag = 0;
+    pi.file_offset = file_offset;
+    pi.part_size = -1;
+    pi.part_org_size = -1;
+    pi.org_file_name = "";
+
+    left_data.reserve(1024*1024);
+    total_read = 0;
+    if (!pFotaTool->PreparePartionFile(&pi))
+        return -1;
+    while(total_read < 1024 * 1023)
+    {
+        size = pFotaTool->ReadPartionFileData((char*)(left_data.c_str() + total_read), 1024);
+        if (size > 0)
+            total_read += size;
+        if (size < 1024)
+            break;
+    }
+
+    count = *(int*)(left_data.c_str());
+    if (count <=0 || count >= MAX_OTA_ROLE/2 )
+    {
+        RLOGE("+[UA]: get bad partition count %d\n", count);
+        return -1;
+    }
+
+    pDesc = (struct partition_desc *)(left_data.c_str() + sizeof(int));
+    pName = (const char*)(left_data.c_str() + sizeof(int) + count*sizeof(struct partition_desc));
+    for(i=0;i<count;i++)
+    {
+        if (pDesc->part_index < 0 || pDesc->part_index >= full_partition_num)
+        {
+            RLOGE("+[UA]: get bad partition desc %d, index %d\n", i, pDesc->part_index);
+            return -1;
+        }
+        if (pDesc->part_size <=0 || pDesc->part_size > max_partition_size ||
+                pDesc->part_org_size <=0 || pDesc->part_org_size > max_partition_size)
+        {
+            RLOGE("+[UA]: get bad partition desc %d, index %d, part_size %s, part_org_size %d \n",
+                  i, pDesc->part_index, pDesc->part_size, pDesc->part_org_size);
+            return -1;
+        }
+        std::string name = pName;
+        auto pos = name.find(".");
+        if ( pos != std::string::npos)
+        {
+            name = name.substr(0, pos);
+        }
+        PartitionInfo *p = find_partition_info_by_index(pDesc->part_index);
+        if (p == NULL){
+            RLOGE("+[UA]: partition desc is not equal %d, name %s\n", pDesc->part_index, pName);
+            return -1;
+        }
+        if (p->part_size != pDesc->part_size || name != p->dest_part_name)
+        {
+            RLOGE("+[UA]: get bad partition desc size %d, name %s, %s-%s\n", pDesc->part_size, pName, p->dest_part_name.c_str(), name.c_str());
+            return -1;
+        }
+        p->part_org_size = pDesc->part_org_size;
+        p->org_file_name = pName;
+        p->zip_flag = pDesc->zip_flag;
+        memcpy(p->part_sha, pDesc->sha_value, SHA_DIGEST_SIZE);
+        pName += strlen(pName) + 1;
+        pDesc++;
+
+    }
+
+    return 0;
+}
+
+static const char *get_dest_part_suffix()
+{
+    if(current_slot==SLOT_B) {
+        return "_a";
+    } else {
+        return "_b";
+    }
+}
+
+static const char *get_src_part_suffix()
+{
+    if(current_slot==SLOT_B) {
+        return "_b";
+    } else {
+        return "_a";
+    }
+}
+
+static bool check_memory(int try_count)
+{
+    FILE *fp;
+    int value;
+    char buffer[64] = {0};
+    fp = popen("free -m | grep Mem | awk '{print $7}'","r");
+    if(fgets(buffer, 63, fp) != NULL)
+    {
+        value = atoi(buffer);
+        if (value > 100)
+            return true;
+        else if (strlen(buffer) >= 0)
+            return false;
+    }
+    fclose(fp);
+    if (try_count > 0)
+    {
+        try_count --;
+        sleep(1);
+        return check_memory(try_count);
+    }
+    return false;
+}
+
+static int rock_update_main(unsigned int rom_base,  unsigned int backup_base, unsigned int backup_len, int read_rom_directly, int first_run, int switch_slot_flag, int 
+                            reboot_flag, int backup_mode) {
+    int status,err,start,fd;
+    int ret = 0;
+    int i = 0;
+    int slot = 0;
+    int retry_cnt = 0;
+    int cpu_flag;
+    IOT_UPDATA_CONTEXT ctx;
+
+    //OTA_STATUS  fota_status;
+
+
+    unsigned int  update_mode = MODE_NORMAL;
+    
+    char digest_s[SHA_DIGEST_SIZE];
+    char digest_t[SHA_DIGEST_SIZE];
+    char str_sha[40];
+    char cmd_sys[100];
+    int core_num;
+    int sha_size = 0;
+    int is_need_fullupdate = 0;
+    int fd_partition_a,fd_partition_b;
+    time_t t1 = time(NULL);
+
+    FotaTool stFotaTool;
+    if (!stFotaTool.Init())
+        return -1;
+
+    if (!check_memory(3))
+    {
+        RLOGD("+[UA]: not enough memory to to fota\n");
+        return -1;
+    }
+
+    //xf.li@20230830 add for ab_recover start
+    //xf.li@20230830 add for ab_recover end
+    memset(&fota_status,0,sizeof(fota_status));
+    fota_status.ota_run = 1;
+    save_fota_status();
+
+
+    current_slot = module->getCurrentSlot(module);
+    
+    int is_successful = module->isSlotMarkedSuccessful(module, current_slot);
+
+    RLOGD("Booting slot = %d, : isSlotMarkedSuccessful= %d\n",current_slot,is_successful);
+
+
+
+    memset(&ctx, 0, sizeof(ctx));
+    ctx.rom_base = 0;
+    ctx.ram_base =(unsigned char *)&ram_buffer[0];
+    ctx.ram_len = ROCK_RAM_LEN;
+    ctx.backup_base = BACKUP_ADDR_FLAG;
+    //ctx.backup_len = ROCK_DEFAULT_BLOCK_SIZE;
+    ctx.backup_len = 0;
+    ctx.update_nvram = 0;
+    ctx.read_rom_directly = read_rom_directly;
+    //ctx.first_run = first_run;
+    ctx.first_run = 1;
+
+    if(0 != init_dev_fd())
+    {
+        RLOGD("+[UA]: get fota addr error\n");
+        return E_ROCK_FOTA_ADDR;
+    }
+
+    RLOGD("+[UA]: up_info.ota_run = %d\n",up_info.ota_run);
+
+#if 0
+    if ((up_info.ota_run>PATCH_BL33)||(up_info.ota_run<PATCH_SYSTEM))
+    {
+        up_info.ota_run = 0;
+    }
+#endif 
+
+    up_info.ota_run = 0;
+    if(backup_mode == 1)
+    {
+        if(current_slot == 0)
+        {
+            update_mode = MODE_A2B;
+        }else
+        {
+            update_mode = MODE_B2A;
+        }
+    }
+    else
+    {
+        update_mode = MODE_NORMAL;
+    }
+    
+    RLOGD("+[UA]: up_info.fota_flag = %s\n",up_info.fota_flag);
+    RLOGD("+[UA]: update_mode = %d\n",update_mode);
+
+    memset(&g_header, 0, sizeof(g_header));
+    PartitionInfo pi;
+    pi.zip_flag = 0;
+    pi.file_offset = 0;
+    pi.org_file_name = "";
+    pi.part_size = sizeof(g_header);
+    if (!stFotaTool.PreparePartionFile(&pi) || stFotaTool.ReadPartionFileData(&g_header, sizeof(g_header)) != sizeof(g_header))
+    {
+        RLOGE("read header fail\n");
+        return -1;
+    }
+
+    get_full_filename();
+
+    /*
+    core_num= check_cpu();
+    if(core_num == 2)
+    {
+        cpu_flag = check(delta_head[64]);
+        if(cpu_flag < 0)
+        {
+            RLOGD("cpu core is error\n");
+            system("echo fota-interface >/sys/power/wake_unlock");
+            return -1;
+        }
+        else
+        {
+            RLOGD("cpu core match\n");
+        }
+    }
+    else if(core_num == 4)
+    {
+        RLOGD("the cpu core is four!!!\n");
+    }
+    else
+    {
+        RLOGD("read the cpu core fail");
+        system("echo fota-interface >/sys/power/wake_unlock");
+        return -1;
+    }
+*/
+    fota_status.switch_slot = WAIT;
+    save_fota_status();
+
+    ret = prepare_header_and_check(&stFotaTool);
+    if (ret != 0)
+    {
+        RLOGD("delta sha verify fail!\n");
+        return -1;
+    }
+    now_patch = 0;
+    up_info.ota_run = 0;
+
+    fota_status.switch_slot = WAIT;
+    save_fota_status();
+    if (memcmp(g_header.full_type, FULL_HEAD, DELTA_FULL_HEARD_SIZE) != 0) {
+        RLOGD("+[UA]: invalid full delta header\r\n");
+        up_info.fota_flag[0] = 'e';
+        up_info.fota_flag[1] = 'n';
+        up_info.fota_flag[2] = 'd';
+        up_info.update_result = -1;
+        up_info.ota_run = 0;
+        save_fota_info();
+
+        //for (i = FULL_SYSTEM;i<=FULL_BL33;i++){
+        
+        for (i = MAX_OTA_ROLE/2;i<(MAX_OTA_ROLE/2+full_partition_num);i++){
+            if (fota_status.update_status[i].need_update ==1) {
+                fota_status.ota_run = i - MAX_OTA_ROLE/2;
+                fota_status.update_status[i].check_delta = ERROR;
+                fota_status.update_status[i].check_rom= WAIT;
+                fota_status.update_status[i].update_result= ERROR;
+            }
+        }
+        fota_status.update_result = ERROR;
+        save_fota_status();
+        return -1;
+    }
+
+
+    for(auto it = g_lstPartitionInfo.begin(); it != g_lstPartitionInfo.end(); ++it) {
+        std::string dest_part_file = std::string("/dev/disk/by-partlabel/") + full_partition_filename[it->part_index] + get_dest_part_suffix();
+        sprintf(cmd_sys,"flash_erase %s 0 0", dest_part_file.c_str());
+        system(cmd_sys);
+        
+        fd_curr = mtk_device_wrap_open(dest_part_file.c_str(), O_RDWR);
+        if (fd_curr < 0) {
+            err = errno;
+            RLOGE("+[UA]: Error opening full id_a[%d] file: %s, %s\n", it->part_index,
+                  dest_part_file.c_str(), strerror(errno));
+            return -err;
+        }
+        fota_status.ota_run =  it->part_index+1;
+        save_fota_status();
+        up_info.ota_run =  it->part_index+1;
+        save_fota_info();
+        retry_cnt = 0;
+        RLOGD("+[UA]: Start upgrading %s full.\n",dest_part_file.c_str());
+        do{
+            status = delta_copyto_nand_new(&stFotaTool,&*it, digest_s);
+            if (status != 0)
+            {
+                if (retry_cnt++ < 3)
+                    continue;
+                else
+                    break;
+            }
+
+            //ROCK_SHA_FILE_COMMON(fd_delta,delta_offset,delta_head[i],digest_s);
+            ROCK_SHA_FILE(fd_curr,0,it->part_org_size,digest_t);
+            retry_cnt++;
+        }while((strncmp(digest_s,digest_t,SHA_DIGEST_SIZE)!=0)&&(retry_cnt <= 3));
+        
+        mtk_device_wrap_close(fd_curr);
+        
+        RLOGD("+[UA]: %s full retry_cnt = %d\n",dest_part_file.c_str(),retry_cnt);
+        
+        if (retry_cnt>3) {
+            if (status == 0) {
+                status = retry_cnt;
+            }
+            std::string src_part_file = std::string("/dev/disk/by-partlabel/") + full_partition_filename[it->part_index] + get_src_part_suffix();
+            nand_copyto_nand(src_part_file.c_str(), dest_part_file.c_str());
+        }
+
+        RLOGD("+[UA]: %s full upgrade result:%d\n",full_partition_filename[it->part_index],status);
+
+        fota_status.update_result = status;
+        fota_status.update_status[i].update_result = status;
+        save_fota_status();
+
+        if (status != 0)
+        {
+
+            up_info.fota_flag[0] = 'e';
+            up_info.fota_flag[1] = 'n';
+            up_info.fota_flag[2] = 'd';
+            up_info.update_result = status;
+            up_info.ota_run = 0;
+            save_fota_info();
+            return status;
+        }
+        
+    }
+    
+    
+    if(update_mode != MODE_NORMAL){ //need backup
+        if(current_slot == SLOT_A) {
+            up_info.fota_flag[0] = 'B';
+            up_info.fota_flag[1] = '-';
+            up_info.fota_flag[2] = 'A';
+
+        }else{
+            up_info.fota_flag[0] = 'A';
+            up_info.fota_flag[1] = '-';
+            up_info.fota_flag[2] = 'B';
+
+        }
+
+    }else{
+        up_info.fota_flag[0] = 'e';
+        up_info.fota_flag[1] = 'n';
+        up_info.fota_flag[2] = 'd';
+
+    }
+
+
+    up_info.update_result = status;
+    up_info.ota_run = 0;
+    save_fota_info();
+
+    //close_dev_fd(fd_curr);
+    
+
+    
+    close(fd_update_status);
+    sync();
+    
+
+    slot = (current_slot == 0) ? 1 : 0;
+    
+    RLOGD("+[UA]: slot SLOT = %d\n",slot);
+    
+    if(switch_slot_flag==1)
+    {
+        module->setActiveBootSlot(module,slot);
+        RLOGD("+[UA]: upgrade is success!!!!\n");
+    }
+
+    fota_status.ota_run = 0;
+    fota_status.switch_slot = PASS;
+    fota_status.update_result = status;
+    save_fota_status();
+    
+    sleep(5);
+    sync();
+    sleep(5);
+
+    time_t t2 = time(NULL);
+    printf("total cost %d\n", t2 - t1);
+
+    if(reboot_flag==1){
+        reboot_device();
+    }
+
+    return status;
+}
+
+
+
+static void rock_fail_handler()
+{
+    int ret = 0;
+    RLOGD("rock_fail_handler start\n");
+    //ret = rock_update_main(0, 0, 0, 0, 1, 1);
+    if(ret)
+    {
+        RLOGD("fota update fail again!\n");
+    }
+}
+
+/* main entrpoint */
+int lynq_rock_main(int first_run)
+{
+
+    int ret = 0;
+    
+#if 0
+    
+    printf("-********copy delta ***-\n");
+    test_write_delta("/data/delta",DEV_DELTA);
+
+#endif 
+    
+    ret = rock_update_main(0, 0, 0, 0, first_run, 1, 1, 1);
+    RLOGD("rock_update_main ret = %d\n", ret);
+    if(ret)
+    {
+        RLOGD("fota update fail!\n");
+    }
+    return ret;
+}
+
+#endif
+
+//xf.li@20230403 add for verfy start
+int lynq_file_md5_verfy(char *source, unsigned char *source_md5, char *target)
+{
+    int fd, size, ret, is_system = 0;
+    int need_copy = 1;
+    int system_mtd_num = 0;
+    int system_ubi_num = BACKUP_UBI_NUM;//max ubi number
+    char cmd_ubi_attach[128] = {0};
+    char cmd_ubi_detach[128] = {0};
+    char md5_target_file_patch[128] = {0};
+
+    RLOGD("in lynq_file_md5_verfy, source:%s, target:%s\n", source, target);
+    if(strcmp(source, DEV_SYSTEM_A) == 0 || strcmp(source, DEV_SYSTEM_B) == 0)
+    {
+        RLOGD("verfy system.img\n");
+        is_system = 1;
+        if(strcmp(source, DEV_SYSTEM_A) == 0)
+        {
+            system_mtd_num = MTD_SYSTEM_B;
+        }
+        else if(strcmp(source, DEV_SYSTEM_B) == 0)
+        {
+            system_mtd_num = MTD_SYSTEM_A;
+        }
+        else
+        {
+            RLOGD("source:%s, target:%s\n", source, target);
+        }
+        for( ; system_ubi_num >= 10; system_ubi_num--)//try from ubi31 to ubi10
+        {
+            sprintf(md5_target_file_patch, "/dev/ubi%d", system_ubi_num);
+            RLOGD("ubi_num = %d\n", system_ubi_num);
+            if((access(md5_target_file_patch, F_OK)) == -1)
+            {
+                RLOGD("no the ubi file, can use this ubi.\n");
+                break;
+            }
+        }
+        if(system_ubi_num < 10)
+        {
+            RLOGE("no the ubi file, can use this ubi.\n");
+            return -1;
+        }
+    }
+    //=========================caculate md5sum start=====================
+    if(is_system == 1)
+    {
+        RLOGD("in system caculate\n");
+        RLOGD("system_mtd_num = %d, ubi_num = %d\n", system_mtd_num, system_ubi_num);
+        sprintf(cmd_ubi_attach, "ubiattach /dev/ubi_ctrl -m %d -d %d", system_mtd_num, system_ubi_num);
+        RLOGD("cmd_ubi_attach:%s", cmd_ubi_attach);
+        ret = system(cmd_ubi_attach);
+        if(ret != 0)
+        {
+            RLOGE("ubi attach error!!!\n");
+            return need_copy;
+        }
+        RLOGD("attach over\n");
+        //attach success
+        sprintf(md5_target_file_patch, "/dev/ubi%d_0", system_ubi_num);
+        RLOGD("md5_target_file_patch:%s", md5_target_file_patch);
+        //make sure the ubi volume is exist
+        if((access(md5_target_file_patch, F_OK)) == -1)
+        {
+            RLOGD("no the ubi file.\n");
+            sprintf(cmd_ubi_detach, "ubidetach -m %d", system_mtd_num);
+            ret = system(cmd_ubi_detach);
+            if(ret != 0)
+            {
+                RLOGD("ubi dettach error!!!\n");
+            }
+
+            return need_copy;
+        }
+        //calculate md5sum
+        //ret = lynq_md5_two_file_verfy("/dev/ubi0_0", md5_target_file_patch);
+        ret = lynq_md5_file_verfy_ab(md5_target_file_patch, source_md5);
+        if(ret == MD5_VERFY_ERROR)
+        {
+            //ubidetach
+            sprintf(cmd_ubi_detach, "ubidetach -m %d", system_mtd_num);
+            ret = system(cmd_ubi_detach);
+            if(ret != 0)
+            {
+                RLOGD("ubi dettach error!!!\n");
+            }
+            return need_copy;
+        }
+        if(ret != 0)
+        {
+            //ubidetach
+            sprintf(cmd_ubi_detach, "ubidetach -m %d", system_mtd_num);
+            ret = system(cmd_ubi_detach);
+            if(ret != 0)
+            {
+                RLOGD("ubi dettach error!!!\n");
+            }
+            RLOGD("calculate system error!!!\n");
+            return -1;
+        }
+
+        RLOGD("verfy system.img over\n");
+    }
+    else
+    {
+        RLOGD("verfy else img\n");
+        //calculate md5sum
+        //ret = lynq_md5_two_file_verfy(source, target);
+        ret = lynq_md5_file_verfy_ab(target, source_md5);
+        if(ret == MD5_VERFY_ERROR)
+        {
+            return need_copy;
+        }
+        if(ret != 0)
+        {
+            RLOGD("calculate %s and %s error!!!\n", source, target);
+            return -1;
+        }
+    }
+    //====================caculate md5sum end======================
+    return 0;
+}
+//xf.li@20230403 add for verfy end
+
+
+//xf.li@20230401 add for ab rollback start
+
+int backup_nand_copyto_nand(char *source, char *target)
+{
+    int fd_source, fd_target, size;
+    int ret = -1;
+    int sleep_count = 0;
+    char cmd_erase_target[128] = {0};
+    int retry = MD5_RETRY_TIME;
+    unsigned char source_md5[MD5_READ_BUFFER_LEN] = {0};
+    char delta_data[ROCK_DEFAULT_BLOCK_SIZE];
+    //caclculate source md5 start
+    if(strcmp(source, DEV_SYSTEM_A) == 0 || strcmp(source, DEV_SYSTEM_B) == 0)
+    {
+        RLOGD("backup_nand_copyto_nand: verfy system.img\n");
+        
+        ret = calculate_file_md5_value("/dev/ubi0_0", source_md5);
+        if(ret < 0)
+        {
+            RLOGD("[+MD5]:calculate source md5 value ERROE!!!\n");
+            return ret;
+        }
+        RLOGD("source_md5 is %s\n", source_md5);
+    }
+    else
+    {
+        ret = calculate_file_md5_value(source, source_md5);
+        if(ret < 0)
+        {
+            RLOGD("[+MD5]:calculate source md5 value ERROE!!!\n");
+            return ret;
+        }
+        RLOGD("source_md5 is %s\n", source_md5);
+    }
+    //caclculate source md5 end
+    //ret = lynq_file_md5_verfy(source, target);//verfy md5 value
+    ret = lynq_file_md5_verfy(source, source_md5, target);//verfy md5 value
+    RLOGD("+[UA]: md5_file_verfy :ret=%d\n", ret);
+    if(ret == 0)
+    {
+        RLOGD("+[UA]: nand_copyto_nand don't neet copy\n");
+    }
+    for(; ret > 0 && retry > 0; retry--)
+    {
+        //erase nand-target start
+        if(fota_interrupt == FOTA_FIRST && (access(FILE_UPDATE_FLAG, F_OK)) == 0)
+        {
+            RLOGD("+[UA]: fota runing\n");
+            return -1;
+        }
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, "ab_recover");//lock
+        RLOGD("+[UA]: ready to flash_erase\n");
+        sprintf(cmd_erase_target, "flash_erase %s 0 0", target);
+        ret = system(cmd_erase_target);
+        release_wake_lock("ab_recover");//unlock
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: erase %s fail\n", target);
+            return -1;
+        }
+        sleep(1);//sleep 1s
+
+        //erase nand-target end
+        RLOGD("+[UA]: ready to copy\n");
+        fd_source = mtk_device_wrap_open(source, O_RDONLY);
+        if (fd_source < 0) {
+            RLOGD("+[UA]: open source error\n");
+            return -1;
+        }
+
+        fd_target = mtk_device_wrap_open(target, O_RDWR);
+        if (fd_target < 0) {
+            RLOGD("+[UA]: open target  error\n");
+            return -1;
+        }
+        ret = 0;//init ret
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, "ab_recover");//lock
+        while(( size = mtk_device_wrap_read(fd_source,delta_data,ROCK_DEFAULT_BLOCK_SIZE))>0)
+        {
+            if(fota_interrupt == FOTA_FIRST && (access(FILE_UPDATE_FLAG, F_OK)) == 0)
+            {
+                RLOGD("+[UA]: fota runing\n");
+                ret = -1;
+                break;
+            }
+            usleep(40000);//sleep 40ms
+            mtk_device_wrap_write(fd_target,delta_data,ROCK_DEFAULT_BLOCK_SIZE);
+            usleep(60000);//sleep 60ms
+            sleep_count++;
+            if(sleep_count >= 20)
+            {
+                //unlock
+                release_wake_lock("ab_recover");
+                sleep(1);//sleep 1s
+                //lock
+                acquire_wake_lock(PARTIAL_WAKE_LOCK, "ab_recover");
+                sleep_count = 0;
+                RLOGD("+[UA]: try sleep one time");
+            }
+        }
+        release_wake_lock("ab_recover");//unlock
+        RLOGD("+[UA]: copy end\n");
+        mtk_device_wrap_close(fd_target);
+        mtk_device_wrap_close(fd_source);
+        if(ret < 0)
+        {
+            RLOGD("+[UA]: ret < 0\n");
+            return -1;
+        }
+        RLOGD("+[UA]: ready to md5_verfy\n");
+        //ret = lynq_file_md5_verfy(source, target);//verfy md5 value
+        ret = lynq_file_md5_verfy(source, source_md5, target);//verfy md5 value
+        RLOGD("+[UA]: md5_file_verfy :ret=%d\n", ret);
+        if(ret == 0)
+        {
+            RLOGD("+[UA]: nand_copyto_nand copy success\n");
+            break;
+        }
+    }
+    if(ret != 0)
+    {
+        RLOGD("+[UA]: md5_file_verfy FAIL!!!\n");
+    }
+    return ret;
+}
+//xf.li@20230401 add for ab rollback end
+
+//xf.li@20230822 add for ab rollback start
+
+int lynq_backup_main()
+{
+    const hw_module_t* hw_module;
+    hw_module = &HAL_MODULE_INFO_SYM;
+    int is_successful;
+    int ret = 0;
+
+
+    if (!hw_module || strcmp(BOOT_CONTROL_HARDWARE_MODULE_ID, hw_module->id) != 0)
+    {
+        ret = -1;
+    }
+    RLOGD("ret = %d\n", ret);
+    if (ret != 0)
+    {
+        RLOGD("+[UA]: Error loading boot_control HAL implementation.\n");
+        return -1;
+    }
+    module = (boot_control_module_t*)hw_module;
+    module->init(module);
+    if (module == NULL)
+    {
+        RLOGD("+[UA]: Error getting bootctrl module.\n");
+        return  -1;
+    }
+    lynq_init_wake_lock_func();
+    current_slot = module->getCurrentSlot(module);
+    is_successful = module->isSlotMarkedSuccessful(module, current_slot);
+    RLOGD("+[UA]: Booting slot = %d, : isSlotMarkedSuccessful= %d\n",current_slot,is_successful);
+    fota_interrupt = RECOVER_FIRST;
+    if(current_slot==SLOT_B)
+    {
+        ret = backup_nand_copyto_nand(DEV_SPM_B,DEV_SPM_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup spm_a fail\n");
+            return 1;
+        }
+        fota_interrupt = FOTA_FIRST;
+        ret = backup_nand_copyto_nand(DEV_SYSTEM_B,DEV_SYSTEM_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup system_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_BOOT_B,DEV_BOOT_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup boot_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_TEE_B,DEV_TEE_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup tee_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_MD1IMG_B,DEV_MD1IMG_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup md1img_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_VBMETA_B,DEV_VBMETA_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup vbmeta_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_MEDMCU_B,DEV_MEDMCU_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup medmcu_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_BL2_B,DEV_BL2_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup bl2_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_BL33_B,DEV_BL33_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup bl33_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_OEMAPP_B,DEV_OEMAPP_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup oemapp_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_OEMAPP2_B,DEV_OEMAPP2_A);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup oemapp2_a fail\n");
+            return 1;
+        }
+    }
+    else
+    {
+        ret = backup_nand_copyto_nand(DEV_SPM_A,DEV_SPM_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup spm_a fail\n");
+            return 1;
+        }
+        fota_interrupt = FOTA_FIRST;
+        ret = backup_nand_copyto_nand(DEV_SYSTEM_A,DEV_SYSTEM_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup system_b fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_BOOT_A,DEV_BOOT_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup boot_b fail\n");
+            return 1;
+        }
+        
+        ret = backup_nand_copyto_nand(DEV_TEE_A,DEV_TEE_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup tee_b fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_MD1IMG_A,DEV_MD1IMG_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup md1img_b fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_VBMETA_A,DEV_VBMETA_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup vbmeta_b fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_MEDMCU_A,DEV_MEDMCU_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup medmcu_b fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_BL2_A,DEV_BL2_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup bl2_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_BL33_A,DEV_BL33_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup bl33_a fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_OEMAPP_A,DEV_OEMAPP_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup oemapp_b fail\n");
+            return 1;
+        }
+        ret = backup_nand_copyto_nand(DEV_OEMAPP2_A,DEV_OEMAPP2_B);
+        if(ret != 0)
+        {
+            RLOGD("+[UA]: backup oemapp2_b fail\n");
+            return 1;
+        }
+    }
+    RLOGD("+[UA]: lynq_backup_main success \n");
+    return 0;
+}
+//xf.li@20230822 add for ab rollback end
+
+
+int lynq_check_oemapp(char* name)
+{
+    FILE *fp;
+    char check_result[64];
+    int ret;
+    if(strcmp(name, "oemapp") == 0)
+    {
+        RLOGD("lynq_check_oemapp oemapp");
+        ret = system("cat /proc/mtd|grep oemapp");
+        if(ret != 0)
+        {
+            return 0;
+        }
+        if(system("df -lh|grep oemapp |grep -v oemapp2") != 0)
+        {
+            return -1;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+    else if(strcmp(name, "oemapp2") == 0)
+    {
+        RLOGD("lynq_check_oemapp oemapp2");
+        ret = system("cat /proc/mtd|grep oemapp2");
+        if(ret != 0)
+        {
+            return 0;
+        }
+        if(system("df -lh|grep oemapp2") != 0)
+        {
+            return -1;
+        }
+        else
+        {
+            return 0;
+        }
+    }
+    return 0;
+}
+
+//lt add @2021.9.23 for  deal with power down \ backup or upgrade.
+int lynq_fota_func(void) 
+{
+    int fd;
+    int first_run = 1;
+    int ret = 0;
+    UPDATE_INFO lynq_up_info;
+    //xf.li@20230822 add for ab backup start
+    unsigned int current_slot, other_slot;
+    int is_other_slot_bootable;
+    const hw_module_t* hw_module;
+    //xf.li@20230822 add for ab backup end
+    RLOGD("[+UP]: ******lynq_fota_func start******\n");
+    //xf.li@20230822 add for ab backup start
+    //----------get current slot and whether other slot  is bootable
+    hw_module = &HAL_MODULE_INFO_SYM;
+    if (!hw_module ||
+            strcmp(BOOT_CONTROL_HARDWARE_MODULE_ID, hw_module->id) != 0) {
+        ret = -EINVAL;
+    }
+    if (ret != 0) {
+        RLOGD("+[UA]: Error loading boot_control HAL implementation.\n");
+        return -1;
+    }
+    module = (boot_control_module_t*)hw_module;
+    module->init(module);
+    if (module == NULL) {
+        RLOGD("+[UA]: Error getting bootctrl module.\n");
+        return  -1;
+    }
+    current_slot = module->getCurrentSlot(module);
+    other_slot = (current_slot == 0) ? 1 : 0;
+    is_other_slot_bootable = module->isSlotBootable(module, other_slot);
+    //-----------end
+    RLOGD("current slot:%u, is_other_slot_bootable : %d\n",current_slot, is_other_slot_bootable);
+    //xf.li@20230822 add for ab backup end
+
+    memset(&lynq_up_info, 0, sizeof(lynq_up_info));
+    fd = open(FILE_UPDATE_STATE,O_RDWR | O_CREAT,0777);
+    if (fd < 0)
+    {
+        return -1;
+    }
+    read(fd,(unsigned char *)&lynq_up_info,sizeof(lynq_up_info));
+    close(fd);
+
+    RLOGD("[+UP]: lynq_up_info.ota_run=%d\n",lynq_up_info.ota_run);
+    if((lynq_check_oemapp("oemapp") != 0) || (lynq_check_oemapp("oemapp2") != 0))
+    {
+        RLOGD("ENTER LYNQ_CHECK_OEMAPP\n");
+        system("echo mode 001 0 > /sys/devices/platform/10005000.pinctrl/mt_gpio");
+        system("echo dir 001 1 > /sys/devices/platform/10005000.pinctrl/mt_gpio");
+        system("echo out 001 1 > /sys/devices/platform/10005000.pinctrl/mt_gpio");
+        RLOGD("need setUnbootable.\n");
+        module->setSlotAsUnbootable(module,current_slot);
+        RLOGD("+[UA]: setSlotAsUnbootable!!!!\n");
+        sync();
+        if(((lynq_up_info.fota_flag[0]=='A')&&(lynq_up_info.fota_flag[1]=='-')&&(lynq_up_info.fota_flag[2]=='B'))||
+                ((lynq_up_info.fota_flag[0]=='B')&&(lynq_up_info.fota_flag[1]=='-')&&(lynq_up_info.fota_flag[2]=='A')))
+        {
+            RLOGD("mark oemapp mount fail\n");
+            lynq_set_value(FOTA_UCI_MODULE,FOTA_UCI_STATE, "1");
+        }
+        sleep(5);
+        reboot_device();
+    }
+
+
+    if(lynq_up_info.ota_run != 0)
+    {
+        //Power off, call UA
+        RLOGD("[+UP]: ***Power off, call UA***\n");
+        ret = rock_update_main(0, 0, 0, 0, first_run, 1, 0, 1);
+        RLOGD("rock_update_main ret = %d\n", ret);
+        if(ret)
+        {
+            RLOGD("fota update fail!\n");
+        }
+    }
+
+    if(((lynq_up_info.fota_flag[0]=='A')&&(lynq_up_info.fota_flag[1]=='-')&&(lynq_up_info.fota_flag[2]=='B'))||
+            ((lynq_up_info.fota_flag[0]=='B')&&(lynq_up_info.fota_flag[1]=='-')&&(lynq_up_info.fota_flag[2]=='A')))
+    {
+        //Upgrade the other side and call UA
+        RLOGD("[+UP]: ***Upgrade the other side and call UA***\n");
+        ret = rock_update_main(0, 0, 0, 0, first_run, 0, 0, 0);
+        RLOGD("rock_update_main ret = %d\n", ret);
+        if(ret)
+        {
+            RLOGD("fota update fail!\n");
+        }
+    }
+    //xf.li@20230822 add for ab backup start
+    else if(is_other_slot_bootable == 0)
+    {
+        RLOGD("need backup\n");
+        ret = lynq_backup_main();
+        if(ret != 0)
+        {
+            RLOGD("ERROE: backup fail!!!\n");
+        }
+        else
+        {
+            RLOGD("backup success!!!\n");
+            module->setCompleteBackup(module, current_slot);
+        }
+    }
+    else
+    {
+        RLOGD("Don't need backup\n");
+    }
+    //xf.li@20230822 add for ab backup end
+    
+    return 0;
+}    
+
+int lynq_nand_open(const char *pathname, int flags)
+{
+    //    printf("pathname:%s---flags:%d",pathname,flags);
+    return open(pathname,flags);
+}
+
+ssize_t lynq_nand_read(int fd, void *buf, size_t count)
+{
+    //    printf("rfd:%d---buf:%s---count:%d",fd,buf,count);
+    return read(fd,buf,count);
+}
+
+ssize_t lynq_nand_write(int fd, void *buf, size_t count)
+{
+    //   printf("wfd:%d---buf:%s---count:%d",fd,buf,count);
+    return write(fd,buf,count);
+}
+
+int lynq_nand_close(int fd)
+{
+    return close(fd);
+}
+
+/**
+ * @brief Obtain the upgrade result
+ *
+ * @param void
+ * @return 0xff:open file fail,0:upgrade success,1,upgrade wait
+ */
+int lynq_get_upgrade_status(void)
+{
+    int lynq_state_fd;
+    int lynq_upgrade_wait = 1;
+    OTA_STATUS lynq_ota_status;
+
+    memset(&lynq_ota_status, 0, sizeof(lynq_ota_status));
+
+    lynq_state_fd = open(FILE_FOTA_STATE,O_RDWR | O_CREAT,0777);
+
+    if (lynq_state_fd < 0)
+    {
+        return 0xff;
+    }
+    read(lynq_state_fd,(unsigned char *)&lynq_ota_status,sizeof(lynq_ota_status));
+    close(lynq_state_fd);
+    if((lynq_ota_status.ota_run != 0) && (lynq_ota_status.update_result == 0))
+    {
+        return lynq_upgrade_wait;
+    }
+    return lynq_ota_status.update_result;
+}
+
+/**
+ * @brief reboot device
+ *
+ * @param void
+ * @return void
+ */
+void lynq_reboot_device(void)
+{
+    reboot_device();
+    return ;
+}
+
+/**
+ * @brief fota no resatrt
+ *
+ * @param void
+ * @return 0:fota success -Other values:fota fail
+ */
+
+int lynq_fota_nrestart(void)
+{
+
+    int ret = 0;
+#if 0
+    printf("-********copy delta ***-\n");
+    test_write_delta("/data/delta",DEV_DELTA);
+#endif
+
+    RLOGD("lynq-fota-zip start\n");
+    time_t t1 = time(NULL);
+    ret = rock_update_main(0, 0, 0, 0, 1, 1, 0, 1);
+    RLOGD("rock_update_nrestart ret = %d\n", ret);
+    if(ret)
+    {
+        RLOGD("fota update fail!\n");
+    }
+    time_t t2 = time(NULL);
+    RLOGE("cy: fota update cost %d\n", t2 - t1);
+    return ret;
+}
+
+std::string g_base_addr;
+/**
+ * @brief Set the upgrade package address
+ *
+ * @param1 value:fota addr
+ * @param1 szie:fota addr length
+ * @return 0:set success other:set fail
+ */
+int lynq_fota_set_addr_value(char *value,int size)
+{
+    int ret;
+    printf("cy: lynq_fota_set_addr_value %s %d!\n", value, size);
+    RLOGE("cy: lynq_fota_set_addr_value %s %d!\n", value, size);
+    if(size < 120)
+    {
+        ret = lynq_set_value(FOTA_UCI_MODULE,FOTA_UCI_ADDR, value);
+        if (ret != 0){
+            RLOGE("cy: lynq_fota_set_addr_value fail %d\n", ret);
+            g_base_addr = value;
+            return 0;
+        }
+        return ret;
+    }
+    return -1;
+}
+/**
+ * @brief get the upgrade package address
+ *
+ * @param1 value:fota addr
+ * @return 0:get success other:set fail
+ */
+int lynq_fota_get_addr_value(char *tmp)
+{
+    return lynq_get_value(FOTA_UCI_FILE, FOTA_UCI_MODULE,FOTA_UCI_ADDR, tmp);
+}
+
+/**
+ * @brief Porting wakes up the demo content
+ */
+static void lynq_init_wake_lock_func(void)
+{
+    const char *lynqLibPath_WakeLock = "/usr/lib64/libpower.so";
+
+    dlHandle_wakelock = dlopen(lynqLibPath_WakeLock, RTLD_NOW);
+    if (dlHandle_wakelock == NULL)
+    {
+        printf("dlopen lynqLibPath_WakeLock failed: %s", dlerror());
+        exit(EXIT_FAILURE);
+    }
+    
+    acquire_wake_lock = (int(*)(int,const char*))dlsym(dlHandle_wakelock, "acquire_wake_lock");
+    if (acquire_wake_lock == NULL) {
+        printf("acquire_wake_lock not defined or exported in %s", lynqLibPath_WakeLock);
+        exit(EXIT_FAILURE);
+    }
+    release_wake_lock = (int(*)( const char*))dlsym(dlHandle_wakelock, "release_wake_lock");
+    if (release_wake_lock == NULL) {
+        printf("release_wake_lock not defined or exported in %s", lynqLibPath_WakeLock);
+        exit(EXIT_FAILURE);
+    }
+    dlerror(); // Clear any previous dlerror
+
+    return;
+}
+
+/**
+ * @brief fota wake lock
+ *
+ * @param1 value:void
+ * @return ;
+ */
+static void lynq_fota_grab_artial_wake_lock(void) 
+{
+    acquire_wake_lock(PARTIAL_WAKE_LOCK, ANDROID_WAKE_LOCK_NAME);
+}
+
+/**
+ * @brief get the upgrade package address
+ *
+ * @param1 value:void
+ * @return ;
+ */
+static void lynq_fota_release_wake_lock(void) 
+{
+    release_wake_lock(ANDROID_WAKE_LOCK_NAME);
+}
+/**
+ * @brief This is the wake up call
+ * end
+ */
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/sha.c b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/sha.c
new file mode 100755
index 0000000..b1a1936
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/sha.c
@@ -0,0 +1,432 @@
+/* sha.c
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**     * Redistributions of source code must retain the above copyright
+**       notice, this list of conditions and the following disclaimer.
+**     * Redistributions in binary form must reproduce the above copyright
+**       notice, this list of conditions and the following disclaimer in the
+**       documentation and/or other materials provided with the distribution.
+**     * Neither the name of Google Inc. nor the names of its contributors may
+**       be used to endorse or promote products derived from this software
+**       without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "sha.h"
+
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "lynq_fota_file.h"
+
+#include "mtk_device_wrap.h"
+
+// Some machines lack byteswap.h and endian.h.  These have to use the
+// slower code, even if they're little-endian.
+
+#if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+
+#include <byteswap.h>
+#include <memory.h>
+
+
+
+// This version is about 28% faster than the generic version below,
+// but assumes little-endianness.
+
+static inline uint32_t ror27(uint32_t val) {
+    return (val >> 27) | (val << 5);
+}
+static inline uint32_t ror2(uint32_t val) {
+    return (val >> 2) | (val << 30);
+}
+static inline uint32_t ror31(uint32_t val) {
+    return (val >> 31) | (val << 1);
+}
+
+static void SHA1_Transform(SHA_CTX* ctx) {
+    uint32_t W[80];
+    register uint32_t A, B, C, D, E;
+    int t;
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+#define SHA_F1(A,B,C,D,E,t)                     \
+    E += ror27(A) +                             \
+        (W[t] = bswap_32(ctx->buf.w[t])) +      \
+        (D^(B&(C^D))) + 0x5A827999;             \
+    B = ror2(B);
+
+    for (t = 0; t < 15; t += 5) {
+        SHA_F1(A,B,C,D,E,t + 0);
+        SHA_F1(E,A,B,C,D,t + 1);
+        SHA_F1(D,E,A,B,C,t + 2);
+        SHA_F1(C,D,E,A,B,t + 3);
+        SHA_F1(B,C,D,E,A,t + 4);
+    }
+    SHA_F1(A,B,C,D,E,t + 0);  // 16th one, t == 15
+
+#undef SHA_F1
+
+#define SHA_F1(A,B,C,D,E,t)                                     \
+    E += ror27(A) +                                             \
+        (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) +   \
+        (D^(B&(C^D))) + 0x5A827999;                             \
+    B = ror2(B);
+
+    SHA_F1(E,A,B,C,D,t + 1);
+    SHA_F1(D,E,A,B,C,t + 2);
+    SHA_F1(C,D,E,A,B,t + 3);
+    SHA_F1(B,C,D,E,A,t + 4);
+
+#undef SHA_F1
+
+#define SHA_F2(A,B,C,D,E,t)                                     \
+    E += ror27(A) +                                             \
+        (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) +   \
+        (B^C^D) + 0x6ED9EBA1;                                   \
+    B = ror2(B);
+
+    for (t = 20; t < 40; t += 5) {
+        SHA_F2(A,B,C,D,E,t + 0);
+        SHA_F2(E,A,B,C,D,t + 1);
+        SHA_F2(D,E,A,B,C,t + 2);
+        SHA_F2(C,D,E,A,B,t + 3);
+        SHA_F2(B,C,D,E,A,t + 4);
+    }
+
+#undef SHA_F2
+
+#define SHA_F3(A,B,C,D,E,t)                                     \
+    E += ror27(A) +                                             \
+        (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) +   \
+        ((B&C)|(D&(B|C))) + 0x8F1BBCDC;                         \
+    B = ror2(B);
+
+    for (; t < 60; t += 5) {
+        SHA_F3(A,B,C,D,E,t + 0);
+        SHA_F3(E,A,B,C,D,t + 1);
+        SHA_F3(D,E,A,B,C,t + 2);
+        SHA_F3(C,D,E,A,B,t + 3);
+        SHA_F3(B,C,D,E,A,t + 4);
+    }
+
+#undef SHA_F3
+
+#define SHA_F4(A,B,C,D,E,t)                                     \
+    E += ror27(A) +                                             \
+        (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) +   \
+        (B^C^D) + 0xCA62C1D6;                                   \
+    B = ror2(B);
+
+    for (; t < 80; t += 5) {
+        SHA_F4(A,B,C,D,E,t + 0);
+        SHA_F4(E,A,B,C,D,t + 1);
+        SHA_F4(D,E,A,B,C,t + 2);
+        SHA_F4(C,D,E,A,B,t + 3);
+        SHA_F4(B,C,D,E,A,t + 4);
+    }
+
+#undef SHA_F4
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+void SHA_update(SHA_CTX* ctx, const void* data, int len) {
+    int i = ctx->count % sizeof(ctx->buf);
+    const uint8_t* p = (const uint8_t*)data;
+
+    ctx->count += len;
+
+    while (len > sizeof(ctx->buf) - i) {
+        memcpy(&ctx->buf.b[i], p, sizeof(ctx->buf) - i);
+        len -= sizeof(ctx->buf) - i;
+        p += sizeof(ctx->buf) - i;
+        SHA1_Transform(ctx);
+        i = 0;
+    }
+
+    while (len--) {
+        ctx->buf.b[i++] = *p++;
+        if (i == sizeof(ctx->buf)) {
+            SHA1_Transform(ctx);
+            i = 0;
+        }
+    }
+}
+
+
+const uint8_t* SHA_final(SHA_CTX* ctx) {
+    uint64_t cnt = ctx->count * 8;
+    int i;
+
+    SHA_update(ctx, (uint8_t*)"\x80", 1);
+    while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) {
+        SHA_update(ctx, (uint8_t*)"\0", 1);
+    }
+    for (i = 0; i < 8; ++i) {
+        uint8_t tmp = cnt >> ((7 - i) * 8);
+        SHA_update(ctx, &tmp, 1);
+    }
+
+    for (i = 0; i < 5; i++) {
+        ctx->buf.w[i] = bswap_32(ctx->state[i]);
+    }
+
+    return ctx->buf.b;
+}
+
+#else   // #if defined(HAVE_ENDIAN_H) && defined(HAVE_LITTLE_ENDIAN)
+
+#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+static void SHA1_transform(SHA_CTX *ctx) {
+    uint32_t W[80];
+    uint32_t A, B, C, D, E;
+    uint8_t *p = ctx->buf;
+    int t;
+
+    for(t = 0; t < 16; ++t) {
+        uint32_t tmp =  *p++ << 24;
+        tmp |= *p++ << 16;
+        tmp |= *p++ << 8;
+        tmp |= *p++;
+        W[t] = tmp;
+    }
+
+    for(; t < 80; t++) {
+        W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
+    }
+
+    A = ctx->state[0];
+    B = ctx->state[1];
+    C = ctx->state[2];
+    D = ctx->state[3];
+    E = ctx->state[4];
+
+    for(t = 0; t < 80; t++) {
+        uint32_t tmp = rol(5,A) + E + W[t];
+
+        if (t < 20)
+            tmp += (D^(B&(C^D))) + 0x5A827999;
+        else if ( t < 40)
+            tmp += (B^C^D) + 0x6ED9EBA1;
+        else if ( t < 60)
+            tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
+        else
+            tmp += (B^C^D) + 0xCA62C1D6;
+
+        E = D;
+        D = C;
+        C = rol(30,B);
+        B = A;
+        A = tmp;
+    }
+
+    ctx->state[0] += A;
+    ctx->state[1] += B;
+    ctx->state[2] += C;
+    ctx->state[3] += D;
+    ctx->state[4] += E;
+}
+
+void SHA_update(SHA_CTX *ctx, const void *data, int len) {
+    int i = ctx->count % sizeof(ctx->buf);
+    const uint8_t* p = (const uint8_t*)data;
+
+    ctx->count += len;
+
+    while (len--) {
+        ctx->buf[i++] = *p++;
+        if (i == sizeof(ctx->buf)) {
+            SHA1_transform(ctx);
+            i = 0;
+        }
+    }
+}
+const uint8_t *SHA_final(SHA_CTX *ctx) {
+    uint8_t *p = ctx->buf;
+    uint64_t cnt = ctx->count * 8;
+    int i;
+
+    SHA_update(ctx, (uint8_t*)"\x80", 1);
+    while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8)) {
+        SHA_update(ctx, (uint8_t*)"\0", 1);
+    }
+    for (i = 0; i < 8; ++i) {
+        uint8_t tmp = cnt >> ((7 - i) * 8);
+        SHA_update(ctx, &tmp, 1);
+    }
+
+    for (i = 0; i < 5; i++) {
+        uint32_t tmp = ctx->state[i];
+        *p++ = tmp >> 24;
+        *p++ = tmp >> 16;
+        *p++ = tmp >> 8;
+        *p++ = tmp >> 0;
+    }
+
+    return ctx->buf;
+}
+
+#endif // endianness
+
+void SHA_init(SHA_CTX* ctx) {
+    ctx->state[0] = 0x67452301;
+    ctx->state[1] = 0xEFCDAB89;
+    ctx->state[2] = 0x98BADCFE;
+    ctx->state[3] = 0x10325476;
+    ctx->state[4] = 0xC3D2E1F0;
+    ctx->count = 0;
+}
+
+/* Convenience function */
+const uint8_t* SHA(const void *data, int len, uint8_t *digest) {
+    const uint8_t *p;
+    int i;
+	
+    SHA_CTX ctx;
+    SHA_init(&ctx);
+    SHA_update(&ctx, data, len);
+    p = SHA_final(&ctx);
+    for (i = 0; i < SHA_DIGEST_SIZE; ++i) {
+        digest[i] = *p++;
+    }
+    return digest;
+}
+
+#define NAND_PAGE_SIZE_SHA  4096
+
+const uint8_t* ROCK_SHA_FILE_COMMON(int fd_sha, int offset,int totle_size, uint8_t *digest) {
+    const uint8_t *p;
+    int i = 0;
+    //int fd_sha;
+    int size = 0;
+    int totale_size_common = totle_size;
+    char data[NAND_PAGE_SIZE_SHA];
+	
+
+    lseek(fd_sha, offset, SEEK_SET);
+    SHA_CTX ctx;
+    SHA_init(&ctx);
+    //int fd = open("/tmp/fota.delta", O_RDWR|O_CREAT);
+
+    do{
+        if(totale_size_common >= NAND_PAGE_SIZE_SHA)
+        {
+            size = read(fd_sha,data,NAND_PAGE_SIZE_SHA);
+        }
+        else
+        {
+            size = read(fd_sha,data,totale_size_common);
+        }
+        if (size == 0){
+		    break;
+		}			
+        //write(fd, data, size);
+        SHA_update(&ctx, data, size);
+        totale_size_common -= size;
+
+    }while(totale_size_common>0);
+    p = SHA_final(&ctx);
+    for (i = 0; i < SHA_DIGEST_SIZE; ++i) 
+    {
+        digest[i] = *p++;
+    }
+    //close(fd);
+    return digest;
+}
+
+const uint8_t* ROCK_SHA_FILE(int fd_sha, int offset,int totle_size, uint8_t *digest) {
+    const uint8_t *p;
+    int i = 0;
+    //int fd_sha;
+    int size = 0;
+    int totale_size_file = totle_size;
+    char data[NAND_PAGE_SIZE_SHA];
+	
+
+    mtk_device_wrap_seek(fd_sha, offset, SEEK_SET);
+    SHA_CTX ctx;
+    SHA_init(&ctx);
+
+    do{
+        if(totale_size_file >= NAND_PAGE_SIZE_SHA)
+        {
+            size = mtk_device_wrap_read(fd_sha,data,NAND_PAGE_SIZE_SHA);   
+        }
+        else
+        {
+            size = mtk_device_wrap_read(fd_sha,data,totale_size_file);
+        }
+	    if (size == 0){
+		    break;
+		}	
+        SHA_update(&ctx, data, size);
+        totale_size_file -= size;
+
+    }while(totale_size_file>0);
+    p = SHA_final(&ctx);
+    for (i = 0; i < SHA_DIGEST_SIZE; ++i) 
+    {
+        digest[i] = *p++;
+    }
+    return digest;
+}
+
+
+
+// Take a string 'str' of 40 hex digits and parse it into the 20
+// byte array 'digest'.  'str' may contain only the digest or be of
+// the form "<digest>:<anything>".  Return 0 on success, -1 on any
+// error.
+int ParseSha1(const char* str, uint8_t* digest) {
+    int i;
+    const char* ps = str;
+    uint8_t* pd = digest;
+    for (i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) {
+        int digit;
+        if (*ps >= '0' && *ps <= '9') {
+            digit = *ps - '0';
+        } else if (*ps >= 'a' && *ps <= 'f') {
+            digit = *ps - 'a' + 10;
+        } else if (*ps >= 'A' && *ps <= 'F') {
+            digit = *ps - 'A' + 10;
+        } else {
+            return -1;
+        }
+        if (i % 2 == 0) {
+            *pd = digit << 4;
+        } else {
+            *pd |= digit;
+            ++pd;
+        }
+    }
+    if (*ps != '\0') return -1;
+    return 0;
+}
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/unzip.c b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/unzip.c
new file mode 100755
index 0000000..ed763f8
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/unzip.c
@@ -0,0 +1,1985 @@
+/* unzip.c -- IO for uncompress .zip files using zlib
+   Version 1.1, February 14h, 2010
+   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+         Modifications of Unzip for Zip64
+         Copyright (C) 2007-2008 Even Rouault
+
+         Modifications for Zip64 support on both zip and unzip
+         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+         For more info read MiniZip_info.txt
+
+
+  ------------------------------------------------------------------------------------
+  Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
+  compatibility with older software. The following is from the original crypt.c.
+  Code woven in by Terry Thorsen 1/2003.
+
+  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.
+
+  See the accompanying file LICENSE, version 2000-Apr-09 or later
+  (the contents of which are also included in zip.h) for terms of use.
+  If, for some reason, all these files are missing, the Info-ZIP license
+  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
+
+        crypt.c (full version) by Info-ZIP.      Last revised:  [see crypt.h]
+
+  The encryption/decryption parts of this source code (as opposed to the
+  non-echoing password parts) were originally written in Europe.  The
+  whole source package can be freely distributed, including from the USA.
+  (Prior to January 2000, re-export from the US was a violation of US law.)
+
+        This encryption code is a direct transcription of the algorithm from
+  Roger Schlafly, described by Phil Katz in the file appnote.txt.  This
+  file (appnote.txt) is distributed with the PKZIP program (even in the
+  version without encryption capabilities).
+
+        ------------------------------------------------------------------------------------
+
+        Changes in unzip.c
+
+        2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos
+  2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz*
+  2007-2008 - Even Rouault - Remove old C style function prototypes
+  2007-2008 - Even Rouault - Add unzip support for ZIP64
+
+        Copyright (C) 2007-2008 Even Rouault
+
+
+  Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again).
+  Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G
+                                should only read the compressed/uncompressed size from the Zip64 format if
+                                the size from normal header was 0xFFFFFFFF
+  Oct-2009 - Mathias Svensson - Applied some bug fixes from patches received from Gilles Vollant
+  Oct-2009 - Mathias Svensson - Applied support to unzip files with compression method BZIP2 (bzip2 lib is required)
+                                Patch created by Daniel Borca
+
+  Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
+
+  Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson
+
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef NOUNCRYPT
+        #define NOUNCRYPT
+#endif
+
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef STDC
+#  include <stddef.h>
+#endif
+#ifdef NO_ERRNO_H
+    extern int errno;
+#else
+#   include <errno.h>
+#endif
+
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+
+#ifndef CASESENSITIVITYDEFAULT_NO
+#  if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
+#    define CASESENSITIVITYDEFAULT_NO
+#  endif
+#endif
+
+
+#ifndef UNZ_BUFSIZE
+#define UNZ_BUFSIZE (16384)
+#endif
+
+#ifndef UNZ_MAXFILENAMEINZIP
+#define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+
+const char unz_copyright[] =
+   " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info64_internal_s
+{
+    ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
+} unz_file_info64_internal;
+
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile,
+    when reading and decompress it */
+typedef struct
+{
+    char  *read_buffer;         /* internal buffer for compressed data */
+    z_stream stream;            /* zLib stream structure for inflate */
+
+#ifdef HAVE_BZIP2
+    bz_stream bstream;          /* bzLib stream structure for bziped */
+#endif
+
+    ZPOS64_T pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/
+    uLong stream_initialised;   /* flag set if stream structure is initialised*/
+
+    ZPOS64_T offset_local_extrafield;/* offset of the local extra field */
+    uInt  size_local_extrafield;/* size of the local extra field */
+    ZPOS64_T pos_local_extrafield;   /* position in the local extra field in read*/
+    ZPOS64_T total_out_64;
+
+    uLong crc32;                /* crc32 of all data uncompressed */
+    uLong crc32_wait;           /* crc32 we must obtain after decompress all */
+    ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */
+    ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/
+    zlib_filefunc64_32_def z_filefunc;
+    voidpf filestream;        /* io structure of the zipfile */
+    uLong compression_method;   /* compression method (0==store) */
+    ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+    int   raw;
+} file_in_zip64_read_info_s;
+
+
+/* unz64_s contain internal information about the zipfile
+*/
+typedef struct
+{
+    zlib_filefunc64_32_def z_filefunc;
+    int is64bitOpenFunction;
+    voidpf filestream;        /* io structure of the zipfile */
+    unz_global_info64 gi;       /* public global information */
+    ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+    ZPOS64_T num_file;             /* number of the current file in the zipfile*/
+    ZPOS64_T pos_in_central_dir;   /* pos of the current file in the central dir*/
+    ZPOS64_T current_file_ok;      /* flag about the usability of the current file*/
+    ZPOS64_T central_pos;          /* position of the beginning of the central dir*/
+
+    ZPOS64_T size_central_dir;     /* size of the central directory  */
+    ZPOS64_T offset_central_dir;   /* offset of start of central directory with
+                                   respect to the starting disk number */
+
+    unz_file_info64 cur_file_info; /* public info about the current file in zip*/
+    unz_file_info64_internal cur_file_info_internal; /* private info about it*/
+    file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current
+                                        file if we are decompressing it */
+    int encrypted;
+
+    int isZip64;
+
+#    ifndef NOUNCRYPT
+    unsigned long keys[3];     /* keys defining the pseudo-random sequence */
+    const z_crc_t* pcrc_32_tab;
+#    endif
+} unz64_s;
+
+
+#ifndef NOUNCRYPT
+#include "crypt.h"
+#endif
+
+
+/* ===========================================================================
+   Reads a long in LSB order from the given gz_stream. Sets
+*/
+
+local int unz64local_getShort(const zlib_filefunc64_32_def* pzlib_filefunc_def,
+                              voidpf filestream,
+                              uLong *pX) {
+    unsigned char c[2];
+    int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,2);
+    if (err==2)
+    {
+        *pX = c[0] | ((uLong)c[1] << 8);
+        return UNZ_OK;
+    }
+    else
+    {
+        *pX = 0;
+        if (ZERROR64(*pzlib_filefunc_def,filestream))
+            return UNZ_ERRNO;
+        else
+            return UNZ_EOF;
+    }
+}
+
+local int unz64local_getLong(const zlib_filefunc64_32_def* pzlib_filefunc_def,
+                             voidpf filestream,
+                             uLong *pX) {
+    unsigned char c[4];
+    int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,4);
+    if (err==4)
+    {
+        *pX = c[0] | ((uLong)c[1] << 8) | ((uLong)c[2] << 16) | ((uLong)c[3] << 24);
+        return UNZ_OK;
+    }
+    else
+    {
+        *pX = 0;
+        if (ZERROR64(*pzlib_filefunc_def,filestream))
+            return UNZ_ERRNO;
+        else
+            return UNZ_EOF;
+    }
+}
+
+
+local int unz64local_getLong64(const zlib_filefunc64_32_def* pzlib_filefunc_def,
+                               voidpf filestream,
+                               ZPOS64_T *pX) {
+    unsigned char c[8];
+    int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,c,8);
+    if (err==8)
+    {
+        *pX = c[0] | ((ZPOS64_T)c[1] << 8) | ((ZPOS64_T)c[2] << 16) | ((ZPOS64_T)c[3] << 24)
+            | ((ZPOS64_T)c[4] << 32) | ((ZPOS64_T)c[5] << 40) | ((ZPOS64_T)c[6] << 48) | ((ZPOS64_T)c[7] << 56);
+        return UNZ_OK;
+    }
+    else
+    {
+        *pX = 0;
+        if (ZERROR64(*pzlib_filefunc_def,filestream))
+            return UNZ_ERRNO;
+        else
+            return UNZ_EOF;
+    }
+}
+
+/* My own strcmpi / strcasecmp */
+local int strcmpcasenosensitive_internal(const char* fileName1, const char* fileName2) {
+    for (;;)
+    {
+        char c1=*(fileName1++);
+        char c2=*(fileName2++);
+        if ((c1>='a') && (c1<='z'))
+            c1 -= 0x20;
+        if ((c2>='a') && (c2<='z'))
+            c2 -= 0x20;
+        if (c1=='\0')
+            return ((c2=='\0') ? 0 : -1);
+        if (c2=='\0')
+            return 1;
+        if (c1<c2)
+            return -1;
+        if (c1>c2)
+            return 1;
+    }
+}
+
+
+#ifdef  CASESENSITIVITYDEFAULT_NO
+#define CASESENSITIVITYDEFAULTVALUE 2
+#else
+#define CASESENSITIVITYDEFAULTVALUE 1
+#endif
+
+#ifndef STRCMPCASENOSENTIVEFUNCTION
+#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
+#endif
+
+/*
+   Compare two filenames (fileName1,fileName2).
+   If iCaseSensitivity = 1, comparison is case sensitive (like strcmp)
+   If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi
+                                                                or strcasecmp)
+   If iCaseSensitivity = 0, case sensitivity is default of your operating system
+        (like 1 on Unix, 2 on Windows)
+
+*/
+extern int ZEXPORT unzStringFileNameCompare (const char*  fileName1,
+                                             const char*  fileName2,
+                                             int iCaseSensitivity) {
+    if (iCaseSensitivity==0)
+        iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
+
+    if (iCaseSensitivity==1)
+        return strcmp(fileName1,fileName2);
+
+    return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+}
+
+#ifndef BUFREADCOMMENT
+#define BUFREADCOMMENT (0x400)
+#endif
+
+#ifndef CENTRALDIRINVALID
+#define CENTRALDIRINVALID ((ZPOS64_T)(-1))
+#endif
+
+/*
+  Locate the Central directory of a zipfile (at the end, just before
+    the global comment)
+*/
+local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) {
+    unsigned char* buf;
+    ZPOS64_T uSizeFile;
+    ZPOS64_T uBackRead;
+    ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+    ZPOS64_T uPosFound=CENTRALDIRINVALID;
+
+    if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+        return CENTRALDIRINVALID;
+
+
+    uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+    if (uMaxBack>uSizeFile)
+        uMaxBack = uSizeFile;
+
+    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+    if (buf==NULL)
+        return CENTRALDIRINVALID;
+
+    uBackRead = 4;
+    while (uBackRead<uMaxBack)
+    {
+        uLong uReadSize;
+        ZPOS64_T uReadPos ;
+        int i;
+        if (uBackRead+BUFREADCOMMENT>uMaxBack)
+            uBackRead = uMaxBack;
+        else
+            uBackRead+=BUFREADCOMMENT;
+        uReadPos = uSizeFile-uBackRead ;
+
+        uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+                     (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+        if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+            break;
+
+        if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+            break;
+
+        for (i=(int)uReadSize-3; (i--)>0;)
+            if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+                ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+            {
+                uPosFound = uReadPos+(unsigned)i;
+                break;
+            }
+
+        if (uPosFound!=CENTRALDIRINVALID)
+            break;
+    }
+    free(buf);
+    return uPosFound;
+}
+
+
+/*
+  Locate the Central directory 64 of a zipfile (at the end, just before
+    the global comment)
+*/
+local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def,
+                                             voidpf filestream) {
+    unsigned char* buf;
+    ZPOS64_T uSizeFile;
+    ZPOS64_T uBackRead;
+    ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+    ZPOS64_T uPosFound=CENTRALDIRINVALID;
+    uLong uL;
+                ZPOS64_T relativeOffset;
+
+    if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+        return CENTRALDIRINVALID;
+
+
+    uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+    if (uMaxBack>uSizeFile)
+        uMaxBack = uSizeFile;
+
+    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+    if (buf==NULL)
+        return CENTRALDIRINVALID;
+
+    uBackRead = 4;
+    while (uBackRead<uMaxBack)
+    {
+        uLong uReadSize;
+        ZPOS64_T uReadPos;
+        int i;
+        if (uBackRead+BUFREADCOMMENT>uMaxBack)
+            uBackRead = uMaxBack;
+        else
+            uBackRead+=BUFREADCOMMENT;
+        uReadPos = uSizeFile-uBackRead ;
+
+        uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+                     (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+        if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+            break;
+
+        if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+            break;
+
+        for (i=(int)uReadSize-3; (i--)>0;)
+            if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+                ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
+            {
+                uPosFound = uReadPos+(unsigned)i;
+                break;
+            }
+
+        if (uPosFound!=CENTRALDIRINVALID)
+            break;
+    }
+    free(buf);
+    if (uPosFound == CENTRALDIRINVALID)
+        return CENTRALDIRINVALID;
+
+    /* Zip64 end of central directory locator */
+    if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
+        return CENTRALDIRINVALID;
+
+    /* the signature, already checked */
+    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+        return CENTRALDIRINVALID;
+
+    /* number of the disk with the start of the zip64 end of  central directory */
+    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+        return CENTRALDIRINVALID;
+    if (uL != 0)
+        return CENTRALDIRINVALID;
+
+    /* relative offset of the zip64 end of central directory record */
+    if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
+        return CENTRALDIRINVALID;
+
+    /* total number of disks */
+    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+        return CENTRALDIRINVALID;
+    if (uL != 1)
+        return CENTRALDIRINVALID;
+
+    /* Goto end of central directory record */
+    if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
+        return CENTRALDIRINVALID;
+
+     /* the signature */
+    if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+        return CENTRALDIRINVALID;
+
+    if (uL != 0x06064b50)
+        return CENTRALDIRINVALID;
+
+    return relativeOffset;
+}
+
+/*
+  Open a Zip file. path contain the full pathname (by example,
+     on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
+     "zlib/zlib114.zip".
+     If the zipfile cannot be opened (file doesn't exist or in not valid), the
+       return value is NULL.
+     Else, the return value is a unzFile Handle, usable with other function
+       of this unzip package.
+*/
+local unzFile unzOpenInternal(const void *path,
+                              zlib_filefunc64_32_def* pzlib_filefunc64_32_def,
+                              int is64bitOpenFunction) {
+    unz64_s us;
+    unz64_s *s;
+    ZPOS64_T central_pos;
+    uLong   uL;
+
+    uLong number_disk;          /* number of the current dist, used for
+                                   spanning ZIP, unsupported, always 0*/
+    uLong number_disk_with_CD;  /* number the the disk with central dir, used
+                                   for spanning ZIP, unsupported, always 0*/
+    ZPOS64_T number_entry_CD;      /* total number of entries in
+                                   the central dir
+                                   (same than number_entry on nospan) */
+
+    int err=UNZ_OK;
+
+    if (unz_copyright[0]!=' ')
+        return NULL;
+
+    us.z_filefunc.zseek32_file = NULL;
+    us.z_filefunc.ztell32_file = NULL;
+    if (pzlib_filefunc64_32_def==NULL)
+        fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
+    else
+        us.z_filefunc = *pzlib_filefunc64_32_def;
+    us.is64bitOpenFunction = is64bitOpenFunction;
+
+
+
+    us.filestream = ZOPEN64(us.z_filefunc,
+                                                 path,
+                                                 ZLIB_FILEFUNC_MODE_READ |
+                                                 ZLIB_FILEFUNC_MODE_EXISTING);
+    if (us.filestream==NULL)
+        return NULL;
+
+    central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
+    if (central_pos!=CENTRALDIRINVALID)
+    {
+        uLong uS;
+        ZPOS64_T uL64;
+
+        us.isZip64 = 1;
+
+        if (ZSEEK64(us.z_filefunc, us.filestream,
+                                      central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+        err=UNZ_ERRNO;
+
+        /* the signature, already checked */
+        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* size of zip64 end of central directory record */
+        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* version made by */
+        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* version needed to extract */
+        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* number of this disk */
+        if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* number of the disk with the start of the central directory */
+        if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* total number of entries in the central directory on this disk */
+        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* total number of entries in the central directory */
+        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        if ((number_entry_CD!=us.gi.number_entry) ||
+            (number_disk_with_CD!=0) ||
+            (number_disk!=0))
+            err=UNZ_BADZIPFILE;
+
+        /* size of the central directory */
+        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* offset of start of central directory with respect to the
+          starting disk number */
+        if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        us.gi.size_comment = 0;
+    }
+    else
+    {
+        central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
+        if (central_pos==CENTRALDIRINVALID)
+            err=UNZ_ERRNO;
+
+        us.isZip64 = 0;
+
+        if (ZSEEK64(us.z_filefunc, us.filestream,
+                                        central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+            err=UNZ_ERRNO;
+
+        /* the signature, already checked */
+        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* number of this disk */
+        if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* number of the disk with the start of the central directory */
+        if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
+            err=UNZ_ERRNO;
+
+        /* total number of entries in the central dir on this disk */
+        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+            err=UNZ_ERRNO;
+        us.gi.number_entry = uL;
+
+        /* total number of entries in the central dir */
+        if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+            err=UNZ_ERRNO;
+        number_entry_CD = uL;
+
+        if ((number_entry_CD!=us.gi.number_entry) ||
+            (number_disk_with_CD!=0) ||
+            (number_disk!=0))
+            err=UNZ_BADZIPFILE;
+
+        /* size of the central directory */
+        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+            err=UNZ_ERRNO;
+        us.size_central_dir = uL;
+
+        /* offset of start of central directory with respect to the
+            starting disk number */
+        if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+            err=UNZ_ERRNO;
+        us.offset_central_dir = uL;
+
+        /* zipfile comment length */
+        if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
+            err=UNZ_ERRNO;
+    }
+
+    if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
+        (err==UNZ_OK))
+        err=UNZ_BADZIPFILE;
+
+    if (err!=UNZ_OK)
+    {
+        ZCLOSE64(us.z_filefunc, us.filestream);
+        return NULL;
+    }
+
+    us.byte_before_the_zipfile = central_pos -
+                            (us.offset_central_dir+us.size_central_dir);
+    us.central_pos = central_pos;
+    us.pfile_in_zip_read = NULL;
+    us.encrypted = 0;
+
+
+    s=(unz64_s*)ALLOC(sizeof(unz64_s));
+    if( s != NULL)
+    {
+        *s=us;
+        unzGoToFirstFile((unzFile)s);
+    }
+    return (unzFile)s;
+}
+
+
+extern unzFile ZEXPORT unzOpen2(const char *path,
+                                zlib_filefunc_def* pzlib_filefunc32_def) {
+    if (pzlib_filefunc32_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
+        return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 0);
+    }
+    else
+        return unzOpenInternal(path, NULL, 0);
+}
+
+extern unzFile ZEXPORT unzOpen2_64(const void *path,
+                                   zlib_filefunc64_def* pzlib_filefunc_def) {
+    if (pzlib_filefunc_def != NULL)
+    {
+        zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+        zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+        zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+        zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+        return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1);
+    }
+    else
+        return unzOpenInternal(path, NULL, 1);
+}
+
+extern unzFile ZEXPORT unzOpen(const char *path) {
+    return unzOpenInternal(path, NULL, 0);
+}
+
+extern unzFile ZEXPORT unzOpen64(const void *path) {
+    return unzOpenInternal(path, NULL, 1);
+}
+
+/*
+  Close a ZipFile opened with unzOpen.
+  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+    these files MUST be closed with unzCloseCurrentFile before call unzClose.
+  return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzClose(unzFile file) {
+    unz64_s* s;
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+
+    if (s->pfile_in_zip_read!=NULL)
+        unzCloseCurrentFile(file);
+
+    ZCLOSE64(s->z_filefunc, s->filestream);
+    free(s);
+    return UNZ_OK;
+}
+
+
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzGetGlobalInfo64(unzFile file, unz_global_info64* pglobal_info) {
+    unz64_s* s;
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    *pglobal_info=s->gi;
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32) {
+    unz64_s* s;
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    /* to do : check if number_entry is not truncated */
+    pglobal_info32->number_entry = (uLong)s->gi.number_entry;
+    pglobal_info32->size_comment = s->gi.size_comment;
+    return UNZ_OK;
+}
+/*
+   Translate date/time from Dos format to tm_unz (readable more easily)
+*/
+local void unz64local_DosDateToTmuDate(ZPOS64_T ulDosDate, tm_unz* ptm) {
+    ZPOS64_T uDate;
+    uDate = (ZPOS64_T)(ulDosDate>>16);
+    ptm->tm_mday = (int)(uDate&0x1f) ;
+    ptm->tm_mon =  (int)((((uDate)&0x1E0)/0x20)-1) ;
+    ptm->tm_year = (int)(((uDate&0x0FE00)/0x0200)+1980) ;
+
+    ptm->tm_hour = (int) ((ulDosDate &0xF800)/0x800);
+    ptm->tm_min =  (int) ((ulDosDate&0x7E0)/0x20) ;
+    ptm->tm_sec =  (int) (2*(ulDosDate&0x1f)) ;
+}
+
+/*
+  Get Info about the current file in the zipfile, with internal only info
+*/
+local int unz64local_GetCurrentFileInfoInternal(unzFile file,
+                                                unz_file_info64 *pfile_info,
+                                                unz_file_info64_internal
+                                                *pfile_info_internal,
+                                                char *szFileName,
+                                                uLong fileNameBufferSize,
+                                                void *extraField,
+                                                uLong extraFieldBufferSize,
+                                                char *szComment,
+                                                uLong commentBufferSize) {
+    unz64_s* s;
+    unz_file_info64 file_info;
+    unz_file_info64_internal file_info_internal;
+    int err=UNZ_OK;
+    uLong uMagic;
+    long lSeek=0;
+    uLong uL;
+
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    if (ZSEEK64(s->z_filefunc, s->filestream,
+              s->pos_in_central_dir+s->byte_before_the_zipfile,
+              ZLIB_FILEFUNC_SEEK_SET)!=0)
+        err=UNZ_ERRNO;
+
+
+    /* we check the magic */
+    if (err==UNZ_OK)
+    {
+        if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+            err=UNZ_ERRNO;
+        else if (uMagic!=0x02014b50)
+            err=UNZ_BADZIPFILE;
+    }
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+        err=UNZ_ERRNO;
+    file_info.compressed_size = uL;
+
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+        err=UNZ_ERRNO;
+    file_info.uncompressed_size = uL;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+                // relative offset of local header
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+        err=UNZ_ERRNO;
+    file_info_internal.offset_curfile = uL;
+
+    lSeek+=file_info.size_filename;
+    if ((err==UNZ_OK) && (szFileName!=NULL))
+    {
+        uLong uSizeRead ;
+        if (file_info.size_filename<fileNameBufferSize)
+        {
+            *(szFileName+file_info.size_filename)='\0';
+            uSizeRead = file_info.size_filename;
+        }
+        else
+            uSizeRead = fileNameBufferSize;
+
+        if ((file_info.size_filename>0) && (fileNameBufferSize>0))
+            if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
+                err=UNZ_ERRNO;
+        lSeek -= uSizeRead;
+    }
+
+    // Read extrafield
+    if ((err==UNZ_OK) && (extraField!=NULL))
+    {
+        ZPOS64_T uSizeRead ;
+        if (file_info.size_file_extra<extraFieldBufferSize)
+            uSizeRead = file_info.size_file_extra;
+        else
+            uSizeRead = extraFieldBufferSize;
+
+        if (lSeek!=0)
+        {
+            if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+                lSeek=0;
+            else
+                err=UNZ_ERRNO;
+        }
+
+        if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+            if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead)
+                err=UNZ_ERRNO;
+
+        lSeek += file_info.size_file_extra - (uLong)uSizeRead;
+    }
+    else
+        lSeek += file_info.size_file_extra;
+
+
+    if ((err==UNZ_OK) && (file_info.size_file_extra != 0))
+    {
+                                uLong acc = 0;
+
+        // since lSeek now points to after the extra field we need to move back
+        lSeek -= file_info.size_file_extra;
+
+        if (lSeek!=0)
+        {
+            if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+                lSeek=0;
+            else
+                err=UNZ_ERRNO;
+        }
+
+        while(acc < file_info.size_file_extra)
+        {
+            uLong headerId;
+                                                uLong dataSize;
+
+            if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK)
+                err=UNZ_ERRNO;
+
+            if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
+                err=UNZ_ERRNO;
+
+            /* ZIP64 extra fields */
+            if (headerId == 0x0001)
+            {
+                if(file_info.uncompressed_size == MAXU32)
+                {
+                    if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
+                        err=UNZ_ERRNO;
+                }
+
+                if(file_info.compressed_size == MAXU32)
+                {
+                    if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
+                        err=UNZ_ERRNO;
+                }
+
+                if(file_info_internal.offset_curfile == MAXU32)
+                {
+                    /* Relative Header offset */
+                    if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
+                        err=UNZ_ERRNO;
+                }
+
+                if(file_info.disk_num_start == 0xffff)
+                {
+                    /* Disk Start Number */
+                    if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
+                        err=UNZ_ERRNO;
+                }
+
+            }
+            else
+            {
+                if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
+                    err=UNZ_ERRNO;
+            }
+
+            acc += 2 + 2 + dataSize;
+        }
+    }
+
+    if ((err==UNZ_OK) && (szComment!=NULL))
+    {
+        uLong uSizeRead ;
+        if (file_info.size_file_comment<commentBufferSize)
+        {
+            *(szComment+file_info.size_file_comment)='\0';
+            uSizeRead = file_info.size_file_comment;
+        }
+        else
+            uSizeRead = commentBufferSize;
+
+        if (lSeek!=0)
+        {
+            if (ZSEEK64(s->z_filefunc, s->filestream,(ZPOS64_T)lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+                lSeek=0;
+            else
+                err=UNZ_ERRNO;
+        }
+
+        if ((file_info.size_file_comment>0) && (commentBufferSize>0))
+            if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
+                err=UNZ_ERRNO;
+        lSeek+=file_info.size_file_comment - uSizeRead;
+    }
+    else
+        lSeek+=file_info.size_file_comment;
+
+
+    if ((err==UNZ_OK) && (pfile_info!=NULL))
+        *pfile_info=file_info;
+
+    if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
+        *pfile_info_internal=file_info_internal;
+
+    return err;
+}
+
+
+
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem.
+*/
+extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file,
+                                           unz_file_info64 * pfile_info,
+                                           char * szFileName, uLong fileNameBufferSize,
+                                           void *extraField, uLong extraFieldBufferSize,
+                                           char* szComment,  uLong commentBufferSize) {
+    return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL,
+                                                 szFileName,fileNameBufferSize,
+                                                 extraField,extraFieldBufferSize,
+                                                 szComment,commentBufferSize);
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo(unzFile file,
+                                         unz_file_info * pfile_info,
+                                         char * szFileName, uLong fileNameBufferSize,
+                                         void *extraField, uLong extraFieldBufferSize,
+                                         char* szComment,  uLong commentBufferSize) {
+    int err;
+    unz_file_info64 file_info64;
+    err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL,
+                                                szFileName,fileNameBufferSize,
+                                                extraField,extraFieldBufferSize,
+                                                szComment,commentBufferSize);
+    if ((err==UNZ_OK) && (pfile_info != NULL))
+    {
+        pfile_info->version = file_info64.version;
+        pfile_info->version_needed = file_info64.version_needed;
+        pfile_info->flag = file_info64.flag;
+        pfile_info->compression_method = file_info64.compression_method;
+        pfile_info->dosDate = file_info64.dosDate;
+        pfile_info->crc = file_info64.crc;
+
+        pfile_info->size_filename = file_info64.size_filename;
+        pfile_info->size_file_extra = file_info64.size_file_extra;
+        pfile_info->size_file_comment = file_info64.size_file_comment;
+
+        pfile_info->disk_num_start = file_info64.disk_num_start;
+        pfile_info->internal_fa = file_info64.internal_fa;
+        pfile_info->external_fa = file_info64.external_fa;
+
+        pfile_info->tmu_date = file_info64.tmu_date;
+
+
+        pfile_info->compressed_size = (uLong)file_info64.compressed_size;
+        pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
+
+    }
+    return err;
+}
+/*
+  Set the current file of the zipfile to the first file.
+  return UNZ_OK if there is no problem
+*/
+extern int ZEXPORT unzGoToFirstFile(unzFile file) {
+    int err=UNZ_OK;
+    unz64_s* s;
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    s->pos_in_central_dir=s->offset_central_dir;
+    s->num_file=0;
+    err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                             &s->cur_file_info_internal,
+                                             NULL,0,NULL,0,NULL,0);
+    s->current_file_ok = (err == UNZ_OK);
+    return err;
+}
+
+/*
+  Set the current file of the zipfile to the next file.
+  return UNZ_OK if there is no problem
+  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+extern int ZEXPORT unzGoToNextFile(unzFile file) {
+    unz64_s* s;
+    int err;
+
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    if (!s->current_file_ok)
+        return UNZ_END_OF_LIST_OF_FILE;
+    if (s->gi.number_entry != 0xffff)    /* 2^16 files overflow hack */
+      if (s->num_file+1==s->gi.number_entry)
+        return UNZ_END_OF_LIST_OF_FILE;
+
+    s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+            s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+    s->num_file++;
+    err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                               &s->cur_file_info_internal,
+                                               NULL,0,NULL,0,NULL,0);
+    s->current_file_ok = (err == UNZ_OK);
+    return err;
+}
+
+
+/*
+  Try locate the file szFileName in the zipfile.
+  For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+  return value :
+  UNZ_OK if the file is found. It becomes the current file.
+  UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+extern int ZEXPORT unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) {
+    unz64_s* s;
+    int err;
+
+    /* We remember the 'current' position in the file so that we can jump
+     * back there if we fail.
+     */
+    unz_file_info64 cur_file_infoSaved;
+    unz_file_info64_internal cur_file_info_internalSaved;
+    ZPOS64_T num_fileSaved;
+    ZPOS64_T pos_in_central_dirSaved;
+
+
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+
+    if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
+        return UNZ_PARAMERROR;
+
+    s=(unz64_s*)file;
+    if (!s->current_file_ok)
+        return UNZ_END_OF_LIST_OF_FILE;
+
+    /* Save the current state */
+    num_fileSaved = s->num_file;
+    pos_in_central_dirSaved = s->pos_in_central_dir;
+    cur_file_infoSaved = s->cur_file_info;
+    cur_file_info_internalSaved = s->cur_file_info_internal;
+
+    err = unzGoToFirstFile(file);
+
+    while (err == UNZ_OK)
+    {
+        char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+        err = unzGetCurrentFileInfo64(file,NULL,
+                                    szCurrentFileName,sizeof(szCurrentFileName)-1,
+                                    NULL,0,NULL,0);
+        if (err == UNZ_OK)
+        {
+            if (unzStringFileNameCompare(szCurrentFileName,
+                                            szFileName,iCaseSensitivity)==0)
+                return UNZ_OK;
+            err = unzGoToNextFile(file);
+        }
+    }
+
+    /* We failed, so restore the state of the 'current file' to where we
+     * were.
+     */
+    s->num_file = num_fileSaved ;
+    s->pos_in_central_dir = pos_in_central_dirSaved ;
+    s->cur_file_info = cur_file_infoSaved;
+    s->cur_file_info_internal = cur_file_info_internalSaved;
+    return err;
+}
+
+
+/*
+///////////////////////////////////////////
+// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
+// I need random access
+//
+// Further optimization could be realized by adding an ability
+// to cache the directory in memory. The goal being a single
+// comprehensive file read to put the file I need in a memory.
+*/
+
+/*
+typedef struct unz_file_pos_s
+{
+    ZPOS64_T pos_in_zip_directory;   // offset in file
+    ZPOS64_T num_of_file;            // # of file
+} unz_file_pos;
+*/
+
+extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) {
+    unz64_s* s;
+
+    if (file==NULL || file_pos==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    if (!s->current_file_ok)
+        return UNZ_END_OF_LIST_OF_FILE;
+
+    file_pos->pos_in_zip_directory  = s->pos_in_central_dir;
+    file_pos->num_of_file           = s->num_file;
+
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetFilePos(unzFile file, unz_file_pos* file_pos) {
+    unz64_file_pos file_pos64;
+    int err = unzGetFilePos64(file,&file_pos64);
+    if (err==UNZ_OK)
+    {
+        file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory;
+        file_pos->num_of_file = (uLong)file_pos64.num_of_file;
+    }
+    return err;
+}
+
+extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) {
+    unz64_s* s;
+    int err;
+
+    if (file==NULL || file_pos==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+
+    /* jump to the right spot */
+    s->pos_in_central_dir = file_pos->pos_in_zip_directory;
+    s->num_file           = file_pos->num_of_file;
+
+    /* set the current file */
+    err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                               &s->cur_file_info_internal,
+                                               NULL,0,NULL,0,NULL,0);
+    /* return results */
+    s->current_file_ok = (err == UNZ_OK);
+    return err;
+}
+
+extern int ZEXPORT unzGoToFilePos(unzFile file, unz_file_pos* file_pos) {
+    unz64_file_pos file_pos64;
+    if (file_pos == NULL)
+        return UNZ_PARAMERROR;
+
+    file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
+    file_pos64.num_of_file = file_pos->num_of_file;
+    return unzGoToFilePos64(file,&file_pos64);
+}
+
+/*
+// Unzip Helper Functions - should be here?
+///////////////////////////////////////////
+*/
+
+/*
+  Read the local header of the current zipfile
+  Check the coherency of the local header and info in the end of central
+        directory about this file
+  store in *piSizeVar the size of extra info in local header
+        (filename and size of extra field data)
+*/
+local int unz64local_CheckCurrentFileCoherencyHeader(unz64_s* s, uInt* piSizeVar,
+                                                     ZPOS64_T * poffset_local_extrafield,
+                                                     uInt  * psize_local_extrafield) {
+    uLong uMagic,uData,uFlags;
+    uLong size_filename;
+    uLong size_extra_field;
+    int err=UNZ_OK;
+
+    *piSizeVar = 0;
+    *poffset_local_extrafield = 0;
+    *psize_local_extrafield = 0;
+
+    if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
+                                s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
+        return UNZ_ERRNO;
+
+
+    if (err==UNZ_OK)
+    {
+        if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+            err=UNZ_ERRNO;
+        else if (uMagic!=0x04034b50)
+            err=UNZ_BADZIPFILE;
+    }
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+        err=UNZ_ERRNO;
+/*
+    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+        err=UNZ_BADZIPFILE;
+*/
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
+        err=UNZ_ERRNO;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+        err=UNZ_ERRNO;
+    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+        err=UNZ_BADZIPFILE;
+
+    if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
+/* #ifdef HAVE_BZIP2 */
+                         (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
+/* #endif */
+                         (s->cur_file_info.compression_method!=Z_DEFLATED))
+        err=UNZ_BADZIPFILE;
+
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
+        err=UNZ_ERRNO;
+
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
+        err=UNZ_ERRNO;
+    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0))
+        err=UNZ_BADZIPFILE;
+
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
+        err=UNZ_ERRNO;
+    else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0))
+        err=UNZ_BADZIPFILE;
+
+    if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
+        err=UNZ_ERRNO;
+    else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0))
+        err=UNZ_BADZIPFILE;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
+        err=UNZ_ERRNO;
+    else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+        err=UNZ_BADZIPFILE;
+
+    *piSizeVar += (uInt)size_filename;
+
+    if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
+        err=UNZ_ERRNO;
+    *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
+                                    SIZEZIPLOCALHEADER + size_filename;
+    *psize_local_extrafield = (uInt)size_extra_field;
+
+    *piSizeVar += (uInt)size_extra_field;
+
+    return err;
+}
+
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile3(unzFile file, int* method,
+                                       int* level, int raw, const char* password) {
+    int err=UNZ_OK;
+    uInt iSizeVar;
+    unz64_s* s;
+    file_in_zip64_read_info_s* pfile_in_zip_read_info;
+    ZPOS64_T offset_local_extrafield;  /* offset of the local extra field */
+    uInt  size_local_extrafield;    /* size of the local extra field */
+#    ifndef NOUNCRYPT
+    char source[12];
+#    else
+    if (password != NULL)
+        return UNZ_PARAMERROR;
+#    endif
+
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    if (!s->current_file_ok)
+        return UNZ_PARAMERROR;
+
+    if (s->pfile_in_zip_read != NULL)
+        unzCloseCurrentFile(file);
+
+    if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+        return UNZ_BADZIPFILE;
+
+    pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
+    if (pfile_in_zip_read_info==NULL)
+        return UNZ_INTERNALERROR;
+
+    pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+    pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+    pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+    pfile_in_zip_read_info->pos_local_extrafield=0;
+    pfile_in_zip_read_info->raw=raw;
+
+    if (pfile_in_zip_read_info->read_buffer==NULL)
+    {
+        free(pfile_in_zip_read_info);
+        return UNZ_INTERNALERROR;
+    }
+
+    pfile_in_zip_read_info->stream_initialised=0;
+
+    if (method!=NULL)
+        *method = (int)s->cur_file_info.compression_method;
+
+    if (level!=NULL)
+    {
+        *level = 6;
+        switch (s->cur_file_info.flag & 0x06)
+        {
+          case 6 : *level = 1; break;
+          case 4 : *level = 2; break;
+          case 2 : *level = 9; break;
+        }
+    }
+
+    if ((s->cur_file_info.compression_method!=0) &&
+/* #ifdef HAVE_BZIP2 */
+        (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
+/* #endif */
+        (s->cur_file_info.compression_method!=Z_DEFLATED))
+
+        err=UNZ_BADZIPFILE;
+
+    pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+    pfile_in_zip_read_info->crc32=0;
+    pfile_in_zip_read_info->total_out_64=0;
+    pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;
+    pfile_in_zip_read_info->filestream=s->filestream;
+    pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
+    pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+
+    pfile_in_zip_read_info->stream.total_out = 0;
+
+    if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw))
+    {
+#ifdef HAVE_BZIP2
+      pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
+      pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
+      pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
+      pfile_in_zip_read_info->bstream.state = (voidpf)0;
+
+      pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+      pfile_in_zip_read_info->stream.zfree = (free_func)0;
+      pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+      pfile_in_zip_read_info->stream.next_in = (voidpf)0;
+      pfile_in_zip_read_info->stream.avail_in = 0;
+
+      err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
+      if (err == Z_OK)
+        pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;
+      else
+      {
+        free(pfile_in_zip_read_info->read_buffer);
+        free(pfile_in_zip_read_info);
+        return err;
+      }
+#else
+      pfile_in_zip_read_info->raw=1;
+#endif
+    }
+    else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))
+    {
+      pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+      pfile_in_zip_read_info->stream.zfree = (free_func)0;
+      pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+      pfile_in_zip_read_info->stream.next_in = 0;
+      pfile_in_zip_read_info->stream.avail_in = 0;
+
+      err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+      if (err == Z_OK)
+        pfile_in_zip_read_info->stream_initialised=Z_DEFLATED;
+      else
+      {
+        free(pfile_in_zip_read_info->read_buffer);
+        free(pfile_in_zip_read_info);
+        return err;
+      }
+        /* windowBits is passed < 0 to tell that there is no zlib header.
+         * Note that in this case inflate *requires* an extra "dummy" byte
+         * after the compressed stream in order to complete decompression and
+         * return Z_STREAM_END.
+         * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+         * size of both compressed and uncompressed data
+         */
+    }
+    pfile_in_zip_read_info->rest_read_compressed =
+            s->cur_file_info.compressed_size ;
+    pfile_in_zip_read_info->rest_read_uncompressed =
+            s->cur_file_info.uncompressed_size ;
+
+
+    pfile_in_zip_read_info->pos_in_zipfile =
+            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+              iSizeVar;
+
+    pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+
+    s->pfile_in_zip_read = pfile_in_zip_read_info;
+                s->encrypted = 0;
+
+#    ifndef NOUNCRYPT
+    if (password != NULL)
+    {
+        int i;
+        s->pcrc_32_tab = get_crc_table();
+        init_keys(password,s->keys,s->pcrc_32_tab);
+        if (ZSEEK64(s->z_filefunc, s->filestream,
+                  s->pfile_in_zip_read->pos_in_zipfile +
+                     s->pfile_in_zip_read->byte_before_the_zipfile,
+                  SEEK_SET)!=0)
+            return UNZ_INTERNALERROR;
+        if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12)
+            return UNZ_INTERNALERROR;
+
+        for (i = 0; i<12; i++)
+            zdecode(s->keys,s->pcrc_32_tab,source[i]);
+
+        s->pfile_in_zip_read->pos_in_zipfile+=12;
+        s->encrypted=1;
+    }
+#    endif
+
+
+    return UNZ_OK;
+}
+
+extern int ZEXPORT unzOpenCurrentFile(unzFile file) {
+    return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
+}
+
+extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file, const char* password) {
+    return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
+}
+
+extern int ZEXPORT unzOpenCurrentFile2(unzFile file, int* method, int* level, int raw) {
+    return unzOpenCurrentFile3(file, method, level, raw, NULL);
+}
+
+/** Addition for GDAL : START */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file) {
+    unz64_s* s;
+    file_in_zip64_read_info_s* pfile_in_zip_read_info;
+    s=(unz64_s*)file;
+    if (file==NULL)
+        return 0; //UNZ_PARAMERROR;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+    if (pfile_in_zip_read_info==NULL)
+        return 0; //UNZ_PARAMERROR;
+    return pfile_in_zip_read_info->pos_in_zipfile +
+                         pfile_in_zip_read_info->byte_before_the_zipfile;
+}
+
+/** Addition for GDAL : END */
+
+/*
+  Read bytes from the current file.
+  buf contain buffer where data must be copied
+  len the size of buf.
+
+  return the number of byte copied if some bytes are copied
+  return 0 if the end of file was reached
+  return <0 with error code if there is an error
+    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+extern int ZEXPORT unzReadCurrentFile(unzFile file, voidp buf, unsigned len) {
+    int err=UNZ_OK;
+    uInt iRead = 0;
+    unz64_s* s;
+    file_in_zip64_read_info_s* pfile_in_zip_read_info;
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+    if (pfile_in_zip_read_info==NULL)
+        return UNZ_PARAMERROR;
+
+
+    if (pfile_in_zip_read_info->read_buffer == NULL)
+        return UNZ_END_OF_LIST_OF_FILE;
+    if (len==0)
+        return 0;
+
+    pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
+
+    pfile_in_zip_read_info->stream.avail_out = (uInt)len;
+
+    if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
+        (!(pfile_in_zip_read_info->raw)))
+        pfile_in_zip_read_info->stream.avail_out =
+            (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
+
+    if ((len>pfile_in_zip_read_info->rest_read_compressed+
+           pfile_in_zip_read_info->stream.avail_in) &&
+         (pfile_in_zip_read_info->raw))
+        pfile_in_zip_read_info->stream.avail_out =
+            (uInt)pfile_in_zip_read_info->rest_read_compressed+
+            pfile_in_zip_read_info->stream.avail_in;
+
+    while (pfile_in_zip_read_info->stream.avail_out>0)
+    {
+        if ((pfile_in_zip_read_info->stream.avail_in==0) &&
+            (pfile_in_zip_read_info->rest_read_compressed>0))
+        {
+            uInt uReadThis = UNZ_BUFSIZE;
+            if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
+                uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
+            if (uReadThis == 0)
+                return UNZ_EOF;
+            if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
+                      pfile_in_zip_read_info->filestream,
+                      pfile_in_zip_read_info->pos_in_zipfile +
+                         pfile_in_zip_read_info->byte_before_the_zipfile,
+                         ZLIB_FILEFUNC_SEEK_SET)!=0)
+                return UNZ_ERRNO;
+            if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
+                      pfile_in_zip_read_info->filestream,
+                      pfile_in_zip_read_info->read_buffer,
+                      uReadThis)!=uReadThis)
+                return UNZ_ERRNO;
+
+
+#            ifndef NOUNCRYPT
+            if(s->encrypted)
+            {
+                uInt i;
+                for(i=0;i<uReadThis;i++)
+                  pfile_in_zip_read_info->read_buffer[i] =
+                      zdecode(s->keys,s->pcrc_32_tab,
+                              pfile_in_zip_read_info->read_buffer[i]);
+            }
+#            endif
+
+
+            pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+
+            pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+
+            pfile_in_zip_read_info->stream.next_in =
+                (Bytef*)pfile_in_zip_read_info->read_buffer;
+            pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
+        }
+
+        if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
+        {
+            uInt uDoCopy,i ;
+
+            if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
+                (pfile_in_zip_read_info->rest_read_compressed == 0))
+                return (iRead==0) ? UNZ_EOF : (int)iRead;
+
+            if (pfile_in_zip_read_info->stream.avail_out <
+                            pfile_in_zip_read_info->stream.avail_in)
+                uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
+            else
+                uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
+
+            for (i=0;i<uDoCopy;i++)
+                *(pfile_in_zip_read_info->stream.next_out+i) =
+                        *(pfile_in_zip_read_info->stream.next_in+i);
+
+            pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy;
+
+            pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
+                                pfile_in_zip_read_info->stream.next_out,
+                                uDoCopy);
+            pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+            pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
+            pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
+            pfile_in_zip_read_info->stream.next_out += uDoCopy;
+            pfile_in_zip_read_info->stream.next_in += uDoCopy;
+            pfile_in_zip_read_info->stream.total_out += uDoCopy;
+            iRead += uDoCopy;
+        }
+        else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED)
+        {
+#ifdef HAVE_BZIP2
+            uLong uTotalOutBefore,uTotalOutAfter;
+            const Bytef *bufBefore;
+            uLong uOutThis;
+
+            pfile_in_zip_read_info->bstream.next_in        = (char*)pfile_in_zip_read_info->stream.next_in;
+            pfile_in_zip_read_info->bstream.avail_in       = pfile_in_zip_read_info->stream.avail_in;
+            pfile_in_zip_read_info->bstream.total_in_lo32  = pfile_in_zip_read_info->stream.total_in;
+            pfile_in_zip_read_info->bstream.total_in_hi32  = 0;
+            pfile_in_zip_read_info->bstream.next_out       = (char*)pfile_in_zip_read_info->stream.next_out;
+            pfile_in_zip_read_info->bstream.avail_out      = pfile_in_zip_read_info->stream.avail_out;
+            pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out;
+            pfile_in_zip_read_info->bstream.total_out_hi32 = 0;
+
+            uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32;
+            bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out;
+
+            err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream);
+
+            uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32;
+            uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+            pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
+
+            pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis));
+            pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;
+            iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+            pfile_in_zip_read_info->stream.next_in   = (Bytef*)pfile_in_zip_read_info->bstream.next_in;
+            pfile_in_zip_read_info->stream.avail_in  = pfile_in_zip_read_info->bstream.avail_in;
+            pfile_in_zip_read_info->stream.total_in  = pfile_in_zip_read_info->bstream.total_in_lo32;
+            pfile_in_zip_read_info->stream.next_out  = (Bytef*)pfile_in_zip_read_info->bstream.next_out;
+            pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out;
+            pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32;
+
+            if (err==BZ_STREAM_END)
+              return (iRead==0) ? UNZ_EOF : iRead;
+            if (err!=BZ_OK)
+              break;
+#endif
+        } // end Z_BZIP2ED
+        else
+        {
+            ZPOS64_T uTotalOutBefore,uTotalOutAfter;
+            const Bytef *bufBefore;
+            ZPOS64_T uOutThis;
+            int flush=Z_SYNC_FLUSH;
+
+            uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+            bufBefore = pfile_in_zip_read_info->stream.next_out;
+
+            /*
+            if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+                     pfile_in_zip_read_info->stream.avail_out) &&
+                (pfile_in_zip_read_info->rest_read_compressed == 0))
+                flush = Z_FINISH;
+            */
+            err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+            if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))
+              err = Z_DATA_ERROR;
+
+            uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
+            /* Detect overflow, because z_stream.total_out is uLong (32 bits) */
+            if (uTotalOutAfter<uTotalOutBefore)
+                uTotalOutAfter += 1LL << 32; /* Add maximum value of uLong + 1 */
+            uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+            pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
+
+            pfile_in_zip_read_info->crc32 =
+                crc32(pfile_in_zip_read_info->crc32,bufBefore,
+                        (uInt)(uOutThis));
+
+            pfile_in_zip_read_info->rest_read_uncompressed -=
+                uOutThis;
+
+            iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+            if (err==Z_STREAM_END)
+                return (iRead==0) ? UNZ_EOF : (int)iRead;
+            if (err!=Z_OK)
+                break;
+        }
+    }
+
+    if (err==Z_OK)
+        return (int)iRead;
+    return err;
+}
+
+
+/*
+  Give the current position in uncompressed data
+*/
+extern z_off_t ZEXPORT unztell(unzFile file) {
+    unz64_s* s;
+    file_in_zip64_read_info_s* pfile_in_zip_read_info;
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+    if (pfile_in_zip_read_info==NULL)
+        return UNZ_PARAMERROR;
+
+    return (z_off_t)pfile_in_zip_read_info->stream.total_out;
+}
+
+extern ZPOS64_T ZEXPORT unztell64(unzFile file) {
+
+    unz64_s* s;
+    file_in_zip64_read_info_s* pfile_in_zip_read_info;
+    if (file==NULL)
+        return (ZPOS64_T)-1;
+    s=(unz64_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+    if (pfile_in_zip_read_info==NULL)
+        return (ZPOS64_T)-1;
+
+    return pfile_in_zip_read_info->total_out_64;
+}
+
+
+/*
+  return 1 if the end of file was reached, 0 elsewhere
+*/
+extern int ZEXPORT unzeof(unzFile file) {
+    unz64_s* s;
+    file_in_zip64_read_info_s* pfile_in_zip_read_info;
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+    if (pfile_in_zip_read_info==NULL)
+        return UNZ_PARAMERROR;
+
+    if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+        return 1;
+    else
+        return 0;
+}
+
+
+
+/*
+Read extra field from the current file (opened by unzOpenCurrentFile)
+This is the local-header version of the extra field (sometimes, there is
+more info in the local-header version than in the central-header)
+
+  if buf==NULL, it return the size of the local extra field that can be read
+
+  if buf!=NULL, len is the size of the buffer, the extra header is copied in
+    buf.
+  the return value is the number of bytes copied in buf, or (if <0)
+    the error code
+*/
+extern int ZEXPORT unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) {
+    unz64_s* s;
+    file_in_zip64_read_info_s* pfile_in_zip_read_info;
+    uInt read_now;
+    ZPOS64_T size_to_read;
+
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+    if (pfile_in_zip_read_info==NULL)
+        return UNZ_PARAMERROR;
+
+    size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
+                pfile_in_zip_read_info->pos_local_extrafield);
+
+    if (buf==NULL)
+        return (int)size_to_read;
+
+    if (len>size_to_read)
+        read_now = (uInt)size_to_read;
+    else
+        read_now = (uInt)len ;
+
+    if (read_now==0)
+        return 0;
+
+    if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
+              pfile_in_zip_read_info->filestream,
+              pfile_in_zip_read_info->offset_local_extrafield +
+              pfile_in_zip_read_info->pos_local_extrafield,
+              ZLIB_FILEFUNC_SEEK_SET)!=0)
+        return UNZ_ERRNO;
+
+    if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
+              pfile_in_zip_read_info->filestream,
+              buf,read_now)!=read_now)
+        return UNZ_ERRNO;
+
+    return (int)read_now;
+}
+
+/*
+  Close the file in zip opened with unzOpenCurrentFile
+  Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+extern int ZEXPORT unzCloseCurrentFile(unzFile file) {
+    int err=UNZ_OK;
+
+    unz64_s* s;
+    file_in_zip64_read_info_s* pfile_in_zip_read_info;
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+    if (pfile_in_zip_read_info==NULL)
+        return UNZ_PARAMERROR;
+
+
+    if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+        (!pfile_in_zip_read_info->raw))
+    {
+        if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+            err=UNZ_CRCERROR;
+    }
+
+
+    free(pfile_in_zip_read_info->read_buffer);
+    pfile_in_zip_read_info->read_buffer = NULL;
+    if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
+        inflateEnd(&pfile_in_zip_read_info->stream);
+#ifdef HAVE_BZIP2
+    else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
+        BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
+#endif
+
+
+    pfile_in_zip_read_info->stream_initialised = 0;
+    free(pfile_in_zip_read_info);
+
+    s->pfile_in_zip_read=NULL;
+
+    return err;
+}
+
+
+/*
+  Get the global comment string of the ZipFile, in the szComment buffer.
+  uSizeBuf is the size of the szComment buffer.
+  return the number of byte copied or an error code <0
+*/
+extern int ZEXPORT unzGetGlobalComment(unzFile file, char * szComment, uLong uSizeBuf) {
+    unz64_s* s;
+    uLong uReadThis ;
+    if (file==NULL)
+        return (int)UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+
+    uReadThis = uSizeBuf;
+    if (uReadThis>s->gi.size_comment)
+        uReadThis = s->gi.size_comment;
+
+    if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)
+        return UNZ_ERRNO;
+
+    if (uReadThis>0)
+    {
+      *szComment='\0';
+      if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)
+        return UNZ_ERRNO;
+    }
+
+    if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
+        *(szComment+s->gi.size_comment)='\0';
+    return (int)uReadThis;
+}
+
+/* Additions by RX '2004 */
+extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) {
+    unz64_s* s;
+
+    if (file==NULL)
+          return 0; //UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+    if (!s->current_file_ok)
+      return 0;
+    if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
+      if (s->num_file==s->gi.number_entry)
+         return 0;
+    return s->pos_in_central_dir;
+}
+
+extern uLong ZEXPORT unzGetOffset(unzFile file) {
+    ZPOS64_T offset64;
+
+    if (file==NULL)
+          return 0; //UNZ_PARAMERROR;
+    offset64 = unzGetOffset64(file);
+    return (uLong)offset64;
+}
+
+extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) {
+    unz64_s* s;
+    int err;
+
+    if (file==NULL)
+        return UNZ_PARAMERROR;
+    s=(unz64_s*)file;
+
+    s->pos_in_central_dir = pos;
+    s->num_file = s->gi.number_entry;      /* hack */
+    err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+                                              &s->cur_file_info_internal,
+                                              NULL,0,NULL,0,NULL,0);
+    s->current_file_ok = (err == UNZ_OK);
+    return err;
+}
+
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) {
+    return unzSetOffset64(file,pos);
+}
diff --git a/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/unzip.h b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/unzip.h
new file mode 100755
index 0000000..1410584
--- /dev/null
+++ b/LYNQ_PUBLIC/IC_src/mtk/lib/liblynq-ftp-fota/rock_ua/unzip.h
@@ -0,0 +1,437 @@
+/* unzip.h -- IO for uncompress .zip files using zlib
+   Version 1.1, February 14h, 2010
+   part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+         Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+         Modifications of Unzip for Zip64
+         Copyright (C) 2007-2008 Even Rouault
+
+         Modifications for Zip64 support on both zip and unzip
+         Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+         For more info read MiniZip_info.txt
+
+         ---------------------------------------------------------------------------------
+
+        Condition of use and distribution are the same than zlib :
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  ---------------------------------------------------------------------------------
+
+        Changes
+
+        See header of unzip64.c
+
+*/
+
+#ifndef _unz64_H
+#define _unz64_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef  _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+    from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__;
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK                          (0)
+#define UNZ_END_OF_LIST_OF_FILE         (-100)
+#define UNZ_ERRNO                       (Z_ERRNO)
+#define UNZ_EOF                         (0)
+#define UNZ_PARAMERROR                  (-102)
+#define UNZ_BADZIPFILE                  (-103)
+#define UNZ_INTERNALERROR               (-104)
+#define UNZ_CRCERROR                    (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s
+{
+    int tm_sec;             /* seconds after the minute - [0,59] */
+    int tm_min;             /* minutes after the hour - [0,59] */
+    int tm_hour;            /* hours since midnight - [0,23] */
+    int tm_mday;            /* day of the month - [1,31] */
+    int tm_mon;             /* months since January - [0,11] */
+    int tm_year;            /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+   These data comes from the end of central dir */
+typedef struct unz_global_info64_s
+{
+    ZPOS64_T number_entry;         /* total number of entries in
+                                     the central dir on this disk */
+    uLong size_comment;         /* size of the global comment of the zipfile */
+} unz_global_info64;
+
+typedef struct unz_global_info_s
+{
+    uLong number_entry;         /* total number of entries in
+                                     the central dir on this disk */
+    uLong size_comment;         /* size of the global comment of the zipfile */
+} unz_global_info;
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info64_s
+{
+    uLong version;              /* version made by                 2 bytes */
+    uLong version_needed;       /* version needed to extract       2 bytes */
+    uLong flag;                 /* general purpose bit flag        2 bytes */
+    uLong compression_method;   /* compression method              2 bytes */
+    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
+    uLong crc;                  /* crc-32                          4 bytes */
+    ZPOS64_T compressed_size;   /* compressed size                 8 bytes */
+    ZPOS64_T uncompressed_size; /* uncompressed size               8 bytes */
+    uLong size_filename;        /* filename length                 2 bytes */
+    uLong size_file_extra;      /* extra field length              2 bytes */
+    uLong size_file_comment;    /* file comment length             2 bytes */
+
+    uLong disk_num_start;       /* disk number start               2 bytes */
+    uLong internal_fa;          /* internal file attributes        2 bytes */
+    uLong external_fa;          /* external file attributes        4 bytes */
+
+    tm_unz tmu_date;
+} unz_file_info64;
+
+typedef struct unz_file_info_s
+{
+    uLong version;              /* version made by                 2 bytes */
+    uLong version_needed;       /* version needed to extract       2 bytes */
+    uLong flag;                 /* general purpose bit flag        2 bytes */
+    uLong compression_method;   /* compression method              2 bytes */
+    uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
+    uLong crc;                  /* crc-32                          4 bytes */
+    uLong compressed_size;      /* compressed size                 4 bytes */
+    uLong uncompressed_size;    /* uncompressed size               4 bytes */
+    uLong size_filename;        /* filename length                 2 bytes */
+    uLong size_file_extra;      /* extra field length              2 bytes */
+    uLong size_file_comment;    /* file comment length             2 bytes */
+
+    uLong disk_num_start;       /* disk number start               2 bytes */
+    uLong internal_fa;          /* internal file attributes        2 bytes */
+    uLong external_fa;          /* external file attributes        4 bytes */
+
+    tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare(const char* fileName1,
+                                            const char* fileName2,
+                                            int iCaseSensitivity);
+/*
+   Compare two filenames (fileName1,fileName2).
+   If iCaseSensitivity = 1, comparison is case sensitive (like strcmp)
+   If iCaseSensitivity = 2, comparison is not case sensitive (like strcmpi
+                                or strcasecmp)
+   If iCaseSensitivity = 0, case sensitivity is default of your operating system
+    (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen(const char *path);
+extern unzFile ZEXPORT unzOpen64(const void *path);
+/*
+  Open a Zip file. path contain the full pathname (by example,
+     on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
+     "zlib/zlib113.zip".
+     If the zipfile cannot be opened (file don't exist or in not valid), the
+       return value is NULL.
+     Else, the return value is a unzFile Handle, usable with other function
+       of this unzip package.
+     the "64" function take a const void* pointer, because the path is just the
+       value passed to the open64_file_func callback.
+     Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
+       is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
+       does not describe the reality
+*/
+
+
+extern unzFile ZEXPORT unzOpen2(const char *path,
+                                zlib_filefunc_def* pzlib_filefunc_def);
+/*
+   Open a Zip file, like unzOpen, but provide a set of file low level API
+      for read/write the zip file (see ioapi.h)
+*/
+
+extern unzFile ZEXPORT unzOpen2_64(const void *path,
+                                   zlib_filefunc64_def* pzlib_filefunc_def);
+/*
+   Open a Zip file, like unz64Open, but provide a set of file low level API
+      for read/write the zip file (see ioapi.h)
+*/
+
+extern int ZEXPORT unzClose(unzFile file);
+/*
+  Close a ZipFile opened with unzOpen.
+  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+    these files MUST be closed with unzCloseCurrentFile before call unzClose.
+  return UNZ_OK if there is no problem. */
+
+extern int ZEXPORT unzGetGlobalInfo(unzFile file,
+                                    unz_global_info *pglobal_info);
+
+extern int ZEXPORT unzGetGlobalInfo64(unzFile file,
+                                      unz_global_info64 *pglobal_info);
+/*
+  Write info about the ZipFile in the *pglobal_info structure.
+  No preparation of the structure is needed
+  return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment(unzFile file,
+                                       char *szComment,
+                                       uLong uSizeBuf);
+/*
+  Get the global comment string of the ZipFile, in the szComment buffer.
+  uSizeBuf is the size of the szComment buffer.
+  return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile(unzFile file);
+/*
+  Set the current file of the zipfile to the first file.
+  return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile(unzFile file);
+/*
+  Set the current file of the zipfile to the next file.
+  return UNZ_OK if there is no problem
+  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile(unzFile file,
+                                 const char *szFileName,
+                                 int iCaseSensitivity);
+/*
+  Try locate the file szFileName in the zipfile.
+  For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+  return value :
+  UNZ_OK if the file is found. It becomes the current file.
+  UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+/* ****************************************** */
+/* Ryan supplied functions */
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_pos_s
+{
+    uLong pos_in_zip_directory;   /* offset in zip file directory */
+    uLong num_of_file;            /* # of file */
+} unz_file_pos;
+
+extern int ZEXPORT unzGetFilePos(
+    unzFile file,
+    unz_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos(
+    unzFile file,
+    unz_file_pos* file_pos);
+
+typedef struct unz64_file_pos_s
+{
+    ZPOS64_T pos_in_zip_directory;   /* offset in zip file directory */
+    ZPOS64_T num_of_file;            /* # of file */
+} unz64_file_pos;
+
+extern int ZEXPORT unzGetFilePos64(
+    unzFile file,
+    unz64_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos64(
+    unzFile file,
+    const unz64_file_pos* file_pos);
+
+/* ****************************************** */
+
+extern int ZEXPORT unzGetCurrentFileInfo64(unzFile file,
+                                           unz_file_info64 *pfile_info,
+                                           char *szFileName,
+                                           uLong fileNameBufferSize,
+                                           void *extraField,
+                                           uLong extraFieldBufferSize,
+                                           char *szComment,
+                                           uLong commentBufferSize);
+
+extern int ZEXPORT unzGetCurrentFileInfo(unzFile file,
+                                         unz_file_info *pfile_info,
+                                         char *szFileName,
+                                         uLong fileNameBufferSize,
+                                         void *extraField,
+                                         uLong extraFieldBufferSize,
+                                         char *szComment,
+                                         uLong commentBufferSize);
+/*
+  Get Info about the current file
+  if pfile_info!=NULL, the *pfile_info structure will contain some info about
+        the current file
+  if szFileName!=NULL, the filemane string will be copied in szFileName
+            (fileNameBufferSize is the size of the buffer)
+  if extraField!=NULL, the extra field information will be copied in extraField
+            (extraFieldBufferSize is the size of the buffer).
+            This is the Central-header version of the extra field
+  if szComment!=NULL, the comment string of the file will be copied in szComment
+            (commentBufferSize is the size of the buffer)
+*/
+
+
+/** Addition for GDAL : START */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64(unzFile file);
+
+/** Addition for GDAL : END */
+
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+   from it, and close it (you can close it before reading all the file)
+   */
+
+extern int ZEXPORT unzOpenCurrentFile(unzFile file);
+/*
+  Open for reading data the current file in the zipfile.
+  If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFilePassword(unzFile file,
+                                              const char* password);
+/*
+  Open for reading data the current file in the zipfile.
+  password is a crypting password
+  If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFile2(unzFile file,
+                                       int* method,
+                                       int* level,
+                                       int raw);
+/*
+  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+    if raw==1
+  *method will receive method of compression, *level will receive level of
+     compression
+  note : you can set level parameter as NULL (if you did not want known level,
+         but you CANNOT set method parameter as NULL
+*/
+
+extern int ZEXPORT unzOpenCurrentFile3(unzFile file,
+                                       int* method,
+                                       int* level,
+                                       int raw,
+                                       const char* password);
+/*
+  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+    if raw==1
+  *method will receive method of compression, *level will receive level of
+     compression
+  note : you can set level parameter as NULL (if you did not want known level,
+         but you CANNOT set method parameter as NULL
+*/
+
+
+extern int ZEXPORT unzCloseCurrentFile(unzFile file);
+/*
+  Close the file in zip opened with unzOpenCurrentFile
+  Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+extern int ZEXPORT unzReadCurrentFile(unzFile file,
+                                      voidp buf,
+                                      unsigned len);
+/*
+  Read bytes from the current file (opened by unzOpenCurrentFile)
+  buf contain buffer where data must be copied
+  len the size of buf.
+
+  return the number of byte copied if some bytes are copied
+  return 0 if the end of file was reached
+  return <0 with error code if there is an error
+    (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern z_off_t ZEXPORT unztell(unzFile file);
+
+extern ZPOS64_T ZEXPORT unztell64(unzFile file);
+/*
+  Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof(unzFile file);
+/*
+  return 1 if the end of file was reached, 0 elsewhere
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield(unzFile file,
+                                         voidp buf,
+                                         unsigned len);
+/*
+  Read extra field from the current file (opened by unzOpenCurrentFile)
+  This is the local-header version of the extra field (sometimes, there is
+    more info in the local-header version than in the central-header)
+
+  if buf==NULL, it return the size of the local extra field
+
+  if buf!=NULL, len is the size of the buffer, the extra header is copied in
+    buf.
+  the return value is the number of bytes copied in buf, or (if <0)
+    the error code
+*/
+
+/***************************************************************************/
+
+/* Get the current file offset */
+extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);
+extern uLong ZEXPORT unzGetOffset (unzFile file);
+
+/* Set the current file offset */
+extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz64_H */
diff --git a/meta/meta-mediatek-mt2735/recipes-core/images/mtk-image-2735.bb b/meta/meta-mediatek-mt2735/recipes-core/images/mtk-image-2735.bb
index e70eec0..866d1bf 100755
--- a/meta/meta-mediatek-mt2735/recipes-core/images/mtk-image-2735.bb
+++ b/meta/meta-mediatek-mt2735/recipes-core/images/mtk-image-2735.bb
@@ -153,6 +153,7 @@
 	rng-tools \
 	${@bb.utils.contains("MOBILETEK_NFS_CFG", "yes", "nfs-utils", "", d)} \
 	ntpq \
+	liblynq-ftp-fota \
 "
 
 do_populate_sdk_prepend() {