`cocos2dx非完整` 添加xxtea加密模塊


在上一篇文章中,我已經開始着手寫自己的模塊,也就是fw部分.其中上一篇文章中完成的是lua部分的配置解析部分,涉及一點點平台方面的封裝.這一片文章我來說明一下我是如何處理cocos2dx資源加密的.首先需要說明白的是,資源是什么?資源分為哪幾類?

在選擇使用lua腳本開發后,包括lua文件,游戲美術資源,游戲的配置,我都統稱為游戲資源,所以我期望的加密是能夠加密所有這些東西.quick提供了xxtea,而cocos2dx也在luastack中整合了xxtea,我稍微做了一些修改.主要的修改思路是:首先要知道lua文件,游戲資源文件的加載入口在哪里.也許很多人聽到我這么說會覺得很怪,不過這確實是解決這個問題的根本出發點.只要找到了加載入口才能做出合適的解決方案.

通過查看源碼,我發現lua_loader加載lua文件的入口其實就是fileutils中的接口,然后使用vs的debug,又定位到fileutils中的文件Io讀取接口.這樣子就知道我們需要手動操作的接口了。我們就看其中一個接口就好了.

CCFileUtils-win32.cpp

 1 static Data getData(const std::string& filename, bool forString)
 2 {
 3     if (filename.empty())
 4     {
 5         return Data::Null;
 6     }
 7 
 8     unsigned char *buffer = nullptr;
 9 
10     size_t size = 0;
11     do
12     {
13         // read the file from hardware
14         std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filename);
15 
16         WCHAR wszBuf[CC_MAX_PATH] = {0};
17         MultiByteToWideChar(CP_UTF8, 0, fullPath.c_str(), -1, wszBuf, sizeof(wszBuf)/sizeof(wszBuf[0]));
18 
19         HANDLE fileHandle = ::CreateFileW(wszBuf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, nullptr);
20         CC_BREAK_IF(fileHandle == INVALID_HANDLE_VALUE);
21         
22         size = ::GetFileSize(fileHandle, nullptr);
23 
24         if (forString)
25         {
26             buffer = (unsigned char*) malloc(size + 1);
27             buffer[size] = '\0';
28         }
29         else
30         {
31             buffer = (unsigned char*) malloc(size);
32         }
33         DWORD sizeRead = 0;
34         BOOL successed = FALSE;
35         successed = ::ReadFile(fileHandle, buffer, size, &sizeRead, nullptr);
36         ::CloseHandle(fileHandle);
37 
38         if (!successed)
39         {
40             free(buffer);
41             buffer = nullptr;
42         }
43     } while (0);
44     
45     Data ret;
46 
47     if (buffer == nullptr || size == 0)
48     {
49         std::string msg = "Get data from file(";
50         // Gets error code.
51         DWORD errorCode = ::GetLastError();
52         char errorCodeBuffer[20] = {0};
53         snprintf(errorCodeBuffer, sizeof(errorCodeBuffer), "%d", errorCode);
54 
55         msg = msg + filename + ") failed, error code is " + errorCodeBuffer;
56         CCLOG("%s", msg.c_str());
57     }
58     else
59     { 
60         unsigned long len = 0;
61         unsigned char* retbuf = FWResEncrypt::getInstance()->decryptData(buffer, size, &len);
62         //ret.fastSet(buffer, size);
63         ret.fastSet(retbuf, len);
64     }
65     return ret;
66 }

 

