open source
This commit is contained in:
@@ -0,0 +1,285 @@
|
||||
/**
|
||||
@file JCAndroidFileSource.h
|
||||
@brief
|
||||
@author James
|
||||
@version 1.0
|
||||
@date 2016_5_11
|
||||
*/
|
||||
|
||||
#ifndef __JCAndroidFileSource_H__
|
||||
#define __JCAndroidFileSource_H__
|
||||
|
||||
//包含头文件
|
||||
#include "JCFileSource.h"
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/log.h>
|
||||
#include "../util/Log.h"
|
||||
#include "../util/JCZipFile.h"
|
||||
|
||||
namespace laya{
|
||||
|
||||
class JCAndroidFileSource : public JCFileSource
|
||||
{
|
||||
public:
|
||||
JCAndroidFileSource()
|
||||
{
|
||||
m_pszRoot = 0;
|
||||
m_pMgr = 0;
|
||||
m_pZipAPKExpansionMain = 0;
|
||||
m_pZipAPKExpansionPatch = 0;
|
||||
}
|
||||
~JCAndroidFileSource()
|
||||
{
|
||||
if( 0 != m_pszRoot )
|
||||
{
|
||||
delete[] m_pszRoot;
|
||||
m_pszRoot = 0;
|
||||
}
|
||||
if( 0 != m_pZipAPKExpansionMain )
|
||||
{
|
||||
delete m_pZipAPKExpansionMain;
|
||||
m_pZipAPKExpansionMain = 0;
|
||||
}
|
||||
if( 0 != m_pZipAPKExpansionPatch )
|
||||
{
|
||||
delete m_pZipAPKExpansionPatch;
|
||||
m_pZipAPKExpansionPatch = 0;
|
||||
}
|
||||
}
|
||||
bool Init( AAssetManager *p_pMgr, const char *p_pszRoot ,const std::string& strAPKExpansionMain, const std::string& strAPKExpansionPatch, const std::string& strWebBase)
|
||||
{
|
||||
m_pMgr = p_pMgr;
|
||||
if( 0 != m_pszRoot )
|
||||
{
|
||||
delete[] m_pszRoot;
|
||||
m_pszRoot = 0;
|
||||
}
|
||||
int len;
|
||||
if( 0 != p_pszRoot && 0 != (len=strlen(p_pszRoot)) )
|
||||
{
|
||||
m_pszRoot = new char[len+1];
|
||||
memcpy( m_pszRoot, p_pszRoot, len+1 );
|
||||
|
||||
if( '\\' == m_pszRoot[len-1] || '/' == m_pszRoot[len-1] )
|
||||
{
|
||||
m_pszRoot[len-1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (strAPKExpansionMain != "")
|
||||
{
|
||||
m_pZipAPKExpansionMain = new JCZipFile();
|
||||
if( m_pZipAPKExpansionMain->open(strAPKExpansionMain.c_str()))
|
||||
{
|
||||
LOGE("打开zip成功:%s", strAPKExpansionMain.c_str());
|
||||
std::string root = "cache/" + strWebBase;
|
||||
m_pZipAPKExpansionMain->InitDir(root.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGE("打开zip失败:%s", strAPKExpansionMain.c_str());
|
||||
delete m_pZipAPKExpansionMain;
|
||||
m_pZipAPKExpansionMain = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (strAPKExpansionPatch != "")
|
||||
{
|
||||
m_pZipAPKExpansionPatch = new JCZipFile();
|
||||
if( m_pZipAPKExpansionPatch->open(strAPKExpansionPatch.c_str()))
|
||||
{
|
||||
LOGE("打开zip成功:%s", strAPKExpansionPatch.c_str());
|
||||
std::string root = "cache/" + strWebBase;
|
||||
m_pZipAPKExpansionPatch->InitDir(root.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGE("打开zip失败:%s", strAPKExpansionPatch.c_str());
|
||||
delete m_pZipAPKExpansionPatch;
|
||||
m_pZipAPKExpansionPatch = nullptr;
|
||||
}
|
||||
}
|
||||
return ((0!=m_pMgr)&&(0!=m_pszRoot));
|
||||
}
|
||||
public:
|
||||
|
||||
bool isFileExistInZipAPKExpansion(const char* p_pszFile)
|
||||
{
|
||||
if (m_pZipAPKExpansionMain && m_pZipAPKExpansionMain->isFileExist(p_pszFile))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_pZipAPKExpansionPatch && m_pZipAPKExpansionPatch->isFileExist(p_pszFile))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool isFileExist( const char* p_pszFile )
|
||||
{
|
||||
char szName[512];
|
||||
char* pathfile = (char*)p_pszFile;
|
||||
if( m_pszRoot ){
|
||||
sprintf(szName,"%s/%s", m_pszRoot, p_pszFile);
|
||||
pathfile = szName;
|
||||
}
|
||||
|
||||
AAsset *pFile = AAssetManager_open( m_pMgr, pathfile, AASSET_MODE_BUFFER );
|
||||
if( 0 != pFile )
|
||||
{
|
||||
AAsset_close( pFile );
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_pZipAPKExpansionMain && m_pZipAPKExpansionMain->isFileExist(p_pszFile))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_pZipAPKExpansionPatch && m_pZipAPKExpansionPatch->isFileExist(p_pszFile))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
virtual unsigned int getFileSize( const char* p_pszFile )
|
||||
{
|
||||
off_t iSize=0;
|
||||
char szName[512];
|
||||
char* pathfile = (char*)p_pszFile;
|
||||
if( m_pszRoot ){
|
||||
sprintf(szName,"%s/%s", m_pszRoot, p_pszFile);
|
||||
pathfile = szName;
|
||||
}
|
||||
AAsset *pFile = AAssetManager_open( m_pMgr, pathfile, AASSET_MODE_BUFFER );
|
||||
if( 0 != pFile )
|
||||
{
|
||||
off_t iSize = AAsset_getLength( pFile );
|
||||
AAsset_close( pFile );
|
||||
if (iSize >= 0)
|
||||
return iSize;
|
||||
}
|
||||
|
||||
if (m_pZipAPKExpansionMain)
|
||||
{
|
||||
int sz=0;
|
||||
int compsz=0;
|
||||
m_pZipAPKExpansionMain->getSize(p_pszFile,sz,compsz);
|
||||
if (sz > 0)
|
||||
{
|
||||
return sz;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pZipAPKExpansionPatch)
|
||||
{
|
||||
int sz=0;
|
||||
int compsz=0;
|
||||
m_pZipAPKExpansionPatch->getSize(p_pszFile,sz,compsz);
|
||||
if (sz > 0)
|
||||
{
|
||||
return sz;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
virtual bool loadFileContent( const char* p_pszFile, char*& p_pBuff, int& p_iBuffSize )
|
||||
{
|
||||
p_iBuffSize = 0;
|
||||
bool bRet = false;
|
||||
char szName[512];
|
||||
char* pathfile = (char*)p_pszFile;
|
||||
if (m_pszRoot) {
|
||||
sprintf(szName, "%s/%s", m_pszRoot, p_pszFile);
|
||||
pathfile = szName;
|
||||
}
|
||||
|
||||
AAsset *pFile = AAssetManager_open(m_pMgr, pathfile, AASSET_MODE_BUFFER);
|
||||
if (0 != pFile)
|
||||
{
|
||||
p_iBuffSize = AAsset_getLength(pFile);
|
||||
p_pBuff = new char[p_iBuffSize+1];
|
||||
if (p_iBuffSize == AAsset_read(pFile, p_pBuff, p_iBuffSize))
|
||||
{
|
||||
bRet = true;
|
||||
}
|
||||
p_pBuff[p_iBuffSize] = 0;
|
||||
AAsset_close(pFile);
|
||||
LOGI("found the file in the package:%s\n", pathfile);
|
||||
if (bRet)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pZipAPKExpansionMain && m_pZipAPKExpansionMain->loadFileContent( p_pszFile, p_pBuff, p_iBuffSize ))
|
||||
{
|
||||
LOGI("found the file in the package expansion main:%s\n", p_pszFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_pZipAPKExpansionPatch && m_pZipAPKExpansionPatch->loadFileContent( p_pszFile, p_pBuff, p_iBuffSize ))
|
||||
{
|
||||
LOGI("found the file in the package expansion patch:%s\n", p_pszFile);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
virtual bool loadFileContent(const char* p_pszFile, ALLOCMEM alloc, void* pUserData, int& p_iBuffSize)
|
||||
{
|
||||
p_iBuffSize = 0;
|
||||
bool bRet = false;
|
||||
char szName[512];
|
||||
char* pathfile = (char*)p_pszFile;
|
||||
if (m_pszRoot) {
|
||||
sprintf(szName, "%s/%s", m_pszRoot, p_pszFile);
|
||||
pathfile = szName;
|
||||
}
|
||||
|
||||
AAsset *pFile = AAssetManager_open(m_pMgr, pathfile, AASSET_MODE_BUFFER);
|
||||
if (0 != pFile)
|
||||
{
|
||||
p_iBuffSize = AAsset_getLength(pFile);
|
||||
unsigned char* pBuff = alloc(p_iBuffSize, pUserData);
|
||||
if (p_iBuffSize == AAsset_read(pFile, pBuff, p_iBuffSize))
|
||||
bRet = true;
|
||||
AAsset_close(pFile);
|
||||
LOGI("found the file in the package:%s\n", pathfile);
|
||||
if (bRet)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pZipAPKExpansionMain && m_pZipAPKExpansionMain->loadFileContent( p_pszFile, alloc, pUserData, p_iBuffSize ))
|
||||
{
|
||||
LOGI("found the file in the package expansion main:%s\n", p_pszFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_pZipAPKExpansionPatch && m_pZipAPKExpansionPatch->loadFileContent( p_pszFile, alloc, pUserData, p_iBuffSize))
|
||||
{
|
||||
LOGI("found the file in the package expansion patch:%s\n", p_pszFile);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
AAssetManager* m_pMgr;
|
||||
char* m_pszRoot;
|
||||
JCZipFile* m_pZipAPKExpansionMain;
|
||||
JCZipFile* m_pZipAPKExpansionPatch;
|
||||
};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#endif //__JCAndroidFileSource_H__
|
||||
|
||||
//-----------------------------END FILE--------------------------------
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
@file JCFileSource.h
|
||||
@brief
|
||||
@author James
|
||||
@version 1.0
|
||||
@date 2016_5_11
|
||||
*/
|
||||
|
||||
#ifndef __JCFileSource_H__
|
||||
#define __JCFileSource_H__
|
||||
|
||||
namespace laya
|
||||
{
|
||||
class JCFileSource
|
||||
{
|
||||
public:
|
||||
virtual ~JCFileSource() {};
|
||||
|
||||
virtual bool isFileExistInZipAPKExpansion(const char* sFileName) = 0;
|
||||
|
||||
/** @brief 直接判断包内是否存在这个文件
|
||||
* @param[in] 文件名字
|
||||
* @return 返回true或者false
|
||||
*/
|
||||
virtual bool isFileExist( const char* sFileName )=0;
|
||||
|
||||
|
||||
/** @brief 获得fileSize
|
||||
* @param[in] 文件名字
|
||||
* @return 返回size
|
||||
*/
|
||||
virtual unsigned int getFileSize(const char* sFileName)=0;
|
||||
|
||||
/** @brief 分配一段空间,函数指针,为了分配内存使用的
|
||||
* @param[in]
|
||||
* @param[in]
|
||||
* @return
|
||||
*/
|
||||
typedef unsigned char* (*ALLOCMEM)(int nBufferSize,void* pBuffer );
|
||||
|
||||
/** @brief 读取文件内容
|
||||
* @param[in] 文件名字
|
||||
* @param[in] alloc的函数指针,调用者自己决定分配策略
|
||||
* @param[in] 获得的buffer
|
||||
* @param[out] 返回的buffersize
|
||||
* @return 是否成功
|
||||
*/
|
||||
virtual bool loadFileContent( const char* sFileName, ALLOCMEM pAllocFunc, void* pUserData, int& nBuffSize ) = 0;
|
||||
|
||||
|
||||
/** @brief 读取文件内容
|
||||
* @param[in] 文件名字
|
||||
* @param[in] 获得的buffer
|
||||
* @param[out] 返回的buffersize
|
||||
* @return 是否成功
|
||||
*/
|
||||
virtual bool loadFileContent(const char* sFileName, char*& pBuffer, int& nBuffSize) = 0;
|
||||
};
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#endif //__JCFileSource_H__
|
||||
|
||||
//-----------------------------END FILE--------------------------------
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
@file JCFileTable.cpp
|
||||
@brief
|
||||
@author James
|
||||
@version 1.0
|
||||
@date 2016_5_11
|
||||
*/
|
||||
|
||||
#include "JCFileTable.h"
|
||||
#include "../fileSystem/JCFileSystem.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace laya
|
||||
{
|
||||
JCFileTable::JCFileTable(){
|
||||
}
|
||||
|
||||
JCFileTable::~JCFileTable(){
|
||||
}
|
||||
|
||||
void JCFileTable::init(){
|
||||
}
|
||||
|
||||
//fileid chksum \r\n
|
||||
//数字都是10进制的
|
||||
int JCFileTable::initByString( const char* p_pszStr ){
|
||||
//split by \r\n
|
||||
const char* pCur = p_pszStr;
|
||||
const char* pCurData=pCur;
|
||||
std::vector<unsigned int> allData;
|
||||
allData.reserve(1024);
|
||||
while(*pCur!=0){
|
||||
while(*pCur==' '||*pCur=='\r'||*pCur=='\n'){
|
||||
pCur++;
|
||||
}
|
||||
if(*pCur==0)
|
||||
break;
|
||||
const char* pData=pCur;
|
||||
while(*pCur!=' '&&*pCur!='\r'&&*pCur!='\n'&&*pCur!=0){
|
||||
pCur++;
|
||||
}
|
||||
int len = (long)pCur-(long)pData-1;
|
||||
//之所以用strtoul是为了能得到unsigned int的值,如果用atoi的话,会出错。
|
||||
allData.push_back( strtoul(pData,0,16));
|
||||
}
|
||||
|
||||
if( allData.size()%2!=0){
|
||||
//printf("fileTable::initByString 不合理的参数,应该为偶数个数据");
|
||||
//throw -1;
|
||||
return 0;
|
||||
}
|
||||
for( int i=0,sz=(int)allData.size()/2; i<sz; i++){
|
||||
_addFile(allData[i*2],allData[i*2+1]);
|
||||
}
|
||||
return (int)allData.size() / 2;
|
||||
}
|
||||
|
||||
void JCFileTable::save(){
|
||||
}
|
||||
|
||||
bool JCFileTable::find(unsigned int p_nFileID, unsigned int& p_nChkSum){
|
||||
Info* pInfo = getInfo(p_nFileID);
|
||||
if(pInfo){
|
||||
p_nChkSum = pInfo->chksum;
|
||||
return true;
|
||||
}
|
||||
p_nChkSum = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void JCFileTable::_addFile( unsigned int p_nFileID, unsigned int p_nChkSum ){
|
||||
unsigned char idx = (p_nFileID>>24)&0xff;
|
||||
std::vector<Info>& b = m_AllItem[idx];
|
||||
for( int i=0,sz=(int)b.size(); i<sz; i++){
|
||||
Info& curI = b[i];
|
||||
if(curI.fileid==p_nFileID ){
|
||||
return;
|
||||
}
|
||||
}
|
||||
Info I={p_nFileID, p_nChkSum};
|
||||
b.push_back(I);
|
||||
}
|
||||
|
||||
void JCFileTable::delFile( unsigned int p_nFileID )
|
||||
{
|
||||
}
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
//-----------------------------END FILE--------------------------------
|
||||
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
@file JCFileTable.h
|
||||
@brief
|
||||
@author James
|
||||
@version 1.0
|
||||
@date 2016_5_11
|
||||
*/
|
||||
|
||||
#ifndef __JCFileTable_H__
|
||||
#define __JCFileTable_H__
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace laya
|
||||
{
|
||||
class JCFileTable
|
||||
{
|
||||
public:
|
||||
|
||||
struct Info
|
||||
{
|
||||
unsigned int fileid;
|
||||
unsigned int chksum;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
JCFileTable();
|
||||
|
||||
~JCFileTable();
|
||||
|
||||
void init();
|
||||
|
||||
/** @brief 根据字符串创建dcc表。
|
||||
* @param[in] p_pszStr dcc信息。每一行描述一个文件
|
||||
* @return 返回文件个数。
|
||||
*/
|
||||
int initByString( const char* p_pszStr );
|
||||
|
||||
void save();
|
||||
|
||||
/** @brief 检查是否是需要缓存的文件
|
||||
* @param[in] 文件ID
|
||||
* @param[in]
|
||||
* @return
|
||||
*/
|
||||
bool find(unsigned int p_nFileID, unsigned int& p_nChkSum);
|
||||
|
||||
/** @brief 下面是对表的操作。建议不要用。可能会由于崩溃等问题损坏表。
|
||||
* @param[in] 文件ID
|
||||
* @param[in]
|
||||
* @return
|
||||
*/
|
||||
void addFile( unsigned int p_nFileID, unsigned int p_nChkSum );
|
||||
|
||||
/** @brief 从表中删除一个文件
|
||||
* @param[in] 文件ID
|
||||
*/
|
||||
void delFile( unsigned int p_nFileID );
|
||||
|
||||
protected:
|
||||
|
||||
/** @brief 只修改表。不保存
|
||||
* @param[in] 文件ID
|
||||
* @param[in]
|
||||
*/
|
||||
void _addFile( unsigned int p_nFileID, unsigned int p_nChkSum );
|
||||
|
||||
//
|
||||
/** @brief 这个会返回一个不可靠的指针。所以不允许外部访问
|
||||
* @param[in] 文件ID
|
||||
* @return 返回一个可靠的指针
|
||||
*/
|
||||
inline Info* getInfo(unsigned int p_nFileID)
|
||||
{
|
||||
unsigned char idx = (p_nFileID>>24)&0xff;
|
||||
std::vector<Info>& b = m_AllItem[idx];
|
||||
for( int i=0,sz=(int)b.size(); i<sz; i++)
|
||||
{
|
||||
Info& curI = b[i];
|
||||
if(curI.fileid==p_nFileID )
|
||||
{
|
||||
return &curI;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
std::vector<Info> m_AllItem[256];
|
||||
|
||||
};
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#endif //__JCFileTable_H__
|
||||
|
||||
//-----------------------------END FILE--------------------------------
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
@file JCIosFileSource.h
|
||||
@brief
|
||||
@author James
|
||||
@version 1.0
|
||||
@date 2016_5_11
|
||||
*/
|
||||
|
||||
#ifndef __JCIosFileSource_H__
|
||||
#define __JCIosFileSource_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include "JCFileSource.h"
|
||||
#include "../util/JCCommonMethod.h"
|
||||
#include "../util/Log.h"
|
||||
#include <string.h>
|
||||
#pragma warning (disable: 4996)
|
||||
|
||||
namespace laya
|
||||
{
|
||||
class JCIosFileSource : public JCFileSource
|
||||
{
|
||||
public:
|
||||
JCIosFileSource()
|
||||
{
|
||||
}
|
||||
~JCIosFileSource()
|
||||
{
|
||||
}
|
||||
bool Init( const char* sRootPath )
|
||||
{
|
||||
if( sRootPath )
|
||||
{
|
||||
m_sRootPath = sRootPath;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public:
|
||||
virtual bool isFileExistInZipAPKExpansion(const char* sFileName) { return false; }
|
||||
virtual bool isFileExist( const char* sFileName )
|
||||
{
|
||||
std::string sFullName = m_sRootPath + "/"+sFileName;
|
||||
FILE* fp = fopen(sFullName.c_str(),"rb");
|
||||
if( !fp )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
virtual unsigned int getFileSize(const char* sFileName)
|
||||
{
|
||||
std::string sFullName = m_sRootPath + "/"+ sFileName;
|
||||
FILE* fp = fopen(sFullName.c_str(), "rb");
|
||||
if (!fp) return 0;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
int nBuffSize = (int)ftell(fp);
|
||||
fclose(fp);
|
||||
return nBuffSize;
|
||||
}
|
||||
virtual bool loadFileContent(const char* sFileName, ALLOCMEM pAllocFunc, void* pUserData, int& nBuffSize)
|
||||
{
|
||||
bool bRet = false;
|
||||
std::string sFullName = m_sRootPath +"/"+ sFileName;
|
||||
FILE* fp = fopen(sFullName.c_str(), "rb");
|
||||
if (!fp) return false;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
nBuffSize = (int)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
unsigned char* pBuff = pAllocFunc(nBuffSize, pUserData);
|
||||
if (!pBuff)
|
||||
{
|
||||
bRet = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
int nReadSize = fread((char*)pBuff, 1, nBuffSize, fp);
|
||||
if (nReadSize == nBuffSize)
|
||||
{
|
||||
LOGI("found the file in the package:%s\n", sFileName);
|
||||
bRet = true;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
return bRet;
|
||||
}
|
||||
virtual bool loadFileContent(const char* sFileName, char*& pBuffer, int& nBuffSize)
|
||||
{
|
||||
bool bRet = false;
|
||||
std::string sFullName = m_sRootPath + "/"+sFileName;
|
||||
FILE* fp = fopen(sFullName.c_str(), "rb");
|
||||
if (!fp) return false;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
nBuffSize = (unsigned int)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
pBuffer = new char[nBuffSize+1];
|
||||
int nReadSize = fread((char*)pBuffer, 1, nBuffSize, fp);
|
||||
if (nReadSize == nBuffSize)
|
||||
{
|
||||
LOGI("found the file in the package:%s\n", sFileName);
|
||||
bRet = true;
|
||||
}
|
||||
pBuffer[nBuffSize] = 0;
|
||||
fclose(fp);
|
||||
return bRet;
|
||||
}
|
||||
private:
|
||||
std::string m_sRootPath;
|
||||
};
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#endif //__JCIosFileSource_H__
|
||||
|
||||
//-----------------------------END FILE--------------------------------
|
||||
|
||||
@@ -0,0 +1,914 @@
|
||||
/**
|
||||
@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"
|
||||
#else
|
||||
#include "../downloadCache/JCIosFileSource.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;
|
||||
#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();
|
||||
#else
|
||||
m_pAssets = new JCIosFileSource();
|
||||
#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;
|
||||
}
|
||||
}
|
||||
#else
|
||||
JCIosFileSource* pAssets = new JCIosFileSource();
|
||||
pAssets->Init(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) ){
|
||||
//先获取资源中的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 "";
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
/**
|
||||
@file JCServerFileCache.h
|
||||
@brief
|
||||
@author guo
|
||||
@version 1.0
|
||||
@date 2016_5_11
|
||||
*/
|
||||
|
||||
#ifndef __JCServerFileCache_H__
|
||||
#define __JCServerFileCache_H__
|
||||
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include "../buffer/JCBuffer.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#define CURCACHEFILEVER 2
|
||||
namespace laya
|
||||
{
|
||||
class JCFileTable;
|
||||
class JCFileSource;
|
||||
class JCResStateDispatcher;
|
||||
|
||||
/**
|
||||
* @brief 用特殊目录和格式管理的文件缓存。
|
||||
* 设置一个目录path,然后会把所有的文件都保存在这个目录下。
|
||||
* path随时可以换。
|
||||
* 文件以id来查找。字符串也可以?
|
||||
* 文件都带一个壳,保存了校验码。
|
||||
* 壳可以与实际文件可以分离。
|
||||
* 可以更新每个文件。
|
||||
*/
|
||||
class JCCachedFileSys {
|
||||
public:
|
||||
typedef unsigned int typeFile;
|
||||
typedef unsigned int typeChkSum;
|
||||
//每个文件的头
|
||||
struct fileShell{
|
||||
enum {
|
||||
magic_filid = 0x7788eeff,
|
||||
};
|
||||
fileShell(){
|
||||
magicNum=magic_filid;
|
||||
version = CURCACHEFILEVER;
|
||||
headSize = sizeof(fileShell);
|
||||
hashtype = ready = link = linkPackID = padd1= chkSum =0;
|
||||
linkSameFile = 1;
|
||||
reserved[0]=reserved[1]=reserved[2]=reserved[3]=0;
|
||||
linkFile=0;
|
||||
extfile = 0;
|
||||
}
|
||||
int magicNum;
|
||||
int version:8;
|
||||
unsigned int headSize:8;
|
||||
unsigned int hashtype:3; //0 simplecrc 1 crc 2:BKDR ; 3:MD5
|
||||
unsigned int ready:1; //1表示已经完成了,内容也是正确的。0表示还没有内容
|
||||
unsigned int link:1; //1表示是一个链接。
|
||||
unsigned int linkPackID:3; //使用哪个外部包
|
||||
unsigned int linkSameFile:1; //1表示链接的文件时同名的。否则,就要使用下面的linkFile;
|
||||
unsigned int extfile : 1; //实际文件内容在一个外部文件中,即头和文件体是分开的。主要是为了满足有的库需要直接访问文件。
|
||||
unsigned int extVersionMgr : 1; //使用外部版本管理,版本號只是一個int,佔用chkSum
|
||||
unsigned int tmpFile : 1; //临时文件。为1的时候,expiredTime有效
|
||||
unsigned int withprocess : 1; //临时文件,但是进程中不允许删除,一般是资源文件。
|
||||
int padd1:3;
|
||||
typeChkSum chkSum;
|
||||
int reserved[4];
|
||||
int linkFile;
|
||||
int svETag; //ETag的hash
|
||||
time_t expiredTime; //过期时间
|
||||
};
|
||||
|
||||
JCCachedFileSys();
|
||||
|
||||
static typeChkSum hashRaw( const char* p_pszStr );
|
||||
|
||||
void setCachePath(const char* p_pszPath);
|
||||
|
||||
/** @brief 从缓存中加载一个文件。
|
||||
* @param p_nFileID
|
||||
* @param p_nChkSum 这个=0 表示不用进行校验
|
||||
* @return
|
||||
* 如果从cache或者包中都找不到文件,则返回false,否则返回true,并设置文件内容和校验码
|
||||
* 可能会导致创建链接文件。对于不存在的不会创建壳。
|
||||
*/
|
||||
bool load(typeFile p_nFileID, typeChkSum& p_nChkSum, JCSharedBuffer& p_BufRet );
|
||||
|
||||
/** @brief 更新cache中的一个资源。不做校验码的检查。检查需要在外面做
|
||||
* @param[in] p_nFileID
|
||||
* @param[in] p_pBuff
|
||||
* @param[in] p_nLen
|
||||
* @param[in] p_nChkSum 这个值必须外部提供。此函数只是直接与头的记录进行比较。
|
||||
* @param[in] p_bExtVersion 外部提供的版本号,如果为true,则 p_nChkSum就是版本号
|
||||
* @param[in] p_tmExpiredTm 过期时间。只对临时文件有效
|
||||
* @param[in] p_bWithProcess 进程内不允许删除。
|
||||
* @return 如果保存成功。返回本地路径。否则返回"";
|
||||
*/
|
||||
std::string updateAFile(typeFile p_nFileID, char* p_pBuff, int p_nLen, typeChkSum p_nChkSum,
|
||||
bool p_bExtVersion, time_t p_tmExpiredTm, bool p_bWithProcess);
|
||||
|
||||
/** @brief 删除cache中的文件资源
|
||||
* @param p_nFileID
|
||||
*/
|
||||
void delFromCache( typeFile p_nFileID );
|
||||
|
||||
static typeChkSum getChkSum( char* p_pBuff, int p_nLen );
|
||||
|
||||
/** @brief 从缓存目录中读取资源。
|
||||
* 基本上相当于简单包装了的 readFileSync
|
||||
* @param p_pszFile
|
||||
* @param p_BufRet[out] 是文件内容,不含壳信息。
|
||||
* @return 如果缓存中没有,就返回false。
|
||||
*/
|
||||
bool load(const char* p_pszFile, JCSharedBuffer& p_BufRet, fileShell& p_nFs ,time_t& p_tmLastModify);
|
||||
|
||||
/*
|
||||
加载缓存的文件的信息。不实际加载文件。通常用来判断是否需要更新。
|
||||
*/
|
||||
bool loadShell(const char* p_pszFile, fileShell& p_nFs, time_t& p_tmLastModify);
|
||||
|
||||
std::string fileToPath(typeFile p_nFile, std::string& p_strPath, bool p_bCreateDir);
|
||||
|
||||
bool createLink( const char* p_pszFile, typeChkSum p_nChkSum);
|
||||
|
||||
//转成字符串。
|
||||
std::string fileToStr(typeFile, bool bHex );
|
||||
|
||||
//创建一个壳。还没有实际内容
|
||||
bool createShell(typeFile p_nFileID, typeChkSum p_nChkSum);
|
||||
|
||||
//返回整个cache的大小。
|
||||
long size();
|
||||
|
||||
//这个主要是为了效率,减少目录是否存在的判断。
|
||||
bool hasDir(unsigned char dir) {
|
||||
int pos = dir / 8;
|
||||
int off = dir % 8;
|
||||
return (m_HasDir[pos] >> off)&1;
|
||||
}
|
||||
void setHasDir(unsigned char dir) {
|
||||
int pos = dir / 8;
|
||||
int off = dir % 8;
|
||||
m_HasDir[pos] |= (1 << off);
|
||||
}
|
||||
protected:
|
||||
typedef std::recursive_mutex _mutex_t;
|
||||
_mutex_t m_lockFileRW;
|
||||
std::string m_strCacheFilesPath;
|
||||
unsigned char m_HasDir[32]; //最多有256個目錄。每個bit表示一個。
|
||||
};
|
||||
|
||||
class JCServerFileCache{
|
||||
public:
|
||||
typedef std::function<void(int,int)> funcOnUpdateProgress; //更新过程
|
||||
typedef std::function<void(void)> funcOnUpdateOK; //所有资源更新完成后的回调
|
||||
|
||||
/*
|
||||
绝对地址的URL转换函数,为了能多个url对应一个cache入口
|
||||
返回0表示放弃转换。
|
||||
不允许直接修改原始url内存。
|
||||
*/
|
||||
typedef char* (*FUN_TRANSLATEURL)(void* pUserData, const char*);
|
||||
public:
|
||||
JCServerFileCache();
|
||||
~JCServerFileCache();
|
||||
|
||||
void saveFileTable(const char* p_pszFileContent);
|
||||
|
||||
/** @brief 设置所有app的缓存根目录
|
||||
* @param p_pszCachePath [in] 文件缓存的目录。是绝对路径。
|
||||
*/
|
||||
void setCachePath(const char* p_pszCachePath );
|
||||
|
||||
/** @brief 得到当前应用的缓存目录。最后没有/
|
||||
*/
|
||||
std::string getAppPath();
|
||||
std::string getDccFile() { return getAppPath() + "/" + "filetable.txt"; };
|
||||
|
||||
/** @brief 切换到某个url的缓存。
|
||||
* 大约相当于把url映射到一个本地path上
|
||||
* 每个process只允许调用一次。
|
||||
* @param p_pszWebBase [in] 是index.html所在网络目录,例如 http://jx.laya8.com/game1/
|
||||
*/
|
||||
void switchToApp(const char* p_pszWebBase);
|
||||
|
||||
/** @brief 设置资源对象。提供访问文件的接口。
|
||||
*/
|
||||
void setAssets(JCFileSource* pAssets );
|
||||
|
||||
JCFileSource* getAssets(){ return m_pAssets;}
|
||||
|
||||
/** @brief 计算相对路径的hash
|
||||
* 注意url必须是一个相对路径,前面可以有 / 或者没有
|
||||
*/
|
||||
JCCachedFileSys::typeChkSum hashURLR(const char* p_pszURL );
|
||||
|
||||
/** @brief 从cache中加载一个文件。
|
||||
* 如果cache中没有则尝试从资源包中加载。
|
||||
* 如果在资源包中存在,会创建一个链接文件。
|
||||
* 如果是需要管理的文件,并且需要下载,则先创建壳,然后再下载。
|
||||
* @param p_nFileID [in]
|
||||
* @param p_nChkSum [in] 为0表示不用进行校验。
|
||||
* @param p_BufRet [out] 返回的内容
|
||||
* @param p_bUseVersion [in] 检查版本号
|
||||
* @return true则存在,并且p_BufRet会有文件内容。否则返回 false
|
||||
*/
|
||||
bool load(JCCachedFileSys::typeFile p_nFileID, JCCachedFileSys::typeChkSum& p_nChkSum, JCSharedBuffer& p_BufRet ,bool p_bUseVersion, bool doCheckSum);
|
||||
|
||||
/** @brief load一个文件。如果有dcc,就会把加载的内容进行dcc校验,否则就直接从缓存中加载。如果缓存中没有,就返回false。
|
||||
* 这个函数实际上最终会调用上面的load函数
|
||||
* @param[in] nFileID 文件的本地id。
|
||||
* @param[out] buff 返回的buffer
|
||||
* @param[in] doCheckSum 是否进行版本号或者校验码的验证
|
||||
* @return 加载成功就返回true,否则返回false
|
||||
*/
|
||||
bool load(unsigned int nFileID, JCBuffer& buff, bool doCheckSum=true);
|
||||
|
||||
/*
|
||||
加载缓存的文件的信息。不实际加载文件。通常用来判断是否需要更新。
|
||||
*/
|
||||
bool loadShell(const char* p_pszFile, JCCachedFileSys::fileShell& p_nFs, time_t& p_tmLastModify);
|
||||
|
||||
/**
|
||||
* @brief 从缓存中加载指定版本号的某个文件。
|
||||
* @param[in] p_nFileID 文件id
|
||||
* @param[in] p_nVersion 版本号
|
||||
* @param[out] p_BufRet 返回的文件内容
|
||||
* @return 如果文件存在,并且版本符合,就返回true,并且p_BufRet有返回内容
|
||||
*/
|
||||
//bool loadByVersion(unsigned int p_nFileID, int p_nVersion, JCSharedBuffer& p_BufRet);
|
||||
|
||||
//删除cache中的文件资源
|
||||
void delFromCache( JCCachedFileSys::typeFile p_nFileID ){ m_FileSys.delFromCache(p_nFileID);}
|
||||
|
||||
/** @brief 根据p_pTable来更新所有的内容。这样以后就不用再需要fileTable了
|
||||
* 如果用索引表的方法(不用分散文件),必须用这种方式
|
||||
* 系统资源也用这种方法更新。
|
||||
* @param p_pTable 如果为空,则直接使用自己的 fileTable 来更新
|
||||
*/
|
||||
void updateAll( JCFileTable* p_pTable, funcOnUpdateOK p_OnUpdateOK);
|
||||
|
||||
/** @brief 获得某个文件的校验码。
|
||||
* @return 如果没有管理这个文件,返回false
|
||||
*/
|
||||
bool getFileInfo(unsigned int p_nFileID, unsigned int& p_nChkSum );
|
||||
|
||||
void setResourceID(const char* p_pszResource, const char* p_pszVal);
|
||||
std::string getResourceID(const char* p_pszResource );
|
||||
|
||||
/** @brief
|
||||
* 删除本url的所有的缓存文件。包括session文件。
|
||||
* 这个函数可能很危险,不要暴露出去。
|
||||
* @return
|
||||
*/
|
||||
void clearAllCachedFile();
|
||||
|
||||
/** @brief 文件下载完成。 更新文件的缓存。
|
||||
* @param[in] p_nFileID 文件ID。
|
||||
* @param[in] p_pBuff
|
||||
* @param[in] p_nLen
|
||||
* @param[in] p_nChkSum 校验值。外部设置的,只是要求这个函数保存,并不要求检验。
|
||||
* @return 如果成功的话,返回本地目录。否则返回"";
|
||||
*/
|
||||
std::string updateAFile(JCCachedFileSys::typeFile p_nFileID, char* p_pBuff, int p_nLen,
|
||||
JCCachedFileSys::typeChkSum p_nChkSum, bool p_bExtVersion, time_t p_tmExpiredTm,
|
||||
bool p_bWithProcess) {
|
||||
return m_FileSys.updateAFile(p_nFileID, p_pBuff, p_nLen, p_nChkSum, p_bExtVersion,
|
||||
p_tmExpiredTm, p_bWithProcess);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重新加载app目录下的dcc文件。一般是在更新dcc之后调用。
|
||||
* @return 创建的dcc中的文件的个数。
|
||||
*/
|
||||
int reloadDccFile();
|
||||
|
||||
/**
|
||||
获得一个url的fileid。
|
||||
如果有转换表需要先转换一下
|
||||
*/
|
||||
unsigned int getFileID(const char* Url);
|
||||
//protected:
|
||||
//这个函数要小心。要避免线程问题。本来是私有的。为了方便改成public了
|
||||
/** @brief 根据字符串设置dcc信息。
|
||||
注意只有开始的时候才能调用这个,当正常使用的时候,不允许设置,否则应该加锁
|
||||
外部不允许调用这个函数。否则不知道怎么处理。
|
||||
* @param[in] p_pszFiles
|
||||
* @return 返回文件的个数。
|
||||
*/
|
||||
int setFileTables( const char* p_pszFiles );
|
||||
|
||||
/**
|
||||
设置url转换表。必须是相对路径。必须以/开头
|
||||
*/
|
||||
void setUrlTransTable(const char* p_pszTable, char split);
|
||||
|
||||
protected:
|
||||
|
||||
//从资源包中读取。返回内容和chksum,如果false则表示没有这个文件
|
||||
bool _loadFromAssets(JCCachedFileSys::typeFile p_nFileID, JCSharedBuffer& p_BufRet, JCCachedFileSys::typeChkSum& p_nChkSum, bool p_bGetChkSum=true );
|
||||
|
||||
//为了统一的解密加的,上面的那个只是统一入口
|
||||
bool __load(JCCachedFileSys::typeFile p_nFileID, JCCachedFileSys::typeChkSum& p_nChkSum, JCSharedBuffer& p_BufRet, bool p_bUseVersion, bool doCheckSum);
|
||||
|
||||
protected:
|
||||
time_t m_tmCacheMgrCreateTime;
|
||||
JCFileTable* m_pFileTable;
|
||||
std::string m_strCachePath;
|
||||
std::string m_strWebBase;
|
||||
std::string m_strCacheFilesPath;//在m_strCachePath下面的files中
|
||||
std::string m_strAppPath; //这是一个相对路径
|
||||
JCFileSource* m_pAssets;
|
||||
std::map<unsigned int, std::string> m_UrlTrans;
|
||||
public://config
|
||||
JCCachedFileSys m_FileSys;
|
||||
enum SessionFileCacheType {
|
||||
CT_UseHeaderInfo=0,
|
||||
CT_ValidInCurProcess,
|
||||
CT_AllwaysReload
|
||||
};
|
||||
|
||||
/*
|
||||
* 是否根据header中的参数来决定是否缓存。
|
||||
* 如果是false,则临时文件都是
|
||||
*/
|
||||
static SessionFileCacheType s_bSessionCacheType ;
|
||||
|
||||
FUN_TRANSLATEURL m_pFuncTransUrl = nullptr;
|
||||
void* m_pFuncTransUrlData = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //__JCServerFileCache_H__
|
||||
Reference in New Issue
Block a user