Пример #1
0
//加入磁盘上单个文件到包中
bool PakMaker::addDiskFile(const char* szFileInDisk, const char* szFileInPak)
{
	assert(szFileInDisk && szFileInPak);

	if(!szFileInDisk || !szFileInPak || szFileInDisk[0]==0 || szFileInPak[0]==0) 
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}
	//check is file exist
	if(!PathFileExists(szFileInDisk)) 
	{
		setLastError(AXP_ERR_FILE_NOTFOUND);
		return false;
	}
	
	FileNode newNode;
	newNode.bExcute = false;
	newNode.strFileInPak = normaliseName(szFileInPak, false, true);
	newNode.strFileInDisk = normaliseName(szFileInDisk, false, true);
	newNode.nCRC = 0;
	newNode.nFileSize = 0;

	m_AllFiles[normaliseName(szFileInPak)] = newNode;

	return true;
}
Пример #2
0
//得到包中某个文件的大小
unsigned int PackFile::getFileSize(const char* szFileName) const
{
	assert(szFileName);
	if(!szFileName || szFileName[0]==0)
	{
		setLastError(AXP_ERR_PARAM);
		return 0;
	}

	//在hash表中搜索
	int nHashPos = getStringPosInHashTable(normaliseName(szFileName, true, true).c_str());
	if(nHashPos < 0) 
	{
		setLastError(AXP_ERR_FILE_NOTFOUND, "%s", szFileName);
		return 0;
	}

	const FILE_HASHNODE& hashNode = m_hashTable[nHashPos];
	
	//得到Block数据
	unsigned int nBlockIndex = getHashNodeBlockIndex(hashNode);
	assert(nBlockIndex < (unsigned int)m_blockTable.size());

	const FILE_BLOCKNODE& blockNode = m_blockTable[nBlockIndex];

	return blockNode.nBlockSize;
}
Пример #3
0
//将磁盘上一个目录加入到包中
bool PakMaker::addDiskFold(const char* szFoldInDisk, const char* szFoldInPak, const char* szExtFilter, bool bRecursive)
{
	assert(szFoldInDisk );
	if(!szFoldInDisk || szFoldInDisk[0]==0 ) 
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	//check is path exist
	if(!PathFileExists(szFoldInDisk))
	{
		setLastError(AXP_ERR_FILE_NOTFOUND, "%s", szFoldInDisk);
		return false;
	}

	//分割后缀过滤器
	std::vector< std::string > vExtFilter;
	convertStringToVector(szExtFilter, vExtFilter, ";", true, true);

	std::set< std::string > sExtFilter;
	for(int i=0; i<(int)vExtFilter.size(); i++)
	{
		sExtFilter.insert(normaliseName(vExtFilter[i], true, false));
	}

	//调用内部递归函数
	return _addDiskFold(szFoldInDisk, sExtFilter, szFoldInPak, bRecursive);
}
Пример #4
0
bool PackFile::removeFile(const char* szFileInPak, bool bSaveAtOnce)
{
	assert(szFileInPak);
	if(!szFileInPak || szFileInPak[0]==0 || !m_hPakFile)
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	//只读模式不支持
	if(m_bConst)
	{
		setLastError(AXP_ERR_FILE_ACCESS);
		return false;
	}

	//在hash表中搜索
	int nHashPos = getStringPosInHashTable(normaliseName(szFileInPak, true, true).c_str());
	if(nHashPos < 0)
	{
		setLastError(AXP_ERR_FILE_NOTFOUND, "%s", szFileInPak);
		return false;
	}

	FILE_HASHNODE& hashNode = m_hashTable[nHashPos];

	//Block Node
	unsigned int nBlockPos = getHashNodeBlockIndex(hashNode);
	FILE_BLOCKNODE& blockNode = m_blockTable[nBlockPos];
	
	//设定值
	setBlockNodeUsed(blockNode, false);
	setHashNodeExists(hashNode, false);

	//保存空闲快
	m_mapFreeBlock.insert(std::make_pair(upBoundBlockSize(blockNode.nBlockSize), nBlockPos));
	m_fileHead.nData_HoleSize += upBoundBlockSize(blockNode.nBlockSize);

	//###################################
	//!! 磁盘操作开始 保存文件
	//###################################
	if(!writeBlockNode((unsigned int)nBlockPos)) return false;
	if(!writeHashNode((unsigned int)nHashPos)) return false;
	if(!writeFileHead()) return false;

	if(bSaveAtOnce)
	{
		FlushFileBuffers(m_hPakFile);
	}
	//###################################
	//!!磁盘操作结束
	//###################################

	return true;
}
Пример #5
0
//某文件在包中是否存在
bool PackFile::isFileExists(const char* szFileName) const
{
	assert(szFileName);
	if(!szFileName || szFileName[0]==0)
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	//在hash表中搜索
	int nHashPos = getStringPosInHashTable(normaliseName(szFileName, true, true).c_str());

	return nHashPos >= 0;
}
Пример #6
0
//以文件流方式打开包中的一个文件
IStream* PackFile::openFile(const char* szFileName)
{
	//进入关键段,考虑多线程访问
	AUTO_LOCK autoLock(&m_secFile);

	assert(szFileName && m_hPakFile);
	if(!szFileName || szFileName[0]==0 || m_hPakFile==0)
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	//在hash表中搜索
	int nHashPos = getStringPosInHashTable(normaliseName(szFileName, true, true).c_str());
	if(nHashPos < 0) 
	{
		setLastError(AXP_ERR_FILE_NOTFOUND, szFileName);
		return 0;
	}

	const FILE_HASHNODE& hashNode = m_hashTable[nHashPos];

	//得到Block数据
	unsigned int nBlockIndex = getHashNodeBlockIndex(hashNode);
	assert(nBlockIndex < (unsigned int)m_blockTable.size());

	const FILE_BLOCKNODE& blockNode = m_blockTable[nBlockIndex];

	//得到当前线程id
	unsigned int uCurrentThread = (unsigned int)::GetCurrentThreadId();
	FileHandleMap::iterator itHandle = m_mapFileHandle.find(uCurrentThread);	//是否已经有句柄
	if(itHandle == m_mapFileHandle.end())
	{
		//分配一个句柄
		HANDLE hFile = ::CreateFile(m_strFileName.c_str(), 
			GENERIC_READ,
			FILE_SHARE_READ|FILE_SHARE_WRITE,
			0,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_SEQUENTIAL_SCAN,
			0);
		if(hFile == INVALID_HANDLE_VALUE)
		{
			setLastError(AXP_ERR_FILE_ACCESS, "File=%s, WinErr=%d", m_strFileName.c_str(), ::GetLastError());
			return 0;
		}

		//加入map
		m_mapFileHandle.insert(std::make_pair(uCurrentThread, hFile));
		itHandle = m_mapFileHandle.find(uCurrentThread);
		assert(itHandle != m_mapFileHandle.end());
	}

	//Alloc a datastream
	DataStream* pNewStream = new DataStream(this, 
		itHandle->second, blockNode.nDataOffset, blockNode.nBlockSize, 
		blockNode.nBlockSize<=STREAM_PREREAD_SIZE);
	m_listStream.push_back(pNewStream);

	return (IStream*)pNewStream;
}
Пример #7
0
/********************************************
添加一个Patch升级包到升级操作中,后添加的后操作
*********************************************/
bool Updater::addPatchFile(const char* szPatchFile)
{
	//参数检查
	assert(szPatchFile);
	if(!szPatchFile || szPatchFile[0]==0)
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	//已经加入过
	if(m_mapPatchFile.find(normaliseName(szPatchFile)) != m_mapPatchFile.end()) 
	{
		//Log something...
		return true;
	}

	//打开zip文件,根据是否是加密后文件自动选择是否需要使用自定义文件读取接口
	zzip_error_t zzipError;
	ZZIP_DIR* mZzipDir = zzip_dir_open_ext_io(szPatchFile, &zzipError, 0, 
		(zzip_plugin_io_t)getEncryptZipPluginIO(szPatchFile));

	if (zzipError != ZZIP_NO_ERROR) 
	{
		setLastError(AXP_ERR_ZIPFILE, "ziperr=%d", zzipError);
		return false;
	}

	//保存zip文件句柄
	m_mapPatchFile.insert(std::make_pair(normaliseName(szPatchFile), (void*)mZzipDir));

	//打开(command)文件
	char* pCmdFile=0;
	unsigned int nCmdFileSize = 0;
	if(!_readContentsFromZip(szPatchFile, PatchMaker::PATCH_COMMAND, 0, &pCmdFile, nCmdFileSize))
		return false;

	//分解command文件
	std::vector< std::string > vCommand;
	convertStringToVector(pCmdFile, vCommand, "\r\n", true, true);

	//空的更新包文件
	if(vCommand.empty())
	{
		//Log some thing...
		return true;
	}

	//逐行分析命令
	for(int i=0; i<(int)vCommand.size(); i++)
	{
		const char* szCmdLine = vCommand[i].c_str();

		std::vector< std::string > vFileCmd;
		convertStringToVector(vCommand[i].c_str(), vFileCmd, "|", true, false);

		if(vFileCmd.size() != 3)
		{
			//Log some thing...
			continue;
		}

		UPDATE_FILE fileCmd;
		fileCmd.process = (UPDATE_PROCESS)atoi(vFileCmd[0].c_str());
		fileCmd.strPakFileName = vFileCmd[1];
		fileCmd.strFileName = vFileCmd[2];
		fileCmd.strSourceZip = szPatchFile;

		//规范后的文件名
		std::string strNorFileName = normaliseName(fileCmd.strFileName);
		std::string strNorPakFile = normaliseName(fileCmd.strPakFileName);
		const char* szNorExt = ::PathFindExtension(strNorFileName.c_str());

		//散文件
		if(fileCmd.strPakFileName.empty())
		{
			m_scatteredFiles[strNorFileName] = fileCmd;

			//如果这个文件本身是一个pak文件
			if(szNorExt && strcmp(szNorExt, PackFile::PAKFILE_EXT) == 0)
			{
				//说明该包被删除或者重新添加, 重置对该pak包的所有操作
				m_pakFiles.erase(strNorFileName);
			}
		}
		//pak包内文件
		else
		{
			//获得目前该包的操作集合
			UPDATE_PAKFILES::iterator itPak = m_pakFiles.find(strNorPakFile);
			if(itPak == m_pakFiles.end())
			{
				//尚未对该pak进行任何操作,创建
				m_pakFiles.insert(std::make_pair(strNorPakFile, UPDATE_FILES()));
				itPak = m_pakFiles.find(strNorPakFile);
			}
			assert(itPak != m_pakFiles.end());

			//加入操作
			itPak->second[strNorFileName] = fileCmd;
		}
	}

	return true;
}
Пример #8
0
//从zip文件中读取全部文件内容到文件中或者内存中, 
//zip文件必须是通过addPatchFile加入的patch文件,
bool Updater::_readContentsFromZip(const char* szZipFile, const char* szFileName, 
					const char* szDiskFileName, char** ppMemoryBuf, unsigned int& nFileSize)
{
	//参数检查
	assert(szZipFile && szFileName && (szDiskFileName || ppMemoryBuf) );
	if(!szZipFile || szZipFile[0]==0 || !szFileName || szFileName[0]==0 || (!szDiskFileName && !ppMemoryBuf))
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	//搜索加入的zip文件
	PATCHFILE_MAP::iterator itPatch = 
		m_mapPatchFile.find(normaliseName(szZipFile));

	//无法找到zip文件
	assert(itPatch != m_mapPatchFile.end());
	if(itPatch == m_mapPatchFile.end()) 
	{
		setLastError(AXP_ERR_PARAM, "%s not inserted", szZipFile);
		return false;
	}

	//获得ZIP句柄
	ZZIP_DIR* mZzipDir = (ZZIP_DIR*)(itPatch->second);
	assert(mZzipDir);

	std::string norFileName = normaliseName(szFileName, false, true);

	//得到文件信息
	ZZIP_STAT zstat;
	memset(&zstat, 0, sizeof(ZZIP_STAT));

	//打开文件,如果打不开,是空文件
	ZZIP_FILE* zzipFile = zzip_file_open(mZzipDir, norFileName.c_str(), ZZIP_ONLYZIP | ZZIP_CASELESS);
	if(zzipFile)
	{
		int zip_err = zzip_dir_stat(mZzipDir, norFileName.c_str(), &zstat, ZZIP_CASEINSENSITIVE);
		if(zip_err!=0)
		{
			zzip_file_close(zzipFile);

			setLastError(AXP_ERR_ZIPFILE, "ziperr=%d", mZzipDir->errcode);
			return false;
		}
	}

	//如果需要写入文件
	if(szDiskFileName)
	{
		//确认文件所在目录存在
		char szDiskFilePath[MAX_PATH] = {0};
		strncpy(szDiskFilePath, szDiskFileName, MAX_PATH);
		PathRemoveFileSpec(szDiskFilePath);
		if(szDiskFilePath[0]!=0 && !forceCreatePath(szDiskFilePath))
		{
			if(zzipFile)zzip_file_close(zzipFile);

			setLastError(AXP_ERR_FILE_ACCESS, "Path=%s, WinErr=%d", szDiskFilePath, ::GetLastError());
			return false;
		}

		//创建该文件
		HANDLE hDiskFile = ::CreateFile(szDiskFileName, 
							GENERIC_READ|GENERIC_WRITE,
							FILE_SHARE_READ|FILE_SHARE_WRITE,
							0,
							CREATE_ALWAYS,
							FILE_ATTRIBUTE_ARCHIVE,
							0);

		if(hDiskFile == INVALID_HANDLE_VALUE)
		{
			if(zzipFile)zzip_file_close(zzipFile);

			setLastError(AXP_ERR_FILE_ACCESS, "File=%s, WinErr=%d", szDiskFileName, ::GetLastError());
			return false;
		}

		if(zstat.st_size > 0)
		{
			const int MAX_BUFFER_SIZE = 4096;
			char buffer[MAX_BUFFER_SIZE] = {0};

			zzip_seek(zzipFile, 0, SEEK_SET);
			zzip_ssize_t zReadSize = zzip_file_read(zzipFile, buffer, sizeof(buffer));
		
			//实际已经写入的尺寸
			unsigned int nActWriteSize = 0;

			//分块读写文件内容
			do
			{
				//文件结束
				if(zReadSize==0) break;

				//写入磁盘文件
				DWORD dwBytesWrite;
				if(!WriteFile(hDiskFile, buffer, (DWORD)zReadSize, &dwBytesWrite, 0) || 
					dwBytesWrite != (DWORD)zReadSize)
				{
					zzip_file_close(zzipFile);
					CloseHandle(hDiskFile);

					setLastError(AXP_ERR_FILE_WRITE, "File=%s, WinErr: %d", szDiskFileName, GetLastError());
					return false;
				}

				//文件结束
				if(zzip_tell(zzipFile) >=zstat.st_size) break;

				zReadSize = zzip_file_read(zzipFile, buffer, sizeof(buffer));
			}while(true);
		}
		//关闭句柄
		CloseHandle(hDiskFile); hDiskFile=0;
	}

	//如果需要读入内存
	if(ppMemoryBuf)
	{
		//所需要的内存
		unsigned int nMemoryNeed = (unsigned int)zstat.st_size+1;
		while(nMemoryNeed%4)nMemoryNeed++;	//upbound 4

		//扩大静态内存大小
		static std::vector< unsigned char > s_autoMemory;
		if(s_autoMemory.size() < nMemoryNeed) 
		{
			s_autoMemory.resize(nMemoryNeed);
		}
		s_autoMemory.assign(s_autoMemory.size(), 0);

		//读入文件内容
		if(zstat.st_size > 0)
		{
			zzip_seek(zzipFile, 0, SEEK_SET);
			zzip_ssize_t nZipSize = zzip_file_read(zzipFile, (char*)&(s_autoMemory[0]), zstat.st_size);
			if(nZipSize != zstat.st_size)
			{
				zzip_file_close(zzipFile);
				setLastError(AXP_ERR_ZIPFILE, "ziperr=%d", mZzipDir->errcode);
				return false;
			}
		}
		//返回内容
		*ppMemoryBuf = (char *)(&(s_autoMemory[0]));
	}

	//关闭句柄
	if(zzipFile)zzip_file_close(zzipFile);	zzipFile=0;

	nFileSize = (unsigned int)zstat.st_size;
	return true;
}
Пример #9
0
//递归加入一批文件, szFoldInDisk=路径名 sFilter=过滤器, strFoldInPak=Pak中的路径 
bool PakMaker::_addDiskFold(const std::string& strFoldInDisk, 
							const std::set< std::string >& sFilter, 
							const std::string& strFoldInPak,
							bool bRecursive)
{
	WIN32_FIND_DATA theFindData;

	// TO Search...
	char szFileToSearch[MAX_PATH] = {0};
	strncpy(szFileToSearch, strFoldInDisk.c_str(), MAX_PATH);
	PathAppend(szFileToSearch, "*.*");

	// find first file
	HANDLE hFind = FindFirstFile(szFileToSearch, &theFindData);
	if(hFind == INVALID_HANDLE_VALUE)
	{
		//empty !
		FindClose(hFind);
		return true;
	}

	BOOL bFind = FALSE;
	do
	{
		if(theFindData.cFileName[0] != '.')
		{
			//File in Disk
			CHAR szPathFileName[MAX_PATH];
			strncpy(szPathFileName, strFoldInDisk.c_str(), MAX_PATH);
			PathAppend(szPathFileName, theFindData.cFileName);

			//File in Pack
			char szFileInPak[MAX_PATH] = {0};
			strncpy(szFileInPak, strFoldInPak.c_str(), MAX_PATH);
			PathAppend(szFileInPak, theFindData.cFileName);

			//文件夹
			if(theFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			{
				if(!bRecursive) goto FIND_NEXT;

				if(!_addDiskFold(szPathFileName, sFilter, szFileInPak, true)) return false;
			}
			//文件
			else
			{
				//是否是合法后缀的文件
				if(!sFilter.empty())
				{
					const char* pExt = ::PathFindExtension(szPathFileName);
					if(!pExt) goto FIND_NEXT;

					if(sFilter.find(normaliseName(pExt+1, true, false)) == sFilter.end())
						goto FIND_NEXT;
				}

				if(!addDiskFile(szPathFileName, szFileInPak)) return false;
			}
		}

FIND_NEXT:
		// Find Next file.
		bFind = FindNextFile(hFind, &theFindData);
	}while(bFind);

	FindClose(hFind);
	return true;
}
Пример #10
0
//将加入的文件和现有的pak文件作内容比较,用于程序测试
bool PakMaker::comparePakFile(const char* szPakFileName, AXP_PAKMAKER_COMPARECALLBACK callbackFunc)
{
	assert(szPakFileName && callbackFunc);
	if(!szPakFileName || szPakFileName[0]==0 || callbackFunc==0)
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	//Pak文件
	PackFile pakFile;
	if(!pakFile.openPakFile(szPakFileName, true)) return false;

	//保存已经检测的文件
	typedef std::set< std::string > FILENAME_SET;
	FILENAME_SET setFileProcessed;

	//加入文件
	FileNodeBuf::iterator it;
	for(it=m_AllFiles.begin(); it!=m_AllFiles.end(); it++)
	{
		FileNode& file = it->second;
		char szTempFileName[1024] = {0};

		//打开文件
		IStream* pStream = pakFile.openFile(file.strFileInPak.c_str());

		//调用Callback
		if(!callbackFunc(file.strFileInDisk.c_str(), pStream))
		{
			setLastError(AXP_ERR_FILE_DIFF, "%s", file.strFileInPak.c_str());
			if(pStream) pStream->close();
			return false;
		}

		if(pStream)
		{
			setFileProcessed.insert(normaliseName(file.strFileInPak));
			//关闭stream
			pStream->close();
		}
	}

	//是否还有尚未检测的文件存在

	//打开List文件
	IStream* pListStream = pakFile.openFile(PackFile::LIST_FILENAME);
	if(!pListStream) return false;

	//skip first line
	pListStream->skipLine();
	
	//read second line
	char szTempLine[MAX_PATH*4] = {0};
	int nLineSize = pListStream->readLine(szTempLine, MAX_PATH*4);
	int nFileCount = atoi(szTempLine);

	while (!pListStream->eof())
	{
		int nLineLength = pListStream->readLine(szTempLine, MAX_PATH*4);
		if(0 == nLineLength) 
		{
			pListStream->close();
			setLastError(AXP_ERR_FILE_FORMAT, "list file second line=0");
			return false;
		}

		//分析文件描述
		std::vector< std::string > vStringVec;
		convertStringToVector(szTempLine, vStringVec, "|", true, false);
		if(vStringVec.size() != 3) 
		{
			pListStream->close();
			setLastError(AXP_ERR_FILE_FORMAT, "list file=%s", szTempLine);
			return false;
		}

		//获得文件信息
		if(setFileProcessed.find(normaliseName(vStringVec[0])) == setFileProcessed.end())
		{
			pListStream->close();
			setLastError(AXP_ERR_FILE_DIFF, "redufile=%s", vStringVec[0].c_str());
			return false;
		}
	}

	pListStream->close();
	return true;
}
Пример #11
0
//文件自检功能
bool PackFile::selfCheck(SELFCHECK_CALLBACK callBack)
{
	if(0==m_hPakFile) 
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	//编辑模式错误
	if(m_fileHead.nEditFlag != 0)
	{
		setLastError(AXP_ERR_FILE_EDITMODE);
		return false;
	}

	//打开List文件
	IStream* pListStream = openFile(LIST_FILENAME);
	if(!pListStream) return false;

	//skip first line
	pListStream->skipLine();

	//read second line
	char szTempLine[MAX_PATH*4] = {0};
	int nLineSize = pListStream->readLine(szTempLine, MAX_PATH*4);
	int nFileCount = atoi(szTempLine);

	//记录已经检查过的HashNode索引
	std::set< unsigned int > setHashNode;
	//记录已经检查过的BlockNode索引
	std::set< unsigned int > setBlockNode;

	//逐行读文件
	int nFileListSize = 0;
	while (!pListStream->eof())
	{
		int nLineLength = pListStream->readLine(szTempLine, MAX_PATH*4);
		if(0 == nLineLength) 
		{
			pListStream->close();
			setLastError(AXP_ERR_FILE_FORMAT, "list file second line=0");
			return false;
		}

		//分析文件描述
		std::vector< std::string > vStringVec;
		convertStringToVector(szTempLine, vStringVec, "|", true, false);
		if(vStringVec.size() != 3) 
		{
			pListStream->close();
			setLastError(AXP_ERR_FILE_FORMAT, "list file=%s", szTempLine);
			return false;
		}

		//获得文件信息
		std::string& strFileName = vStringVec[0];
		unsigned int nFileSize, nFileCRC;
		sscanf(vStringVec[1].c_str(), "%08X", &(nFileSize));
		sscanf(vStringVec[2].c_str(), "%08X", &(nFileCRC));

		//读入文件
		IStream* pFileStream = openFile(strFileName.c_str());	//打开文件
		if(!pFileStream)
		{
			pListStream->close();
			return false;
		}

		unsigned int nStreamSize = pFileStream->size();
		if(nStreamSize != nFileSize)
		{
			pFileStream->close();
			pListStream->close();
			setLastError(AXP_ERR_FILE_FORMAT, "file=%s, sizedif(%d!=%d)", 
				strFileName.c_str(), nStreamSize, nFileSize);
			return false;
		}

		char* pTempBuf = new char[nStreamSize];
		if(nStreamSize != pFileStream->read(pTempBuf, nStreamSize))
		{
			pFileStream->close();
			pListStream->close();
			setLastError(AXP_ERR_FILE_READ, "file=%s", strFileName.c_str());
		}
		pFileStream->close(); pFileStream=0;

		//计算文件实际crc
		unsigned int  nStreamCRC;
		crcMemory32(pTempBuf, nStreamSize, nStreamCRC);
		delete[] pTempBuf; pTempBuf=0;

		if(nStreamCRC != nFileCRC)
		{
//			pFileStream->close();
			pListStream->close();
			setLastError(AXP_ERR_FILE_FORMAT, "file=%s, crcdif(%d!=%d)", 
				strFileName.c_str(), nStreamCRC, nFileCRC);
			return false;
		}

		//保存分析过的文件Hash和Block数据

		//得到Hash数据
		int nHashPos = getStringPosInHashTable(normaliseName(strFileName).c_str());
		setHashNode.insert(nHashPos);

		//得到Block数据
		unsigned int nBlockIndex = getHashNodeBlockIndex(m_hashTable[nHashPos]);
		setBlockNode.insert(nBlockIndex);

		nFileListSize++;
	};
	pListStream->close(); pListStream=0;

	//文件个数检查
	if(nFileListSize != nFileCount)
	{
		setLastError(AXP_ERR_FILE_FORMAT, "file countdif(%d!=%d)", nFileListSize, nFileCount);
		return false;
	}

	//得到(list)的Hash数据
	int nListFileHashPos = getStringPosInHashTable(LIST_FILENAME);
	//得到(list)的Block数据
	unsigned int nListFileBlockIndex = getHashNodeBlockIndex(m_hashTable[nListFileHashPos]);

	//检查是否有未引用的Hash数据
	for(int i=0; i<HASH_TABLE_SIZE; i++)
	{
		const FILE_HASHNODE& hashNode = m_hashTable[i];
		if(!getHashNodeExists(hashNode)) continue;

		if(setHashNode.find(i) != setHashNode.end()) continue;
		if(i==nListFileHashPos) continue;

		//未引用的Hash数据
		setLastError(AXP_ERR_FILE_FORMAT, "unref hashnode(%d)", i);
		return false;
	}

	//检查是否有未引用的BlockNode数据
	for(int i=0; i<(int)m_blockTable.size(); i++)
	{
		const FILE_BLOCKNODE& blockNode = m_blockTable[i];
		if(!getBlockNodeUsed(blockNode)) continue;
		if(setBlockNode.find(i) != setBlockNode.end()) continue;
		if(i==nListFileBlockIndex) continue;

		//未引用的Hash数据
		setLastError(AXP_ERR_FILE_FORMAT, "unref blocknode(%d)", i);
		return false;
	}

	return true;
}
Пример #12
0
//加入/更新一个磁盘文件到包中
bool PackFile::insertContents(const char* szContents, unsigned int nContentsLen, 
					const char* szFileInPak, AXP_CONTENTS sourceType, bool bSaveAtOnce)
{
	assert(szContents && szFileInPak);
	if(!szFileInPak || szFileInPak[0]==0 || !m_hPakFile)
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	if(sourceType==AC_DISKFILE && (!szContents || szContents[0]==0))
	{
		setLastError(AXP_ERR_PARAM);
		return false;
	}

	//只读模式不支持
	if(m_bConst)
	{
		setLastError(AXP_ERR_FILE_ACCESS);
		return false;
	}

	//察看文件是否存在
	if(sourceType==AC_DISKFILE && !PathFileExists(szContents))
	{
		setLastError(AXP_ERR_FILE_NOTFOUND, "%s", szContents);
		return false;
	}

	//在Hash表中分配位置
	int nHashPos = allocStringPosInHashTable(normaliseName(szFileInPak, true, true).c_str());
	if(nHashPos < 0)
	{
		setLastError(AXP_ERR_HASHFULL);
		return false;
	}

	FILE_HASHNODE& hashNode = m_hashTable[nHashPos];

	//获得文件大小
	unsigned int nFileSize = sourceType==AC_DISKFILE ? getDiskFileSize(szContents) : nContentsLen;

	//如果同名文件已经存在
	if(getHashNodeExists(hashNode))
	{
		//Block
		unsigned int nBlockIndex = getHashNodeBlockIndex(hashNode);
		FILE_BLOCKNODE& blockNode = m_blockTable[nBlockIndex];

		//如果尺寸接近
		if(upBoundBlockSize(blockNode.nBlockSize) == upBoundBlockSize(nFileSize))
		{
			//直接替换文件内容

			//###################################
			//!! 磁盘操作开始 保存文件
			//###################################
			if(sourceType==AC_DISKFILE)
			{
				if(!writeDiskFile(blockNode.nDataOffset, 
					upBoundBlockSize(blockNode.nBlockSize), szContents)) return false;
			}
			else
			{
				if(!writeMemory(blockNode.nDataOffset, 
					upBoundBlockSize(blockNode.nBlockSize), szContents, nContentsLen)) return false;
			}

			if(blockNode.nBlockSize != nFileSize)
			{
				//文件尺寸有差异,保存BlockNode数据
				blockNode.nBlockSize = nFileSize;
				if(!writeBlockNode(nBlockIndex)) return false;
			}
			// 确认写入磁盘
			if(bSaveAtOnce)
			{
				FlushFileBuffers(m_hPakFile);
			}
			//###################################
			//!!磁盘操作结束
			//###################################
		}
		//尺寸发生变化,需要删除旧空间,分配新空间
		else 
		{
			//旧块内容设置为不再使用
			setBlockNodeUsed(blockNode, false);

			//将旧块加入空闲块列表
			m_mapFreeBlock.insert(std::make_pair(upBoundBlockSize(blockNode.nBlockSize), nBlockIndex));
			m_fileHead.nData_HoleSize += upBoundBlockSize(blockNode.nBlockSize);

			//重新尝试分配空间
			std::pair< int, int > nNewBlockPair = allocFreeBlock(nFileSize);
			int nNewBlockIndex = nNewBlockPair.first;
			if(nNewBlockIndex < 0) 
			{
				setLastError(AXP_ERR_BLOCKFULL);	//Block表满了
				return false;
			}

			//设置Hash表数据
			setHashNodeExists(hashNode, true);
			setHashNodeBlockIndex(hashNode, nNewBlockIndex);

			//###################################
			//!! 磁盘操作开始 保存文件
			//###################################
			if(nNewBlockPair.second> 0)
			{
				//分割大空间时产生的副空间
				if(!writeBlockNode((unsigned int)(nNewBlockPair.second))) return false;
			}

			//保存文件内容
			if(sourceType==AC_DISKFILE)
			{
				if(!writeDiskFile(m_blockTable[nNewBlockIndex].nDataOffset, 
					upBoundBlockSize(m_blockTable[nNewBlockIndex].nBlockSize), szContents)) return false;
			}
			else
			{
				if(!writeMemory(m_blockTable[nNewBlockIndex].nDataOffset, 
					upBoundBlockSize(m_blockTable[nNewBlockIndex].nBlockSize), 
					szContents, nContentsLen)) return false;
			}

			//文件所在的新的BlockNode
			if(!writeBlockNode((unsigned int)nNewBlockIndex)) return false;
			//原文件所在的BlockNode
			if(nBlockIndex != nNewBlockIndex)
			{
				if(!writeBlockNode((unsigned int)nBlockIndex)) return false;
			}
			//文件的HashNode
			if(!writeHashNode((unsigned int)nHashPos)) return false;
			//文件头
			if(!writeFileHead()) return false;

			// 确认写入磁盘
			if(bSaveAtOnce)
			{
				FlushFileBuffers(m_hPakFile);
			}
			//###################################
			//!!磁盘操作结束
			//###################################
		}
	}
	else
	{
		//获取一块合适空间
		std::pair< int, int > nNewBlockPair = allocFreeBlock(nFileSize);
		int nBlockIndex = nNewBlockPair.first;
		if(nBlockIndex < 0) 
		{
			setLastError(AXP_ERR_BLOCKFULL);	//Block表满了
			return false;
		}

		//设置Hash表数据
		setHashNodeBlockIndex(hashNode, nBlockIndex);
		setHashNodeExists(hashNode, true);
		
		//###################################
		//!! 磁盘操作开始 保存文件
		//###################################
		if(nNewBlockPair.second> 0)
		{
			//分割大空间时产生的副空间
			if(!writeBlockNode((unsigned int)(nNewBlockPair.second))) return false;
		}

		if(sourceType==AC_DISKFILE)
		{
			if(!writeDiskFile(m_blockTable[nBlockIndex].nDataOffset, 
				upBoundBlockSize(m_blockTable[nBlockIndex].nBlockSize), szContents)) return false;
		}
		else
		{
			if(!writeMemory(m_blockTable[nBlockIndex].nDataOffset, 
					upBoundBlockSize(m_blockTable[nBlockIndex].nBlockSize), 
					szContents, nContentsLen)) return false;
		}

		if(!writeBlockNode((unsigned int)nBlockIndex)) return false;
		if(!writeHashNode((unsigned int)nHashPos)) return false;
		if(!writeFileHead()) return false;

		// 确认写入磁盘
		if(bSaveAtOnce)
		{
			FlushFileBuffers(m_hPakFile);
		}
		//###################################
		//!!磁盘操作结束
		//###################################
	}

	return true;
}