Files
LayaNative2.0/Conch/source/common/downloadCache/JCServerFileCache.cpp
T
2024-07-12 11:44:27 +08:00

929 lines
29 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
@file JCServerFileCache.cpp
@brief
@author guo
@version 1.0
@date 2016_5_11
*/
#include "JCServerFileCache.h"
#include "../downloadCache/JCFileTable.h"
#include "../util/JCCrypto.h"
#include "../util/JCSimpleCRC.h"
#include <zlib.h>
#include <sys/stat.h>
#include "../resource/JCFileResManager.h"
#include "../fileSystem/JCFileSystem.h"
#include "../util/JCCommonMethod.h"
#include "../util/Log.h"
#include "../util/JCZipFile.h"
#include "../util/JCCrypto.h"
#include <time.h>
#include <chrono>
#include "../downloadMgr/JCHttpHeader.h"
#ifdef ANDROID
#include "../downloadCache/JCAndroidFileSource.h"
#elif __APPLE__
#include "../downloadCache/JCIosFileSource.h"
#elif OHOS
#include "../downloadCache/JCOHOSFileSource.h"
#include "napi/plugin_manager.h"
#endif
#define PATH_SOURCEID "sourceid"
#define ERROR_FILE_C_R_W (-6)
extern std::string gRedistPath;
//这个对象不依赖于process,所以放到外面。
#ifdef ANDROID
AAssetManager* g_pAssetManager=nullptr;
std::string gAssetRootPath="";
std::string gAPKExpansionMainPath="";
std::string gAPKExpansionPatchPath="";
#elif __APPLE__
extern std::string gAssetRootPath;
#elif OHOS
NativeResourceManager* g_pAssetManager = nullptr;
std::string gAssetRootPath="";
#else
std::string gAssetRootPath="d:/temp/myassets";
#endif
namespace laya
{
#define FALSE_RET(v,msg,...) {if(!(v)){ /*LOGE(msg,__VA_ARGS__);*/ return false;}}
#define FALSE_RET0(v,msg) {if(!(v)){ LOGE(msg); return false;}}
JCServerFileCache::SessionFileCacheType JCServerFileCache::s_bSessionCacheType =
JCServerFileCache::CT_ValidInCurProcess;
JCCachedFileSys::JCCachedFileSys() {
memset(m_HasDir, 0, sizeof(m_HasDir));
}
std::string JCCachedFileSys::fileToStr( JCCachedFileSys::typeFile file, bool bHex ){
char ret[32];
if( bHex )
sprintf(ret, "%08x", file );
else
sprintf(ret, "%u", file );
return std::string(ret);
}
JCCachedFileSys::typeChkSum JCCachedFileSys::hashRaw(const char* p_pszStr){
if(!p_pszStr)
return 0;
return ::crc32(0, (const Bytef*)p_pszStr, strlen(p_pszStr));
}
void JCCachedFileSys::setCachePath(const char* p_pszPath){
m_strCacheFilesPath = p_pszPath;
memset(m_HasDir, 0, sizeof(m_HasDir));
/* 有两种方案,一种是在这里创建所有的目录,这样下载某个文件的时候就不用再检查和创建了。
这种可能会启动的时候慢一些,文件少的时候查找慢一些。
std::string preDir = m_strCacheFilesPath+"00/";
const char* pPreDir = preDir.c_str();
int stPos = m_strCacheFilesPath.length();
static unsigned char hexchar[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
for(int i=0; i<256; i++){
unsigned char v=i;
preDir[stPos]=hexchar[((v&0xf0)>>4)];
preDir[stPos+1]=hexchar[(v&0xf)];
if( !fs::exists(pPreDir)){
//如果目录不存在
fs::create_directories(pPreDir);
}
}
*/
}
bool JCCachedFileSys::load(const char* p_pszFile, JCSharedBuffer& p_BufRet, fileShell& p_nFs,
time_t& p_tmLastModify){
std::lock_guard<std::recursive_mutex> lock(m_lockFileRW);
struct stat buf;
int fd=0;
FILE* pf = fopen(p_pszFile,"rb+");
if(pf){//如果存在文件
fd = fileno(pf);
fstat(fd, &buf);
p_tmLastModify = buf.st_mtime; //最后修改时间
//fseek(pf,0,SEEK_END);
unsigned int filesz = buf.st_size;// ftell(pf); //注意:这个函数对于超过2G的文件无法返回正确的结果
//fseek(pf,0,SEEK_SET);
int l = fread(&p_nFs,1,sizeof(fileShell),pf);
if(l<sizeof(fileShell)){
fclose(pf);
LOGE("Error! JCServerFileCache::loadInCache read error! len=%d, should %d\n",l, sizeof(fileShell));
//throw -1;
return false;
}
if( !p_nFs.ready){
fclose(pf);
return false;
}
int contentSz = filesz-sizeof(fileShell);
if(contentSz>0){
p_BufRet.create(contentSz);
int nReadSz = fread(p_BufRet.m_pBuffer.get(), 1, contentSz, pf);
if( nReadSz!=contentSz ){
//LOGE("Error! JCServerFileCache::_loadFromCache fread error, want=%d, read=%d\n", contentSz, nReadSz);
fclose(pf);
return false;
}
}
fclose(pf);
return true;
}else
return false;
}
bool JCCachedFileSys::loadShell(const char* p_pszFile, fileShell& p_nFs, time_t& p_tmLastModify){
std::lock_guard<std::recursive_mutex> lock(m_lockFileRW);
struct stat buf;
int fd=0;
FILE* pf = fopen(p_pszFile,"rb+");
if(pf){//如果存在文件
fd = fileno(pf);
fstat(fd, &buf);
p_tmLastModify = buf.st_mtime; //最后修改时间
//fseek(pf,0,SEEK_END);
unsigned int filesz = buf.st_size;// ftell(pf); //注意:这个函数对于超过2G的文件无法返回正确的结果
//fseek(pf,0,SEEK_SET);
int l = fread(&p_nFs,1,sizeof(fileShell),pf);
if(l<sizeof(fileShell)){
fclose(pf);
LOGE("Error! JCServerFileCache::loadInCache read error! len=%d, should %d\n",l, sizeof(fileShell));
//throw -1;
return false;
}
if( !p_nFs.ready){
fclose(pf);
return false;
}
int contentSz = filesz-sizeof(fileShell);
if(contentSz>0){
}
fclose(pf);
return true;
}else
return false;
}
bool JCCachedFileSys::load(typeFile p_nFileID, typeChkSum& p_nChkSum, JCSharedBuffer& p_bufRet){
std::string path;
std::string pathfile = fileToPath(p_nFileID,path,false);
fileShell fs;
time_t tmModify = 0;
bool bret = load(pathfile.c_str(), p_bufRet, fs, tmModify);
p_nChkSum = fs.chkSum;
return bret;
}
JCCachedFileSys::typeChkSum JCCachedFileSys::getChkSum( char* p_pBuff, int p_nLen ){
JCSimpleCRC crc;
crc.process_bytes(p_pBuff, p_nLen);
typeChkSum chksum = crc.checksum();
return chksum;
}
std::string JCCachedFileSys::updateAFile(typeFile p_nFileID, char* p_pBuff, int p_nLen, typeChkSum p_nChkSum,
bool p_bExtVersion, time_t p_tmExpiredTm, bool p_bWithProcess){
std::lock_guard<std::recursive_mutex> lock(m_lockFileRW);
//写文件
std::string path;
try {
std::string pathfile = fileToPath(p_nFileID,path,true);
FILE* pf = fopen(pathfile.c_str(),"wb");
if(pf){
fileShell fs;
if (p_bExtVersion)
fs.extVersionMgr = 1;
fs.chkSum = p_nChkSum;
fs.expiredTime = p_tmExpiredTm;
fs.withprocess = p_bWithProcess;
//p_tmExpiredTm==0也是持久的。==0并且不持久的话,不会到这里
if (p_bExtVersion || p_nChkSum != 0 || p_tmExpiredTm==0) {
fs.tmpFile = 0;
#ifdef _DEBUG
if (p_tmExpiredTm != 0) {
LOGE("持久缓存类型的文件,不能设置失效期");
*(int*)0 = 10;
}
#endif
}
else {
fs.tmpFile = 1;
#ifdef _DEBUG
if (p_tmExpiredTm == 0) {
LOGE("临时缓存类型的文件,必须设置失效期");
*(int*)0 = 10;
}
#endif
}
int l = fwrite(&fs,1,sizeof(fs),pf);
if(l<sizeof(fs)){
fclose(pf);
throw ERROR_FILE_C_R_W;
}
l = fwrite( p_pBuff, 1,p_nLen, pf);
if(l<p_nLen){
fclose(pf);
throw ERROR_FILE_C_R_W;
}
fs.ready=true;
fflush(pf);
fseek(pf,0,SEEK_SET);
l = fwrite(&fs,1,sizeof(fs),pf);
if(l<sizeof(fs)){
fclose(pf);
throw ERROR_FILE_C_R_W;
}
fflush(pf);
fclose(pf);
return pathfile;
}else{
//打开文件失败,应该是目录不对,或者没有权限。
LOGE("Error! JCServerFileCache::onFileDownloaded fopen error! file=%08x\n", p_nFileID);
throw ERROR_FILE_C_R_W;
}
}catch(...){
if( global_onCreateFileError){
global_onCreateFileError();
}
}
static string errret = "";
return errret;
}
void JCCachedFileSys::delFromCache( typeFile p_nFileID ){
std::string path;
std::string pathfile = fileToPath(p_nFileID,path,false);
remove(pathfile.c_str());
}
bool JCCachedFileSys::createShell(JCCachedFileSys::typeFile p_nFileID, JCCachedFileSys::typeChkSum p_nChkSum){
std::lock_guard<std::recursive_mutex> lock(m_lockFileRW);
std::string path;
try{
std::string pathfile = fileToPath(p_nFileID, path,true);
FILE* pf = fopen(pathfile.c_str(),"wb");
if(pf){
fileShell fs;
fs.chkSum = p_nChkSum;
int l = fwrite(&fs,1,sizeof(fs),pf);
if(l<sizeof(fs)){
fclose(pf);
throw ERROR_FILE_C_R_W;
}
fclose(pf);
return true;
}else{
//打开文件失败,应该是目录不对,或者没有权限。
throw ERROR_FILE_C_R_W;
return false;
}
}catch(...){
if( global_onCreateFileError){
global_onCreateFileError();
}
return false;
}
return true;
}
bool JCCachedFileSys::createLink( const char* p_pszFile, typeChkSum p_nChkSum){
std::lock_guard<std::recursive_mutex> lock(m_lockFileRW);
try{
FILE* linkf = fopen(p_pszFile, "wb");
if(!linkf){
LOGE("Error: can't create link file %s\n", p_pszFile);
throw ERROR_FILE_C_R_W;
return false;
}
fileShell fs;
fs.link = 1;
fs.chkSum=p_nChkSum;
fs.ready = 1;
int l = fwrite(&fs,1,sizeof(fs),linkf);
if(l<sizeof(fs)){
fclose(linkf);
throw ERROR_FILE_C_R_W;
}
fclose(linkf);
}catch(int e){
if( e==ERROR_FILE_C_R_W && global_onCreateFileError){
global_onCreateFileError();
}
return false;
}
return true;
}
long JCCachedFileSys::size() {
return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////
JCServerFileCache::JCServerFileCache(){
m_pAssets = NULL;
/*
#ifdef ANDROID
m_pAssets = new JCAndroidFileSource();
#elif __APPLE__
m_pAssets = new JCIosFileSource();
#elif OHOS
m_pAssets = new JCOHOSFileSource();
#endif
*/
m_pFileTable=NULL;
m_strAppPath="app";
m_tmCacheMgrCreateTime = 0;
}
JCServerFileCache::~JCServerFileCache(){
if( m_pFileTable ){
delete m_pFileTable;
m_pFileTable=NULL;
}
if( m_pAssets ){
delete m_pAssets ;
m_pAssets = NULL;
}
}
void JCServerFileCache::saveFileTable(const char* p_pszFileContent)
{
if(!p_pszFileContent)
p_pszFileContent="";//写空的
std::string file = this->getAppPath()+"/"+"filetable.txt";
JCBuffer buf((char*)p_pszFileContent, strlen(p_pszFileContent),false,false);
writeFileSync( file.c_str(), buf, JCBuffer::utf8);
}
void JCServerFileCache::setCachePath( const char* p_pszCachePath ){
static char buf[512];
int len = strlen(p_pszCachePath);
strcpy(buf,p_pszCachePath);
if( p_pszCachePath[len-1]=='\\' )buf[len-1]='/';
else if(buf[len-1]!='/')strcat(buf,"/");
m_strCachePath = buf;
LOGI("setCachePath:%s", buf);
try{
if( !fs::exists(m_strCachePath.c_str())){
//如果目录不存在
fs::create_directories(m_strCachePath.c_str());
}
}catch(...){
if( global_onCreateFileError){
global_onCreateFileError();
}
}
}
std::string& replace_all(std::string& str,const std::string& old_value, const std::string& new_value){
while(true) {
std::string::size_type pos(0);
if( (pos=str.find(old_value))!=std::string::npos )
str.replace(pos,old_value.length(),new_value);
else break;
}
return str;
}
void JCServerFileCache::switchToApp(const char* p_pszWebBase){
static char buf[512];
int len = strlen(p_pszWebBase);
strcpy(buf,p_pszWebBase);
if( buf[len-1]=='\\') buf[len-1]='/';
else if(buf[len-1]!='/')strcat(buf,"/");
m_strWebBase = buf;
JCCachedFileSys::typeChkSum appurlchk = m_FileSys.hashRaw(p_pszWebBase);
sprintf(buf,"%08x", appurlchk);
m_strAppPath = buf;
//文件对象目录
m_strCacheFilesPath = m_strCachePath+m_strAppPath+ "/files/";
try {
if (!fs::exists(m_strCacheFilesPath.c_str())) {
//如果目录不存在
fs::create_directories(m_strCacheFilesPath.c_str());
}
}
catch (...) {
if(global_onCreateFileError)
global_onCreateFileError();
}
m_FileSys.setCachePath( m_strCacheFilesPath.c_str());
//资源id目录
std::string sourceidPath = m_strCachePath+m_strAppPath+ "/"+PATH_SOURCEID+"/";
try {
if (!fs::exists(sourceidPath.c_str())) {
fs::create_directories(sourceidPath.c_str());
}
}
catch (...) {
if(global_onCreateFileError)
global_onCreateFileError();
}
std::string tmpWebBase = m_strWebBase;
if(tmpWebBase[tmpWebBase.length()-1]=='/' || tmpWebBase[tmpWebBase.length()-1]=='\\'){
tmpWebBase = tmpWebBase.substr(0,tmpWebBase.length()-1);
}
replace_all(tmpWebBase,"http://","");
replace_all(tmpWebBase,":",".");
replace_all(tmpWebBase,"/","_");
replace_all(tmpWebBase,"\\","_");
std::string assetsPath = gAssetRootPath+"/"+tmpWebBase;
JCFileSource* pFileReader = NULL;
#ifdef ANDROID
if(g_pAssetManager)
{
JCAndroidFileSource* pAssets = new JCAndroidFileSource();
pAssets->Init((AAssetManager*)g_pAssetManager, assetsPath.c_str(), gAPKExpansionMainPath, gAPKExpansionPatchPath, tmpWebBase);
pFileReader = pAssets;
}
else
{
JCZipFile* pfr = new JCZipFile();
if( pfr->open(gAssetRootPath.c_str())){
pfr->InitDir(assetsPath.c_str());
pFileReader = pfr;
}else{
LOGE("打开jar失败:%s", gAssetRootPath.c_str());
delete pfr;
}
}
#elif __APPLE__
JCIosFileSource* pAssets = new JCIosFileSource();
pAssets->Init(assetsPath.c_str());
pFileReader = pAssets;
#elif OHOS
JCOHOSFileSource* pAssets = new JCOHOSFileSource();
pAssets->Init((NativeResourceManager*)g_pAssetManager, assetsPath.c_str());
pFileReader = pAssets;
#endif
setAssets( pFileReader);
if(m_pFileTable){
delete m_pFileTable;
m_pFileTable=NULL;
}
std::string filetable = getAppPath()+"/"+"filetable.txt";
JCBuffer ftbuf;
readFileSync(filetable.c_str(), ftbuf, JCBuffer::utf8);
LOGI("read index:%s", filetable.c_str());
if(ftbuf.m_pPtr)
setFileTables(ftbuf.m_pPtr);
else
LOGW("read DCC file table failed");
time(&m_tmCacheMgrCreateTime);
}
void JCServerFileCache::clearAllCachedFile() {
//保护一下,防止设置错误导致的删除了其他目录
if (m_strCachePath.length() < 4 || m_strAppPath.length() <= 0) {
LOGE("clearAllCachedFile error");
return;
}
std::string sourceidPath = m_strCachePath + m_strAppPath + "/files/";
try {
fs::remove_all(sourceidPath.c_str());
fs::create_directories(sourceidPath.c_str());
}
catch (...) {
}
}
std::string JCServerFileCache::getAppPath(){
return m_strCachePath+m_strAppPath;
}
JCCachedFileSys::typeChkSum JCServerFileCache::hashURLR(const char* p_pszURL ){
if(!p_pszURL)
return 0;
static char url[512];
//前面加上'/'主要是为了与以前的版本兼容。
if( p_pszURL[0]!='/'){
url[0]='/'; url[1]=0;
strcat(url,p_pszURL);
return m_FileSys.hashRaw(url);
}
return m_FileSys.hashRaw(p_pszURL);
}
void JCServerFileCache::setAssets( JCFileSource* pAssets ){
if( m_pAssets ){
delete m_pAssets ;
m_pAssets = NULL;
}
m_pAssets = pAssets;
/*
说明:
如果 assetsid和本地记录的assetsid 不一致,则表示重新安装了(较少可能是清理资源了),则从资源包中拷贝filetable,并记录资源id
如果之前已经从网络更新过,则相当于抛弃掉网络下载的filetable
如果没有资源包信息,则不从资源包更新assetsid和filetable。一切从网络下载。
网络获得的assetsid在本地记录为netassetsid
*/
//打开资源中的版本
char* assetsid = NULL;
int assetsidLen = 0;
if( m_pAssets->isFileExist("assetsid.txt"))
{
if( m_pAssets->loadFileContent("assetsid.txt", assetsid, assetsidLen) == false)
{
LOGE("something was wrong that reading file assetsid.txt from the resource package.\n");
}
}
//查看版本,看是否需要更新
std::string cachedAssetsID = getResourceID("assetsid");
//拷贝资源包中的fileTable
const char* ftfile="filetable.txt";
std::string filetable = getAppPath()+"/"+ftfile;
bool hasAssetsFt = m_pAssets->isFileExist(ftfile);
bool hasAssetsID = assetsidLen>0;
bool hasAssets = hasAssetsFt || hasAssetsID ;
if(hasAssets && (cachedAssetsID.length()==0 || assetsidLen != cachedAssetsID.length()|| strcmp(assetsid, cachedAssetsID.c_str())!=0) ){
//清理文件缓存
clearAllCachedFile();
//先获取资源中的filteTable
char* pFileTableBuf=NULL;
int nFileTableLen = 0;
if(hasAssetsFt)
{
if( m_pAssets->loadFileContent(ftfile, pFileTableBuf, nFileTableLen ) == false )
{
LOGE("read the file which names filetable.txt error!");
}
}
else
{
LOGI("the file which names filetable.txt is not exist");
}
if( pFileTableBuf )
{
//如果没有指定assetsid,则需要根据filetables来计算
if( assetsidLen==0 ){
JCCachedFileSys::typeChkSum chksum = m_FileSys.hashRaw(pFileTableBuf);
sprintf(assetsid,"%x",chksum);
assetsidLen = strlen(assetsid);
if( assetsidLen==cachedAssetsID.length() && strcmp(assetsid,cachedAssetsID.c_str())==0)
{
delete[] assetsid;
delete[] pFileTableBuf;
return;
}
}
try
{
writeFileSync1(filetable.c_str(), pFileTableBuf, nFileTableLen);
}
catch (...)
{
if(global_onCreateFileError)
global_onCreateFileError();
}
delete[] pFileTableBuf;
//记录资源id
setResourceID("assetsid",assetsid);
}
else{
char emptybuf[]={'\0'};
JCBuffer ftbuf(emptybuf,sizeof(emptybuf),false,false);
try {
writeFileSync(filetable.c_str(), ftbuf);
}
catch (...) {
if(global_onCreateFileError)
global_onCreateFileError();
}
}
}
delete[] assetsid;
}
int JCServerFileCache::setFileTables(const char* p_pszFiles ){
if( m_pFileTable ){
delete m_pFileTable;
m_pFileTable = NULL;
}
m_pFileTable = new JCFileTable();
//buffer buf;
//readFileSync(p_pszFile, buf, buffer::utf8);
return m_pFileTable->initByString(p_pszFiles);
}
/**
这个能处理绝对路径和相对路径,以后要代替 hashURLFull和 hashURLR
*/
unsigned int JCServerFileCache::getFileID(const char* Url) {
if (Url==nullptr)
return 0;
char* nUrl = (char*)Url;
bool bChanged = false;
if (m_pFuncTransUrl && m_pFuncTransUrlData) {
//先做外部提供的url转换。url转换通常是为了让不同的url指向同一个缓存,例如不同的cdn指向同一个缓存。
nUrl = (*m_pFuncTransUrl)(m_pFuncTransUrlData,Url);
if (!nUrl)
nUrl = (char*)Url;
else if(nUrl!=Url)//这里有个规则,就是转换函数不允许直接操作字符串内存。
bChanged = true;
}
int len = strlen(nUrl);
char* pRelUrl =(char*)nUrl;
bool isAbs = (len > 7 && memcmp(nUrl, "http://", 7)==0) || (len > 8 && memcmp(nUrl, "https://", 8)==0);
if (isAbs) {
if (memcmp(nUrl, m_strWebBase.c_str(), m_strWebBase.length()) == 0) {
pRelUrl = (char*)(nUrl + m_strWebBase.length() - 1);
}
else {
LOGW("Error: %s[%s] does not belong to the same app domain: %s ", Url,(bChanged?nUrl:""), m_strWebBase.c_str());
return m_FileSys.hashRaw(Url);
}
}
//如果是相对路径需要保证以/开头
static char _url[512];//注意:这个是非线程安全的
//前面加上'/'主要是为了与以前的版本兼容。
if (pRelUrl[0] != '/') {
_url[0] = '/'; _url[1] = 0;
strcat(_url, pRelUrl);
pRelUrl = _url;
}
unsigned int hv = m_FileSys.hashRaw(pRelUrl);
//然后再做相对路径的转换。
auto it = m_UrlTrans.find(hv);
if (it != m_UrlTrans.end()) {
hv = m_FileSys.hashRaw(it->second.c_str());
}
return hv;
}
void JCServerFileCache::setUrlTransTable(const char* p_pszTable,char split) {
m_UrlTrans.clear();
const char* pCur = p_pszTable;
const char* pCurData = pCur;
static char svUrl[2048];
static char cacheUrl[2048];
while (*pCur != 0) {
while (*pCur == split || *pCur == '\r' || *pCur == '\n') {
pCur++;
}
if (*pCur == 0)
break;
const char* pData = pCur; //起点
while (*pCur != split && *pCur != 0) {
pCur++;
}
int len = (long)pCur - (long)pData ;
memcpy(svUrl, pData, len);
svUrl[len] = 0;
if (*pCur == 0)
break;
while (*pCur == split || *pCur == '\r' || *pCur == '\n') {
pCur++;
}
if (*pCur == 0)
break;
pData = pCur;
while (*pCur != '\r'&&*pCur != '\n'&&*pCur != 0) {
pCur++;
}
len = (long)pCur - (long)pData;
memcpy(cacheUrl, pData, len);
cacheUrl[len] = 0;
int hv = m_FileSys.hashRaw(svUrl);
if (m_UrlTrans.find(hv) != m_UrlTrans.end()) {
LOGE("错误:设置url转换表有问题,路径重复,或者hash计算冲突!这个会导致更新cache或者从cache中取文件的时候出错!");
}
m_UrlTrans[hv] = cacheUrl;
}
}
int JCServerFileCache::reloadDccFile() {
std::string filetable = getAppPath() + "/" + "filetable.txt";
JCBuffer ftbuf;
readFileSync(filetable.c_str(), ftbuf, JCBuffer::utf8);
LOGI("read index:%s", filetable.c_str());
if (ftbuf.m_pPtr)
return setFileTables(ftbuf.m_pPtr);
else
LOGE("read index failed");
return 0;
}
bool JCServerFileCache::getFileInfo(unsigned int p_nFileID, unsigned int& p_nChkSum ){
if( !m_pFileTable )
return false;
return m_pFileTable->find(p_nFileID, p_nChkSum );
}
bool _after_cache_loaded(const char* pfilename, char* ptr, int len, char*& newptr, int& newlen) {
//如果加密了要先解密
int rlen = len;
bool temp = JCEncrypt::decrypt(ptr, rlen);
if (temp) {
rlen = rlen - JCEncrypt::s_nPreLen;
}
newlen = rlen;
newptr = ptr;
return temp;
}
bool JCServerFileCache::load(JCCachedFileSys::typeFile p_nFileID, JCCachedFileSys::typeChkSum& p_nChkSum,
JCSharedBuffer& p_bufRet, bool p_bUseVersion, bool doCheckSum) {
bool bret = __load(p_nFileID, p_nChkSum, p_bufRet, p_bUseVersion, doCheckSum);
char* ptr = p_bufRet.m_pBuffer.get();
if (bret && p_bufRet.m_nLen && ptr) {
char* newptr = nullptr;
int newlen = 0;
bool bchanged = _after_cache_loaded(nullptr, ptr, p_bufRet.m_nLen, newptr, newlen);
if (bchanged) {
}
if (newptr ){
if (newptr != ptr) {
p_bufRet.create(newlen);
memcpy(p_bufRet.m_pBuffer.get(), newptr, newlen);
delete[] newptr;
}
else {
if (newlen < p_bufRet.m_nLen) {
p_bufRet.m_nLen = newlen;//这个需要重新分配一下么
}
}
}
}
return bret;
}
bool JCServerFileCache::__load(JCCachedFileSys::typeFile p_nFileID, JCCachedFileSys::typeChkSum& p_nChkSum,
JCSharedBuffer& p_bufRet, bool p_bUseVersion, bool doCheckSum){
try {
std::string path;
std::string pathfile = m_FileSys.fileToPath(p_nFileID, path, true);
//struct stat statbuf;
//if(stat(pathfile, &statbuf)<0){
// if( errno == ENOENT){//文件不存在
// }
//}
JCCachedFileSys::typeChkSum assetChk = 0;
JCCachedFileSys::fileShell fs;
time_t tmModify = 0;
if (m_FileSys.load(pathfile.c_str(), p_bufRet, fs,tmModify)) {
//如果已经读取到了
if (fs.link) {
//资源包中的文件一定是要管理的。
FALSE_RET(_loadFromAssets(p_nFileID, p_bufRet, assetChk, p_nChkSum != 0), "Error! _loadFromAssets failed :file=%08x\n", p_nFileID);
FALSE_RET0((!p_nChkSum || assetChk == p_nChkSum), "Waring! _loadFromAssets returns incorrect contents! what happened!\n");
}
else {
if (!fs.ready) //如果还没下载下来
return false;
//如果是其他版本的不能使用
if (fs.version != CURCACHEFILEVER)
return false;
//不检查版本号的话,就成功了
if (!doCheckSum)
return true;
if (p_bUseVersion) {
return (fs.extVersionMgr && fs.chkSum == p_nChkSum);
}
else if (p_nChkSum) {
return (fs.chkSum == p_nChkSum);
}
//不走dcc和版本号的话。
switch (s_bSessionCacheType) {
case CT_AllwaysReload:
return false;
break;
case CT_UseHeaderInfo:
break;
case CT_ValidInCurProcess:
default:
//如果没有校验值,就是临时文件,通过时间来判断是不是新的(比管理器启动时间大就是新的)。
return tmModify >= m_tmCacheMgrCreateTime;
}
}
return true;
}
else {
FALSE_RET(_loadFromAssets(p_nFileID, p_bufRet, assetChk), "Error! _loadFromAssets failed :file=%08x\n", p_nFileID);
FALSE_RET0((!p_nChkSum || assetChk == p_nChkSum), "Waring! _loadFromAssets returns incorrect contents! what happened!\n");
return m_FileSys.createLink(pathfile.c_str(), assetChk);
}
}catch (...) {
if (global_onCreateFileError) {
global_onCreateFileError();
}
}
return false;
}
bool JCServerFileCache::load(unsigned int nFileID, JCBuffer& buff, bool doCheckSum) {
unsigned int chksum = 0;
JCSharedBuffer sbuf;
//如果是dcc的,就能获得一个chksum
bool inDcc = getFileInfo(nFileID, chksum);
bool bloaded = load(nFileID, chksum, sbuf,false, doCheckSum);
if (bloaded && sbuf.m_pBuffer.get()) {
buff.create(sbuf.m_nLen);
memcpy(buff.m_pPtr, sbuf.m_pBuffer.get(), sbuf.m_nLen);
return true;
}
return false;
}
bool JCServerFileCache::loadShell(const char* p_pszFile, JCCachedFileSys::fileShell& p_nFs, time_t& p_tmLastModify) {
return m_FileSys.loadShell(p_pszFile, p_nFs, p_tmLastModify);
}
std::string JCCachedFileSys::fileToPath(typeFile p_nFile, std::string& p_strPath, bool p_bCreateDir) {
std::string file = fileToStr(p_nFile, true);
std::string fileGroup = file.substr(0, 2);
p_strPath = m_strCacheFilesPath + fileGroup + "/";
file = p_strPath + file.substr(2, file.length());
//因为这里比较容易得到子目录,所以检测和创建目录放到这个函数里面。
if (p_bCreateDir) {
const char* pFG = fileGroup.c_str();
int dirID = hexStringToInt(pFG);
if (!hasDir(dirID)) {
if (!fs::exists(p_strPath.c_str())) {
//如果目录不存在
fs::create_directories(p_strPath.c_str());
setHasDir(dirID);
}
else {
setHasDir(dirID);
}
}
}
return file;
}
unsigned char* AllocSharedBuffer(int sz, void* pUserData) {
JCSharedBuffer* pSB = (JCSharedBuffer*)pUserData;
if (!pSB)
return NULL;
pSB->create(sz);
return (unsigned char*)pSB->m_pBuffer.get();
}
bool JCServerFileCache::_loadFromAssets(JCCachedFileSys::typeFile p_nFileID, JCSharedBuffer& p_BufRet, JCCachedFileSys::typeChkSum& p_nChkSum, bool p_bGetChkSum ){
if (!m_pAssets)
return false;
int sz = 0;
//2M,4ms
if (m_pAssets->loadFileContent(m_FileSys.fileToStr(p_nFileID,true).c_str(),AllocSharedBuffer, (void*)&p_BufRet, sz)) {
//生成校验码
if (p_bGetChkSum) {
JCSimpleCRC crc;
crc.process_bytes(p_BufRet.m_pBuffer.get(), sz);
p_nChkSum = crc.checksum();
}
return true;
}
return false;
}
void JCServerFileCache::updateAll( JCFileTable* p_pTable, funcOnUpdateOK p_OnUpdateOK ){
JCFileTable* pUsedTable = p_pTable?p_pTable:m_pFileTable;
}
void JCServerFileCache::setResourceID(const char* p_pszResource, const char* p_pszVal){
if(!p_pszVal)
return;
std::string resourceidfile = getAppPath()+"/"+PATH_SOURCEID+"/"+p_pszResource;
JCBuffer buf((char*)p_pszVal,strlen(p_pszVal),false,false);
writeFileSync(resourceidfile.c_str(),buf,JCBuffer::utf8);
}
std::string JCServerFileCache::getResourceID(const char* p_pszResource ){
std::string resourceidfile = getAppPath()+"/"+PATH_SOURCEID+"/"+p_pszResource;
JCBuffer buf;
readFileSync(resourceidfile.c_str(),buf, JCBuffer::utf8);
if( buf.m_pPtr )
return buf.m_pPtr;
return "";
}
}
//------------------------------------------------------------------------------