⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 evacachedfile.cpp

📁 linux 下最好用的 QQ 客房端。支持传文件
💻 CPP
字号:
/*************************************************************************** *   Copyright (C) 2005 by yunfan                                          * *   yunfan_zg@163.com                                                     * *                                                                         * *   This program is free software; you can redistribute it and/or modify  * *   it under the terms of the GNU General Public License as published by  * *   the Free Software Foundation; either version 2 of the License, or     * *   (at your option) any later version.                                   * *                                                                         * *   This program is distributed in the hope that it will be useful,       * *   but WITHOUT ANY WARRANTY; without even the implied warranty of        * *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         * *   GNU General Public License for more details.                          * *                                                                         * *   You should have received a copy of the GNU General Public License     * *   along with this program; if not, write to the                         * *   Free Software Foundation, Inc.,                                       * *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             * ***************************************************************************/#include "evacachedfile.h"#include "../../libeva/evautil.h"#include <stdio.h>#include <string.h>#include <qfile.h>#include <qfileinfo.h>#include <qtextcodec.h>#define InfoFileName_Ext       ".info"#define CacheFileName_Ext      ".cache"/*! * This class is to implement the file related functionalities of file transfering. * \a EvaCachedFile provides loading fragment from a file and save a fragment to a  * temporary file and method to generate the final file from the temporary cached  * file. * */EvaCachedFile::EvaCachedFile(const QString &srcDir, const QString &srcFilename, const unsigned int size)	: m_IsLoading(false), m_DirPath(srcDir), m_FileName(srcFilename), 	m_FileSize(size), m_State(ENone){	changeFileInfo();}// we know that we don't need the info file for loadingEvaCachedFile::EvaCachedFile(const QString &srcDir, const QString &srcFilename)	: m_IsLoading(true), m_DirPath(srcDir), m_FileName(srcFilename), m_CachedFileName(""),	m_State(ENone){	QString filePath = m_DirPath + "/" + m_FileName;	QFileInfo info(filePath);	if(!info.exists()){		fprintf(stderr, "EvaCachedFile::constructor -- \"%s\" dosen't exist!\n", filePath.ascii());		m_State = ENotExists;		return;	}}EvaCachedFile::~EvaCachedFile(){}const bool EvaCachedFile::setFileInfo(const QString &fileName, const unsigned int size){	m_FileName = fileName;	m_FileSize = size;	changeFileInfo();	return true;	//return changeFileInfo();}const bool EvaCachedFile::changeFileInfo(){	m_CachedFileName = m_FileName + CacheFileName_Ext;	m_InfoFileName = m_FileName + InfoFileName_Ext;	QString filePath = m_DirPath + "/" + m_CachedFileName;	QFileInfo info(filePath);	if(info.exists()){		fprintf(stderr, "EvaCachedFile::constructor -- \"%s\" already exist!\n", filePath.ascii());		m_State = EExists;		return false;	}	//m_InfoFileName = m_FileName + InfoFileName_Ext;	filePath = m_DirPath + "/" + m_InfoFileName;	info.setFile(filePath);	if(info.exists()){			fprintf(stderr, "EvaCachedFile::constructor -- \"%s\" already exists! delete it!\n", filePath.ascii());		QFile file(filePath);		if(!file.remove()){			fprintf(stderr, "EvaCachedFile::constructor -- cannot remove \"%s\"!\n", filePath.ascii());			m_State = EError;			return false;		}	}	return true;}/*! *  save one fragment onto disk *  * \param offset the abusolute offset address, the start position * \param len the length of wanted * \param buf the contents to save * \return true if saving success, otherwise false * * \note this method is to save the data into a temporary file which  *         each fragment contains 8 extra header bytes \e *  */const bool EvaCachedFile::saveFragment(const unsigned int offset, 					const unsigned int len, 					unsigned char *buf){	if(m_IsLoading) return false;	if( ! isNewFragment(offset, len)){		printf("EvaCachedFile::saveFragment -- already got this fragment!\n");		return true; // if we got it already, always return true	}	QString fullpath = m_DirPath + "/" + m_CachedFileName;	QFile file(fullpath);	if(!file.open(IO_Raw | IO_WriteOnly | IO_Append)){		printf("EvaCachedFile::saveFragment -- cannot open \"%s\"!\n", fullpath.ascii());		return false;	}	char strHeader[8];	memcpy(strHeader, &offset, 4);	memcpy(strHeader+4, &len, 4);	file.writeBlock(strHeader, 8);	file.writeBlock((char *)buf, len);	file.close();	if( ! updateInfoFile(offset, len)) return false;	// let user control this// 	if( isFinished() )// 		return generateDestFile();	return true;}/*! *  read one fragment from the source file in the disk * * \param offset the abusolute start position of this read operation * \param len the length of read * \param buf the pre-allocated buffer all the read data written into with length of len * \return the exact bytes of read */const unsigned int EvaCachedFile::getFragment(const unsigned int offset, 						const unsigned int len, 						unsigned char *buf){	if(!m_IsLoading) return false;	unsigned int bytesRead = 0;	QFile file(m_DirPath + "/" + m_FileName);	if(!file.open(IO_Raw | IO_ReadOnly)){		printf("EvaCachedFile::getFragment -- \"%s\" dosen't exist!\n", m_FileName.ascii());		return bytesRead;	}	if(file.at(offset))		bytesRead = file.readBlock((char *)buf, len);	file.close();	if( !bytesRead){		m_State = EReadError;		return 0;	}	return bytesRead;}void EvaCachedFile::setCheckValues(const unsigned char *fileNameMd5, const unsigned char *fileMd5){	memcpy(m_FileNameMd5, fileNameMd5, 16);	memcpy(m_FileMd5, fileMd5, 16);	}const bool EvaCachedFile::isFinished(){	return isInfoFinished();}const bool EvaCachedFile::isNewFragment(const unsigned int offset, const unsigned int /*len*/){	if(m_IsLoading) return false;	QMap<unsigned int, unsigned int>::Iterator iter;	iter = m_FragInfo.find(offset);	// we might need to check the length of this fragment	if(iter != m_FragInfo.end()){		m_State = EDupFragment;		return false;	}	return true;}const bool EvaCachedFile::updateInfoFile(const unsigned int offset, const unsigned int len){	if(m_IsLoading) return false;	QFile file(m_DirPath + "/" + m_InfoFileName);	if(!file.open(IO_WriteOnly | IO_Truncate)){		fprintf(stderr, "EvaCachedFile::updateInfoFile -- cannot update info file!\n");		m_State = EInfoOpen;		return false;	}	m_FragInfo[offset] = len;	QDataStream stream(&file);	Q_UINT32 qsize = m_FileSize;	// we save the basic info first	stream<< m_FileName;	stream<<qsize;	stream.writeRawBytes(m_FileNameMd5, 16);	stream.writeRawBytes(m_FileMd5, 16);	QMap<unsigned int, unsigned int>::Iterator iter;	Q_UINT32 qoffset, qlen;	for(iter=m_FragInfo.begin(); iter!=m_FragInfo.end(); ++iter){		qoffset = iter.key();		qlen = iter.data();		stream<<qoffset<<qlen;	}	file.close();	return true;}const bool EvaCachedFile::loadInfoFile(){	if(m_IsLoading) return false;	QFile file(m_DirPath + "/" + m_InfoFileName);	if(!file.open(IO_ReadOnly)){		fprintf(stderr, "EvaCachedFile::loadInfoFile -- no info file available.\n");		m_State = EInfoOpen;		return false;	}		QDataStream stream(&file);	QString fileName;	stream>> fileName;	if(fileName != m_FileName)		return false;		Q_UINT32 tmp;	stream>>tmp;	if(tmp != m_FileSize) {		file.close();		return false;	}	char *fnmd5 = new char[16];	stream.readRawBytes(fnmd5, 16);	if(memcmp(fnmd5, m_FileNameMd5, 16)){		m_State = EMd5Error;		file.close();		delete [] fnmd5;		return false;	}	delete [] fnmd5;	char *fmd5 = new char[16];	stream.readRawBytes(fmd5, 16);	if(memcmp(fmd5, m_FileMd5, 16)){		m_State = EMd5Error;		file.close();		delete [] fmd5;		return false;	}	delete [] fmd5;	Q_UINT32 qoffset, qlen;	while(!stream.atEnd()){		stream>>qoffset>>qlen;		m_FragInfo[qoffset]=qlen;	}	file.close();	return true;}// we only test the size of the fileconst bool EvaCachedFile::isInfoFinished(){	if(m_IsLoading) return false;	Q_UINT32 tmp = 0;	QMap<unsigned int, unsigned int>::Iterator iter;	//Q_UINT32 qoffset, qlen;	for(iter=m_FragInfo.begin(); iter!=m_FragInfo.end(); ++iter){		tmp += iter.data();	}	printf("EvaCachedFile::isInfoFinished -- tmp: %d, m_FileSize: %d\n", tmp, m_FileSize);	if(tmp == m_FileSize) return true;	return false;}const unsigned int EvaCachedFile::getNextOffset(){	if(m_IsLoading) return 0;	Q_UINT32 offset = 0;	QMap<unsigned int, unsigned int>::Iterator iter;	for(iter=m_FragInfo.begin(); iter!=m_FragInfo.end(); ++iter){		offset += iter.data();	}	return offset;}const bool EvaCachedFile::isFileCorrect(){	if(m_IsLoading) return true; // if we are loading file, this would be always true	// check dest-file size	QFileInfo info(m_DirPath + "/" + m_FileName);	if(!info.exists())		return false;		if(info.size() != m_FileSize) return false;	// check dest-file md5 value	char *md5 = new char[16];	if(!getSourceFileMd5(md5)){		m_State = EMd5Error;		return false;	}	if(memcmp(m_FileMd5, md5, 16)){		m_State = EMd5Error;		return false;	}	// check dest-file name md5	getSourceFileNameMd5(md5);	if(memcmp(m_FileNameMd5, md5, 16)){		fprintf(stderr, "EvaCachedFile::isFileCorrect -- \"%s\" file name saved might be wrong but file contents should be all right.\n", m_FileName.ascii());	}	delete []md5;	return true;}const bool EvaCachedFile::generateDestFile(){	if(m_IsLoading) return false;	if(m_DirPath.isEmpty()) return false;	QString cachedFileName = m_DirPath + "/" + m_FileName + CacheFileName_Ext;	QString destFileName = m_DirPath + "/" + m_FileName;	QFile cached(cachedFileName);	QFile dest(destFileName);	if(!cached.open(IO_ReadOnly)){		fprintf(stderr, "EvaCachedFile::generateDestFile -- cannot open cached file \"%s\"!\n", cachedFileName.ascii());		return false;	}	if(!dest.open(IO_WriteOnly)){		fprintf(stderr, "EvaCachedFile::generateDestFile -- cannot create destination file \"%s\"!\n", destFileName.ascii());		return false;	}	char *buf; // we might create a fixed-size buffer to save time	char strHeader[8];	unsigned int offset, len;	while(!cached.atEnd()){		cached.readBlock(strHeader, 8);		memcpy(&offset, strHeader, 4);		memcpy(&len, strHeader+4, 4);		buf = new char [len];		cached.readBlock(buf, len);		dest.at(offset);		dest.writeBlock(buf, len);		delete []buf;	}	cached.close();	dest.close();	if(!isFileCorrect()){		//dest.remove();		fprintf(stderr, "EvaCachedFile::generateDestFile -- md5 checking wrong\n");		return false;	}	// actually we got all we want, we don't care about the result of removing following files	cached.remove();	QFile info(m_DirPath + "/" + m_InfoFileName);	info.remove();	m_FragInfo.clear();	return true;}const bool EvaCachedFile::calculateFileMd5(const QString& fullpath, char *md5Buf){	QFileInfo info(fullpath);	if(!info.exists()){		fprintf(stderr, "EvaCachedFile::calculateFileMd5 -- \"%s\" dosen't exist!\n", fullpath.ascii());		return false;	}	unsigned int len = info.size();	if(len > MaxMd5CheckLength)		len = MaxMd5CheckLength;	char *buf = new char[len];	QFile file(fullpath);	if(!file.open(IO_ReadOnly)){		printf("EvaCachedFile::calculateFileMd5 -- \"%s\" dosen't exist!\n", fullpath.ascii());		delete []buf;		return false;	}	unsigned int numRead = file.readBlock(buf, len);	file.close();	if(numRead!=len){		delete []buf;		return false;	}	memcpy(md5Buf, EvaUtil::doMd5(buf, len), 16);	delete []buf;	return true;}const bool EvaCachedFile::getSourceFileMd5(char *md5){	if(!md5) return false;	if(m_DirPath.isEmpty() || m_FileName.isEmpty()) return false;	return calculateFileMd5(m_DirPath + "/" + m_FileName, md5);}const bool EvaCachedFile::getSourceFileNameMd5(char *md5){	if(!md5) return false;	QTextCodec *codec = QTextCodec::codecForName("GB18030");	QCString tmp = codec->fromUnicode(m_FileName);	memcpy(md5, EvaUtil::doMd5(tmp.data(), tmp.length()), 16);	return true;}const unsigned int EvaCachedFile::getFileSize(){	if(!m_IsLoading) return m_FileSize;	QFileInfo info(m_DirPath + "/" + m_FileName);	if(!info.exists())		return 0;	return info.size();}void EvaCachedFile::setDestFileDir( const QString & dir ){	if(m_IsLoading) return;	m_DirPath = dir;	changeFileInfo();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -