#include "stdafx.h" #include "FileCmder.h" #include #include #include #include #include #include "FileSession.h" #include "OIClientConnect.h" #include #ifdef _WIN32 #include #include #else #include #include #include #include #endif #define ERROR_FILE_NOT_FOUND 2L namespace OIFileC { ///////////////////////////////////////////////////////////////////////////// // CFileCmder window CFileCmder::CFileCmder(void) { m_bIsFirst = true; m_dwOption = 0; m_pFile = NULL; m_nReaded = 0; m_nFileSize = 0; m_bIsBase64 = false; // m_pdlgUpload = NULL; // m_pdlgDownload = NULL; m_nBlockCount = 0; m_pszCurBlock = NULL; m_nCurBlock = 0; m_nCurBlockSize = 0; m_nSendedOfBlock = 0; m_nCurBlockRelSize = 0; m_nResendCount = 0; m_pszFileData = NULL; } CFileCmder::~CFileCmder(void) { CloseFile(); if ( m_pszCurBlock ) { if ( m_bIsBase64 ) free( m_pszCurBlock ); m_pszCurBlock = NULL; } if ( m_pszFileData ) delete m_pszFileData; /* if ( m_pdlgUpload ) { m_pdlgUpload->DestroyWindow(); delete m_pdlgUpload; m_pdlgUpload = NULL; } if ( m_pdlgDownload ) { m_pdlgDownload->DestroyWindow(); delete m_pdlgDownload; m_pdlgDownload = NULL; } */ } ///////////////////////////////////////////////////////////////////////////// // CFileCmder message handlers bool CFileCmder::CanPrsCmd( const wstring &strCmdName ) { if ( CMD_FILE_UPLOAD == strCmdName || CMD_FILE_DOWNLOAD == strCmdName || CMD_FILE_COPY == strCmdName || CMD_FILE_DELETE == strCmdName || CMD_FILE_GETFILEINFO == strCmdName ) { return true; } return false; } /* void CFileCmder::SetAppType( const wstring &strAppType ) { m_strAppType = strAppType; } */ void CFileCmder::SetUploadFile( const wstring &strFileName ) { m_strPathName = strFileName; m_strFileName = COICommFun::GetFileName( m_strPathName ); } void CFileCmder::SetDownloadFile( const wstring &strFolderName, const wstring &strSaveFile ) { m_strFolderName = strFolderName; if ( m_strFolderName.empty() ) m_strFolderName = COICommFun::GetPathName( strSaveFile ); else { m_strFolderName = COICommFun::ReplaceStr( m_strFolderName, L"\\", L"/" ); COICommFun::TrimRight( m_strFolderName, L'/' ); } m_strSavedFile = strSaveFile; } void CFileCmder::SetResumeInfoPath( const wstring &strPath ) { m_strResumeInfoPath = strPath; } void CFileCmder::OnDisconnect( COIClientSocket *pSocket, short nInfo, int nCode ) { if ( m_pConnect ) { wstring strParam; wchar_t szBuff[1024]; int nErrCode; // 关闭文件 CloseFile(); // 断点续传关闭 m_infoFileResume.CloseFile(); // 关闭上传窗口,如果有的话 ShowUploadDlg( L"", 0, 0 ); // 关闭下载窗口,如果有的话 ShowDownloadDlg( L"", 0, 0 ); if ( IsCancel() ) nErrCode = ERR_CMD_CANCELED; else nErrCode = ERR_CONNCET_CLOSE; // strParam.Format( _T( "Method=%s;ErrCode=%d;TrID=%d;AppType=%s;ConnectType=%s" ), // m_strMethod, nErrCode, m_nTrID, m_pSession->m_strAppType, m_pSession->m_strConnectType ); swprintf( szBuff, 1024, L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s", m_strMethod.c_str(), nErrCode, m_nTrID, m_pSession->m_strAppType.c_str() ); strParam = szBuff; m_pConnect->OnCmderError( nErrCode, this, strParam ); } } void CFileCmder::OnConnectFailed( COIClientSocket *pSocket, int nErrorCode ) { if ( m_pConnect ) { wstring strParam; wchar_t szBuff[1024]; // 关闭文件 CloseFile(); // 断点续传关闭 m_infoFileResume.CloseFile(); // 关闭上传窗口,如果有的话 ShowUploadDlg( L"", 0, 0 ); // 关闭下载窗口,如果有的话 ShowDownloadDlg( L"", 0, 0 ); // 如果是主动取消引起的连接失败,返回取消 if ( IsCancel() ) nErrorCode = ERR_CMD_CANCELED; // strParam.Format( _T( "Method=%s;ErrCode=%d;TrID=%d;AppType=%s;ConnectType=%s" ), // m_strMethod, nErrorCode, m_nTrID, m_pSession->m_strAppType, m_pSession->m_strConnectType ); swprintf( szBuff, 1024, L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s", m_strMethod.c_str(), nErrorCode, m_nTrID, m_pSession->m_strAppType.c_str() ); strParam = szBuff; m_pConnect->OnCmderError( nErrorCode, this, strParam ); } } void CFileCmder::OnConnected( COIClientSocket *pSocket ) { if ( CMD_FILE_UPLOAD == m_strMethod ) // 上传文件 UploadFile( pSocket ); else if ( CMD_FILE_DOWNLOAD == m_strMethod ) // 下载文件 DownloadFile( pSocket ); else if ( CMD_FILE_COPY == m_strMethod ) // 复制文件 CopyFile( pSocket ); else if ( CMD_FILE_DELETE == m_strMethod ) // 删除文件 DeleteFile( pSocket ); else if ( CMD_FILE_GETFILEINFO == m_strMethod ) // 得到文件信息 GetFileInfo( pSocket ); return; } int CFileCmder::ExportBuff( COIBuffer *pBuff, size_t nNeedLen ) { if ( IsCancel() ) { CloseFile(); return false; } int nDataLen; nDataLen = m_nCurBlockSize - m_nSendedOfBlock; if ( nDataLen > SIZE_PACK_BASE64 ) nDataLen = SIZE_PACK_BASE64; pBuff->Write( m_pszCurBlock + m_nSendedOfBlock, nDataLen ); m_nSendedOfBlock += nDataLen; // 通知发送进度 if ( (m_dwOption & OPTION_TRANOPTION_SHOWDLG) || (m_dwOption & OPTION_TRANOPTION_REPORT) ) { int nFileLen; // 目前已经发送的文件 if ( m_bIsBase64 ) nFileLen = (m_nSendedOfBlock + 3) / 4 * 3; else nFileLen = m_nSendedOfBlock; if ( m_dwOption & OPTION_TRANOPTION_SHOWDLG ) ShowUploadDlg( m_strFileName, m_nReaded + nFileLen, 0 ); if ( m_pSession && (m_dwOption & OPTION_TRANOPTION_REPORT) ) ((CFileSession *)m_pSession)->ReportUploadProgress( m_strMethod, m_strFileID, m_nTrID, m_strFileName, m_nReaded + nFileLen, m_nFileSize ); } return true; } bool CFileCmder::OnResponse( COIResponse *pResponse, COIClientSocket *pSocket ) { wstring strMethod; strMethod = pResponse->GetMethod(); if ( L"ERR" == strMethod ) { // 出错,如果文件打开,则先关闭文件 CloseFile(); // 关闭续传信息文件 m_infoFileResume.CloseFile(); if ( m_pConnect ) { wstring strParam, strErrParam; wchar_t szBuff[1024]; long nErrCode; nErrCode = pResponse->GetParamInt( 1 ); strErrParam = pResponse->GetParam( 2 ); // strParam.Format( _T( "%s;ErrCode=%d;TrID=%d;AppType=%s;ConnectType=%s" ), // strErrParam, nErrCode, m_nTrID, m_pSession->m_strAppType, m_pSession->m_strConnectType ); swprintf( szBuff, 1024, L"%s;ErrCode=%d;TrID=%d;AppType=%s", strErrParam.c_str(), nErrCode, m_nTrID, m_pSession->m_strAppType.c_str() ); strParam = szBuff; m_pConnect->OnCmderError( nErrCode, this, strParam ); } if ( pResponse->GetStatus() == COIResponse::Status_Done ) pSocket->Free(); return true; } // 命令反馈 if ( CMD_FILE_UPLOAD == strMethod ) // 发送文件 return ResponseUploadFile( pResponse, pSocket ); else if ( CMD_FILE_DOWNLOAD == strMethod ) // 下载文件 return ResponseDownloadFile( pResponse, pSocket ); else if ( CMD_FILE_COPY == strMethod ) // 复制文件 return ResponseCopyFile( pResponse, pSocket ); else if ( CMD_FILE_DELETE == strMethod ) // 删除文件 return ResponseDeleteFile( pResponse, pSocket ); else if ( CMD_FILE_GETFILEINFO == strMethod ) // 得到文件信息 return ResponseGetFileInfo( pResponse, pSocket ); return false; } //======================================================= // << ULF nTrID nOption // AppType : // Operator : // OperatorName : // FileName : // FileMD5 : // PathName : // FileSize : // BlockCount : void CFileCmder::UploadFile( COIClientSocket *pSocket ) { if ( !pSocket ) return; COIBasePtr ptrRequest; wstring strFileName; wstring strModifyTime; long nFlag = m_dwOption; ptrRequest = new COIRequest( this ); ptrRequest->SetMethod( m_strMethod ); ptrRequest->AppendParam( (long)m_nTrID ); ptrRequest->AppendParam( nFlag ); if ( !m_strFolderName.empty() ) ptrRequest->SetProperty( L"PathName", m_strFolderName ); ptrRequest->SetProperty( L"AppType", m_pSession->m_strAppType ); ptrRequest->SetProperty( L"Operator", m_pSession->m_strUserLogin ); ptrRequest->SetProperty( L"OperatorName", m_pSession->m_strUserName ); strFileName = COICommFun::GetFileName( m_strPathName ); if ( strFileName.empty() ) { UploadFileErr( ptrRequest, pSocket, ERR_LOCAL_FILE_NAME_EMPTY ); return; } if ( strFileName.length() > 80 ) { // 文件名太长了 wstring strExName; int nIndex; nIndex = strFileName.rfind( L"." ); if ( wstring::npos != nIndex ) strExName = strFileName.substr( nIndex ); strFileName = strFileName.substr( 0, 81 - strExName.length() ); strFileName += strExName; } ptrRequest->SetProperty( L"FileName", strFileName ); // 生成文件 MD5 if ( m_strFileMD5.empty() ) { CMD5Fun funMD5; char szFileMD5[33] = { 0 }; string strByteFilePath; strByteFilePath = COICommFun::WideChar2MultiByte( m_strPathName.c_str(), false ); funMD5.digest_filemd5( (unsigned char *)strByteFilePath.c_str(), (unsigned char *)szFileMD5 ); m_strFileMD5 = COICommFun::MultiByte2WideChar( szFileMD5, false ); } ptrRequest->SetProperty( L"FileMD5", m_strFileMD5 ); // 关闭原打开文件 CloseFile(); // 打开文件 //m_pFile = _wfopen( m_strPathName.c_str(), L"rb" ); m_pFile = fopen( COICommFun::WideChar2MultiByte(m_strPathName.c_str()).c_str(), "rb" ); if ( !m_pFile ) { // 打开文件失败,可能文件正在被打开中,Windows系统尝试复制到临时目录下打开 #ifdef WIN32 // if File is Open then Copy File to Temp Folder wstring strTempPath; wchar_t szPath[MAX_PATH] = { 0 }; ::GetTempPath( MAX_PATH, szPath ); strTempPath = szPath; strTempPath += strFileName; ::DeleteFile( strTempPath.c_str() ); if ( !::CopyFile( m_strPathName.c_str(), strTempPath.c_str(), false ) ) { UploadFileErr( ptrRequest, pSocket, ERR_LOCAL_FILE_OPEN ); return; } Sleep( 500 ); m_strCopyedPathName = strTempPath; m_pFile = _wfopen( strTempPath.c_str(), L"rb" ); if ( !m_pFile ) { UploadFileErr( ptrRequest, pSocket, ERR_LOCAL_FILE_OPEN ); return; } #else UploadFileErr( ptrRequest, pSocket, ERR_LOCAL_FILE_OPEN ); return ; #endif } // End of if ( !m_pFile ) // 文件大小及最后修改时间 size_t nSize = 0; COIHighTime tmFile; #ifdef WIN32 struct _stat info; _wstat( m_strPathName.c_str(), &info ); #else struct stat info; stat( COICommFun::WideChar2MultiByte( m_strPathName.c_str()).c_str(), &info ); #endif m_nFileSize = info.st_size; tmFile = info.st_mtime; strModifyTime = tmFile.FormatGmt( L"%Y-%m-%d %H:%M:%S" ); ptrRequest->SetProperty( L"FileModifyTime", strModifyTime ); // ptrRequest->SetProperty( L"Content-Type", L"Appliction/Download" ); // CONTYPE_FILE ptrRequest->SetProperty( L"FileSize", (__int64)m_nFileSize ); //@Terry in 2015.11.2,内容在文件头发送返回后再分包发送 // ptrRequest->SetBodySize( m_nFileSize ); // 文件内容采用 BASE64 编码进行发送,需采用 BASE64 的长度 // ptrRequest->SetBodySize( (m_nFileSize + 2) / 3 * 4 ); // 计算分块数量 m_nBlockCount = (m_nFileSize + SIZE_BLOCK - 1) / SIZE_BLOCK; m_nCurBlock = 0; ptrRequest->SetProperty( L"BlockCount", (long)m_nBlockCount ); // 申请文件读取的内存空间,以免每次读取时申请 m_pszFileData = new char[SIZE_BLOCK + 1]; memset( m_pszFileData, 0, SIZE_BLOCK + 1 ); // int nSet = 1; // pSocket->SetSockOpt( TCP_NODELAY, (void *)&nSet, sizeof( int ), IPPROTO_TCP ); pSocket->SendRequest( ptrRequest ); // 通知开始传送文件 if ( m_dwOption & OPTION_TRANOPTION_SHOWDLG ) ShowUploadDlg( m_strFileName, m_nReaded, m_nFileSize ); if ( m_pSession && (m_dwOption & OPTION_TRANOPTION_REPORT) ) ((CFileSession *)m_pSession)->ReportUploadProgress( m_strMethod, m_strFileID, m_nTrID, m_strFileName, m_nReaded, m_nFileSize ); } //======================================================= // << DLF nTrID strFileID // Operator : // OperatorName : void CFileCmder::DownloadFile( COIClientSocket *pSocket ) { if ( !pSocket ) return; // 读取续传的断点信息 if ( !m_strResumeInfoPath.empty() ) { m_infoFileResume.m_strResumeInfoFile = m_strResumeInfoPath + L"/" + m_strFileID + L".rem"; m_infoFileResume.LoadData(); // 校验有效性 m_infoFileResume.VerifyValid(); m_infoFileResume.m_strFileID = m_strFileID; } COIBasePtr ptrRequest; ptrRequest = new COIRequest( this ); ptrRequest->SetMethod( m_strMethod ); ptrRequest->AppendParam( (long)m_nTrID ); ptrRequest->AppendParam( m_strFileID ); ptrRequest->SetProperty( L"Operator", m_pSession->m_strUserLogin ); ptrRequest->SetProperty( L"OperatorName", m_pSession->m_strUserName ); if ( 0 != m_infoFileResume.m_nReceivedSize ) ptrRequest->SetProperty( L"StartPos", m_infoFileResume.m_nReceivedSize ); pSocket->SendRequest( ptrRequest ); } //============================================= // << CPF nTrID strFileID nOption // AppType : // PathName : // Operator : // OperatorName : void CFileCmder::CopyFile( COIClientSocket *pSocket ) { if ( !pSocket ) return; COIBasePtr ptrRequest; ptrRequest = new COIRequest( this ); ptrRequest->SetMethod( m_strMethod ); ptrRequest->AppendParam( (long)m_nTrID ); ptrRequest->AppendParam( m_strFileID ); ptrRequest->AppendParam( (long)m_dwOption ); if ( !m_strFolderName.empty() ) ptrRequest->SetProperty( L"PathName", m_strFolderName ); ptrRequest->SetProperty( L"AppType", m_pSession->m_strAppType ); ptrRequest->SetProperty( L"Operator", m_pSession->m_strUserLogin ); ptrRequest->SetProperty( L"OperatorName", m_pSession->m_strUserName ); pSocket->SendRequest( ptrRequest ); } //============================================= // << DTF nTrID strFileID // Operator : // OperatorName : void CFileCmder::DeleteFile( COIClientSocket *pSocket ) { if ( !pSocket ) return; COIBasePtr ptrRequest; ptrRequest = new COIRequest( this ); ptrRequest->SetMethod( m_strMethod ); ptrRequest->AppendParam( (long)m_nTrID ); ptrRequest->AppendParam( m_strFileID ); ptrRequest->SetProperty( L"Operator", m_pSession->m_strUserLogin ); ptrRequest->SetProperty( L"OperatorName", m_pSession->m_strUserName ); pSocket->SendRequest( ptrRequest ); } //============================================= // << GFI nTrID strFileID // Operator : // OperatorName : void CFileCmder::GetFileInfo( COIClientSocket *pSocket ) { if ( !pSocket ) return; COIBasePtr ptrRequest; ptrRequest = new COIRequest( this ); ptrRequest->SetMethod( m_strMethod ); ptrRequest->AppendParam( (long)m_nTrID ); ptrRequest->AppendParam( m_strFileID ); ptrRequest->SetProperty( L"Operator", m_pSession->m_strUserLogin ); ptrRequest->SetProperty( L"OperatorName", m_pSession->m_strUserName ); pSocket->SendRequest( ptrRequest ); } bool CFileCmder::ResponseUploadFile( COIResponse *pResponse, COIClientSocket *pSocket ) { if ( pResponse->GetStatus() != COIResponse::Status_Done ) return true; // 文件服务器已经存在此 FileMD5 的文件,无需发送,直接服务端复制 wstring strFileID = pResponse->GetParam( 1 ); if ( !strFileID.empty() ) { pSocket->Free(); // 关闭文件 CloseFile(); // 关闭续传信息文件 m_infoFileResume.CloseFile(); // 关掉上传对话框 ShowUploadDlg( L"", 0, 0 ); // 消息发送成功 if ( m_pConnect ) m_pConnect->OnCmderResponse( pResponse, this ); return true; } // 是否主动取消 if ( IsCancel() ) { // 关闭文件 CloseFile(); // 关闭续传信息文件 m_infoFileResume.CloseFile(); // 反馈取消指令 OnConnectFailed( pSocket, ERR_CMD_CANCELED ); return false; } // 是否需要重发 wstring strResendFlag = pResponse->GetProperty( L"Resend" ); if ( L"1" == strResendFlag ) { // 重发次数 +1 if ( !m_bIsBase64 ) { m_nResendCount++; if ( 3 == m_nResendCount ) { CMD5Fun funMD5; unsigned char szMD5[33] = { 0 }; m_bIsBase64 = true; // 将数据转为 Base64 m_pszCurBlock = COICommFun::Str2Base64( (const unsigned char *)m_pszFileData, NULL, m_nCurBlockRelSize ); m_nCurBlockSize = strlen( m_pszCurBlock ); // 生成数据的验证码 MD5 funMD5.digest_md5( (unsigned char *)m_pszCurBlock, m_nCurBlockSize, szMD5 ); m_strBlockMD5 = COICommFun::MultiByte2WideChar( (const char *)szMD5, false ); } } // 数据块重发 UploadBlockData( pSocket ); } // End of if ( _T( "1" ) == strResendFlag ) else { // 第一次返回,得到发送的事务ID // if ( 0 == m_nReaded ) // 第一次发送,传输的数据块为 0 大小 if ( 0 == m_nCurBlockRelSize ) { m_strTrSessonID = pResponse->GetProperty( L"SessionID" ); //@Terry in 2017.1.5,提供客户端可以强制要求采用 Base64 传输 // 客户端没要求强制采用 Base64 ,读取服务端是否有强制要求 if ( !m_bIsBase64 ) { // 是否要采用 Base64 编码传输 m_bIsBase64 = pResponse->GetPropertyInt( L"Base64" ) != 0 ? true : false; } // 返回断点续传信息 m_nReaded = pResponse->GetPropertyInt64( L"ReceivedSize" ); if ( m_nReaded > 0 ) { fseek( m_pFile, m_nReaded, SEEK_SET ); m_nCurBlock = m_nReaded / SIZE_BLOCK; } } else { // 已经传完的长度 + 本块长度 m_nReaded += m_nCurBlockRelSize; } /* //## 只看反馈是否有 FileID 来确定是否成功 if ( m_nReaded == m_nFileSize ) { pSocket->Free(); // 关掉上传对话框 ShowUploadDlg( _T( "" ), 0, 0 ); // 消息发送成功 if ( m_pConnect ) m_pConnect->OnCmderResponse( pResponse, this ); return true; } */ // 发送下一个数据包 if ( m_nReaded < m_nFileSize ) { // 发送完成,发送的数据块计数 +1 m_nCurBlock++; // 读取下一块数据,并生成相关数据 ReadBlockData(); // 发送数据包 UploadBlockData( pSocket ); } } // End of if ( _T( "1" ) == strResendFlag ) else ... return true; } bool CFileCmder::ResponseDownloadFile( COIResponse *pResponse, COIClientSocket *pSocket ) { // 是否客户端主动取消 if ( IsCancel() ) { pSocket->Free(); // 关闭文件 CloseFile(); // 关闭续传信息文件 m_infoFileResume.CloseFile(); // 释放缓存 if ( m_pszFileData ) { delete m_pszFileData; m_pszFileData = NULL; } // 不删除下载文件,为后续断点续传使用 // ::DeleteFile( m_strPathName ); if ( m_pConnect ) { wstring strParam; wchar_t szBuff[1024] = { 0 }; swprintf( szBuff, 1024, // L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s;ConnectType=%s", L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s", // m_strMethod.c_str(), ERR_CMD_CANCELED, m_nTrID, m_pSession->m_strAppType.c_str(), m_pSession->m_strConnectType.c_str() ); m_strMethod.c_str(), ERR_CMD_CANCELED, m_nTrID, m_pSession->m_strAppType.c_str() ); strParam = szBuff; m_pConnect->OnCmderError( ERR_CMD_CANCELED, this, strParam ); pSocket->Release(); } return false; } // End of if ( IsCancel() ) // 是第一个数据包,先处理文件头 if ( m_bIsFirst ) { m_strFileName = pResponse->GetProperty( L"FileName" ); if ( m_strFileName.empty() ) return false; // 文件名 if ( !m_strSavedFile.empty() ) m_strPathName = m_strSavedFile; else m_strPathName = m_strFolderName + L"/" + m_strFileName; m_strPathName += RESUME_TEMPFILE_EXT; m_bIsBase64 = pResponse->GetPropertyInt( L"Base64" ) != 0 ? true : false; // 得到文件真实大小 m_nFileSize = pResponse->GetPropertyInt64( L"FileSize" ); // 如果未指定,则得到传输的内容大小 if ( 0 == m_nFileSize ) { pResponse->GetBodySize(); m_nFileSize = pResponse->GetPropertyInt64( L"Content-Length" ); // 如果传输的内容是 Base64 编码,则长度需做处理 if ( m_bIsBase64 ) m_nFileSize = (m_nFileSize + 3) / 4 * 3; } // 检测选择保存时的硬盘空间是否充足 if ( COICommFun::GetDiskFreeSize( m_strFolderName ) < m_nFileSize ) { DownloadFileErr( pResponse, pSocket, ERR_LOCAL_SPACE_NOT_ENOUGH ); return false; } // 将原来续传的文件移至当前位置 if ( !m_infoFileResume.m_strResumeInfoFile.empty() ) { if ( m_infoFileResume.m_strFilePath.empty() ) m_infoFileResume.m_strFilePath = m_strPathName; else { // 文件存储位置不同,则需将原临时文件移过来 if ( qstricmp( COICommFun::WideChar2MultiByte(m_infoFileResume.m_strFilePath.c_str()).c_str(), COICommFun::WideChar2MultiByte(m_strPathName.c_str()).c_str() ) != 0 ) { // 删除文件 COICommFun::DeleteFile( m_strPathName ); // 将原临时文件移过来 COICommFun::MoveFile( m_infoFileResume.m_strFilePath, m_strPathName ); m_infoFileResume.m_strFilePath = m_strPathName; } } } // End of if ( !m_infoFileResume.m_strResumeInfoFile.empty() ) //@Terry in 2019.3.13,如果是断点续传,文件是存在的,不能因为文件存在而直接报错 //@Terry in 2018.6.28,创建文件前先判断文件是否存在,以免直接创建会有句柄问题 /* if ( CFileCommFun::ExistFile( m_strPathName ) ) { DownloadFileErr( pResponse, pSocket, ERR_LOCAL_FILE_CREATE ); return false; } */ // 创建本地文件准备写 //m_pFile = _wfopen( m_strPathName.c_str(), L"w+b" ); m_pFile = fopen( COICommFun::WideChar2MultiByte(m_strPathName.c_str()).c_str(),"w+b" ); if ( !m_pFile ) { DownloadFileErr( pResponse, pSocket, ERR_LOCAL_FILE_CREATE ); return false; } // 定位至上一次保存的位置 if ( 0 != m_infoFileResume.m_nWritedSize ) { fseek( m_pFile, m_infoFileResume.m_nWritedSize, SEEK_SET ); m_nReaded = m_infoFileResume.m_nWritedSize; } // 申请缓存 if ( m_pszFileData ) delete m_pszFileData; m_pszFileData = new char[SIZE_PACK_BASE64 + 1]; memset( m_pszFileData, 0, SIZE_PACK_BASE64 + 1 ); m_bIsFirst = false; } // End of if ( m_bIsFirst ) // 接收内容 int nBodySize = pResponse->GetBufferSize(); if ( 0 == nBodySize ) return true; COIBasePtr ptrBodyBuff; char *pszBody; ptrBodyBuff = pResponse->GetBodyBuffer(); if ( !ptrBodyBuff ) return true; // pszBody = new char[nBodySize + 1]; // 从缓存中读取数据 // ptrBodyBuff->Read( pszBody, nBodySize ); pszBody = (char *)ptrBodyBuff->GetStart(); // 将数据写入文件缓存,缓存满了则写入文件 WriteFileData( pszBody, nBodySize ); // delete [] pszBody; // 汇报进度 if ( nBodySize > 0 || m_nReaded == (UINT)m_nFileSize ) { // Option if ( m_dwOption & OPTION_TRANOPTION_SHOWDLG ) ShowDownloadDlg( m_strFileName, m_nReaded, m_nFileSize ); // 通知文件大小 if ( m_pSession && (m_dwOption & OPTION_TRANOPTION_REPORT) ) ((CFileSession *)m_pSession)->ReportDownloadProgress( m_nTrID, m_strFileID, m_strFileName, m_nReaded, m_nFileSize ); } // 是否传输完毕 if ( pResponse->GetStatus() == COIResponse::Status_Done ) { // 释放连接 pSocket->Free(); // 保存缓存 if ( m_nSendedOfBlock > 0 ) WriteToFile(); // 关闭文件 CloseFile(); // 删除断点续传文件 m_infoFileResume.DeleteFile(); // 关闭下载窗口 ShowDownloadDlg( L"", 0, 0 ); wstring strModifyDate = pResponse->GetProperty( L"FileModifyTime" ); if ( !strModifyDate.empty() ) { COIHighTime tmModify; if ( tmModify.ParseDateTime( strModifyDate.c_str() ) && tmModify > COIHighTime( 1970, 1, 1, 0, 0, 0 ) ) { // 服务端保存的为 格林时间,需转为本地时间 tmModify.LocalTime(); COICommFun::SetFileModifyTime( m_strPathName, tmModify ); } } // End of if ( !strModifyDate.empty() ) // 去掉临时文件的最后 .fd try { m_strCopyedPathName = m_strPathName.substr( 0, m_strPathName.length() - 3 ); if ( !COICommFun::DeleteFile( m_strCopyedPathName ) ) { DWORD dwErrCode; #ifdef WIN32 dwErrCode = GetLastError(); #else dwErrCode = errno; #endif if ( ERROR_FILE_NOT_FOUND != dwErrCode ) { DownloadFileErr( pResponse, pSocket, ERR_LOCAL_FILE_OVERWRITE ); return false; } } #ifdef WIN32 int nRet = ::_wrename( m_strPathName.c_str(), m_strCopyedPathName.c_str() ); #else int nRet = ::rename( COICommFun::WideChar2MultiByte(m_strPathName.c_str()).c_str() ,COICommFun::WideChar2MultiByte(m_strCopyedPathName.c_str()).c_str()); #endif if ( 0 != nRet ) { DownloadFileErr( pResponse, pSocket, ERR_LOCAL_FILE_OVERWRITE ); return false; } } catch (...) { DownloadFileErr( pResponse, pSocket, ERR_LOCAL_FILE_OVERWRITE ); return false; } pResponse->SetProperty( L"LocalPath", m_strCopyedPathName ); pResponse->SetProperty( L"IsOk", L"1" ); if ( m_pConnect ) m_pConnect->OnCmderResponse( pResponse, this ); } // End of if ( pResponse->m_resStatus == RES_DONE ) return true; } bool CFileCmder::ResponseCopyFile( COIResponse *pResponse, COIClientSocket *pSocket ) { if ( pResponse->GetStatus() == COIResponse::Status_Done ) { pSocket->Free(); // 消息发送成功 if ( m_pConnect ) m_pConnect->OnCmderResponse( pResponse, this ); } return true; } bool CFileCmder::ResponseDeleteFile( COIResponse *pResponse, COIClientSocket *pSocket ) { if ( pResponse->GetStatus() == COIResponse::Status_Done ) { pSocket->Free(); // 消息发送成功 if ( m_pConnect ) m_pConnect->OnCmderResponse( pResponse, this ); } return true; } bool CFileCmder::ResponseGetFileInfo( COIResponse *pResponse, COIClientSocket *pSocket ) { if ( pResponse->GetStatus() == COIResponse::Status_Done ) { pSocket->Free(); // 消息发送成功 if ( m_pConnect ) m_pConnect->OnCmderResponse( pResponse, this ); } return true; } void CFileCmder::ShowUploadDlg( const wstring &strFileName, __int64 nUploaded, __int64 nFileSize ) { /* // 文件名为空,则关闭对话框 if ( strFileName.empty() ) { if ( m_pdlgUpload ) { m_pdlgUpload->DestroyWindow(); delete m_pdlgUpload; m_pdlgUpload = NULL; } return; } if ( !m_pdlgUpload ) { CResourceMgr mgrResource( _T( "OIFileC.dll" ) ); m_pdlgUpload = new CUploadDlg; if ( !m_pdlgUpload->Create( IDD_UPLOAD, m_pdlgUpload ) ) { delete m_pdlgUpload; m_pdlgUpload = NULL; return; } m_pdlgUpload->ShowWindow( SW_SHOW ); m_pdlgUpload->m_pSession = (CFileSession *)m_pSession; m_pdlgUpload->m_nTrID = m_nTrID; m_pdlgUpload->SetAttachInfo( strFileName ); m_pdlgUpload->SetForegroundWindow(); } m_pdlgUpload->SetUploadedInfo( nUploaded, nFileSize ); */ } void CFileCmder::ShowDownloadDlg( const wstring &strFileName, __int64 nDownloaded, __int64 nFileSize ) { /* // 文件名为空,则关闭对话框 if ( strFileName.empty() ) { if ( m_pdlgDownload ) { m_pdlgDownload->DestroyWindow(); delete m_pdlgDownload; m_pdlgDownload = NULL; } return; } if ( !m_pdlgDownload ) { CResourceMgr mgrResource( _T( "OIFileC.dll" ) ); m_pdlgDownload = new CDownloadDlg; if ( !m_pdlgDownload->Create( IDD_DOWNLOAD, m_pdlgDownload ) ) { delete m_pdlgDownload; m_pdlgDownload = NULL; return; } m_pdlgDownload->ShowWindow( SW_SHOW ); m_pdlgDownload->m_pSession = (CFileSession *)m_pSession; m_pdlgDownload->m_nTrID = m_nTrID; m_pdlgDownload->SetAttachInfo( strFileName, m_strFolderName ); m_pdlgDownload->SetForegroundWindow(); } m_pdlgDownload->SetDownloadedInfo( nDownloaded, nFileSize ); */ } bool CFileCmder::UploadFileErr( COIRequest *pRequest, COIClientSocket *pSocket, DWORD dwErrorCode ) { if ( !pRequest || !pSocket ) return false; pSocket->Free(); // 关闭文件 CloseFile(); // 关闭上传窗口,如果有的话 ShowUploadDlg( L"", 0, 0 ); if ( m_pConnect ) { wstring strParam; wchar_t szBuff[1024] = { 0 }; swprintf( szBuff, 1024, // L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s;ConnectType=%s;FileID=%s;FileName=%s", L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s;FileID=%s;FileName=%s", // pRequest->GetMethod().c_str(), dwErrorCode, m_nTrID, m_pSession->m_strAppType.c_str(), m_pSession->m_strConnectType.c_str(), pRequest->GetMethod().c_str(), dwErrorCode, m_nTrID, m_pSession->m_strAppType.c_str(), pRequest->GetParam( 1 ).c_str(), pRequest->GetProperty( L"FileName" ).c_str() ); strParam = szBuff; m_pConnect->OnCmderError( dwErrorCode, this, strParam ); } return true; } bool CFileCmder::DownloadFileErr( COIResponse *pResponse, COIClientSocket *pSocket, DWORD dwErrorCode ) { if ( !pResponse || !pSocket ) return false; SetCancel(); pSocket->Free(); // 关闭文件 CloseFile(); // 断点续传关闭 m_infoFileResume.CloseFile(); // 关闭下载窗口,如果有的话 ShowDownloadDlg( L"", 0, 0 ); if ( m_pConnect ) { wstring strParam; wchar_t szBuff[1024] = { 0 }; swprintf( szBuff, 1024, // L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s;ConnectType=%s;FileID=%s;FileName=%s", L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s;FileID=%s;FileName=%s", // pResponse->GetMethod().c_str(), dwErrorCode, m_nTrID, m_pSession->m_strAppType.c_str(), m_pSession->m_strConnectType.c_str(), pResponse->GetMethod().c_str(), dwErrorCode, m_nTrID, m_pSession->m_strAppType.c_str(), pResponse->GetParam( 1 ).c_str(), pResponse->GetProperty( L"FileName" ).c_str() ); strParam = szBuff; m_pConnect->OnCmderError( dwErrorCode, this, strParam ); } return true; } bool CFileCmder::DeleteFileErr( COIRequest *pRequest, COIClientSocket *pSocket, DWORD dwErrorCode ) { if ( !pRequest || !pSocket ) return false; pSocket->Free(); if ( m_pConnect ) { wstring strParam; wchar_t szBuff[1024] = { 0 }; swprintf( szBuff, 1024, // L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s;ConnectType=%s;FileID=%s;FileName=%s", L"Method=%s;ErrCode=%d;TrID=%d;AppType=%s;FileID=%s;FileName=%s", // pRequest->GetMethod().c_str(), dwErrorCode, m_nTrID, m_pSession->m_strAppType.c_str(), m_pSession->m_strConnectType.c_str(), pRequest->GetMethod().c_str(), dwErrorCode, m_nTrID, m_pSession->m_strAppType.c_str(), pRequest->GetParam( 1 ).c_str(), pRequest->GetProperty( L"FileName" ).c_str() ); strParam = szBuff; m_pConnect->OnCmderError( dwErrorCode, this, strParam ); } return true; } void CFileCmder::ReadBlockData() { // 释放原数据 if ( m_pszCurBlock ) { if ( m_bIsBase64 ) free( m_pszCurBlock ); m_pszCurBlock = NULL; m_nCurBlockSize = 0; } // 从文件读取一个数据块 m_nCurBlockRelSize = fread( m_pszFileData, 1, SIZE_BLOCK, m_pFile ); if ( m_nCurBlockRelSize > 0 ) { m_pszFileData[m_nCurBlockRelSize] = '\0'; if ( m_bIsBase64 ) { // 转成 Base64 编码 m_pszCurBlock = COICommFun::Str2Base64( (const unsigned char *)m_pszFileData, NULL, m_nCurBlockRelSize ); m_nCurBlockSize = strlen( m_pszCurBlock ); } else { m_pszCurBlock = m_pszFileData; m_nCurBlockSize = m_nCurBlockRelSize; } // 生成数据的验证码 MD5 CMD5Fun funMD5; unsigned char szMD5[33] = { 0 }; funMD5.digest_md5( (unsigned char *)m_pszCurBlock, m_nCurBlockSize, szMD5 ); m_strBlockMD5 = COICommFun::MultiByte2WideChar( (const char *)szMD5, false ); } // End of if ( m_nCurBlockRelSize > 0 ) if ( m_nCurBlockRelSize < SIZE_BLOCK ) // 数据读完了 { CloseFile(); // Is Folder then Delete Compress File if ( !m_strCopyedPathName.empty( ) ) { COICommFun::DeleteFile( m_strCopyedPathName ); // 删除TEMP目录中的拷贝的独占临时文件 m_strCopyedPathName.clear(); } } } void CFileCmder::UploadBlockData( COIClientSocket *pSocket ) { if ( !pSocket ) return; COIBasePtr ptrRequest; ptrRequest = new COIRequest( this ); ptrRequest->SetMethod( m_strMethod ); ptrRequest->AppendParam( (long)m_nTrID ); ptrRequest->SetProperty( L"SessionID", m_strTrSessonID ); ptrRequest->SetProperty( L"Block", (long)m_nCurBlock ); ptrRequest->SetProperty( L"VerifyMD5", m_strBlockMD5 ); if ( m_bIsBase64 ) ptrRequest->SetProperty( L"Base64", L"1" ); ptrRequest->SetProperty( L"Content-Type", L"application/download" ); ptrRequest->SetBodySize( m_nCurBlockSize ); m_nSendedOfBlock = 0; pSocket->SendRequest( ptrRequest ); } void CFileCmder::WriteFileData( char *pszData, int nDataLen ) { int nSpareLen; char *pszBuff = pszData; int nBuffSize; // 将数据写入缓存 nSpareLen = SIZE_PACK_BASE64 - m_nSendedOfBlock; if ( nDataLen <= nSpareLen ) { memcpy( m_pszFileData + m_nSendedOfBlock, pszBuff, nDataLen ); m_nSendedOfBlock += nDataLen; nBuffSize = 0; } else { memcpy( m_pszFileData + m_nSendedOfBlock, pszBuff, nSpareLen ); m_nSendedOfBlock += nSpareLen; pszBuff += nSpareLen; nBuffSize = nDataLen - nSpareLen; } // 缓存满了,写入文件 if ( SIZE_PACK_BASE64 == m_nSendedOfBlock ) { WriteToFile(); // 清除缓存 memset( m_pszFileData, 0, SIZE_PACK_BASE64 ); m_nSendedOfBlock = 0; // 还有内容未处理,则写入缓存 if ( nBuffSize > 0 ) { memcpy( m_pszFileData, pszBuff, nBuffSize ); m_pszFileData[nBuffSize] = '\0'; m_nSendedOfBlock = nBuffSize; } } // End of if ( SIZE_BLOCK_BASE64 == m_nSendedOfBlock ) // m_nReaded += nDataLen; } void CFileCmder::WriteToFile() { // 如果是 Base64 编码,则需进行解码 if ( !m_bIsBase64 ) { fwrite( m_pszFileData, 1, m_nSendedOfBlock, m_pFile ); m_nReaded += m_nSendedOfBlock; } else { int nAscLen = 0; char *pszAscData = NULL; pszAscData = (char *)COICommFun::Base642Str( m_pszFileData, NULL, m_nSendedOfBlock, &nAscLen ); if ( pszAscData ) { //@Terry in 2016.11.3,为处理非 Base64 数据流被标为 Base64 而做修正处理。 // (有数据但转为非 Base64 时长度为 0,说明原数据并非 Base64 数据内容) if ( 0 != nAscLen ) { fwrite( pszAscData, 1, nAscLen, m_pFile ); free( pszAscData ); m_nReaded += nAscLen; } } } // 断点续传信息 if ( !m_infoFileResume.m_strResumeInfoFile.empty() ) { m_infoFileResume.m_nReceivedSize += m_nSendedOfBlock; m_infoFileResume.m_nWritedSize = m_nReaded; m_infoFileResume.SaveData(); } } void CFileCmder::CloseFile() { if ( m_pFile ) { fclose( m_pFile ); m_pFile = NULL; } } } // End of namespace OIFileC