如果讀取文件成功的話,在62行中buffer保存的就是從文件讀取的字符流. 所以如果資源文件是被加密的,那么我們只需要在這個時候進行相關的解密操作然后調用ret.fastSet接口傳入解密后的字符就行了。也就是上面我修改的那幾句代碼,請具體參考源碼文件對比.好了,知道這么做以后我們就去看一下xxtea的操作方式.xxtea是在external提供過得第三方擴展,其實這是一個比較舊的版本,不過引擎自帶的,我也懶得去添加新的了.看下面我從CCLuaStack.cpp中截取的部分代碼,觀察一下xxtea加密接口的使用.

 1 int LuaStack::luaLoadBuffer(lua_State *L, const char *chunk, int chunkSize, const char *chunkName)
 2 {
 3     int r = 0;
 4     
 5     if (_xxteaEnabled && strncmp(chunk, _xxteaSign, _xxteaSignLen) == 0)
 6     {
 7         // decrypt XXTEA
 8         xxtea_long len = 0;
 9         unsigned char* result = xxtea_decrypt((unsigned char*)chunk + _xxteaSignLen,
10                                               (xxtea_long)chunkSize - _xxteaSignLen,
11                                               (unsigned char*)_xxteaKey,
12                                               (xxtea_long)_xxteaKeyLen,
13                                               &len);
14         r = luaL_loadbuffer(L, (char*)result, len, chunkName);
15         free(result);
16     }
17     else
18     {
19         r = luaL_loadbuffer(L, chunk, chunkSize, chunkName);
20     }

 

然后繼續觀察其他部分的使用,如xxtea簽名的設置:

 1 void LuaStack::setXXTEAKeyAndSign(const char *key, int keyLen, const char *sign, int signLen)
 2 {
 3     cleanupXXTEAKeyAndSign();
 4     
 5     if (key && keyLen && sign && signLen)
 6     {
 7         _xxteaKey = (char*)malloc(keyLen);
 8         memcpy(_xxteaKey, key, keyLen);
 9         _xxteaKeyLen = keyLen;
10         
11         _xxteaSign = (char*)malloc(signLen);
12         memcpy(_xxteaSign, sign, signLen);
13         _xxteaSignLen = signLen;
14         
15         _xxteaEnabled = true;
16     }
17     else
18     {
19         _xxteaEnabled = false;
20     }
21 }
22 
23 void LuaStack::cleanupXXTEAKeyAndSign()
24 {
25     if (_xxteaKey)
26     {
27         free(_xxteaKey);
28         _xxteaKey = nullptr;
29         _xxteaKeyLen = 0;
30     }
31     if (_xxteaSign)
32     {
33         free(_xxteaSign);
34         _xxteaSign = nullptr;
35         _xxteaSignLen = 0;
36     }
37 }

 

好了,有了這些作為基礎,我們可以動手寫自己的加密管理類了。為什么說要另外寫,很多人第一反應可能是在引擎中添加更方便.不可那么做,第一,不應該隨便修改引擎核心部分的源碼,除非迫不得已.第二,我們這邊的情況確實不應該在libluacocos2dx vs項目中去做.因為libluacocos2dx對libcocos2dx是依賴關系,不應該前后倒置。所以第一步是用VS打開項目解決方案.然后在libcocos2dx extern篩選器下面再添加一個刪選器,命名為xxtea,然后加入cocos2dx/extern/xxtea下面的xxtea第三方依賴源碼.第二步,由於fileutils涉及到跨平台部分,所以我們應該提供一個加密操作類,放在cocos/platform下面是我認為比較合適的位置.所以我添加了如下的源碼:

 1 #ifndef __firework_ResEncrypt__
 2 #define __firework_ResEncrypt__
 3 
 4 #include "platform/CCPlatformMacros.h"
 5 
 6 class CC_DLL FWResEncrypt
 7 {
 8 public:
 9     static FWResEncrypt* getInstance();
10 
11 public:
12     unsigned char* decryptData(unsigned char* buf, unsigned long size, unsigned long *pSize);
13     unsigned char* getFileData(const char* fileName, const char* mode, unsigned long *pSize);
14     unsigned char* encryptData(unsigned char* buf, unsigned long size, unsigned long *pSize);
15     void setXXTeaKeyAndSign(const char* xxteaKey, int xxteaKeyLen, const char* xxteaSign, int xxteaSignLen);
16     void cleanupXXTeaKeyAndSign();
17 private:
18     static FWResEncrypt* pFWResEncrypt_;
19 
20     bool xxteaEnabled_;
21     char* xxteaKey_;
22     int xxteaKeyLen_;
23     char* xxteaSign_;
24     int xxteaSignLen_;
25 private:
26     FWResEncrypt();
27     FWResEncrypt(const FWResEncrypt&);
28     FWResEncrypt& operator = (const FWResEncrypt&);
29 };
30 
31 #endif

 

#include "FWResEncrypt.h"
#include "cocos2d.h"
#include "CCFileUtils.h"
#include "xxtea/xxtea.h"

FWResEncrypt* FWResEncrypt::pFWResEncrypt_ = nullptr;

FWResEncrypt* FWResEncrypt::getInstance()
{
    if(!pFWResEncrypt_) 
    {
        pFWResEncrypt_ = new FWResEncrypt();
    }
    return pFWResEncrypt_;
}

FWResEncrypt::FWResEncrypt()
    :xxteaEnabled_(false)
    ,xxteaKey_(nullptr)
    ,xxteaKeyLen_(0)
    ,xxteaSign_(nullptr)
    ,xxteaSignLen_(0)
{

}

void FWResEncrypt::setXXTeaKeyAndSign(const char* xxteaKey, int xxteaKeyLen, const char* xxteaSign, int xxteaSignLen)
{
    cleanupXXTeaKeyAndSign();

    if( xxteaKey && xxteaKeyLen && xxteaSign && xxteaSignLen) 
    {
        xxteaKey_ = (char*)malloc(xxteaKeyLen);
        memcpy(xxteaKey_, xxteaKey, xxteaKeyLen);
        xxteaKeyLen_ = xxteaKeyLen;

        xxteaSign_ = (char*)malloc(xxteaSignLen);
        memcpy(xxteaSign_, xxteaSign, xxteaSignLen);
        xxteaSignLen_ = xxteaSignLen;

        xxteaEnabled_ = true;
    } else
    {
        xxteaEnabled_ = false;
    }
}

void FWResEncrypt::cleanupXXTeaKeyAndSign()
{
    if(xxteaKey_)
    {
        free(xxteaKey_);
        xxteaKey_ = nullptr;
        xxteaKeyLen_ = 0;
    }
    if(xxteaSign_)
    {
        free(xxteaSign_);
        xxteaSign_ = nullptr;
        xxteaSignLen_ = 0;
    }
}

unsigned char* FWResEncrypt::getFileData(const char* fileName, const char* mode, unsigned long* pSize)
{
    ssize_t size;
    unsigned char* buf = cocos2d::FileUtils::getInstance()->getFileData(fileName, mode, &size);
    if(nullptr == buf)
    {
        return nullptr;
    }

    unsigned char* buffer = nullptr;
    FWResEncrypt* pFWResEncrypt = FWResEncrypt::getInstance();

    bool isXXTEA = pFWResEncrypt && pFWResEncrypt->xxteaEnabled_;

    for(unsigned int i = 0; isXXTEA && i < pFWResEncrypt->xxteaSignLen_ && i < size; ++ i )
    {
        isXXTEA = buf[i] == pFWResEncrypt->xxteaSign_[i];
    }

    if(isXXTEA)
    {
        xxtea_long len = 0;
        buffer = xxtea_decrypt(    buf+pFWResEncrypt->xxteaSignLen_,
            (xxtea_long)size - (xxtea_long)pFWResEncrypt->xxteaSignLen_,
            (unsigned char*)pFWResEncrypt->xxteaKey_,
            (xxtea_long)pFWResEncrypt->xxteaKeyLen_, &len);
        delete [] buf;
        buf = nullptr;
        size = len;
    } else 
    {
        buffer = buf;
    }

    if(pSize)
    {
        *pSize = size;
    }
    return buffer;
}

unsigned char *FWResEncrypt::decryptData(unsigned char* buf, unsigned long size, unsigned long* pSize)
{
    CCAssert(buf != nullptr, "decryptData buf cannot nullptr");

    unsigned char* buffer = nullptr;
    FWResEncrypt* pFWResEncrypt = FWResEncrypt::getInstance();
    bool isXXTEA = pFWResEncrypt && pFWResEncrypt->xxteaEnabled_;

    for(unsigned int i = 0; isXXTEA && i < pFWResEncrypt->xxteaSignLen_ && i < size; ++ i )
    {
        isXXTEA = buf[i] == pFWResEncrypt->xxteaSign_[i];
    }

    if(isXXTEA)
    {
        xxtea_long len = 0;
        buffer = xxtea_decrypt(    buf+pFWResEncrypt->xxteaSignLen_,
            (xxtea_long)size - (xxtea_long)pFWResEncrypt->xxteaSignLen_,
            (unsigned char*)pFWResEncrypt->xxteaKey_,
            (xxtea_long)pFWResEncrypt->xxteaKeyLen_, &len);
        delete [] buf;
        buf = nullptr;
        size = len;
    } else
    {
        buffer = buf;
    }
    if(pSize)
    {
        *pSize = size;
    }
    return buffer;
}

unsigned char* FWResEncrypt::encryptData(unsigned char* buf, unsigned long size, unsigned long* pSize)
{
    CCAssert(buf != nullptr, "encryptData buf cannot nullptr");
    unsigned char* buffer = nullptr;
    unsigned char* ret = nullptr;
    FWResEncrypt* pFWResEncrypt = FWResEncrypt::getInstance();
    bool isXXTEA = pFWResEncrypt && pFWResEncrypt->xxteaEnabled_;
    for(unsigned int i = 0; isXXTEA && i < pFWResEncrypt->xxteaSignLen_ && i < size; ++ i )
    {
        isXXTEA = buf[i] == pFWResEncrypt->xxteaSign_[i];
    }
    if(!isXXTEA)
    {
        xxtea_long len = 0;
        buffer = xxtea_encrypt(    buf,
            (xxtea_long)size,
            (unsigned char*)pFWResEncrypt->xxteaKey_,
            (xxtea_long)pFWResEncrypt->xxteaKeyLen_, &len);
        delete [] buf;
        buf = nullptr;
        size = len;
        ret = (unsigned char*)malloc(size+pFWResEncrypt->xxteaSignLen_+1);
        memcpy(ret, pFWResEncrypt->xxteaSign_, pFWResEncrypt->xxteaSignLen_);
        memcpy(ret+pFWResEncrypt->xxteaSignLen_, buffer, size);
        ret[len+pFWResEncrypt->xxteaSignLen_] = '\0';
    } else
    {
        ret = buf;
    }
    if(pSize)
    {
        *pSize = size+pFWResEncrypt->xxteaSignLen_;
    }
    return ret;
}

 

其中設置簽名,清除簽名那些方法我都是直接從CCLuaStack中拿過來的,加密接口也可以直接從那邊改一下就好了,最主要的是decryptData這個接口,也就是解密接口. 我發現xxtea提供的sign的功能就是用來同時解析加密和非加密文件,也就是直接加載文件頭.如果我的Sign是FW的話,那么我會發現我加密后文件頭就有FW.所以加密接口實現的思路是使用xxtea加密,得到加密后的字符串,再做字符串操作,將Sign拼接到加密字符串前面,也就是生成一個新的字符串,再寫入文件流就行了.好了,下面我給出我綁定接口到lua的源碼:

 1 #include "lua_fw_encrypt.h"
 2 #if __cplusplus
 3 extern "C" {
 4 #endif
 5 #include <lualib.h>
 6 #include <lauxlib.h>
 7 #if __cplusplus
 8 }
 9 #endif
10 
11 #include <string>
12 #include "FWResEncrypt.h"
13 #include "cocos2d.h"
14 int
15 lua_fw_encrypt_encryptData(lua_State* lua_state)
16 {
17     std::string data = lua_tostring(lua_state, 1);
18     unsigned char* encryptData = (unsigned char*)malloc(data.size());
19     memcpy(encryptData, data.c_str(), data.size());
20     unsigned long len = 0;
21     unsigned char* encryptedData = FWResEncrypt::getInstance()->encryptData(encryptData, data.size(), &len);
22     lua_pushlstring(lua_state, (char*)encryptedData, len);
23     return 1;
24 }
25 int
26 lua_fw_encrypt_decryptData(lua_State* lua_state)
27 {
28     size_t len = 0;
29     const char *data = lua_tolstring(lua_state, 1,&len);
30     unsigned char* decryptData = (unsigned char*)malloc(len);
31     memcpy(decryptData, data, len);
32     unsigned char* decryptedData = FWResEncrypt::getInstance()->decryptData(decryptData, len, nullptr);
33     lua_pushstring(lua_state, (char*)decryptedData);
34     return 1;
35 }
36 
37 namespace fw {
38     const luaL_Reg
39     g_fw_encrypt_funcs[] = {
40         {"encrypt_data", lua_fw_encrypt_encryptData},
41         {"decrypt_data", lua_fw_encrypt_decryptData},
42         {nullptr,nullptr},
43     };
44 
45     void 
46     register_fw_encrypt(lua_State* lua_state) {
47         luaL_register(lua_state, "fw.encrypt", g_fw_encrypt_funcs);
48     }
49 }

 

我並不喜歡cocos2dx使用的tolua++的方式綁定接口,會生成太多冗余的代碼,而是采用傳統的C方式去做這件事情,這里面注意lua_pushlstring的使用,為什么要用這個接口?而不是直接使用lua_pushstring.這個問題可能是因為引擎綁定的lua源碼中做了一些修改(我是這樣推測的),因為使用lua_pushstring錯誤,應該是不能正確獲取指針指向的字符長度.改用lua_pushlstring傳入長度len就可以解決這個問題了.

下面也是我在lua那邊fw模塊做了一下簡單的包裝,非常的簡單.這么做的目的就是能夠讓使用lua的人不關心c++部分的實現,不會覺得這個接口出現的莫名其妙.

1 --小岩<757011285@qq.com>
2 --2015-5-26 16:45
3 return 
4 {
5      encrypt = fw.encrypt.encrypt_data,
6      decrypt = fw.encrypt.decrypt_data,    
7 }

 

好了,有了這個加解密的接口,我們就可以在配置文件讀取的那部分做一下修改,在持久化和讀取的時候就可以正確讀取了.如果是windows需要修改platform下面ccFileutils-win32.cpp中的接口,如果是android則對用修改ccFileutils-android.cpp中的接口.我給一下源碼:(android同樣):

  1 /****************************************************************************
  2 Copyright (c) 2010-2012 cocos2d-x.org
  3 Copyright (c) 2013-2014 Chukong Technologies Inc.
  4 
  5 http://www.cocos2d-x.org
  6 
  7 Permission is hereby granted, free of charge, to any person obtaining a copy
  8 of this software and associated documentation files (the "Software"), to deal
  9 in the Software without restriction, including without limitation the rights
 10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11 copies of the Software, and to permit persons to whom the Software is
 12 furnished to do so, subject to the following conditions:
 13 
 14 The above copyright notice and this permission notice shall be included in
 15 all copies or substantial portions of the Software.
 16 
 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23 THE SOFTWARE.
 24 ****************************************************************************/
 25 
 26 #include "platform/CCPlatformConfig.h"
 27 #if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
 28 
 29 #include "CCFileUtils-win32.h"
 30 #include "platform/CCCommon.h"
 31 #include <Shlobj.h>
 32 #include "FWResEncrypt.h"
 33 using namespace std;
 34 
 35 NS_CC_BEGIN
 36 
 37 #define CC_MAX_PATH  512
 38 
 39 // The root path of resources, the character encoding is UTF-8.
 40 // UTF-8 is the only encoding supported by cocos2d-x API.
 41 static std::string s_resourcePath = "";
 42 
 43 // D:\aaa\bbb\ccc\ddd\abc.txt --> D:/aaa/bbb/ccc/ddd/abc.txt
 44 static inline std::string convertPathFormatToUnixStyle(const std::string& path)
 45 {
 46     std::string ret = path;
 47     int len = ret.length();
 48     for (int i = 0; i < len; ++i)
 49     {
 50         if (ret[i] == '\\')
 51         {
 52             ret[i] = '/';
 53         }
 54     }
 55     return ret;
 56 }
 57 
 58 static void _checkPath()
 59 {
 60     if (0 == s_resourcePath.length())
 61     {
 62         WCHAR utf16Path[CC_MAX_PATH] = {0};
 63         GetCurrentDirectoryW(sizeof(utf16Path)-1, utf16Path);
 64         
 65         char utf8Path[CC_MAX_PATH] = {0};
 66         int nNum = WideCharToMultiByte(CP_UTF8, 0, utf16Path, -1, utf8Path, sizeof(utf8Path), nullptr, nullptr);
 67 
 68         s_resourcePath = convertPathFormatToUnixStyle(utf8Path);
 69         s_resourcePath.append("/");
 70     }
 71 }
 72 
 73 FileUtils* FileUtils::getInstance()
 74 {
 75     if (s_sharedFileUtils == nullptr)
 76     {
 77         s_sharedFileUtils = new FileUtilsWin32();
 78         if(!s_sharedFileUtils->init())
 79         {
 80           delete s_sharedFileUtils;
 81           s_sharedFileUtils = nullptr;
 82           CCLOG("ERROR: Could not init CCFileUtilsWin32");
 83         }
 84     }
 85     return s_sharedFileUtils;
 86 }
 87 
 88 FileUtilsWin32::FileUtilsWin32()
 89 {
 90 }
 91 
 92 bool FileUtilsWin32::init()
 93 {
 94     _checkPath();
 95     _defaultResRootPath = s_resourcePath;
 96     return FileUtils::init();
 97 }
 98 
 99 bool FileUtilsWin32::isFileExistInternal(const std::string& strFilePath) const
100 {
101     if (0 == strFilePath.length())
102     {
103         return false;
104     }
105     
106     std::string strPath = strFilePath;
107     if (!isAbsolutePath(strPath))
108     { // Not absolute path, add the default root path at the beginning.
109         strPath.insert(0, _defaultResRootPath);
110     }
111 
112     WCHAR utf16Buf[CC_MAX_PATH] = {0};
113     MultiByteToWideChar(CP_UTF8, 0, strPath.c_str(), -1, utf16Buf, sizeof(utf16Buf)/sizeof(utf16Buf[0]));
114 
115     DWORD attr = GetFileAttributesW(utf16Buf);
116     if(attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY))
117         return false;   //  not a file
118     return true;
119 }
120 
121 bool FileUtilsWin32::isAbsolutePath(const std::string& strPath) const
122 {
123     if (   strPath.length() > 2 
124         && ( (strPath[0] >= 'a' && strPath[0] <= 'z') || (strPath[0] >= 'A' && strPath[0] <= 'Z') )
125         && strPath[1] == ':')
126     {
127         return true;
128     }
129     return false;
130 }
131 
132 static Data getData(const std::string& filename, bool forString)
133 {
134     if (filename.empty())
135     {
136         return Data::Null;
137     }
138 
139     unsigned char *buffer = nullptr;
140 
141     size_t size = 0;
142     do
143     {
144         // read the file from hardware
145         std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filename);
146 
147         WCHAR wszBuf[CC_MAX_PATH] = {0};
148         MultiByteToWideChar(CP_UTF8, 0, fullPath.c_str(), -1, wszBuf, sizeof(wszBuf)/sizeof(wszBuf[0]));
149 
150         HANDLE fileHandle = ::CreateFileW(wszBuf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, nullptr);
151         CC_BREAK_IF(fileHandle == INVALID_HANDLE_VALUE);
152         
153         size = ::GetFileSize(fileHandle, nullptr);
154 
155         if (forString)
156         {
157             buffer = (unsigned char*) malloc(size + 1);
158             buffer[size] = '\0';
159         }
160         else
161         {
162             buffer = (unsigned char*) malloc(size);
163         }
164         DWORD sizeRead = 0;
165         BOOL successed = FALSE;
166         successed = ::ReadFile(fileHandle, buffer, size, &sizeRead, nullptr);
167         ::CloseHandle(fileHandle);
168 
169         if (!successed)
170         {
171             free(buffer);
172             buffer = nullptr;
173         }
174     } while (0);
175     
176     Data ret;
177 
178     if (buffer == nullptr || size == 0)
179     {
180         std::string msg = "Get data from file(";
181         // Gets error code.
182         DWORD errorCode = ::GetLastError();
183         char errorCodeBuffer[20] = {0};
184         snprintf(errorCodeBuffer, sizeof(errorCodeBuffer), "%d", errorCode);
185 
186         msg = msg + filename + ") failed, error code is " + errorCodeBuffer;
187         CCLOG("%s", msg.c_str());
188     }
189     else
190     { 
191         unsigned long len = 0;
192         unsigned char* retbuf = FWResEncrypt::getInstance()->decryptData(buffer, size, &len);
193         //ret.fastSet(buffer, size);
194         ret.fastSet(retbuf, len);
195     }
196     return ret;
197 }
198 
199 std::string FileUtilsWin32::getStringFromFile(const std::string& filename)
200 {
201     Data data = getData(filename, true);
202     if (data.isNull())
203     {
204         return "";
205     }
206 
207     std::string ret((const char*)data.getBytes());
208     return ret;
209 }
210     
211 Data FileUtilsWin32::getDataFromFile(const std::string& filename)
212 {
213     return getData(filename, false);
214 }
215 
216 unsigned char* FileUtilsWin32::getFileData(const std::string& filename, const char* mode, ssize_t* size)
217 {
218     unsigned char * pBuffer = nullptr;
219     *size = 0;
220     do
221     {
222         // read the file from hardware
223         std::string fullPath = fullPathForFilename(filename);
224 
225         WCHAR wszBuf[CC_MAX_PATH] = {0};
226         MultiByteToWideChar(CP_UTF8, 0, fullPath.c_str(), -1, wszBuf, sizeof(wszBuf)/sizeof(wszBuf[0]));
227 
228         HANDLE fileHandle = ::CreateFileW(wszBuf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, nullptr);
229         CC_BREAK_IF(fileHandle == INVALID_HANDLE_VALUE);
230         
231         *size = ::GetFileSize(fileHandle, nullptr);
232 
233         pBuffer = (unsigned char*) malloc(*size);
234         DWORD sizeRead = 0;
235         BOOL successed = FALSE;
236         successed = ::ReadFile(fileHandle, pBuffer, *size, &sizeRead, nullptr);
237         ::CloseHandle(fileHandle);
238 
239         if (!successed)
240         {
241             free(pBuffer);
242             pBuffer = nullptr;
243         }
244     } while (0);
245     
246     if (! pBuffer)
247     {
248         std::string msg = "Get data from file(";
249         // Gets error code.
250         DWORD errorCode = ::GetLastError();
251         char errorCodeBuffer[20] = {0};
252         snprintf(errorCodeBuffer, sizeof(errorCodeBuffer), "%d", errorCode);
253 
254         msg = msg + filename + ") failed, error code is " + errorCodeBuffer;
255         CCLOG("%s", msg.c_str());
256     }
257     //return pBuffer;
258     return FWResEncrypt::getInstance()->decryptData(pBuffer, *size, (unsigned long*)size);
259 }
260 
261 std::string FileUtilsWin32::getPathForFilename(const std::string& filename, const std::string& resolutionDirectory, const std::string& searchPath)
262 {
263     std::string unixFileName = convertPathFormatToUnixStyle(filename);
264     std::string unixResolutionDirectory = convertPathFormatToUnixStyle(resolutionDirectory);
265     std::string unixSearchPath = convertPathFormatToUnixStyle(searchPath);
266 
267     return FileUtils::getPathForFilename(unixFileName, unixResolutionDirectory, unixSearchPath);
268 }
269 
270 std::string FileUtilsWin32::getFullPathForDirectoryAndFilename(const std::string& strDirectory, const std::string& strFilename)
271 {
272     std::string unixDirectory = convertPathFormatToUnixStyle(strDirectory);
273     std::string unixFilename = convertPathFormatToUnixStyle(strFilename);
274     
275     return FileUtils::getFullPathForDirectoryAndFilename(unixDirectory, unixFilename);
276 }
277 
278 string FileUtilsWin32::getWritablePath() const
279 {
280     // Get full path of executable, e.g. c:\Program Files (x86)\My Game Folder\MyGame.exe
281     char full_path[CC_MAX_PATH + 1];
282     ::GetModuleFileNameA(nullptr, full_path, CC_MAX_PATH + 1);
283 
284     // Debug app uses executable directory; Non-debug app uses local app data directory
285 //#ifndef _DEBUG
286         // Get filename of executable only, e.g. MyGame.exe
287         char *base_name = strrchr(full_path, '\\');
288 
289         if(base_name)
290         {
291             char app_data_path[CC_MAX_PATH + 1];
292 
293             // Get local app data directory, e.g. C:\Documents and Settings\username\Local Settings\Application Data
294             if (SUCCEEDED(SHGetFolderPathA(nullptr, CSIDL_LOCAL_APPDATA, nullptr, SHGFP_TYPE_CURRENT, app_data_path)))
295             {
296                 string ret((char*)app_data_path);
297 
298                 // Adding executable filename, e.g. C:\Documents and Settings\username\Local Settings\Application Data\MyGame.exe
299                 ret += base_name;
300 
301                 // Remove ".exe" extension, e.g. C:\Documents and Settings\username\Local Settings\Application Data\MyGame
302                 ret = ret.substr(0, ret.rfind("."));
303 
304                 ret += "\\";
305 
306                 // Create directory
307                 if (SUCCEEDED(SHCreateDirectoryExA(nullptr, ret.c_str(), nullptr)))
308                 {
309                     return convertPathFormatToUnixStyle(ret);
310                 }
311             }
312         }
313 //#endif // not defined _DEBUG
314 
315     // If fetching of local app data directory fails, use the executable one
316     string ret((char*)full_path);
317 
318     // remove xxx.exe
319     ret =  ret.substr(0, ret.rfind("\\") + 1);
320 
321     ret = convertPathFormatToUnixStyle(ret);
322 
323     return ret;
324 }
325 
326 NS_CC_END
327 
328 #endif // CC_TARGET_PLATFORM == CC_PLATFORM_WIN32 

