图片加密

修改 CCFileUtils 这个类

  1. 在头文件cocos2d/cocos/platform/CCFileUtils.h里增加一个成员变量

    class FileUtils {
    protected:
    mutable std::unordered_map<std::string, std::string> _fullPathCache;//原来就有的代码
    std::unordered_map<std::string, std::string> m_my_hash_map_xxxxx;//新增的代码
    }
  1. 在实现文件里修改一下构造函数,用来初始化刚才添加的map。并且修改一下获取全路径的函数。

    FileUtils::FileUtils()
        : _writablePath("")
    {
        //replace_flag_tai_shang_lao_jun
        //replace_flag_tai_shang_lao_jun
    }
    
    std::string FileUtils::fullPathForFilename(const std::string &filename) const
    {
        
        DECLARE_GUARD;
    
        if (filename.empty())
        {
            return "";
        }
    
        std::string filename2 = filename;
        if (m_my_hash_map_xxxxx.find(filename) != m_my_hash_map_xxxxx.end())
        {
            filename2 = m_my_hash_map_xxxxx.at(filename);
        }
    
        if (isAbsolutePath(filename2))
        {
            return filename2;
        }
    
        // Already Cached ?
        auto cacheIter = _fullPathCache.find(filename2);
        if(cacheIter != _fullPathCache.end())
        {
            return cacheIter->second;
        }
    
        // Get the new file name.
        const std::string newFilename( getNewFilename(filename2) );
    
        std::string fullpath;
    
        for (const auto& searchIt : _searchPathArray)
        {
            for (const auto& resolutionIt : _searchResolutionsOrderArray)
            {
                fullpath = this->getPathForFilename(newFilename, resolutionIt, searchIt);
    
                if (!fullpath.empty())
                {
                    // Using the filename passed in as key.
                    _fullPathCache.emplace(filename2, fullpath);
                    return fullpath;
                }
    
            }
        }
    
        if(isPopupNotify()){
            CCLOG("cocos2d: fullPathForFilename: No file found at %s. Possible missing file.", filename2.c_str());
        }
    
        // The file wasn't found, return empty string.
        return "";
    }

    说明1:构造函数里加了两句注释。这个注释是用来给Python脚本识别的,好在此处插入字符串。
    说明2:获取全路径函数的修改意图,就是在map里找一下,找到了就用心的文件名,否则用原来的。

修改 Image 这个类

cocos2d/cocos/platform/CCImage.cpp这个是实现文件的路径。

bool Image::initWithImageData(const unsigned char * data, ssize_t dataLen)
{
    //省略其他代码
    if (ZipUtils::isCCZBuffer(data, dataLen))
    {
        unpackedLen = ZipUtils::inflateCCZBuffer(data, dataLen, &unpackedData);
    }
    else if (ZipUtils::isGZipBuffer(data, dataLen))
    {
        unpackedLen = ZipUtils::inflateMemory(const_cast<unsigned char*>(data), dataLen, &unpackedData);
    }
    else
    {
        unpackedData = const_cast<unsigned char*>(data);
        unpackedLen = dataLen;
        //添加这一行
        for (ssize_t i = 0; i < unpackedLen; ++i) { unpackedData[i] ^= 0xFF; }
    }
    //省略其他代码
}

修改的目的就是为了在生成图片前做一次异或操作。

拷贝加密图片的可执行程序

拷贝加密图片的exe到跟 Resources 目录同级的地方。

附上生成这个exe的代码:

#include <iostream>
#include <cassert>
#include <cstdlib>
#include <string>
#include <vector>

#define BUFFERSIZE 1024

void func(const char* file_old, const char* file_new)
{
    FILE* fp = fopen(file_old, "rb");
    FILE* fp2 = fopen(file_new, "wb");
    if (fp == NULL)
    {
        printf("error:fp == NULL %s %s\n", file_old, file_new);
        return;
    }
    if (fp == NULL)
    {
        printf("error:fp2 == NULL %s %s\n", file_old, file_new);
        return;
    }
    char buf[BUFFERSIZE];
    char buf2[BUFFERSIZE];
    unsigned char MASK = 2;
    int len = 0;
    while (!feof(fp))
    {
        len = fread(buf, 1, BUFFERSIZE, fp);
        if (len > 0)
        {
            memset(buf2, 0, BUFFERSIZE);
            for (int i = 0; i < len; ++i)
            {
                buf2[i] = buf[i];
                buf2[i] ^= 0xFF;
            }
            int write_result = fwrite(buf2, 1, len, fp2);
        }
    }
    fclose(fp);
    fclose(fp2);
}
void func2(const char* file_old, const char* file_new)
{
    remove(file_old);
    rename(file_new, file_old);
}

int main()
{
    std::vector<std::string> vec1;
    FILE* fp = fopen("zzz_output_encode_png.txt", "r");
    char buf[BUFFERSIZE] = { 0 };
    while (fgets(buf, BUFFERSIZE, fp))
    {
        
        if (buf[0] == '{' || buf[0] == '}')
        {
            printf("%s\n", buf);
        }
        else
        {
            printf("%s\n", buf);
            vec1.push_back(std::string(buf));
        }
    }
    fclose(fp);
    for (auto s : vec1)
    {
        std::string str;
        for (auto ch : s)
        {
            if (ch != '\n' && ch != '\r' && ch != '\"' && ch != ',')
            {
                str += ch;
            }
        }
        func(str.c_str(), std::string(str + "xx").c_str());
        func2(str.c_str(), std::string(str + "xx").c_str());
    }
    system("pause");
    return 0;
}

给 Resources 目录下所有文件重命名,并调整路径

# -*- coding: utf-8 -*-
import os
import string
import random
import shutil

g_str_png = ""
g_str_jpg = ""
g_str_webp = ""
g_str_ttf = ""
g_str_others = ""
g_file_cnt = 0
g_exclude_file_list = ['8429kznywme9rgdem7ffp443.json', 'supplierconfig.json']

# 读取Resources目录下的所有文件,将每种类型的文件路径存入全局变量
def func_get_filename(current_folder_path):
    global g_str_png
    global g_str_jpg
    global g_str_webp
    global g_str_ttf
    global g_str_others
    list = os.listdir(current_folder_path)
    for file_or_dir_name in list:
        full_path = os.path.join(current_folder_path, file_or_dir_name)
        if os.path.isfile(full_path):
            if full_path[-4:] == ".png":
                g_str_png += full_path + '\n'
            elif full_path[-4:] == ".jpg":
                g_str_jpg += full_path + '\n'
            elif full_path[-5:] == ".webp":
                g_str_webp += full_path + '\n'
            elif full_path[-4:] == ".ttf":
                g_str_ttf += full_path + '\n'
            else:
                g_str_others += full_path + '\n'
        elif os.path.isdir(full_path):
            func_get_filename(full_path)

# 将全局变量里存的文件名,写入文件1
def func_save_all_filename():
    global g_str_png
    global g_str_jpg
    global g_str_webp
    global g_str_ttf
    global g_str_others
    str_write = ""
    str_write += g_str_png
    str_write += 'we_should_create_new_floder\n'
    str_write += g_str_jpg
    str_write += 'we_should_create_new_floder\n'
    str_write += g_str_webp
    str_write += 'we_should_create_new_floder\n'
    str_write += g_str_ttf
    str_write += 'we_should_create_new_floder\n'
    str_write += g_str_others
    str_write += 'we_should_create_new_floder\n'
    f = open('zzz_output_1.txt', 'w')
    f.write(str_write)
    f.close()

# 随机生成长度为num的字符串
def ranstr(num):
    salt = ''.join(random.sample(string.ascii_letters, num))
    return salt

# 生成映射表,写入文件2
def func_generate_hash_map():
    global g_file_cnt
    max_file_cnt_in_one_dir = 300#一个目录下最多有多少个文件
    current_dir_file_cnt = 0#当前目录已经有多少个文件了
    new_dir_name_len = 9#新目录的文件夹名字有多少个随机字符
    new_dir_name = ranstr(new_dir_name_len)#新目录的名字前缀
    current_generated_dir_cnt = 0#当前已经生成了多少个新目录了
    str_write_for_cpp = ""#给cpp代码做初始化用的文件
    str_write_2 = ""#给第三步用的文件
    
    #读文件1,生成字符串str_write_for_cpp
    f = open('zzz_output_1.txt', 'r')
    for line in f.readlines():
        line = line.replace('\n', '')#按行读取文件路径,去掉每一行末尾的换行符
        str_dir_prefix = '.\\Resources\\'#路径前面的这个字符串要删掉,因为映射表里的路径应该是相对于Resources的路径
        var_index = string.find(line, str_dir_prefix)
        assert var_index == 0, '文件1里存的路径不是以.\\Resources\\开头的'
        str_dir_prefix_len = len(str_dir_prefix)
        line = line[str_dir_prefix_len:]#把.\Resources\这个串删掉

        # 这里有个分支,有些文件是不改路径,不改文件名的
        find_flag = False
        for unchangeable_file in g_exclude_file_list:
            pos = line.find(unchangeable_file)
            if pos != -1 :
                find_flag = True
                break
        if find_flag:
            str_write_2 += line + "," + line + '\n'
            continue

        #每个新文件夹能存多少个文件
        if current_dir_file_cnt == max_file_cnt_in_one_dir:
            current_dir_file_cnt = 0
            current_generated_dir_cnt += 1
            new_dir_name = ranstr(new_dir_name_len)

        #拼接新文件夹的名字
        new_dir_name_with_index = new_dir_name + str(current_generated_dir_cnt) + '\\'
        
        #保持文件的后缀名不变
        last_dot_pos = line.rfind('.')
        new_file_name = line[last_dot_pos:]
        g_file_cnt += 1
        new_file_name = "%05d"%(g_file_cnt) + ranstr(5) + new_file_name
        
        #更新需要写入文件的字符串
        str_write_for_cpp += "{\"" + line + "\", \"" + new_dir_name_with_index + new_file_name + "\"},\n"
        str_write_2 += line + "," + new_dir_name_with_index + new_file_name + '\n'
        
        #当前目录下的文件数加1
        current_dir_file_cnt += 1
    f.close()
    
    #把得到的字符串写入文件2
    last_comma_pos = str_write_for_cpp.rfind(',')
    assert last_comma_pos != -1, "ERROR"
    str_write_for_cpp = str_write_for_cpp[0:last_comma_pos]
    str_write_for_cpp = "{\n" + str_write_for_cpp + "\n};"
    str_write_for_cpp = str_write_for_cpp.replace('\\', '/')
    f2 = open("zzz_output_2.cpp", 'w')
    f2.write(str_write_for_cpp)
    f2.close()
    
    f3 = open('zzz_output_2.txt', 'w')
    f3.write(str_write_2)
    f3.close()
    
    return str_write_for_cpp


# 生成映射表,写入文件2,按后缀名来分文件夹
def func_generate_hash_map_2():
    global g_file_cnt
    current_dir_file_cnt = 0#当前目录已经有多少个文件了
    new_dir_name_len = 9#新目录的文件夹名字有多少个随机字符
    new_dir_name = ranstr(new_dir_name_len)#新目录的名字前缀
    current_generated_dir_cnt = 0#当前已经生成了多少个新目录了
    str_write_for_cpp = ""#给cpp代码做初始化用的文件
    str_write_2 = ""#给第三步用的文件
    
    #读文件1,生成字符串str_write_for_cpp
    f = open('zzz_output_1.txt', 'r')
    for line in f.readlines():
        line = line.replace('\n', '')#按行读取文件路径,去掉每一行末尾的换行符
        if line.find('we_should_create_new_floder') != -1:
            current_dir_file_cnt = 0
            current_generated_dir_cnt += 1
            new_dir_name = ranstr(new_dir_name_len)
            continue

        str_dir_prefix = '.\\Resources\\'#路径前面的这个字符串要删掉,因为映射表里的路径应该是相对于Resources的路径
        var_index = string.find(line, str_dir_prefix)
        assert var_index == 0, '文件1里存的路径不是以.\\Resources\\开头的'
        str_dir_prefix_len = len(str_dir_prefix)
        line = line[str_dir_prefix_len:]#把.\Resources\这个串删掉

        # 这里有个分支,有些文件是不改路径,不改文件名的
        find_flag = False
        for unchangeable_file in g_exclude_file_list:
            pos = line.find(unchangeable_file)
            if pos != -1 :
                find_flag = True
                break
        if find_flag:
            str_write_2 += line + "," + line + '\n'
            continue

        #拼接新文件夹的名字
        new_dir_name_with_index = new_dir_name + str(current_generated_dir_cnt) + '\\'
        
        #保持文件的后缀名不变
        last_dot_pos = line.rfind('.')
        new_file_name = line[last_dot_pos:]
        g_file_cnt += 1
        new_file_name = "%05d"%(g_file_cnt) + ranstr(5) + new_file_name
        
        #更新需要写入文件的字符串
        str_write_for_cpp += "{\"" + line + "\", \"" + new_dir_name_with_index + new_file_name + "\"},\n"
        str_write_2 += line + "," + new_dir_name_with_index + new_file_name + '\n'
        
        #当前目录下的文件数加1
        current_dir_file_cnt += 1
    f.close()
    
    #把得到的字符串写入文件2
    last_comma_pos = str_write_for_cpp.rfind(',')
    assert last_comma_pos != -1, "ERROR"
    str_write_for_cpp = str_write_for_cpp[0:last_comma_pos]
    str_write_for_cpp = "{\n" + str_write_for_cpp + "\n};"
    str_write_for_cpp = str_write_for_cpp.replace('\\', '/')
    f2 = open("zzz_output_2.cpp", 'w')
    f2.write(str_write_for_cpp)
    f2.close()
    
    f3 = open('zzz_output_2.txt', 'w')
    f3.write(str_write_2)
    f3.close()
    
    return str_write_for_cpp

# 修改对应的cpp文件
def func_modify_cpp_file(str_replace):
    str_mark = '//replace_flag_tai_shang_lao_jun' # 标记字符串
    str_mark_len = len(str_mark)

    f1 = open('.\\cocos2d\\cocos\\platform\\CCFileUtils.cpp', 'r')
    str_content = f1.read()
    f1.close()

    pos1 = str_content.find(str_mark)
    assert pos1 > 0, "ERROR"
    pos2 = str_content.rfind(str_mark)
    assert pos2 > 0, "ERROR"
    str_front = str_content[0 : pos1 + str_mark_len]
    str_back = str_content[pos2 : ]

    f2 = open('.\\cocos2d\\cocos\\platform\\CCFileUtils.cpp', 'w')
    f2.write(str_front + '\n\tm_my_hash_map_xxxxx=' + str_replace + '\n' + str_back)
    f2.close()

# 根据生成的映射表,重命名并移动文件
def func_rename_and_move_file():
    # 判断Resources2这个文件夹是否存在,如果不存在就创建
    py_file_directory = os.path.abspath('.')
    resources2_dir = os.path.join(py_file_directory, "Resources2")
    resources2_dir_exist = os.path.exists(resources2_dir)
    if not resources2_dir_exist:
        os.mkdir(resources2_dir)

    f3 = open('zzz_output_2.txt', 'r')
    for line in f3.readlines():
        line = line.replace('\n', '')
        path_list = line.split(',')
        assert len(path_list) == 2, "ERROR"
        
        # 原文件必须存在
        path_old = path_list[0]
        full_path_old = os.path.join('.\\Resources\\', path_old)
        assert os.path.exists(full_path_old), "ERROR"

        # 新路径必须由两部分组成,一个文件夹,一个文件名。也可以不是,比方说不变的文件
        path_new = path_list[1]
        first_slash_pos = path_new.find('\\')
        if first_slash_pos == -1:
            dir_under_res2 = os.path.join(resources2_dir, path_new)
            full_path_old = os.path.abspath(full_path_old)
            shutil.copy(full_path_old, dir_under_res2)
            continue

        # 获取新路径的文件夹
        directory_new = path_new[0:first_slash_pos]

        # 获取新路径的文件名
        filename_new = path_new[first_slash_pos + 1:]
        
        # 在Resources2目录下创建新的文件夹
        dir_under_res2 = os.path.join(resources2_dir, directory_new)
        dir_under_res2_exist = os.path.exists(dir_under_res2)
        if not dir_under_res2_exist:
            os.mkdir(dir_under_res2)
            
        # 在Resources2目录下的新文件夹里创建新文件
        file_under_res2 = os.path.join(dir_under_res2, filename_new)
        
        # 拷贝文件
        try:
            shutil.copy(full_path_old, file_under_res2)
        except IOError as e:
            print("Unable to copy file. %s" % e)
        except:
            print("Unexpected error:", sys.exc_info())
    f3.close()
 
def func_encode_pic(str_pic_type):
    list_all_pic = []
    f = open('zzz_output_2.txt', 'r')
    for line in f.readlines():
        line = line.replace('\n', '')
        list_tmp = line.split(',')
        if len(list_tmp) == 2:
            str_back = list_tmp[1]
            if str_back[-4:] == str_pic_type:
                list_all_pic.append(str_back)
    f.close()
    return list_all_pic
    

def func_write_jpg_list_to_file(list_all_jpg):
    str_for_write = '{'
    path_befor = os.path.abspath('.\\Resources')
    for jpg_file in list_all_jpg:
        jpg_file = jpg_file.strip()
        jpg_file = os.path.join(path_befor, jpg_file)
        str_for_write += '\"' + jpg_file + '\"\n'
    str_for_write = str_for_write.replace('\\', '/')
    str_for_write += '}'
    f = open('.\\zzz_output_encode_jpg.txt', 'w')
    f.write(str_for_write)
    f.close()

def func_write_png_list_to_file(list_all_png):
    str_for_write = '{\n'
    path_befor = os.path.abspath('.\\Resources')
    for i in range(len(list_all_png)):
        png_file = list_all_png[i]
        png_file = list_all_png[i].strip()
        png_file = os.path.join(path_befor, png_file)
        str_for_write += '\"' + png_file + '\"'
        if i < len(list_all_png) - 1:
            str_for_write += ','
        str_for_write += '\n'
    str_for_write = str_for_write.replace('\\', '/')
    str_for_write += '}'
    f = open('.\\zzz_output_encode_png.txt', 'w')
    f.write(str_for_write)
    f.close()

if __name__ == "__main__":
    # step 1
    func_get_filename('.\\Resources')
    func_save_all_filename()
    # step 2
    str1 = func_generate_hash_map_2()
    func_modify_cpp_file(str1)
    # step 3
    func_rename_and_move_file()
    # step 4
    #func_write_jpg_list_to_file(func_encode_pic('.jpg'))
    func_write_png_list_to_file(func_encode_pic('.png'))
    os.rename(".\\Resources", ".\\ResourcesOld")
    os.rename(".\\Resources2", ".\\Resources")
    #os.remove(".\\zzz_output_1.txt")
    #os.remove(".\\zzz_output_2.txt")
    #os.remove(".\\zzz_output_2.cpp")

拷贝上面的代码,保存成一个Python文件,比方说叫 a.py ,放到跟 Resources 同级的目录下。

在此目录下打开命令行,输入 python a.py

执行完后,会生成一个新的 Resources 目录。原来的目录会被改名为 ResourcesOld

cocos2d/cocos/platform/CCFileUtils.cpp这个文件会被修改。

加密图片

  1. 目前只加密了png图片,即 zzz_output_encode_png.txt 这个文件里的图片。如果你想加密别的,可以修改脚本。

  2. 双击执行 ConsoleApplication2.exe,执行完后会发现 Resources 目录下的png图片被修改过了。

运行程序

删除 Debug.win32 目录下的 Resources 文件夹,保证用的是新的 Resources 目录。