图片加密
修改 CCFileUtils 这个类
在头文件
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;//新增的代码 }
在实现文件里修改一下构造函数,用来初始化刚才添加的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的代码:
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
这个文件会被修改。
加密图片
目前只加密了png图片,即
zzz_output_encode_png.txt
这个文件里的图片。如果你想加密别的,可以修改脚本。双击执行 ConsoleApplication2.exe,执行完后会发现 Resources 目录下的png图片被修改过了。
运行程序
删除 Debug.win32 目录下的 Resources 文件夹,保证用的是新的 Resources 目录。