當我們使用cc.FileUtils:getInstance():getStringFromFile()讀取文件內容的時候就獲取到的是解密后的內容了,這個解密的過程是在引擎層面做好的了,也可以說對使用者來說是透明的.這樣也是契合了為什么在前一篇文章中我為什么會說我堅持使用這個接口作為配置文件讀取的主要原因.同樣,如果是加密圖片,plist文件,只需要按照一般我們使用過的方式使用就好了,不需要做任何的改動.

加密工具可以去下載一份quick的源碼,里面有提供一個pack_files.bat腳本,用它來打包就好了,然后在引擎啟動的時候設置好我們的簽名,如下:

 1 bool AppDelegate::applicationDidFinishLaunching()
 2 {
 3     auto engine = LuaEngine::getInstance();
 4     ScriptEngineManager::getInstance()->setScriptEngine(engine);
 5     lua_State* L = engine->getLuaStack()->getLuaState();
 6     lua_module_register(L);
 7 
 8     cocos2d::FileUtils::getInstance()->setPopupNotify(false);
 9     
10     FWResEncrypt::getInstance()->setXXTeaKeyAndSign("RESPAWN", strlen("RESPAWN"), "FW", strlen("FW"));
11     engine->getLuaStack()->setXXTEAKeyAndSign("RESPAWN", strlen("RESPAWN"), "FW", strlen("FW"));
12     
13     // If you want to use Quick-Cocos2d-X, please uncomment below code
14     // register_all_quick_manual(L);
15     if (engine->executeScriptFile("src/main.lua")) {
16         return false;
17     }
18 
19     return true;
20 }

 

好吧,到這里就結束了.下一篇文章考慮可能會做一下增量動態更新,敬請期待.歡迎交流.我好久沒用我的github了,待我稍微整理一下,然后以合適的方式上傳我的代碼,開源給大家.另外,我現在在找相關游戲資源,期望是整套的網游資源,要不然我也就只能做做這些架構方面的事情了,涉及不到游戲的業務邏輯.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM