精华内容
下载资源
问答
  • 怎么对比md5
    2021-07-02 17:52:30

    下面的比较将会返回 true,这是为什么呢?

    $a = md5('240610708');// 0e462097431906509019562988736854
    $b = md5('QNKCDZO'); // 0e830400451993494058024219903391
    
    var_dump($a == $b); // true
    

    因为两个 md5 值都有开始’0e’,所以PHP类型理解这些字符串是科学符号。根据定义,0 的任何次方都是 0,所以在这里会成立‎,所以当你确定一个变量的类型时,你最好使用 ===(恒等于)进行比较。

    所以在存储密码时,应该放弃使用 md5,改用为 password_hash 系列方法。

    来自:https://www.php.net/manual/zh/function.md5.php#123392

    更多相关内容
  • MD5校验对比工具

    2018-11-09 12:04:41
    一个看一读取文件MD5值的工具,同时在工具读取文件MD5值的下方还增加了一个文本行,可以填入原MD5值,然后点击对比MD5值即可知道自己下载的文件MD5值是否正确。
  • 易语言源码易语言MD5对比源码.rar
  • 文件MD5批量对比器 图片MD5批量对比器 文件图片MD5查看
  • MD5检验对比工具

    2018-11-30 15:22:21
    绿色,比较好用,直接输入MD5和你文件生成的md5对比,不对是红色,很方便
  • 迷你Md5多文件对比工具
  • MD5对比.rar

    2020-04-05 04:54:50
    MD5对比.rar
  • 新手菜鸟,把用vs2010开发时,如何在登录窗口判断数据库中MD5加密的密码。 今天写个简单的程序,创建用户名和密码,写入到Excel中,Excel中的密码是MD5加密的效果。 添加引用 //自定义引用 using System.Data....

    新手菜鸟,把用vs2010开发时,如何在登录窗口判断数据库中MD5加密的密码。

    今天写个简单的程序,创建用户名和密码,写入到Excel中,Excel中的密码是MD5加密的效果。

    添加引用

    //自定义引用
    using System.Data.OleDb;
    using System.Security.Cryptography;

    打开Excel

    简单的理解,就是把Excel当成是sql来进行操作。

    string Conn_Str = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=D:/个人/VS2010/用户登录/userinfo.xls;" + "Extended Properties=Excel 8.0;";
    OleDbConnection conn = new OleDbConnection(Conn_Str);
    备注:Provider=Microsoft.Jet.OLEDB.4.0只支持Office97-2003,不支持2007。

    如果需要支持2007,使用 Provider=’Microsoft.Ace.OLEDB.12.0

    MD5加密的密码保存到Excel中

    简单的理解就是把用户输入的密码通过MD5加密的方式,把加密后的数据存入Excel里边。

    我的excel是这样设置的

    username:用户名
    
    passowrd:MD5加密密码

    把用户输入的密码转成MD5加密格式,保存到变量。

    部分核心代码如下:

    string md5mm = "";
    MD5 md5 = MD5.Create();
    byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(textBox_PassWord.Text.Trim()));
    for (int i = 0; i < s.Length; i++)
    {
    md5mm = md5mm + s[i].ToString("X");
    }


    打开数据库,执行写入命令。成功后返回提示。
    部分核心代码如下:

     

    string Conn_Str = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=D:/个人/VS2010/用户登录/userinfo.xls;" + "Extended Properties=Excel 8.0;";
    OleDbConnection conn = new OleDbConnection(Conn_Str);
    string SQLSTR = "INSERT INTO [Sheet1$] VALUES ('"+textBox_UserName.Text.Trim()+"','"+md5mm+"')";
    OleDbCommand cmd = new OleDbCommand(SQLSTR, conn);
    conn.Open();
    cmd.ExecuteNonQuery();
    MessageBox.Show("用户"+textBox_UserName.Text.Trim()+"添加成功!");
    conn.Close();


    说明:因为Excel的工作簿,默认的第一个是Sheet1,所以在insert into 后边写[Sheet1$];

    这语句简单的很,就不重复解释了。

    效果

    根据上边的所有代码,可以总结成这样的一条命令:

    首先,把用户输入的普通的密码字符转换成MD5加密格式,存到变量MD5MM;

    其次,把用户名和加密后的密码写入到EXCEL中。

    最后,弹出提示框,提示添加成功。

    添加成功的图

    excel中的数据效果

    最后的结束语
    希望对你有所帮助吧~

    展开全文
  • 优点,自动更新源码,自动对比MD5值,缺点,需使用服务器,自己搭建网站,并将文件上传到服务器,用md5
  • 文件MD5对比工具 EXE

    2021-10-15 10:05:50
    文件MD5计算工具,校验工具,Windows平台,免安装。支持MD5,SHA1,SHA256算法。 md5_tool.exe
  • 多文件内容快速对比MD5

    千次阅读 2021-07-08 19:37:04
    有一个文件要和很多文件比较内容,看是否相同,如果文件大小相同,一个一个字节地比较内容,速度很慢,可以根据文件的内容各自生成MD5,然后对比文件的MD5值就可以快速排除不相同的文件。MD5值相同,极大概率就是...

    有一个文件要和很多文件比较内容,看是否相同,如果文件大小相同,一个一个字节地比较内容,速度很慢,可以根据文件的内容各自生成MD5,然后对比文件的MD5值就可以快速排除不相同的文件。MD5值相同,极大概率就是相同的文件,不放心的话可以再遍历字节对比一下。

    文件越多,效率越明显。增加文件时就可以存储对应的MD5值,改动文件时更新MD5值。

    MD5:
    明文被处理后会成为16字节的密文。
    一个明文只对应一个密文,但一个密文会对应很多的明文。
    MD5可以防篡改,防可见,数据验证。
    MD5的算法是将明文凑够N个512比特,每个512比特分成16个32比特的组,处理后得到4个32比特的组,也就是128位比特,16字节。
    介绍:https://blog.csdn.net/u012611878/article/details/54000607

    密文不能直接处理得到明文,也就是不可逆。只能暴力穷举、查表碰撞或者彩虹表。
    https://blog.csdn.net/u014600626/article/details/108185444

    还有杂凑冲撞:
    https://zhidao.baidu.com/question/194156199.html
    杂凑碰撞就是已知一个明文,能得出其它密文相同的明文。
    http://www.cyanprobe.com/code/learn/1613.html

    展开全文
  • MD5检测对比工具

    2015-08-16 07:56:31
    MD5检测工具,可以验证文件完整性;防止程序中途篡改造成不可挽回的后果
  • 易语言MD5对比源码.rar
  • 文件MD5对比工具 好用

    2018-11-09 16:58:00
    查看文件MD5等相关信息 对比是否是源文件 Size: 29184 bytes File Version: 1, 0, 4, 0 Modified: 2006年10月14日, 19:31:24 MD5: 5ED9D3341034C227B46A2B393B1B70BD SHA1: 118444E07183A56D77F9B629035CF1015AF5F...
  • MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特...
  • MD5_Tool文件MD5值获取对比
  • 40位MD5加密和32位MD5加密对比.txt
  • 优点,自动更新源码,自动对比MD5值,缺点,需使用服务器,自己搭建网站,并将文件上传到服务器,用md5 值生成更新文本工具,自动校验文件md5,本地通过对比服务器md5值方式实现自动更新
  • MD5是一种常见的加密方式,相对比较稳定,同时也是校验文件的一种方式,本文给大家介绍了利用C#获取文件MD5值的方法,直接使用即可,可用于对比文件是否相同。下面话不多说,来看示例代码吧 示例代码如下: /// ...
  • md5文件对比

    2015-06-17 15:30:57
    先记录两个目标文件下的所有文件,并保存一个MD5目录。之后对比两个目录得出差异文件
  • 大家在使用Cococ Creator提供的热更新 assetsManagers ,做md5校验的时候,一定会遇到卡顿的问题。 备注:文末有完整实现源码 原因是 Cococ Creator 官方提供的热更新校验回调是在ui线程进行,如下代码所示: ...


    大家在使用Cococ Creator提供的热更新 assetsManagers ,做md5校验的时候,一定会遇到卡顿的问题。

    备注:文末有完整实现源码



    原因是 Cococ Creator 官方提供的热更新校验回调是在ui线程进行,如下代码所示:



    assetsManagers.setVerifyCallback(function (path, asset)) {
    
    			let compressed = asset.compressed;
          let expectedMD5 = asset.md5;
          let relativePath = asset.path;
          let size = asset.size;
          if (compressed) {
          
             cc.log(`Verification passed : ${relativePath}`);
             
             .... 
             
             return true;
          }
          else {
             
              cc.log(`Verification passed : ${relativePath} ( ${expectedMD5} )`);
              .... 
              return true;
         }
    });
    


    为了解决这个问题,需要对引擎热更新部分稍加改造。

    下面以android 环境为例进行详细说明。



    第一步:增加 md5库, 放在 cocos2d-x/extensions/assets-manager文件夹下 。



    在这里插入图片描述



    第二步,改造AssetsManagerEx.h 和 AssetsManagerEx.cpp 增加默认校验方法



    在AssetsManagerEx.h 增加函数声明:

    private:
        virtual bool onVerifyDefault(const std::string storagePath, Manifest::Asset asset);
    
    


    在AssetsManagerEx.cpp 实现函数:



    bool AssetsManagerEx::onVerifyDefault(const std::string storagePath,Manifest::Asset asset)
    {
        //cocos2d::log("onVerifyDefault 0");
        Data data = cocos2d::FileUtils::getInstance()->getDataFromFile(storagePath);
        if (data.isNull() ||(data.getSize()== 0 )){
            CCLOG("onVerifyDefault 1");
            return false;
        }
    
        std::string result = md5(data.getBytes(), data.getSize());
        //cocos2d::log("onVerifyDefault:%s - assetmd5:%s-resultmd5:%s",storagePath.c_str(),asset.md5.c_str(),result.c_str());
        if (memcmp(result.c_str(), asset.md5.c_str(), result.length()) == 0){
            CCLOG("onVerifyDefault 2");
            return  true;
        }
    
       // cocos2d::log("onVerifyDefault 3");
        return false;
    }
    
    


    在 AssetsManagerEx.cpp 的 onSuccess方法中,做md5比较部分改造。



    当_verifyCallback 为nullptr 时,采用默认 onVerifyDefault 进行校验,如下:



    void AssetsManagerEx::onSuccess(const std::string &/*srcUrl*/, const std::string &storagePath, const std::string &customId)
    {
        if (customId == VERSION_ID)
        {
            _updateState = State::VERSION_LOADED;
            parseVersion();
        }
        else if (customId == MANIFEST_ID)
        {
            _updateState = State::MANIFEST_LOADED;
            parseManifest();
        }
        else
        {
            if (_downloadingTask.find(customId) != _downloadingTask.end()) {
                _downloadingTask.erase(customId);
            }
    
            bool ok = true;
            auto &assets = _remoteManifest->getAssets();
            auto assetIt = assets.find(customId);
            if (assetIt != assets.end())
            {
                Manifest::Asset asset = assetIt->second;
                if (_verifyCallback != nullptr)
                {
                    ok = _verifyCallback(storagePath, asset);
                } else{
    
                    ok =onVerifyDefault( storagePath,asset);
                }
            }
    
            if (ok)
            {
                bool compressed = assetIt != assets.end() ? assetIt->second.compressed : false;
                if (compressed)
                {
                    decompressDownloadedZip(customId, storagePath);
                }
                else
                {
                    fileSuccess(customId, storagePath);
                }
            }
            else
            {
                fileError(customId, "Asset file verification failed after downloaded");
            }
        }
    }
    
    

    第三步,修改 Android.mk,增加MD5.cpp 文件的编译

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    
    LOCAL_MODULE    := cocos_extension_static
    
    LOCAL_MODULE_FILENAME := libextension
    
    ifeq ($(USE_ARM_MODE),1)
    LOCAL_ARM_MODE := arm
    endif
    
    LOCAL_SRC_FILES := \
    assets-manager/MD5.cpp \
    assets-manager/Manifest.cpp \
    assets-manager/AssetsManagerEx.cpp \
    assets-manager/CCEventAssetsManagerEx.cpp \
    assets-manager/CCAsyncTaskPool.cpp \
    
    LOCAL_CXXFLAGS += -fexceptions
    
    LOCAL_C_INCLUDES := $(LOCAL_PATH)/. \
                        $(LOCAL_PATH)/.. \
                        $(LOCAL_PATH)/../cocos \
                        $(LOCAL_PATH)/../cocos/platform \
                        $(LOCAL_PATH)/../external/sources
    
    LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/. \
                               $(LOCAL_PATH)/..
                        
    include $(BUILD_STATIC_LIBRARY)
    
    


    第四步,删除上层校验回调实现,默认采用c++新增的校验方法。

    即:js 或ts 代码中不再调用 assetsManagers.setVerifyCallback 方法。



    以上就是 Cocos Creator 热更新资源 md5值比较的调整,此方案可有效解决渲染线程卡顿问题。



    下面是完整源码



    MD5.h源码



    #ifndef _LUA_MD5_H__
    #define _LUA_MD5_H__
    
    #include <stdio.h>
    #include <string>
    using namespace std;
    
    class MD5 {
    public:
    	typedef unsigned int size_type; // must be 32bit
    
    	MD5();
    	MD5(const std::string& text);
    	void update(const unsigned char *buf, size_type length);
    	void update(const char *buf, size_type length);
    	MD5& finalize();
    	std::string hexdigest(bool bUpper = false) const;
    	friend std::ostream& operator<<(std::ostream&, MD5 md5);
    
    private:
    	void init();
    	typedef unsigned char uint1; //  8bit
    	typedef unsigned int uint4;  // 32bit
    	enum {
    		blocksize = 64
    	}; // VC6 won't eat a const static int here
    
    	void transform(const uint1 block[blocksize]);
    	static void decode(uint4 output[], const uint1 input[], size_type len);
    	static void encode(uint1 output[], const uint4 input[], size_type len);
    
    	bool finalized;
    	uint1 buffer[blocksize];
    	uint4 count[2];
    	uint4 state[4];
    	uint1 digest[16];
    
    	static inline uint4 F(uint4 x, uint4 y, uint4 z);
    	static inline uint4 G(uint4 x, uint4 y, uint4 z);
    	static inline uint4 H(uint4 x, uint4 y, uint4 z);
    	static inline uint4 I(uint4 x, uint4 y, uint4 z);
    	static inline uint4 rotate_left(uint4 x, int n);
    	static inline void FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s,
    			uint4 ac);
    	static inline void GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s,
    			uint4 ac);
    	static inline void HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s,
    			uint4 ac);
    	static inline void II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s,
    			uint4 ac);
    };
    
    extern std::string md5(const std::string str);
    extern std::string md5(const wchar_t* pwstr);
    extern std::string md5(const unsigned char *buf, const unsigned int length);
    
    
    #endif
    
    
    


    MD5.cpp文件源码



    //MD5.cpp
    /* MD5
    
    based on:
    
    md5.h and md5.c
    reference implemantion of RFC 1321
    
    Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
    rights reserved.
    
    License to copy and use this software is granted provided that it
    is identified as the "RSA Data Security, Inc. MD5 Message-Digest
    Algorithm" in all material mentioning or referencing this software
    or this function.
    
    License is also granted to make and use derivative works provided
    that such works are identified as "derived from the RSA Data
    Security, Inc. MD5 Message-Digest Algorithm" in all material
    mentioning or referencing the derived work.
    
    RSA Data Security, Inc. makes no representations concerning either
    the merchantability of this software or the suitability of this
    software for any particular purpose. It is provided "as is"
    without express or implied warranty of any kind.
    
    These notices must be retained in any copies of any part of this
    documentation and/or software.
    
    */
    /* interface header */
    #include "MD5.h"
    #include <stdlib.h>
    /* system implementation headers */
    
    // Constants for MD5Transform routine.
    #define S11 7
    #define S12 12
    #define S13 17
    #define S14 22
    #define S21 5
    #define S22 9
    #define S23 14
    #define S24 20
    #define S31 4
    #define S32 11
    #define S33 16
    #define S34 23
    #define S41 6
    #define S42 10
    #define S43 15
    #define S44 21
    
    ///
    
    // F, G, H and I are basic MD5 functions.
    inline MD5::uint4 MD5::F(uint4 x, uint4 y, uint4 z) {
    	return x&y | ~x&z;
    }
    
    inline MD5::uint4 MD5::G(uint4 x, uint4 y, uint4 z) {
    	return x&z | y&~z;
    }
    
    inline MD5::uint4 MD5::H(uint4 x, uint4 y, uint4 z) {
    	return x^y^z;
    }
    
    inline MD5::uint4 MD5::I(uint4 x, uint4 y, uint4 z) {
    	return y ^ (x | ~z);
    }
    
    // rotate_left rotates x left n bits.
    inline MD5::uint4 MD5::rotate_left(uint4 x, int n) {
    	return (x << n) | (x >> (32-n));
    }
    
    // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
    // Rotation is separate from addition to prevent recomputation.
    inline void MD5::FF(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
    	a = rotate_left(a+ F(b,c,d) + x + ac, s) + b;
    }
    
    inline void MD5::GG(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
    	a = rotate_left(a + G(b,c,d) + x + ac, s) + b;
    }
    
    inline void MD5::HH(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
    	a = rotate_left(a + H(b,c,d) + x + ac, s) + b;
    }
    
    inline void MD5::II(uint4 &a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac) {
    	a = rotate_left(a + I(b,c,d) + x + ac, s) + b;
    }
    
    //
    
    // default ctor, just initailize
    MD5::MD5()
    {
    	init();
    }
    
    //
    
    // nifty shortcut ctor, compute MD5 for string and finalize it right away
    MD5::MD5(const std::string &text)
    {
    	init();
    	update(text.c_str(), text.length());
    	finalize();
    }
    
    //
    
    void MD5::init()
    {
    	finalized=false;
    
    	count[0] = 0;
    	count[1] = 0;
    
    	// load magic initialization constants.
    	state[0] = 0x67452301;
    	state[1] = 0xefcdab89;
    	state[2] = 0x98badcfe;
    	state[3] = 0x10325476;
    }
    
    //
    
    // decodes input (unsigned char) into output (uint4). Assumes len is a multiple of 4.
    void MD5::decode(uint4 output[], const uint1 input[], size_type len)
    {
    	for (unsigned int i = 0, j = 0; j < len; i++, j += 4)
    		output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
    		(((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
    }
    
    //
    
    // encodes input (uint4) into output (unsigned char). Assumes len is
    // a multiple of 4.
    void MD5::encode(uint1 output[], const uint4 input[], size_type len)
    {
    	for (size_type i = 0, j = 0; j < len; i++, j += 4) {
    		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;
    	}
    }
    
    //
    
    // apply MD5 algo on a block
    void MD5::transform(const uint1 block[blocksize])
    {
    	uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
    	decode (x, block, blocksize);
    
    	/* Round 1 */
    	FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
    	FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
    	FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
    	FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
    	FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
    	FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
    	FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
    	FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
    	FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
    	FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
    	FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
    	FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
    	FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
    	FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
    	FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
    	FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
    
    	/* Round 2 */
    	GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
    	GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
    	GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
    	GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
    	GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
    	GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
    	GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
    	GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
    	GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
    	GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
    	GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
    	GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
    	GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
    	GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
    	GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
    	GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
    
    	/* Round 3 */
    	HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
    	HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
    	HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
    	HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
    	HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
    	HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
    	HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
    	HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
    	HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
    	HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
    	HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
    	HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
    	HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
    	HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
    	HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
    	HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
    
    	/* Round 4 */
    	II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
    	II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
    	II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
    	II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
    	II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
    	II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
    	II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
    	II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
    	II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
    	II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
    	II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
    	II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
    	II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
    	II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
    	II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
    	II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
    
    	state[0] += a;
    	state[1] += b;
    	state[2] += c;
    	state[3] += d;
    
    	// Zeroize sensitive information.
    	memset(x, 0, sizeof x);
    }
    
    //
    
    // MD5 block update operation. Continues an MD5 message-digest
    // operation, processing another message block
    void MD5::update(const unsigned char input[], size_type length)
    {
    	// compute number of bytes mod 64
    	size_type index = count[0] / 8 % blocksize;
    
    	// Update number of bits
    	if ((count[0] += (length << 3)) < (length << 3))
    		count[1]++;
    	count[1] += (length >> 29);
    
    	// number of bytes we need to fill in buffer
    	size_type firstpart = 64 - index;
    
    	size_type i;
    
    	// transform as many times as possible.
    	if (length >= firstpart)
    	{
    		// fill buffer first, transform
    		memcpy(&buffer[index], input, firstpart);
    		transform(buffer);
    
    		// transform chunks of blocksize (64 bytes)
    		for (i = firstpart; i + blocksize <= length; i += blocksize)
    			transform(&input[i]);
    
    		index = 0;
    	}
    	else
    		i = 0;
    
    	// buffer remaining input
    	memcpy(&buffer[index], &input[i], length-i);
    }
    
    //
    
    // for convenience provide a verson with signed char
    void MD5::update(const char input[], size_type length)
    {
    	update((const unsigned char*)input, length);
    }
    
    //
    
    // MD5 finalization. Ends an MD5 message-digest operation, writing the
    // the message digest and zeroizing the context.
    MD5& MD5::finalize()
    {
    	static unsigned char padding[64] = {
    		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
    	};
    
    	if (!finalized) {
    		// Save number of bits
    		unsigned char bits[8];
    		encode(bits, count, 8);
    
    		// pad out to 56 mod 64.
    		size_type index = count[0] / 8 % 64;
    		size_type padLen = (index < 56) ? (56 - index) : (120 - index);
    		update(padding, padLen);
    
    		// Append length (before padding)
    		update(bits, 8);
    
    		// Store state in digest
    		encode(digest, state, 16);
    
    		// Zeroize sensitive information.
    		memset(buffer, 0, sizeof buffer);
    		memset(count, 0, sizeof count);
    
    		finalized=true;
    	}
    
    	return *this;
    }
    
    //
    
    // return hex representation of digest as string
    std::string MD5::hexdigest(bool bUpper) const
    {
    	if (!finalized)
    		return "";
    
    	char buf[33];
    	for (int i=0; i<16; i++){
    		sprintf(buf+i*2, "%02x", digest[i]);
    	}
    
    	if (bUpper){
    		for(int i = 0;i<33;i++){
    			buf[i] = toupper((unsigned char)buf[i]);
    		}
    	}
    
    	buf[32]=0;
    
    	return std::string(buf);
    }
    
    //
    
    std::ostream& operator<<(std::ostream& out, MD5 md5)
    {
    	return out << md5.hexdigest();
    }
    
    //
    
    std::string md5(const std::string str)
    {
    	MD5 md5 = MD5(str);
    
    	return md5.hexdigest();
    }
    
    
    std::string md5(const wchar_t* pwstr)
    {
    	if(pwstr == NULL)
    		return "";
    	char *ptmp = (char *)new char[2*wcslen(pwstr)+1];
    	memset(ptmp,0,2*wcslen(pwstr)+1);
    	wcstombs(ptmp,pwstr,2*wcslen(pwstr)+1);
    	MD5 md5 = MD5(ptmp);
    	delete [] ptmp;
    	return md5.hexdigest();
    }
    
    
    std::string md5(const unsigned char *buf, const unsigned int length)
     {
    	 MD5 md5 = MD5();
    	 md5.update(buf, length);
    	 md5.finalize();
    	 return md5.hexdigest();
     }
    
    


    AssetsManagerEx.h 源码



    /****************************************************************************
     Copyright (c) 2013 cocos2d-x.org
     Copyright (c) 2014-2016 Chukong Technologies Inc.
     Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
     
     http://www.cocos2d-x.org
     
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"), to deal
     in the Software without restriction, including without limitation the rights
     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     copies of the Software, and to permit persons to whom the Software is
     furnished to do so, subject to the following conditions:
     
     The above copyright notice and this permission notice shall be included in
     all copies or substantial portions of the Software.
     
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     THE SOFTWARE.
     ****************************************************************************/
    
    #ifndef __AssetsManagerEx__
    #define __AssetsManagerEx__
    
    #include <string>
    #include <unordered_map>
    #include <vector>
    
    #include "platform/CCFileUtils.h"
    #include "network/CCDownloader.h"
    
    #include "CCEventAssetsManagerEx.h"
    
    #include "Manifest.h"
    #include "extensions/ExtensionMacros.h"
    #include "extensions/ExtensionExport.h"
    #include "json/document-wrapper.h"
    
    
    NS_CC_EXT_BEGIN
    
    /**
     * @brief   This class is used to auto update resources, such as pictures or scripts.
     */
    class CC_EX_DLL AssetsManagerEx : public Ref
    {
    public:
        
        //! Update states
        enum class State
        {
            UNINITED,
            UNCHECKED,
            PREDOWNLOAD_VERSION,
            DOWNLOADING_VERSION,
            VERSION_LOADED,
            PREDOWNLOAD_MANIFEST,
            DOWNLOADING_MANIFEST,
            MANIFEST_LOADED,
            NEED_UPDATE,
            READY_TO_UPDATE,
            UPDATING,
            UNZIPPING,
            UP_TO_DATE,
            FAIL_TO_UPDATE
        };
        
        const static std::string VERSION_ID;
        const static std::string MANIFEST_ID;
        
        typedef std::function<int(const std::string& versionA, const std::string& versionB)> VersionCompareHandle;
        typedef std::function<bool(const std::string& path, Manifest::Asset asset)> VerifyCallback;
        typedef std::function<void(EventAssetsManagerEx *event)> EventCallback;
        
        /** @brief Create function for creating a new AssetsManagerEx
         @param manifestUrl   The url for the local manifest file
         @param storagePath   The storage path for downloaded assets
         @warning   The cached manifest in your storage path have higher priority and will be searched first,
                    only if it doesn't exist, AssetsManagerEx will use the given manifestUrl.
         */
        static AssetsManagerEx* create(const std::string &manifestUrl, const std::string &storagePath);
        
        /** @brief  Check out if there is a new version of manifest.
         *          You may use this method before updating, then let user determine whether
         *          he wants to update resources.
         */
        void checkUpdate();
        
        /** @brief Prepare the update process, this will cleanup download process flags, fill up download units with temporary manifest or remote manifest
         */
        void prepareUpdate();
        
        /** @brief Update with the current local manifest.
         */
        void update();
        
        /** @brief Reupdate all failed assets under the current AssetsManagerEx context
         */
        void downloadFailedAssets();
        
        /** @brief Gets the current update state.
         */
        State getState() const;
        
        /** @brief Gets storage path.
         */
        const std::string& getStoragePath() const;
        
        /** @brief Function for retrieving the local manifest object
         */
        const Manifest* getLocalManifest() const;
        
        /** @brief Load a custom local manifest object, the local manifest must be loaded already.
         * You can only manually load local manifest when the update state is UNCHECKED, it will fail once the update process is began.
         * This API will do the following things:
         * 1. Reset storage path
         * 2. Set local storage
         * 3. Search for cached manifest and compare with the local manifest
         * 4. Init temporary manifest and remote manifest
         * If successfully load the given local manifest and inited other manifests, it will return true, otherwise it will return false
         * @param localManifest    The local manifest object to be set
         * @param storagePath    The local storage path
         */
        bool loadLocalManifest(Manifest* localManifest, const std::string& storagePath);
        
        /** @brief Load a local manifest from url.
         * You can only manually load local manifest when the update state is UNCHECKED, it will fail once the update process is began.
         * This API will do the following things:
         * 1. Reset storage path
         * 2. Set local storage
         * 3. Search for cached manifest and compare with the local manifest
         * 4. Init temporary manifest and remote manifest
         * If successfully load the given local manifest and inited other manifests, it will return true, otherwise it will return false
         * @param manifestUrl    The local manifest url
         */
        bool loadLocalManifest(const std::string& manifestUrl);
        
        /** @brief Function for retrieving the remote manifest object
         */
        const Manifest* getRemoteManifest() const;
        
        /** @brief Load a custom remote manifest object, the manifest must be loaded already.
         * You can only manually load remote manifest when the update state is UNCHECKED and local manifest is already inited, it will fail once the update process is began.
         * @param remoteManifest    The remote manifest object to be set
         */
        bool loadRemoteManifest(Manifest* remoteManifest);
        
        /** @brief Gets whether the current download is resuming previous unfinished job, this will only be available after READY_TO_UPDATE state, under unknown states it will return false by default.
         */
        bool isResuming() const {return _downloadResumed;};
        
        /** @brief Gets the total byte size to be downloaded of the update, this will only be available after READY_TO_UPDATE state, under unknown states it will return 0 by default.
         */
        double getTotalBytes() const {return _totalSize;};
        
        /** @brief Gets the current downloaded byte size of the update, this will only be available after READY_TO_UPDATE state, under unknown states it will return 0 by default.
         */
        double getDownloadedBytes() const {return _totalDownloaded;};
        
        /** @brief Gets the total files count to be downloaded of the update, this will only be available after READY_TO_UPDATE state, under unknown states it will return 0 by default.
         */
        int getTotalFiles() const {return _totalToDownload;};
        
        /** @brief Gets the current downloaded files count of the update, this will only be available after READY_TO_UPDATE state, under unknown states it will return 0 by default.
         */
        int getDownloadedFiles() const {return _totalToDownload - _totalWaitToDownload;};
        
        /** @brief Function for retrieving the max concurrent task count
         */
        const int getMaxConcurrentTask() const {return _maxConcurrentTask;};
        
        /** @brief Function for setting the max concurrent task count
         */
        void setMaxConcurrentTask(const int max) {_maxConcurrentTask = max;};
        
        /** @brief Set the handle function for comparing manifests versions
         * @param handle    The compare function
         */
        void setVersionCompareHandle(const VersionCompareHandle& handle) {_versionCompareHandle = handle;};
        
        /** @brief Set the verification function for checking whether downloaded asset is correct, e.g. using md5 verification
         * @param callback  The verify callback function
         */
        void setVerifyCallback(const VerifyCallback& callback) {_verifyCallback = callback;};
        
        /** @brief Set the event callback for receiving update process events
         * @param callback  The event callback function
         */
        void setEventCallback(const EventCallback& callback) {_eventCallback = callback;};
    
        /** @brief Cancel update
         */
        void cancelUpdate();
    	
    	/**
    	 * @brief 设置热更新地址,由于热更新地址会动态的发生变化,热更新的地址以下发的地址为准,设置热更新地址后,会自动的替换所有热更新的源地址
    	 */
    	void setHotUpdateUrl(const std::string& url) { _hotUpdateUrl = url; };
        
    CC_CONSTRUCTOR_ACCESS:
        
        AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath);
        
        AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath, const VersionCompareHandle& handle);
        
        virtual ~AssetsManagerEx();
        
    protected:
        
        void init(const std::string& manifestUrl, const std::string& storagePath);
        
        std::string basename(const std::string& path) const;
        
        std::string get(const std::string& key) const;
        
        void initManifests();
        
        void prepareLocalManifest();
        
        void setStoragePath(const std::string& storagePath);
        
        void adjustPath(std::string &path);
        
        void dispatchUpdateEvent(EventAssetsManagerEx::EventCode code, const std::string &message = "", const std::string &assetId = "", int curle_code = 0, int curlm_code = 0);
        
        void downloadVersion();
        void parseVersion();
        void downloadManifest();
        void parseManifest();
        void startUpdate();
        void updateSucceed();
        bool decompress(const std::string &filename);
        void decompressDownloadedZip(const std::string &customId, const std::string &storagePath);
        
        /** @brief Update a list of assets under the current AssetsManagerEx context
         */
        void updateAssets(const DownloadUnits& assets);
        
        /** @brief Retrieve all failed assets during the last update
         */
        const DownloadUnits& getFailedAssets() const;
        
        /** @brief Function for destroying the downloaded version file and manifest file
         */
        void destroyDownloadedVersion();
        
        /** @brief Download items in queue with max concurrency setting
         */
        void queueDowload();
        
        void fileError(const std::string& identifier, const std::string& errorStr, int errorCode = 0, int errorCodeInternal = 0);
        
        void fileSuccess(const std::string &customId, const std::string &storagePath);
        
        /** @brief  Call back function for error handling,
         the error will then be reported to user's listener registed in addUpdateEventListener
         @param error   The error object contains ErrorCode, message, asset url, asset key
         @warning AssetsManagerEx internal use only
         * @js NA
         * @lua NA
         */
        virtual void onError(const network::DownloadTask& task,
                             int errorCode,
                             int errorCodeInternal,
                             const std::string& errorStr);
        
        /** @brief  Call back function for recording downloading percent of the current asset,
         the progression will then be reported to user's listener registed in addUpdateProgressEventListener
         @param total       Total size to download for this asset
         @param downloaded  Total size already downloaded for this asset
         @param url         The url of this asset
         @param customId    The key of this asset
         @warning AssetsManagerEx internal use only
         * @js NA
         * @lua NA
         */
        virtual void onProgress(double total, double downloaded, const std::string &url, const std::string &customId);
        
        /** @brief  Call back function for success of the current asset
         the success event will then be send to user's listener registed in addUpdateEventListener
         @param srcUrl      The url of this asset
         @param customId    The key of this asset
         @warning AssetsManagerEx internal use only
         * @js NA
         * @lua NA
         */
        virtual void onSuccess(const std::string &srcUrl, const std::string &storagePath, const std::string &customId);
    private:
    
        virtual bool onVerifyDefault(const std::string storagePath, Manifest::Asset asset);
    
    private:
        void batchDownload();
    
        // Called when one DownloadUnits finished
        void onDownloadUnitsFinished();
        
        //! The event of the current AssetsManagerEx in event dispatcher
        std::string _eventName;
        
        //! Reference to the global event dispatcher
    //    EventDispatcher *_eventDispatcher;
        //! Reference to the global file utils
        FileUtils *_fileUtils;
        
        //! State of update
        State _updateState;
        
        //! Downloader
        std::shared_ptr<network::Downloader> _downloader;
        
        //! The reference to the local assets
        const std::unordered_map<std::string, Manifest::Asset> *_assets;
        
        //! The path to store successfully downloaded version.
        std::string _storagePath;
        
        //! The path to store downloading version.
        std::string _tempStoragePath;
        
        //! The local path of cached temporary version file
        std::string _tempVersionPath;
        
        //! The local path of cached manifest file
        std::string _cacheManifestPath;
        
        //! The local path of cached temporary manifest file
        std::string _tempManifestPath;
        
        //! The path of local manifest file
        std::string _manifestUrl;
        
        //! Local manifest
        Manifest *_localManifest;
        
        //! Local temporary manifest for download resuming
        Manifest *_tempManifest;
        
        //! Remote manifest
        Manifest *_remoteManifest;
        
        //! Whether user have requested to update
        enum class UpdateEntry : char
        {
            NONE,
            CHECK_UPDATE,
            DO_UPDATE
        };
    
        UpdateEntry _updateEntry;
        
        //! All assets unit to download
        DownloadUnits _downloadUnits;
        
        //! All failed units
        DownloadUnits _failedUnits;
        
        //! Download queue
        std::vector<std::string> _queue;
        
        bool _downloadResumed;
        
        //! Max concurrent task count for downloading
        int _maxConcurrentTask;
        
        //! Current concurrent task count
        int _currConcurrentTask;
        
        //! Download percent
        float _percent;
        
        //! Download percent by file
        float _percentByFile;
        
        //! Indicate whether the total size should be enabled
        int _totalEnabled;
        
        //! Indicate the number of file whose total size have been collected
        int _sizeCollected;
        
        //! Total file size need to be downloaded (sum of all files)
        double _totalSize;
        
        //! Total downloaded file size (sum of all downloaded files)
        double _totalDownloaded;
        
        //! Downloaded size for each file
        std::unordered_map<std::string, double> _downloadedSize;
        
        //! Total number of assets to download
        int _totalToDownload;
        //! Total number of assets still waiting to be downloaded
        int _totalWaitToDownload;
        //! Next target percent for saving the manifest file
        float _nextSavePoint;
        
        //! Handle function to compare versions between different manifests
        VersionCompareHandle _versionCompareHandle;
        
        //! Callback function to verify the downloaded assets
        VerifyCallback _verifyCallback;
        
        //! Callback function to dispatch events
        EventCallback _eventCallback;
        
        //! Marker for whether the assets manager is inited
        bool _inited;
    
        //! Marker for whether the update is canceled
        bool _canceled;
        //! Downloading task container
        std::unordered_map<std::string, std::shared_ptr<const network::DownloadTask>> _downloadingTask;
    	/*是否启用资源下载类型*/
    	bool _isUsingAssetsType;
    	/*资源类型 ""为大厅 其它为子游戏包名*/
    	std::string _assetsType;
    	/* 热更新地址*/
    	std::string _hotUpdateUrl;
    };
    
    NS_CC_EXT_END
    
    #endif /* defined(__AssetsManagerEx__) */
    
    


    AssetsManagerEx.cpp 源码

    /****************************************************************************
     Copyright (c) 2014 cocos2d-x.org
     Copyright (c) 2015-2016 Chukong Technologies Inc.
     Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
    
     http://www.cocos2d-x.org
    
     Permission is hereby granted, free of charge, to any person obtaining a copy
     of this software and associated documentation files (the "Software"), to deal
     in the Software without restriction, including without limitation the rights
     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     copies of the Software, and to permit persons to whom the Software is
     furnished to do so, subject to the following conditions:
    
     The above copyright notice and this permission notice shall be included in
     all copies or substantial portions of the Software.
    
     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     THE SOFTWARE.
     ****************************************************************************/
    #include "AssetsManagerEx.h"
    #include "base/ccUTF8.h"
    #include "CCAsyncTaskPool.h"
    
    #include <stdio.h>
    #include <errno.h>
    #include "MD5.h"
    
    #ifdef MINIZIP_FROM_SYSTEM
    #include <minizip/unzip.h>
    #else // from our embedded sources
    #include "unzip/unzip.h"
    #endif
    
    NS_CC_EXT_BEGIN
    
    #define VERSION_FILENAME        "version.manifest"
    #define TEMP_MANIFEST_FILENAME  "project.manifest.temp"
    #define TEMP_PACKAGE_SUFFIX     "_temp"
    #define MANIFEST_FILENAME       "project.manifest"
    
    #define BUFFER_SIZE    8192
    #define MAX_FILENAME   512
    
    #define DEFAULT_CONNECTION_TIMEOUT 45
    
    #define SAVE_POINT_INTERVAL 0.1
    
    const std::string AssetsManagerEx::VERSION_ID = "@version";
    const std::string AssetsManagerEx::MANIFEST_ID = "@manifest";
    
    // Implementation of AssetsManagerEx
    
    AssetsManagerEx::AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath)
    : _updateState(State::UNINITED)
    , _assets(nullptr)
    , _storagePath("")
    , _tempVersionPath("")
    , _cacheManifestPath("")
    , _tempManifestPath("")
    , _localManifest(nullptr)
    , _tempManifest(nullptr)
    , _remoteManifest(nullptr)
    , _updateEntry(UpdateEntry::NONE)
    , _percent(0)
    , _percentByFile(0)
    , _totalSize(0)
    , _sizeCollected(0)
    , _totalDownloaded(0)
    , _totalToDownload(0)
    , _totalWaitToDownload(0)
    , _nextSavePoint(0.0)
    , _downloadResumed(false)
    , _maxConcurrentTask(32)
    , _currConcurrentTask(0)
    , _verifyCallback(nullptr)
    , _inited(false)
    , _canceled(false)
    {
        init(manifestUrl, storagePath);
    }
    
    AssetsManagerEx::AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath, const VersionCompareHandle& handle)
    : _updateState(State::UNINITED)
    , _assets(nullptr)
    , _storagePath("")
    , _tempVersionPath("")
    , _cacheManifestPath("")
    , _tempManifestPath("")
    , _localManifest(nullptr)
    , _tempManifest(nullptr)
    , _remoteManifest(nullptr)
    , _updateEntry(UpdateEntry::NONE)
    , _percent(0)
    , _percentByFile(0)
    , _totalSize(0)
    , _sizeCollected(0)
    , _totalDownloaded(0)
    , _totalToDownload(0)
    , _totalWaitToDownload(0)
    , _nextSavePoint(0.0)
    , _downloadResumed(false)
    , _maxConcurrentTask(32)
    , _currConcurrentTask(0)
    , _versionCompareHandle(handle)
    , _verifyCallback(nullptr)
    , _eventCallback(nullptr)
    , _inited(false)
    , _isUsingAssetsType(false)
    , _assetsType("")
    , _hotUpdateUrl("")
    {
        init(manifestUrl, storagePath);
    }
    
    void AssetsManagerEx::init(const std::string& manifestUrl, const std::string& storagePath)
    {
        // Init variables
        std::string pointer = StringUtils::format("%p", this);
        _eventName = "__cc_assets_manager_" + pointer;
        _fileUtils = FileUtils::getInstance();
    
        network::DownloaderHints hints =
        {
            static_cast<uint32_t>(_maxConcurrentTask),
            DEFAULT_CONNECTION_TIMEOUT,
            ".tmp"
        };
        _downloader = std::shared_ptr<network::Downloader>(new network::Downloader(hints));
        _downloader->onTaskError = std::bind(&AssetsManagerEx::onError, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4);
        _downloader->onTaskProgress = [this](const network::DownloadTask& task,
                                             int64_t /*bytesReceived*/,
                                             int64_t totalBytesReceived,
                                             int64_t totalBytesExpected)
        {
            this->onProgress(totalBytesExpected, totalBytesReceived, task.requestURL, task.identifier);
        };
    
    
        _downloader->onFileTaskSuccess = [this](const network::DownloadTask& task)
        {
            this->onSuccess(task.requestURL, task.storagePath, task.identifier);
        };
    
    
    
        setStoragePath(storagePath);
    	
    	//这里做一下处理,当传入的是一个特定的格式时,修改当前3个缓存的路径
    	std::string typeString = "type.";
    	auto pos = manifestUrl.find(typeString);
    	if ( pos != std::string::npos) {
    		auto amType = manifestUrl.substr(typeString.size());
    		this->_isUsingAssetsType = true;
    		if (amType == "hall") {
    			//大厅
    			this->_assetsType = "";
    			_tempVersionPath = _tempStoragePath + VERSION_FILENAME;
    			_cacheManifestPath = _storagePath + MANIFEST_FILENAME;
    			_tempManifestPath = _tempStoragePath + TEMP_MANIFEST_FILENAME;
    		}
    		else {
    			this->_assetsType = amType;
    			_tempVersionPath = _tempStoragePath + amType + VERSION_FILENAME;
    			_cacheManifestPath = _storagePath + amType + MANIFEST_FILENAME;
    			_tempManifestPath = _tempStoragePath + amType + TEMP_MANIFEST_FILENAME;
    		}
    	}
    	else {
    		this->_isUsingAssetsType = false;
    		this->_assetsType = "";
    		_tempVersionPath = _tempStoragePath + VERSION_FILENAME;
    		_cacheManifestPath = _storagePath + MANIFEST_FILENAME;
    		_tempManifestPath = _tempStoragePath + TEMP_MANIFEST_FILENAME;
    		if (manifestUrl.size() > 0)
    		{
    			loadLocalManifest(manifestUrl);
    		}
    	}
    
        
    }
    
    AssetsManagerEx::~AssetsManagerEx()
    {
        _downloader->onTaskError = (nullptr);
        _downloader->onFileTaskSuccess = (nullptr);
        _downloader->onTaskProgress = (nullptr);
        CC_SAFE_RELEASE(_localManifest);
        // _tempManifest could share a ptr with _remoteManifest or _localManifest
        if (_tempManifest != _localManifest && _tempManifest != _remoteManifest)
            CC_SAFE_RELEASE(_tempManifest);
        CC_SAFE_RELEASE(_remoteManifest);
    }
    
    AssetsManagerEx* AssetsManagerEx::create(const std::string& manifestUrl, const std::string& storagePath)
    {
        AssetsManagerEx* ret = new (std::nothrow) AssetsManagerEx(manifestUrl, storagePath);
        if (ret)
        {
            ret->autorelease();
        }
        else
        {
            CC_SAFE_DELETE(ret);
        }
        return ret;
    }
    
    void AssetsManagerEx::initManifests()
    {
        _inited = true;
        _canceled = false;
        // Init and load temporary manifest
        _tempManifest = new (std::nothrow) Manifest();
        if (_tempManifest)
        {
    		_tempManifest->setHotUpdateUrl(_hotUpdateUrl);
            _tempManifest->parseFile(_tempManifestPath);
            // Previous update is interrupted
            if (_fileUtils->isFileExist(_tempManifestPath))
            {
                // Manifest parse failed, remove all temp files
                if (!_tempManifest->isLoaded())
                {
                    _fileUtils->removeDirectory(_tempStoragePath);
                    CC_SAFE_RELEASE(_tempManifest);
                    _tempManifest = nullptr;
                }
            }
        }
        else
        {
            _inited = false;
        }
    
        // Init remote manifest for future usage
        _remoteManifest = new (std::nothrow) Manifest();
        if (!_remoteManifest)
        {
            _inited = false;
        }
    
        if (!_inited)
        {
            CC_SAFE_RELEASE(_localManifest);
            CC_SAFE_RELEASE(_tempManifest);
            CC_SAFE_RELEASE(_remoteManifest);
            _localManifest = nullptr;
            _tempManifest = nullptr;
            _remoteManifest = nullptr;
        }
    }
    
    void AssetsManagerEx::prepareLocalManifest()
    {
        // An alias to assets
        _assets = &(_localManifest->getAssets());
    
        // Add search paths
        _localManifest->prependSearchPaths();
    }
    
    bool AssetsManagerEx::loadLocalManifest(Manifest* localManifest, const std::string& storagePath)
    {
        if (_updateState > State::UNINITED)
        {
            return false;
        }
        if (!localManifest || !localManifest->isLoaded())
        {
            return false;
        }
        _inited = true;
        _canceled = false;
        // Reset storage path
        if (storagePath.size() > 0)
        {
            setStoragePath(storagePath);
            _tempVersionPath = _tempStoragePath + VERSION_FILENAME;
            _cacheManifestPath = _storagePath + MANIFEST_FILENAME;
            _tempManifestPath = _tempStoragePath + TEMP_MANIFEST_FILENAME;
        }
        // Release existing local manifest
        if (_localManifest)
        {
            CC_SAFE_RELEASE(_localManifest);
        }
        _localManifest = localManifest;
        _localManifest->retain();
        // Find the cached manifest file
        Manifest *cachedManifest = nullptr;
        if (_fileUtils->isFileExist(_cacheManifestPath))
        {
            cachedManifest = new (std::nothrow) Manifest();
            if (cachedManifest)
            {
    			cachedManifest->setHotUpdateUrl(_hotUpdateUrl);
                cachedManifest->parseFile(_cacheManifestPath);
                if (!cachedManifest->isLoaded())
                {
                    _fileUtils->removeFile(_cacheManifestPath);
                    CC_SAFE_RELEASE(cachedManifest);
                    cachedManifest = nullptr;
                }
            }
        }
        // Compare with cached manifest to determine which one to use
        if (cachedManifest)
        {
            bool localNewer = _localManifest->versionGreater(cachedManifest, _versionCompareHandle);
            if (localNewer)
            {
                // Recreate storage, to empty the content
                _fileUtils->removeDirectory(_storagePath);
                _fileUtils->createDirectory(_storagePath);
                CC_SAFE_RELEASE(cachedManifest);
            }
            else
            {
                CC_SAFE_RELEASE(_localManifest);
                _localManifest = cachedManifest;
            }
        }
        prepareLocalManifest();
    
        // Init temp manifest and remote manifest
        initManifests();
    
        if (!_inited)
        {
            return false;
        }
        else
        {
            _updateState = State::UNCHECKED;
            return true;
        }
    }
    
    bool AssetsManagerEx::loadLocalManifest(const std::string& manifestUrl)
    {
        if (manifestUrl.size() == 0)
        {
            return false;
        }
        if (_updateState > State::UNINITED)
        {
            return false;
        }
        _manifestUrl = manifestUrl;
        // Init and load local manifest
        _localManifest = new (std::nothrow) Manifest();
        if (!_localManifest)
        {
            return false;
        }
        Manifest *cachedManifest = nullptr;
        // Find the cached manifest file
        if (_fileUtils->isFileExist(_cacheManifestPath))
        {
            cachedManifest = new (std::nothrow) Manifest();
            if (cachedManifest)
            {
    			cachedManifest->setHotUpdateUrl(_hotUpdateUrl);
                cachedManifest->parseFile(_cacheManifestPath);
                if (!cachedManifest->isLoaded())
                {
                    _fileUtils->removeFile(_cacheManifestPath);
                    CC_SAFE_RELEASE(cachedManifest);
                    cachedManifest = nullptr;
                }
            }
        }
    
        // Ensure no search path of cached manifest is used to load this manifest
        std::vector<std::string> searchPaths = _fileUtils->getSearchPaths();
        if (cachedManifest)
        {
            std::vector<std::string> cacheSearchPaths = cachedManifest->getSearchPaths();
            std::vector<std::string> trimmedPaths = searchPaths;
            for (auto path : cacheSearchPaths)
            {
                const auto pos = std::find(trimmedPaths.begin(), trimmedPaths.end(), path);
                if (pos != trimmedPaths.end())
                {
                    trimmedPaths.erase(pos);
                }
            }
            _fileUtils->setSearchPaths(trimmedPaths);
        }
    	_localManifest->setHotUpdateUrl(_hotUpdateUrl);
        // Load local manifest in app package
        _localManifest->parseFile(_manifestUrl);
        if (cachedManifest)
        {
            // Restore search paths
            _fileUtils->setSearchPaths(searchPaths);
        }
        if (_localManifest->isLoaded())
        {
            // Compare with cached manifest to determine which one to use
            if (cachedManifest)
            {
                bool localNewer = _localManifest->versionGreater(cachedManifest, _versionCompareHandle);
                if (localNewer)
                {
                    // Recreate storage, to empty the content
                    _fileUtils->removeDirectory(_storagePath);
                    _fileUtils->createDirectory(_storagePath);
                    CC_SAFE_RELEASE(cachedManifest);
                }
                else
                {
                    CC_SAFE_RELEASE(_localManifest);
                    _localManifest = cachedManifest;
                }
            }
            prepareLocalManifest();
        }
    
        // Fail to load local manifest
        if (!_localManifest->isLoaded())
        {
            CCLOG("AssetsManagerEx : No local manifest file found error.\n");
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
            return false;
        }
        initManifests();
        _updateState = State::UNCHECKED;
        return true;
    }
    
    bool AssetsManagerEx::loadRemoteManifest(Manifest* remoteManifest)
    {
        if (!_inited || _updateState > State::UNCHECKED)
        {
            return false;
        }
        if (!remoteManifest || !remoteManifest->isLoaded())
        {
            return false;
        }
        // Release existing remote manifest
        if (_remoteManifest)
        {
            CC_SAFE_RELEASE(_remoteManifest);
        }
        _remoteManifest = remoteManifest;
        _remoteManifest->retain();
        // Compare manifest version and set state
        if (_localManifest->versionGreaterOrEquals(_remoteManifest, _versionCompareHandle))
        {
            _updateState = State::UP_TO_DATE;
            _fileUtils->removeDirectory(_tempStoragePath);
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
        }
        else
        {
            _updateState = State::NEED_UPDATE;
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
        }
        return true;
    }
    
    std::string AssetsManagerEx::basename(const std::string& path) const
    {
        size_t found = path.find_last_of("/\\");
    
        if (std::string::npos != found)
        {
            return path.substr(0, found);
        }
        else
        {
            return path;
        }
    }
    
    std::string AssetsManagerEx::get(const std::string& key) const
    {
        auto it = _assets->find(key);
        if (it != _assets->cend()) {
            return _storagePath + it->second.path;
        }
        else return "";
    }
    
    const Manifest* AssetsManagerEx::getLocalManifest() const
    {
        return _localManifest;
    }
    
    const Manifest* AssetsManagerEx::getRemoteManifest() const
    {
        return _remoteManifest;
    }
    
    const std::string& AssetsManagerEx::getStoragePath() const
    {
        return _storagePath;
    }
    
    void AssetsManagerEx::setStoragePath(const std::string& storagePath)
    {
        _storagePath = storagePath;
        adjustPath(_storagePath);
        _fileUtils->createDirectory(_storagePath);
    
        _tempStoragePath = _storagePath;
        _tempStoragePath.insert(_storagePath.size() - 1, TEMP_PACKAGE_SUFFIX);
        _fileUtils->createDirectory(_tempStoragePath);
    }
    
    void AssetsManagerEx::adjustPath(std::string &path)
    {
        if (path.size() > 0 && path[path.size() - 1] != '/')
        {
            path.append("/");
        }
    }
    
    bool AssetsManagerEx::decompress(const std::string &zip)
    {
        // Find root path for zip file
        size_t pos = zip.find_last_of("/\\");
        if (pos == std::string::npos)
        {
            CCLOG("AssetsManagerEx : no root path specified for zip file %s\n", zip.c_str());
            return false;
        }
        const std::string rootPath = zip.substr(0, pos+1);
    
        // Open the zip file
        unzFile zipfile = unzOpen(FileUtils::getInstance()->getSuitableFOpen(zip).c_str());
        if (! zipfile)
        {
            CCLOG("AssetsManagerEx : can not open downloaded zip file %s\n", zip.c_str());
            return false;
        }
    
        // Get info about the zip file
        unz_global_info global_info;
        if (unzGetGlobalInfo(zipfile, &global_info) != UNZ_OK)
        {
            CCLOG("AssetsManagerEx : can not read file global info of %s\n", zip.c_str());
            unzClose(zipfile);
            return false;
        }
    
        // Buffer to hold data read from the zip file
        char readBuffer[BUFFER_SIZE];
        // Loop to extract all files.
        uLong i;
        for (i = 0; i < global_info.number_entry; ++i)
        {
            // Get info about current file.
            unz_file_info fileInfo;
            char fileName[MAX_FILENAME];
            if (unzGetCurrentFileInfo(zipfile,
                                      &fileInfo,
                                      fileName,
                                      MAX_FILENAME,
                                      NULL,
                                      0,
                                      NULL,
                                      0) != UNZ_OK)
            {
                CCLOG("AssetsManagerEx : can not read compressed file info\n");
                unzClose(zipfile);
                return false;
            }
            const std::string fullPath = rootPath + fileName;
    
            // Check if this entry is a directory or a file.
            const size_t filenameLength = strlen(fileName);
            if (fileName[filenameLength-1] == '/')
            {
                //There are not directory entry in some case.
                //So we need to create directory when decompressing file entry
                if ( !_fileUtils->createDirectory(basename(fullPath)) )
                {
                    // Failed to create directory
                    CCLOG("AssetsManagerEx : can not create directory %s\n", fullPath.c_str());
                    unzClose(zipfile);
                    return false;
                }
            }
            else
            {
                // Create all directories in advance to avoid issue
                std::string dir = basename(fullPath);
                if (!_fileUtils->isDirectoryExist(dir)) {
                    if (!_fileUtils->createDirectory(dir)) {
                        // Failed to create directory
                        CCLOG("AssetsManagerEx : can not create directory %s\n", fullPath.c_str());
                        unzClose(zipfile);
                        return false;
                    }
                }
                // Entry is a file, so extract it.
                // Open current file.
                if (unzOpenCurrentFile(zipfile) != UNZ_OK)
                {
                    CCLOG("AssetsManagerEx : can not extract file %s\n", fileName);
                    unzClose(zipfile);
                    return false;
                }
    
                // Create a file to store current file.
                FILE *out = fopen(FileUtils::getInstance()->getSuitableFOpen(fullPath).c_str(), "wb");
                if (!out)
                {
                    CCLOG("AssetsManagerEx : can not create decompress destination file %s (errno: %d)\n", fullPath.c_str(), errno);
                    unzCloseCurrentFile(zipfile);
                    unzClose(zipfile);
                    return false;
                }
    
                // Write current file content to destinate file.
                int error = UNZ_OK;
                do
                {
                    error = unzReadCurrentFile(zipfile, readBuffer, BUFFER_SIZE);
                    if (error < 0)
                    {
                        CCLOG("AssetsManagerEx : can not read zip file %s, error code is %d\n", fileName, error);
                        fclose(out);
                        unzCloseCurrentFile(zipfile);
                        unzClose(zipfile);
                        return false;
                    }
    
                    if (error > 0)
                    {
                        fwrite(readBuffer, error, 1, out);
                    }
                } while(error > 0);
    
                fclose(out);
            }
    
            unzCloseCurrentFile(zipfile);
    
            // Goto next entry listed in the zip file.
            if ((i+1) < global_info.number_entry)
            {
                if (unzGoToNextFile(zipfile) != UNZ_OK)
                {
                    CCLOG("AssetsManagerEx : can not read next file for decompressing\n");
                    unzClose(zipfile);
                    return false;
                }
            }
        }
    
        unzClose(zipfile);
        return true;
    }
    
    void AssetsManagerEx::decompressDownloadedZip(const std::string &customId, const std::string &storagePath)
    {
        struct AsyncData
        {
            std::string customId;
            std::string zipFile;
            bool succeed;
        };
    
        AsyncData* asyncData = new AsyncData;
        asyncData->customId = customId;
        asyncData->zipFile = storagePath;
        asyncData->succeed = false;
    
        std::function<void(void*)> decompressFinished = [this](void* param) {
            auto dataInner = reinterpret_cast<AsyncData*>(param);
            if (dataInner->succeed)
            {
                fileSuccess(dataInner->customId, dataInner->zipFile);
            }
            else
            {
                std::string errorMsg = "Unable to decompress file " + dataInner->zipFile;
                // Ensure zip file deletion (if decompress failure cause task thread exit anormally)
                _fileUtils->removeFile(dataInner->zipFile);
                dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS, "", errorMsg);
                fileError(dataInner->customId, errorMsg);
            }
            delete dataInner;
        };
        AsyncTaskPool::getInstance()->enqueue(AsyncTaskPool::TaskType::TASK_OTHER, decompressFinished, (void*)asyncData, [this, asyncData]() {
            // Decompress all compressed files
            if (decompress(asyncData->zipFile))
            {
                asyncData->succeed = true;
            }
            _fileUtils->removeFile(asyncData->zipFile);
        });
    }
    
    void AssetsManagerEx::dispatchUpdateEvent(EventAssetsManagerEx::EventCode code, const std::string &assetId/* = ""*/, const std::string &message/* = ""*/, int curle_code/* = CURLE_OK*/, int curlm_code/* = CURLM_OK*/)
    {
        switch (code)
        {
            case EventAssetsManagerEx::EventCode::ERROR_UPDATING:
            case EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST:
            case EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST:
            case EventAssetsManagerEx::EventCode::ERROR_DECOMPRESS:
            case EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST:
            case EventAssetsManagerEx::EventCode::UPDATE_FAILED:
            case EventAssetsManagerEx::EventCode::UPDATE_FINISHED:
            case EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE:
                _updateEntry = UpdateEntry::NONE;
                break;
            case EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION:
                break;
            case EventAssetsManagerEx::EventCode::ASSET_UPDATED:
                break;
            case EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND:
                if (_updateEntry == UpdateEntry::CHECK_UPDATE)
                {
                    _updateEntry = UpdateEntry::NONE;
                }
                break;
            default:
                break;
        }
    
        if (_eventCallback != nullptr) {
            EventAssetsManagerEx* event = new (std::nothrow) EventAssetsManagerEx(_eventName, this, code, assetId, message, curle_code, curlm_code);
            _eventCallback(event);
            event->release();
        }
    }
    
    AssetsManagerEx::State AssetsManagerEx::getState() const
    {
        return _updateState;
    }
    
    void AssetsManagerEx::downloadVersion()
    {
        if (_updateState > State::PREDOWNLOAD_VERSION)
            return;
    
        std::string versionUrl = _localManifest->getVersionFileUrl();
    
        if (versionUrl.size() > 0)
        {
            _updateState = State::DOWNLOADING_VERSION;
            // Download version file asynchronously
            _downloader->createDownloadFileTask(versionUrl, _tempVersionPath, VERSION_ID);
        }
        // No version file found
        else
        {
            CCLOG("AssetsManagerEx : No version file found, step skipped\n");
            _updateState = State::PREDOWNLOAD_MANIFEST;
            downloadManifest();
        }
    }
    
    void AssetsManagerEx::parseVersion()
    {
        if (_updateState != State::VERSION_LOADED)
            return;
    	_remoteManifest->setHotUpdateUrl(_hotUpdateUrl);
        _remoteManifest->parseVersion(_tempVersionPath);
    
        if (!_remoteManifest->isVersionLoaded())
        {
            CCLOG("AssetsManagerEx : Fail to parse version file, step skipped\n");
            _updateState = State::PREDOWNLOAD_MANIFEST;
            downloadManifest();
        }
        else
        {
            if (_localManifest->versionGreaterOrEquals(_remoteManifest, _versionCompareHandle))
            {
                _updateState = State::UP_TO_DATE;
                _fileUtils->removeDirectory(_tempStoragePath);
                dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
            }
            else
            {
                _updateState = State::PREDOWNLOAD_MANIFEST;
                downloadManifest();
            }
        }
    }
    
    void AssetsManagerEx::downloadManifest()
    {
        if (_updateState != State::PREDOWNLOAD_MANIFEST)
            return;
    
        std::string manifestUrl = _localManifest->getManifestFileUrl();
    
        if (manifestUrl.size() > 0)
        {
            _updateState = State::DOWNLOADING_MANIFEST;
            // Download version file asynchronously
            _downloader->createDownloadFileTask(manifestUrl, _tempManifestPath, MANIFEST_ID);
        }
        // No manifest file found
        else
        {
            CCLOG("AssetsManagerEx : No manifest file found, check update failed\n");
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST);
            _updateState = State::UNCHECKED;
        }
    }
    
    void AssetsManagerEx::parseManifest()
    {
        if (_updateState != State::MANIFEST_LOADED)
            return;
    
    	_remoteManifest->setHotUpdateUrl(_hotUpdateUrl);
        _remoteManifest->parseFile(_tempManifestPath);
    
        if (!_remoteManifest->isLoaded())
        {
            CCLOG("AssetsManagerEx : Error parsing manifest file, %s", _tempManifestPath.c_str());
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_PARSE_MANIFEST);
            _updateState = State::UNCHECKED;
        }
        else
        {
            if (_localManifest->versionGreaterOrEquals(_remoteManifest, _versionCompareHandle))
            {
                _updateState = State::UP_TO_DATE;
                _fileUtils->removeDirectory(_tempStoragePath);
                dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
            }
            else
            {
                _updateState = State::NEED_UPDATE;
                
                if (_updateEntry == UpdateEntry::DO_UPDATE)
                {
                    startUpdate();
                }
                else if (_updateEntry == UpdateEntry::CHECK_UPDATE)
                {
                    prepareUpdate();
                }
                
                dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
            }
        }
    }
    
    void AssetsManagerEx::prepareUpdate()
    {
        if (_updateState != State::NEED_UPDATE)
            return;
    
        // Clean up before update
        _failedUnits.clear();
        _downloadUnits.clear();
        _totalWaitToDownload = _totalToDownload = 0;
        _nextSavePoint = 0;
        _percent = _percentByFile = _sizeCollected = _totalDownloaded = _totalSize = 0;
        _downloadResumed = false;
        _downloadedSize.clear();
        _totalEnabled = false;
    
        // Temporary manifest exists, previously updating and equals to the remote version, resuming previous download
        if (_tempManifest && _tempManifest->isLoaded() && _tempManifest->isUpdating() && _tempManifest->versionEquals(_remoteManifest))
        {
            _tempManifest->saveToFile(_tempManifestPath);
            _tempManifest->genResumeAssetsList(&_downloadUnits);
            _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
            _downloadResumed = true;
    
            // Collect total size
            for(auto iter : _downloadUnits)
            {
                const DownloadUnit& unit = iter.second;
                if (unit.size > 0)
                {
                    _totalSize += unit.size;
                }
            }
        }
        else
        {
            // Temporary manifest exists, but can't be parsed or version doesn't equals remote manifest (out of date)
            if (_tempManifest)
            {
                // Remove all temp files
                _fileUtils->removeDirectory(_tempStoragePath);
                CC_SAFE_RELEASE(_tempManifest);
                // Recreate temp storage path and save remote manifest
                _fileUtils->createDirectory(_tempStoragePath);
                _remoteManifest->saveToFile(_tempManifestPath);
            }
    
            // Temporary manifest will be used to register the download states of each asset,
            // in this case, it equals remote manifest.
            _tempManifest = _remoteManifest;
    
            // Check difference between local manifest and remote manifest
            std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest);
            if (diff_map.size() == 0)
            {
                updateSucceed();
                return;
            }
            else
            {
                // Generate download units for all assets that need to be updated or added
                std::string packageUrl = _remoteManifest->getPackageUrl();
                // Preprocessing local files in previous version and creating download folders
                for (auto it = diff_map.begin(); it != diff_map.end(); ++it)
                {
                    Manifest::AssetDiff diff = it->second;
                    if (diff.type != Manifest::DiffType::DELETED)
                    {
                        std::string path = diff.asset.path;
                        DownloadUnit unit;
                        unit.customId = it->first;
                        unit.srcUrl = packageUrl + path + "?md5=" + diff.asset.md5;
                        unit.storagePath = _tempStoragePath + path;
                        unit.size = diff.asset.size;
                        _downloadUnits.emplace(unit.customId, unit);
                        _tempManifest->setAssetDownloadState(it->first, Manifest::DownloadState::UNSTARTED);
                        _totalSize += unit.size;
                    }
                }
                // Start updating the temp manifest
                _tempManifest->setUpdating(true);
                // Save current download manifest information for resuming
                _tempManifest->saveToFile(_tempManifestPath);
    
                _totalWaitToDownload = _totalToDownload = (int)_downloadUnits.size();
            }
        }
        _updateState = State::READY_TO_UPDATE;
    }
    
    void AssetsManagerEx::startUpdate()
    {
        if (_updateState == State::NEED_UPDATE)
        {
            prepareUpdate();
        }
        if (_updateState == State::READY_TO_UPDATE)
        {
            _totalSize = 0;
            _updateState = State::UPDATING;
            std::string msg;
            if (_downloadResumed)
            {
                msg = StringUtils::format("Resuming from previous unfinished update, %d files remains to be finished.", _totalToDownload);
            }
            else
            {
                msg = StringUtils::format("Start to update %d files from remote package.", _totalToDownload);
            }
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "", msg);
            batchDownload();
        }
    }
    
    void AssetsManagerEx::updateSucceed()
    {
        // Set temp manifest's updating
        if (_tempManifest != nullptr) {
            _tempManifest->setUpdating(false);
        }
    
        // Every thing is correctly downloaded, do the following
        // 1. rename temporary manifest to valid manifest
    	if (this->_isUsingAssetsType) {
    		if (_fileUtils->isFileExist(_tempManifestPath)) {
    			_fileUtils->renameFile(_tempStoragePath, this->_assetsType + TEMP_MANIFEST_FILENAME, this->_assetsType + MANIFEST_FILENAME);
    		}
    	}else {
    		if (_fileUtils->isFileExist(_tempManifestPath)) {
    			_fileUtils->renameFile(_tempStoragePath, TEMP_MANIFEST_FILENAME, MANIFEST_FILENAME);
    		}
    	}
        
    
        // 2. Get the delete files
        std::unordered_map<std::string, Manifest::AssetDiff> diff_map = _localManifest->genDiff(_remoteManifest);
    
        // 3. merge temporary storage path to storage path so that temporary version turns to cached version
        if (_fileUtils->isDirectoryExist(_tempStoragePath))
        {
            // Merging all files in temp storage path to storage path
            std::vector<std::string> files;
            _fileUtils->listFilesRecursively(_tempStoragePath, &files);
            int baseOffset = (int)_tempStoragePath.length();
            std::string relativePath, dstPath;
            for (std::vector<std::string>::iterator it = files.begin(); it != files.end(); ++it)
            {
                relativePath.assign((*it).substr(baseOffset));
                dstPath.assign(_storagePath + relativePath);
                // Create directory
                if (relativePath.back() == '/')
                {
                    _fileUtils->createDirectory(dstPath);
                }
                // Copy file
                else
                {
                    if (_fileUtils->isFileExist(dstPath))
                    {
                        _fileUtils->removeFile(dstPath);
                    }
                    _fileUtils->renameFile(*it, dstPath);
                }
    
                // Remove from delete list for safe, although this is not the case in general.
                auto diff_itr = diff_map.find(relativePath);
                if (diff_itr != diff_map.end()) {
                    diff_map.erase(diff_itr);
                }
            }
    
            // Preprocessing local files in previous version and creating download folders
            for (auto it = diff_map.begin(); it != diff_map.end(); ++it)
            {
                Manifest::AssetDiff diff = it->second;
                if (diff.type == Manifest::DiffType::DELETED)
                {
                    // TODO: Do this when download finish, it don’t matter delete or not.
                    std::string exsitedPath = _storagePath + diff.asset.path;
                    _fileUtils->removeFile(exsitedPath);
                }
            }
        }
    
        // 4. swap the localManifest
        CC_SAFE_RELEASE(_localManifest);
        _localManifest = _remoteManifest;
        _localManifest->setManifestRoot(_storagePath);
        _remoteManifest = nullptr;
        // 5. make local manifest take effect
        prepareLocalManifest();
        // 6. Set update state
        _updateState = State::UP_TO_DATE;
        // 7. Notify finished event
        dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FINISHED);
        // 8. Remove temp storage path
        _fileUtils->removeDirectory(_tempStoragePath);
    }
    
    void AssetsManagerEx::checkUpdate()
    {
        if (_updateEntry != UpdateEntry::NONE)
        {
            CCLOGERROR("AssetsManagerEx::checkUpdate, updateEntry isn't NONE");
            return;
        }
    
        if (!_inited){
            CCLOG("AssetsManagerEx : Manifests uninited.\n");
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
            return;
        }
        if (!_localManifest->isLoaded())
        {
            CCLOG("AssetsManagerEx : No local manifest file found error.\n");
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
            return;
        }
    
        _updateEntry = UpdateEntry::CHECK_UPDATE;
    
        switch (_updateState) {
            case State::FAIL_TO_UPDATE:
                _updateState = State::UNCHECKED;
            case State::UNCHECKED:
            case State::PREDOWNLOAD_VERSION:
            {
                downloadVersion();
            }
                break;
            case State::UP_TO_DATE:
            {
                dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ALREADY_UP_TO_DATE);
            }
                break;
            case State::NEED_UPDATE:
            {
                dispatchUpdateEvent(EventAssetsManagerEx::EventCode::NEW_VERSION_FOUND);
            }
                break;
            default:
                break;
        }
    }
    
    void AssetsManagerEx::update()
    {
        if (_updateEntry != UpdateEntry::NONE)
        {
            CCLOGERROR("AssetsManagerEx::update, updateEntry isn't NONE");
            return;
        }
    
        if (!_inited){
            CCLOG("AssetsManagerEx : Manifests uninited.\n");
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
            return;
        }
        if (!_localManifest->isLoaded())
        {
            CCLOG("AssetsManagerEx : No local manifest file found error.\n");
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
            return;
        }
    
        _updateEntry = UpdateEntry::DO_UPDATE;
    
        switch (_updateState) {
            case State::UNCHECKED:
            {
                _updateState = State::PREDOWNLOAD_VERSION;
            }
            case State::PREDOWNLOAD_VERSION:
            {
                downloadVersion();
            }
                break;
            case State::VERSION_LOADED:
            {
                parseVersion();
            }
                break;
            case State::PREDOWNLOAD_MANIFEST:
            {
                downloadManifest();
            }
                break;
            case State::MANIFEST_LOADED:
            {
                parseManifest();
            }
                break;
            case State::FAIL_TO_UPDATE:
            case State::READY_TO_UPDATE:
            case State::NEED_UPDATE:
            {
                // Manifest not loaded yet
                if (!_remoteManifest->isLoaded())
                {
                    _updateState = State::PREDOWNLOAD_MANIFEST;
                    downloadManifest();
                }
                else if (_updateEntry == UpdateEntry::DO_UPDATE)
                {
                    startUpdate();
                }
            }
                break;
            case State::UP_TO_DATE:
            case State::UPDATING:
            case State::UNZIPPING:
                _updateEntry = UpdateEntry::NONE;
                break;
            default:
                break;
        }
    }
    
    void AssetsManagerEx::updateAssets(const DownloadUnits& assets)
    {
        if (!_inited){
            CCLOG("AssetsManagerEx : Manifests uninited.\n");
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_NO_LOCAL_MANIFEST);
            return;
        }
    
        if (_updateState != State::UPDATING && _localManifest->isLoaded() && _remoteManifest->isLoaded())
        {
            _updateState = State::UPDATING;
            _downloadUnits.clear();
            _downloadedSize.clear();
            _percent = _percentByFile = _sizeCollected = _totalDownloaded = _totalSize = 0;
            _totalWaitToDownload = _totalToDownload = (int)assets.size();
            _nextSavePoint = 0;
            _totalEnabled = false;
            if (_totalToDownload > 0)
            {
                _downloadUnits = assets;
                this->batchDownload();
            }
            else if (_totalToDownload == 0)
            {
                onDownloadUnitsFinished();
            }
        }
    }
    
    const DownloadUnits& AssetsManagerEx::getFailedAssets() const
    {
        return _failedUnits;
    }
    
    void AssetsManagerEx::downloadFailedAssets()
    {
        CCLOG("AssetsManagerEx : Start update %lu failed assets.\n", static_cast<unsigned long>(_failedUnits.size()));
        updateAssets(_failedUnits);
    }
    
    void AssetsManagerEx::fileError(const std::string& identifier, const std::string& errorStr, int errorCode, int errorCodeInternal)
    {
        auto unitIt = _downloadUnits.find(identifier);
        // Found unit and add it to failed units
        if (unitIt != _downloadUnits.end())
        {
            _totalWaitToDownload--;
    
            DownloadUnit unit = unitIt->second;
            _failedUnits.emplace(unit.customId, unit);
        }
        dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_UPDATING, identifier, errorStr, errorCode, errorCodeInternal);
        _tempManifest->setAssetDownloadState(identifier, Manifest::DownloadState::UNSTARTED);
    
        _currConcurrentTask = std::max(0, _currConcurrentTask-1);
        queueDowload();
    }
    
    void AssetsManagerEx::fileSuccess(const std::string &customId, const std::string &storagePath)
    {
        // Set download state to SUCCESSED
        _tempManifest->setAssetDownloadState(customId, Manifest::DownloadState::SUCCESSED);
    
        auto unitIt = _failedUnits.find(customId);
        // Found unit and delete it
        if (unitIt != _failedUnits.end())
        {
            // Remove from failed units list
            _failedUnits.erase(unitIt);
        }
    
        unitIt = _downloadUnits.find(customId);
        if (unitIt != _downloadUnits.end())
        {
            // Reduce count only when unit found in _downloadUnits
            _totalWaitToDownload--;
    
            _percentByFile = 100 * (float)(_totalToDownload - _totalWaitToDownload) / _totalToDownload;
            // Notify progression event
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, "");
        }
        // Notify asset updated event
        dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ASSET_UPDATED, customId);
    
        _currConcurrentTask = std::max(0, _currConcurrentTask-1);
        queueDowload();
    }
    
    void AssetsManagerEx::onError(const network::DownloadTask& task,
                                  int errorCode,
                                  int errorCodeInternal,
                                  const std::string& errorStr)
    {
        // Skip version error occurred
        if (task.identifier == VERSION_ID)
        {
            CCLOG("AssetsManagerEx : Fail to download version file, step skipped\n");
            _updateState = State::PREDOWNLOAD_MANIFEST;
            downloadManifest();
        }
        else if (task.identifier == MANIFEST_ID)
        {
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::ERROR_DOWNLOAD_MANIFEST, task.identifier, errorStr, errorCode, errorCodeInternal);
            _updateState = State::FAIL_TO_UPDATE;
        }
        else
        {
            if (_downloadingTask.find(task.identifier) != _downloadingTask.end()) {
                _downloadingTask.erase(task.identifier);
            }
            fileError(task.identifier, errorStr, errorCode, errorCodeInternal);
        }
    }
    
    void AssetsManagerEx::onProgress(double total, double downloaded, const std::string& /*url*/, const std::string &customId)
    {
        if (customId == VERSION_ID || customId == MANIFEST_ID)
        {
            _percent = 100 * downloaded / total;
            // Notify progression event
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, customId);
            return;
        }
        else
        {
            // Calcul total downloaded
            bool found = false;
            _totalDownloaded = 0;
            for (auto it = _downloadedSize.begin(); it != _downloadedSize.end(); ++it)
            {
                if (it->first == customId)
                {
                    it->second = downloaded;
                    found = true;
                }
                _totalDownloaded += it->second;
            }
            // Collect information if not registed
            if (!found)
            {
                // Set download state to DOWNLOADING, this will run only once in the download process
                _tempManifest->setAssetDownloadState(customId, Manifest::DownloadState::DOWNLOADING);
                // Register the download size information
                _downloadedSize.emplace(customId, downloaded);
                // Check download unit size existance, if not exist collect size in total size
                if (_downloadUnits[customId].size == 0)
                {
                    _totalSize += total;
                    _sizeCollected++;
                    // All collected, enable total size
                    if (_sizeCollected == _totalToDownload)
                    {
                        _totalEnabled = true;
                    }
                }
            }
    
            if (_totalEnabled && _updateState == State::UPDATING)
            {
                float currentPercent = 100 * _totalDownloaded / _totalSize;
                // Notify at integer level change
                if ((int)currentPercent != (int)_percent) {
                    _percent = currentPercent;
                    // Notify progression event
                    dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_PROGRESSION, customId);
                }
            }
        }
    }
    
    void AssetsManagerEx::onSuccess(const std::string &/*srcUrl*/, const std::string &storagePath, const std::string &customId)
    {
        if (customId == VERSION_ID)
        {
            _updateState = State::VERSION_LOADED;
            parseVersion();
        }
        else if (customId == MANIFEST_ID)
        {
            _updateState = State::MANIFEST_LOADED;
            parseManifest();
        }
        else
        {
            if (_downloadingTask.find(customId) != _downloadingTask.end()) {
                _downloadingTask.erase(customId);
            }
    
            bool ok = true;
            auto &assets = _remoteManifest->getAssets();
            auto assetIt = assets.find(customId);
            if (assetIt != assets.end())
            {
                Manifest::Asset asset = assetIt->second;
                if (_verifyCallback != nullptr)
                {
                    ok = _verifyCallback(storagePath, asset);
                } else{
    
                    ok =onVerifyDefault( storagePath,asset);
                }
            }
    
            if (ok)
            {
                bool compressed = assetIt != assets.end() ? assetIt->second.compressed : false;
                if (compressed)
                {
                    decompressDownloadedZip(customId, storagePath);
                }
                else
                {
                    fileSuccess(customId, storagePath);
                }
            }
            else
            {
                fileError(customId, "Asset file verification failed after downloaded");
            }
        }
    }
    
    
    bool AssetsManagerEx::onVerifyDefault(const std::string storagePath,Manifest::Asset asset)
    {
        //cocos2d::log("onVerifyDefault 0");
        Data data = cocos2d::FileUtils::getInstance()->getDataFromFile(storagePath);
        if (data.isNull() ||(data.getSize()== 0 )){
            CCLOG("onVerifyDefault 1");
            return false;
        }
    
        std::string result = md5(data.getBytes(), data.getSize());
        //cocos2d::log("onVerifyDefault:%s - assetmd5:%s-resultmd5:%s",storagePath.c_str(),asset.md5.c_str(),result.c_str());
        if (memcmp(result.c_str(), asset.md5.c_str(), result.length()) == 0){
            CCLOG("onVerifyDefault 2");
            return  true;
        }
    
       // cocos2d::log("onVerifyDefault 3");
        return false;
    }
    
    
    
    void AssetsManagerEx::destroyDownloadedVersion()
    {
        _fileUtils->removeDirectory(_storagePath);
        _fileUtils->removeDirectory(_tempStoragePath);
    }
    
    void AssetsManagerEx::batchDownload()
    {
        _queue.clear();
        for(auto iter : _downloadUnits)
        {
            const DownloadUnit& unit = iter.second;
            if (unit.size > 0)
            {
                _totalSize += unit.size;
                _sizeCollected++;
            }
    
            _queue.push_back(iter.first);
        }
        // All collected, enable total size
        if (_sizeCollected == _totalToDownload)
        {
            _totalEnabled = true;
        }
    
        queueDowload();
    }
    
    void AssetsManagerEx::queueDowload()
    {
        if (_totalWaitToDownload == 0 || (_canceled && _currConcurrentTask == 0))
        {
            this->onDownloadUnitsFinished();
            return;
        }
    
        while (_currConcurrentTask < _maxConcurrentTask && _queue.size() > 0 && !_canceled)
        {
            std::string key = _queue.back();
            _queue.pop_back();
    
            _currConcurrentTask++;
            DownloadUnit& unit = _downloadUnits[key];
            _fileUtils->createDirectory(basename(unit.storagePath));
            auto downloadTask = _downloader->createDownloadFileTask(unit.srcUrl, unit.storagePath, unit.customId);
            _downloadingTask.emplace(unit.customId, downloadTask);
            _tempManifest->setAssetDownloadState(key, Manifest::DownloadState::DOWNLOADING);
        }
        if (_percentByFile / 100 > _nextSavePoint)
        {
            // Save current download manifest information for resuming
            _tempManifest->saveToFile(_tempManifestPath);
            _nextSavePoint += SAVE_POINT_INTERVAL;
        }
    }
    
    void AssetsManagerEx::onDownloadUnitsFinished()
    {
        // Always save current download manifest information for resuming
        _tempManifest->saveToFile(_tempManifestPath);
        
        // Finished with error check
        if (_failedUnits.size() > 0)
        {
            _updateState = State::FAIL_TO_UPDATE;
            dispatchUpdateEvent(EventAssetsManagerEx::EventCode::UPDATE_FAILED);
        }
        else if (_updateState == State::UPDATING)
        {
            updateSucceed();
        }
    }
    
    void AssetsManagerEx::cancelUpdate()
    {
        if (_canceled)
    	{
            return;
        }
        _canceled = true;
        std::vector<std::shared_ptr<const network::DownloadTask>> tasks;
        for (const auto& it : _downloadingTask)
        {
            tasks.push_back(it.second);
        }
        for (const auto& it : tasks)
        {
            _downloader->abort(*it);
        }
        _downloadingTask.clear();
    }
    
    NS_CC_EXT_END
    
    
    展开全文
  • MD5文件比对神器

    2016-05-24 23:16:55
    windows下用md5比对文件内容
  • 碰撞出你指定位置是指定字符的md5
  • 易语言程序MD5监控

    2020-07-21 18:58:45
    易语言程序MD5监控源码,程序MD5监控,子程序_取程序名,子程序_列表框加入项目,子程序_初始化,子程序_MD5校检,新进程接口,DLL_取模块文件名
  • md5校验码生成工具软件免安装,md5校验码对比工具软件,免安装,解压缩后可直接使用,程序员必备小工具。
  • Linux下批量校验文件md5值(find+diff)

    千次阅读 2021-05-13 03:24:02
    为了安全需要,第一次部署完linux之后,生成...这样的话,在怀疑被入侵的时候可以批量对比文件md5值,看是否被恶意修改过。1、生成某个目录文件的md5值,以/sbin为例find /sbin -type f | xargs md5sum > sbin.md...
  • 亲测可用,无毒,大家可以下,东西很不错,二十个字!

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 67,280
精华内容 26,912
关键字:

怎么对比md5