在上一篇文章中,我已经开始着手写自己的模块,也就是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 = ;
  11. do
  12. {
  13. // read the file from hardware
  14. std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filename);
  15.  
  16. WCHAR wszBuf[CC_MAX_PATH] = {};
  17. MultiByteToWideChar(CP_UTF8, , fullPath.c_str(), -, wszBuf, sizeof(wszBuf)/sizeof(wszBuf[]));
  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 + );
  27. buffer[size] = '\0';
  28. }
  29. else
  30. {
  31. buffer = (unsigned char*) malloc(size);
  32. }
  33. DWORD sizeRead = ;
  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 ();
  44.  
  45. Data ret;
  46.  
  47. if (buffer == nullptr || size == )
  48. {
  49. std::string msg = "Get data from file(";
  50. // Gets error code.
  51. DWORD errorCode = ::GetLastError();
  52. char errorCodeBuffer[] = {};
  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 = ;
  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 = ;
  4.  
  5. if (_xxteaEnabled && strncmp(chunk, _xxteaSign, _xxteaSignLen) == )
  6. {
  7. // decrypt XXTEA
  8. xxtea_long len = ;
  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 = ;
  30. }
  31. if (_xxteaSign)
  32. {
  33. free(_xxteaSign);
  34. _xxteaSign = nullptr;
  35. _xxteaSignLen = ;
  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
  1. #include "FWResEncrypt.h"
  2. #include "cocos2d.h"
  3. #include "CCFileUtils.h"
  4. #include "xxtea/xxtea.h"
  5.  
  6. FWResEncrypt* FWResEncrypt::pFWResEncrypt_ = nullptr;
  7.  
  8. FWResEncrypt* FWResEncrypt::getInstance()
  9. {
  10. if(!pFWResEncrypt_)
  11. {
  12. pFWResEncrypt_ = new FWResEncrypt();
  13. }
  14. return pFWResEncrypt_;
  15. }
  16.  
  17. FWResEncrypt::FWResEncrypt()
  18. :xxteaEnabled_(false)
  19. ,xxteaKey_(nullptr)
  20. ,xxteaKeyLen_()
  21. ,xxteaSign_(nullptr)
  22. ,xxteaSignLen_()
  23. {
  24.  
  25. }
  26.  
  27. void FWResEncrypt::setXXTeaKeyAndSign(const char* xxteaKey, int xxteaKeyLen, const char* xxteaSign, int xxteaSignLen)
  28. {
  29. cleanupXXTeaKeyAndSign();
  30.  
  31. if( xxteaKey && xxteaKeyLen && xxteaSign && xxteaSignLen)
  32. {
  33. xxteaKey_ = (char*)malloc(xxteaKeyLen);
  34. memcpy(xxteaKey_, xxteaKey, xxteaKeyLen);
  35. xxteaKeyLen_ = xxteaKeyLen;
  36.  
  37. xxteaSign_ = (char*)malloc(xxteaSignLen);
  38. memcpy(xxteaSign_, xxteaSign, xxteaSignLen);
  39. xxteaSignLen_ = xxteaSignLen;
  40.  
  41. xxteaEnabled_ = true;
  42. } else
  43. {
  44. xxteaEnabled_ = false;
  45. }
  46. }
  47.  
  48. void FWResEncrypt::cleanupXXTeaKeyAndSign()
  49. {
  50. if(xxteaKey_)
  51. {
  52. free(xxteaKey_);
  53. xxteaKey_ = nullptr;
  54. xxteaKeyLen_ = ;
  55. }
  56. if(xxteaSign_)
  57. {
  58. free(xxteaSign_);
  59. xxteaSign_ = nullptr;
  60. xxteaSignLen_ = ;
  61. }
  62. }
  63.  
  64. unsigned char* FWResEncrypt::getFileData(const char* fileName, const char* mode, unsigned long* pSize)
  65. {
  66. ssize_t size;
  67. unsigned char* buf = cocos2d::FileUtils::getInstance()->getFileData(fileName, mode, &size);
  68. if(nullptr == buf)
  69. {
  70. return nullptr;
  71. }
  72.  
  73. unsigned char* buffer = nullptr;
  74. FWResEncrypt* pFWResEncrypt = FWResEncrypt::getInstance();
  75.  
  76. bool isXXTEA = pFWResEncrypt && pFWResEncrypt->xxteaEnabled_;
  77.  
  78. for(unsigned int i = ; isXXTEA && i < pFWResEncrypt->xxteaSignLen_ && i < size; ++ i )
  79. {
  80. isXXTEA = buf[i] == pFWResEncrypt->xxteaSign_[i];
  81. }
  82.  
  83. if(isXXTEA)
  84. {
  85. xxtea_long len = ;
  86. buffer = xxtea_decrypt( buf+pFWResEncrypt->xxteaSignLen_,
  87. (xxtea_long)size - (xxtea_long)pFWResEncrypt->xxteaSignLen_,
  88. (unsigned char*)pFWResEncrypt->xxteaKey_,
  89. (xxtea_long)pFWResEncrypt->xxteaKeyLen_, &len);
  90. delete [] buf;
  91. buf = nullptr;
  92. size = len;
  93. } else
  94. {
  95. buffer = buf;
  96. }
  97.  
  98. if(pSize)
  99. {
  100. *pSize = size;
  101. }
  102. return buffer;
  103. }
  104.  
  105. unsigned char *FWResEncrypt::decryptData(unsigned char* buf, unsigned long size, unsigned long* pSize)
  106. {
  107. CCAssert(buf != nullptr, "decryptData buf cannot nullptr");
  108.  
  109. unsigned char* buffer = nullptr;
  110. FWResEncrypt* pFWResEncrypt = FWResEncrypt::getInstance();
  111. bool isXXTEA = pFWResEncrypt && pFWResEncrypt->xxteaEnabled_;
  112.  
  113. for(unsigned int i = ; isXXTEA && i < pFWResEncrypt->xxteaSignLen_ && i < size; ++ i )
  114. {
  115. isXXTEA = buf[i] == pFWResEncrypt->xxteaSign_[i];
  116. }
  117.  
  118. if(isXXTEA)
  119. {
  120. xxtea_long len = ;
  121. buffer = xxtea_decrypt( buf+pFWResEncrypt->xxteaSignLen_,
  122. (xxtea_long)size - (xxtea_long)pFWResEncrypt->xxteaSignLen_,
  123. (unsigned char*)pFWResEncrypt->xxteaKey_,
  124. (xxtea_long)pFWResEncrypt->xxteaKeyLen_, &len);
  125. delete [] buf;
  126. buf = nullptr;
  127. size = len;
  128. } else
  129. {
  130. buffer = buf;
  131. }
  132. if(pSize)
  133. {
  134. *pSize = size;
  135. }
  136. return buffer;
  137. }
  138.  
  139. unsigned char* FWResEncrypt::encryptData(unsigned char* buf, unsigned long size, unsigned long* pSize)
  140. {
  141. CCAssert(buf != nullptr, "encryptData buf cannot nullptr");
  142. unsigned char* buffer = nullptr;
  143. unsigned char* ret = nullptr;
  144. FWResEncrypt* pFWResEncrypt = FWResEncrypt::getInstance();
  145. bool isXXTEA = pFWResEncrypt && pFWResEncrypt->xxteaEnabled_;
  146. for(unsigned int i = ; isXXTEA && i < pFWResEncrypt->xxteaSignLen_ && i < size; ++ i )
  147. {
  148. isXXTEA = buf[i] == pFWResEncrypt->xxteaSign_[i];
  149. }
  150. if(!isXXTEA)
  151. {
  152. xxtea_long len = ;
  153. buffer = xxtea_encrypt( buf,
  154. (xxtea_long)size,
  155. (unsigned char*)pFWResEncrypt->xxteaKey_,
  156. (xxtea_long)pFWResEncrypt->xxteaKeyLen_, &len);
  157. delete [] buf;
  158. buf = nullptr;
  159. size = len;
  160. ret = (unsigned char*)malloc(size+pFWResEncrypt->xxteaSignLen_+);
  161. memcpy(ret, pFWResEncrypt->xxteaSign_, pFWResEncrypt->xxteaSignLen_);
  162. memcpy(ret+pFWResEncrypt->xxteaSignLen_, buffer, size);
  163. ret[len+pFWResEncrypt->xxteaSignLen_] = '\0';
  164. } else
  165. {
  166. ret = buf;
  167. }
  168. if(pSize)
  169. {
  170. *pSize = size+pFWResEncrypt->xxteaSignLen_;
  171. }
  172. return ret;
  173. }

其中设置签名,清除签名那些方法我都是直接从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, );
  18. unsigned char* encryptData = (unsigned char*)malloc(data.size());
  19. memcpy(encryptData, data.c_str(), data.size());
  20. unsigned long len = ;
  21. unsigned char* encryptedData = FWResEncrypt::getInstance()->encryptData(encryptData, data.size(), &len);
  22. lua_pushlstring(lua_state, (char*)encryptedData, len);
  23. return ;
  24. }
  25. int
  26. lua_fw_encrypt_decryptData(lua_State* lua_state)
  27. {
  28. size_t len = ;
  29. const char *data = lua_tolstring(lua_state, ,&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 ;
  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 = ; 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 ( == s_resourcePath.length())
  61. {
  62. WCHAR utf16Path[CC_MAX_PATH] = {};
  63. GetCurrentDirectoryW(sizeof(utf16Path)-, utf16Path);
  64.  
  65. char utf8Path[CC_MAX_PATH] = {};
  66. int nNum = WideCharToMultiByte(CP_UTF8, , utf16Path, -, 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 ( == 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(, _defaultResRootPath);
  110. }
  111.  
  112. WCHAR utf16Buf[CC_MAX_PATH] = {};
  113. MultiByteToWideChar(CP_UTF8, , strPath.c_str(), -, utf16Buf, sizeof(utf16Buf)/sizeof(utf16Buf[]));
  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() >
  124. && ( (strPath[] >= 'a' && strPath[] <= 'z') || (strPath[] >= 'A' && strPath[] <= 'Z') )
  125. && strPath[] == ':')
  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 = ;
  142. do
  143. {
  144. // read the file from hardware
  145. std::string fullPath = FileUtils::getInstance()->fullPathForFilename(filename);
  146.  
  147. WCHAR wszBuf[CC_MAX_PATH] = {};
  148. MultiByteToWideChar(CP_UTF8, , fullPath.c_str(), -, wszBuf, sizeof(wszBuf)/sizeof(wszBuf[]));
  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 + );
  158. buffer[size] = '\0';
  159. }
  160. else
  161. {
  162. buffer = (unsigned char*) malloc(size);
  163. }
  164. DWORD sizeRead = ;
  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 ();
  175.  
  176. Data ret;
  177.  
  178. if (buffer == nullptr || size == )
  179. {
  180. std::string msg = "Get data from file(";
  181. // Gets error code.
  182. DWORD errorCode = ::GetLastError();
  183. char errorCodeBuffer[] = {};
  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 = ;
  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 = ;
  220. do
  221. {
  222. // read the file from hardware
  223. std::string fullPath = fullPathForFilename(filename);
  224.  
  225. WCHAR wszBuf[CC_MAX_PATH] = {};
  226. MultiByteToWideChar(CP_UTF8, , fullPath.c_str(), -, wszBuf, sizeof(wszBuf)/sizeof(wszBuf[]));
  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 = ;
  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 ();
  245.  
  246. if (! pBuffer)
  247. {
  248. std::string msg = "Get data from file(";
  249. // Gets error code.
  250. DWORD errorCode = ::GetLastError();
  251. char errorCodeBuffer[] = {};
  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 + ];
  282. ::GetModuleFileNameA(nullptr, full_path, CC_MAX_PATH + );
  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 + ];
  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(, 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(, ret.rfind("\\") + );
  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了,待我稍微整理一下,然后以合适的方式上传我的代码,开源给大家.另外,我现在在找相关游戏资源,期望是整套的网游资源,要不然我也就只能做做这些架构方面的事情了,涉及不到游戏的业务逻辑.

`cocos2dx非完整` 添加xxtea加密模块的更多相关文章

  1. `cocos2dx非完整` 游戏架构缩影 添加启动流程

    这期的话题可能不是很好, 我没有想到很好的词句去更好的表达. 我一直都是很固执的认为, 同一类型的游戏,在开发做的前期工作上面其实都是可以复用的,也就是大同小异的.从游戏启动,启动日志,启动检查,检查 ...

  2. `cocos2dx 非完整` UI解析模块

    昨天在cocos2dx的一个群里,遇到一位匿名为x的朋友询问的问题,是关于ui的.他使用c++写了不少的ui封装节点,用来实现游戏中的各种不同效果.然后现在想改用lua,于是尝试使用最小代价去复用自己 ...

  3. `cocos2dx非完整` 日志模块 增量更新

    在上一篇文章中,说到了"流程"的由来,以及我对流程的使用. 这一片就是对流程的应用.前一篇文章中说到了三条流程 check_log_measure, check_env_measu ...

  4. `cocos2dx非完整` 开始自己的FW模块

    上一篇的文章中说到了一些个人习惯的东西以及一些简单的项目配置,这一篇文章我们来进一步完善一些东西.首先,打开编译以后的客户端执行,会看到一大堆的fileutils加载luac文件的提示,在终端显示一大 ...

  5. `cocos2dx非完整`开篇

    相信每个人都有一些自己的项目开发习惯,在·开篇·中我主要是会提到一些项目的配置问题.无论做一款什么样的手游项目,我们总是会从需求的角度出发去选择开发引擎,开发工具等一些列的工具去完善我们的开发环境.当 ...

  6. 新版本ffmpeg解码非完整H264帧失败

    按照ffmpeg/doc/examples/decoding_encoding.c中video_decode_example解码H264,新版本ffmpeg解码非完整H264帧,定量读取数据直接给av ...

  7. `fw服务端非完整` 工程开发初期的工作

    前面写到了一些关于cocos2dx在开发中的一些模块以及一些解决方法,那些都属于本人的个人简介和个人倾向的解决方案.最近这几天我完善了一下ui解析的部分,当然也只是抽出一点点时间去做的这件事情.我添加 ...

  8. MFC非模态添加进程控件方法二(自定义消息方法)

    以下内容有大部分转载自CSDN,经过自己整理完成. 该文主要的方法为在非模态对话框中自定义一组消息函数,然后在主窗口中开辟一个线程通过线程把消息传递给子窗口进行更新. 在子窗口类中定义消息如下: /* ...

  9. MFC非模态添加进程控件方法一(线程方法)

    由于非模态对话框的自己没有消息循环,创建后无法进行消息处理.需要和父窗口共用消息循环.如果单独在子窗口进行控件由于自己没有单独的消息循环,更新是无法进行的. 如果在父窗口更新控件会造成程序假死.如以下 ...

随机推荐

  1. paip.提升效率--gui 的选择--swing最佳实践swt awt

    paip.提升效率--gui 的选择--swing最佳实践swt awt ////////////////弹出消息框. ////////////////myeclipse swing 开发最佳实践.. ...

  2. DL 小记之序

    在开通博客的1小时03分钟50秒,我写下了第一篇文字.不知道从什么时候开始,什么东西都有个期限,在写下几小时几分几秒之后,我总是习惯性的加上不知道从什么时候开始. 本博客不含惊天动地的故事,想看故事请 ...

  3. asp.net的JSON数据进行序列化和反序列化

    先要引用在程序集 System.Web.Extensions.dll 的类库,在类中 using System.Web.Script.Serialization 命名空间. 1.定义一个强类型的类(m ...

  4. Leetcode 198 House Robber 动态规划

    题意是强盗能隔个马抢马,看如何获得的价值最高 动态规划题需要考虑状态,阶段,还有状态转移,这个可以参考<动态规划经典教程>,网上有的下的,里面有大量的经典题目讲解 dp[i]表示到第i匹马 ...

  5. SQL Server 内存中OLTP内部机制概述(三)

    ----------------------------我是分割线------------------------------- 本文翻译自微软白皮书<SQL Server In-Memory ...

  6. STL的string和wstring

    STL有字符串处理类——stirng和wstring,但是用的时候会觉得不是很方便,因为它不能像TCHAR一样根据定义的宏在char类型字符串和wchar_t进行转换,总不能因为程序要Unicode就 ...

  7. (转)TRANSFORM_TEX详解

    原创文章如需转载请注明:转载自风宇冲Unity3D教程学院 特别讲:常见问题回答   本讲会陆续补充一些问题的解答. 问: (1) TRANSFORM_TEX是做什么的 (2)float4 _Main ...

  8. 制作6寸 kindle pdf

    设置word 纸张大小为 90mm*117mm 然后保存为 pdf 就好了.

  9. CoreOS实践(2)—在coreos上安装Kubernetes

    下载kubernetes sudo mkdir -p /opt/bin sudo wget https://storage.googleapis.com/kubernetes/binaries.tar ...

  10. 利用Android Studio、MAT对Android进行内存泄漏检测

    利用Android Studio.MAT对Android进行内存泄漏检测 Android开发中难免会遇到各种内存泄漏,如果不及时发现处理,会导致出现内存越用越大,可能会因为内存泄漏导致出现各种奇怪的c ...