📄 httpdownloaddlg.cpp
字号:
/*
Module : HTTPDOWNLOADDLG.CPP
Purpose: Defines the implementation for an MFC dialog which performs HTTP downloads
similiar to the Internet Explorer download dialog
Created: PJN / 14-11-1999
History: PJN / 25-01-2000 1. Fixed a problem where server authentication was not being detected correctly,
while proxy authentication was being handled.
2. Updated the way and periodicity certain UI controls are updated during the
HTTP download
Copyright (c) 1999 - 2000 by PJ Naughter.
All rights reserved.
*/
///////////////////////////////// Includes //////////////////////////////////
#include "stdafx.h"
#include "emule.h"
#include "HttpDownloadDlg.h"
#include "OtherFunctions.h"
///////////////////////////////// Defines /////////////////////////////////////
#define HAS_ZLIB
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
void InitWindowStyles(CWnd* pWnd);
const UINT WM_HTTPDOWNLOAD_THREAD_FINISHED = WM_APP + 1;
////////////////////////////////////// gzip ///////////////////////////////////
//in the spirit of zlib, lets do something horrible with defines ;)
#ifdef HAS_ZLIB
#include <zlib/zlib.h>
static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
/* gzip flag byte */
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
#define COMMENT 0x10 /* bit 4 set: file comment present */
#define RESERVED 0xE0 /* bits 5..7: reserved */
static int get_byte(HINTERNET m_hHttpFile) {
unsigned char c;
DWORD dwBytesRead;
BOOL b = ::InternetReadFile(m_hHttpFile, &c, 1, &dwBytesRead);
if(!b)
return EOF;
else
return c;
}
static int check_header(z_stream *stream, HINTERNET m_hHttpFile) {
int method; /* method byte */
int flags; /* flags byte */
uInt len;
int c;
/* Check the gzip magic header */
for(len = 0; len < 2; len++) {
c = get_byte(m_hHttpFile);
if(c != gz_magic[len]) {
if(len != 0) stream->avail_in++, stream->next_in--;
if(c != EOF) {
stream->avail_in++, stream->next_in--;
//do not support transparent streams
return stream->avail_in != 0 ? Z_DATA_ERROR : Z_STREAM_END;
}
return stream->avail_in != 0 ? Z_OK : Z_STREAM_END;
}
}
method = get_byte(m_hHttpFile);
flags = get_byte(m_hHttpFile);
if(method != Z_DEFLATED || (flags & RESERVED) != 0)
return Z_DATA_ERROR;
/* Discard time, xflags and OS code: */
for(len = 0; len < 6; len++) (void)get_byte(m_hHttpFile);
if((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
len = (uInt)get_byte(m_hHttpFile);
len += ((uInt)get_byte(m_hHttpFile))<<8;
/* len is garbage if EOF but the loop below will quit anyway */
while(len-- != 0 && get_byte(m_hHttpFile) != EOF) ;
}
if((flags & ORIG_NAME) != 0) { /* skip the original file name */
while((c = get_byte(m_hHttpFile)) != 0 && c != EOF) ;
}
if((flags & COMMENT) != 0) { /* skip the .gz file comment */
while((c = get_byte(m_hHttpFile)) != 0 && c != EOF) ;
}
if((flags & HEAD_CRC) != 0) { /* skip the header crc */
for(len = 0; len < 2; len++) (void)get_byte(m_hHttpFile);
}
//return Z_DATA_ERROR if we hit EOF?
return Z_OK;
}
#define ACCEPT_ENCODING_HEADER _T("Accept-Encoding: gzip, x-gzip, identity, *;q=0\r\n")
#define ENCODING_CLEAN_UP if(bEncodedWithGZIP) inflateEnd(&zs)
#define ENCODING_INIT BOOL bEncodedWithGZIP = FALSE; \
z_stream zs; \
unsigned char cBufferGZIP[1024 * 8]
#define ENCODING_QUERY { \
/*check for gzip or x-gzip stream*/ \
TCHAR szContentEncoding[32]; \
DWORD dwEncodeStringSize = 32; \
if(::HttpQueryInfo(m_hHttpFile, HTTP_QUERY_CONTENT_ENCODING, \
szContentEncoding, &dwEncodeStringSize, NULL)) { \
if(szContentEncoding[0] == 'x' && szContentEncoding[1] == '-') \
szContentEncoding += 2; \
if(!stricmp(szContentEncoding, "gzip") \
bEncodedWithGZIP = TRUE; \
} \
}
#define PREPARE_DECODER \
if(bEncodedWithGZIP) { \
zs.next_out = cBufferGZIP; \
zs.zalloc = (alloc_func)0; \
zs.zfree = (free_func)0; \
zs.opaque = (voidpf)0; \
zs.next_in = (unsigned char*)szReadBuf; \
zs.next_out = Z_NULL; \
zs.avail_in = 0; \
zs.avail_out = sizeof(szReadBuf); \
\
VERIFY(inflateInit2(&zs, -MAX_WBITS) == Z_OK); \
int result = check_header(&zs, m_hHttpFile); \
if(result != Z_OK) { \
TRACE(_T("An exception occured while decoding the download file\n")); \
HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_ERROR_READFILE));\
inflateEnd(&zs); \
} \
}
#define DECODE_DATA(CFILE, DATA, LEN) \
if(bEncodedWithGZIP) { \
zs.next_in = (unsigned char*)DATA; \
zs.avail_in = LEN; \
int iResult; \
do { \
zs.total_out = 0; \
zs.next_out = cBufferGZIP; \
zs.avail_out = 1024; \
iResult = inflate(&zs, Z_SYNC_FLUSH); \
CFILE.Write(cBufferGZIP, zs.total_out); \
if(iResult == Z_STREAM_ERROR || iResult == Z_DATA_ERROR) { \
TRACE(_T("An exception occured while decoding the download file\n"));\
HandleThreadErrorWithLastError(GetResString(IDS_HTTPDOWNLOAD_ERROR_READFILE));\
ENCODING_CLEAN_UP; \
return; \
} \
/*if(iResult == Z_STREAM_END) {*/ \
/*}*/ \
} while(iResult == Z_OK && zs.avail_out == 0); \
} else \
CFILE.Write(DATA, LEN)
#else
#define ACCEPT_ENCODING_HEADER _T("Accept-Encoding: identity, *;q=0\r\n")
#define ENCODING_CLEAN_UP ((void)0)
#define ENCODING_INIT ((void)0)
#define ENCODING_QUERY ((void)0)
#define PREPARE_DECODER ((void)0)
#define DECODE_DATA(CFILE, DATA, LEN) CFILE.Write(DATA, LEN)
#endif
///////////////////////////////// Implementation //////////////////////////////
IMPLEMENT_DYNAMIC(CHttpDownloadDlg, CDialog);
CHttpDownloadDlg::CHttpDownloadDlg(CWnd* pParent /*=NULL*/)
: CDialog(CHttpDownloadDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CHttpDownloadDlg)
//}}AFX_DATA_INIT
m_hInternetSession = NULL;
m_hHttpConnection = NULL;
m_hHttpFile = NULL;
m_bAbort = FALSE;
m_bSafeToClose = FALSE;
m_pThread = NULL;
}
void CHttpDownloadDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CHttpDownloadDlg)
DDX_Control(pDX, IDC_STATUS, m_ctrlStatus);
DDX_Control(pDX, IDC_TRANSFER_RATE, m_ctrlTransferRate);
DDX_Control(pDX, IDC_TIMELEFT, m_ctrlTimeLeft);
DDX_Control(pDX, IDC_PROGRESS1, m_ctrlProgress);
DDX_Control(pDX, IDC_FILESTATUS, m_ctrlFileStatus);
DDX_Control(pDX, IDC_ANIMATE1, m_ctrlAnimate);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CHttpDownloadDlg, CDialog)
//{{AFX_MSG_MAP(CHttpDownloadDlg)
ON_WM_DESTROY()
ON_WM_CLOSE()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_HTTPDOWNLOAD_THREAD_FINISHED, OnThreadFinished)
END_MESSAGE_MAP()
LRESULT CHttpDownloadDlg::OnThreadFinished(WPARAM wParam, LPARAM /*lParam*/)
{
//It's now safe to close since the thread has signaled us
m_bSafeToClose = TRUE;
//Stop the animation
m_ctrlAnimate.Stop();
Sleep(1000);
//If an error occured display the message box
if (m_bAbort)
EndDialog(IDCANCEL);
else if (wParam)
{
if (!m_sError.IsEmpty())
theApp.AddDebugLogLine(false, _T("%s"), m_sError);
EndDialog(IDCANCEL);
}
else
EndDialog(IDOK);
return 0L;
}
BOOL CHttpDownloadDlg::OnInitDialog()
{
CString cap;
cap = GetResString(IDS_CANCEL);
GetDlgItem(IDCANCEL)->SetWindowText(cap);
if (!m_strTitle.IsEmpty())
SetWindowText(m_strTitle);
//Let the parent class do its thing
CDialog::OnInitDialog();
InitWindowStyles(this);
//Setup the animation control
m_ctrlAnimate.Open(IDR_HTTPDOWNLOAD_ANIMATION);
//Validate the URL
ASSERT(m_sURLToDownload.GetLength()); //Did you forget to specify the file to download
if (!AfxParseURL(m_sURLToDownload, m_dwServiceType, m_sServer, m_sObject, m_nPort))
{
//Try sticking "http://" before it
m_sURLToDownload = _T("http://") + m_sURLToDownload;
if (!AfxParseURL(m_sURLToDownload, m_dwServiceType, m_sServer, m_sObject, m_nPort))
{
TRACE(_T("Failed to parse the URL: %s\n"), m_sURLToDownload);
EndDialog(IDCANCEL);
return TRUE;
}
}
//Check to see if the file we are downloading to exists and if
//it does, then ask the user if they were it overwritten
// edited: we always want to overwrite old language dlls and server.mets
/*CFileStatus fs;
ASSERT(m_sFileToDownloadInto.GetLength());
if (CFile::GetStatus(m_sFileToDownloadInto, fs))
{
CString sMsg;
sMsg.Format(GetResString(IDS_HTTPDOWNLOAD_OK_TO_OVERWRITE), m_sFileToDownloadInto);
if (AfxMessageBox(sMsg, MB_YESNO) != IDYES)
{
TRACE(_T("Failed to confirm file overwrite, download aborted\n"));
EndDialog(IDCANCEL);
return TRUE;
}
}*/
//Try and open the file we will download into
if (!m_FileToWrite.Open(m_sFileToDownloadInto, CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite))
{
TRACE(_T("Failed to open the file to download into, Error:%d\n"), GetLastError());
CString sError;
sError.Format(_T("%d"), ::GetLastError());
CString sMsg;
sMsg.Format(GetResString(IDS_HTTPDOWNLOAD_FAIL_FILE_OPEN), sError);
AfxMessageBox(sMsg);
EndDialog(IDCANCEL);
return TRUE;
}
//Pull out just the filename component
int nSlash = m_sObject.ReverseFind(_T('/'));
if (nSlash == -1)
nSlash = m_sObject.ReverseFind(_T('\\'));
if (nSlash != -1 && m_sObject.GetLength() > 1)
m_sFilename = m_sObject.Right(m_sObject.GetLength() - nSlash - 1);
else
m_sFilename = m_sObject;
//Set the file status text
CString sFileStatus;
ASSERT(m_sObject.GetLength());
ASSERT(m_sServer.GetLength());
sFileStatus.Format(GetResString(IDS_HTTPDOWNLOAD_FILESTATUS), m_sFilename, m_sServer);
m_ctrlFileStatus.SetWindowText(sFileStatus);
// set labels
SetDlgItemText(IDC_TIMELEFTTEXT,GetResString(IDS_ESTTIMELEFT));
SetDlgItemText(IDC_TRANSFER_RATE_LABEL,GetResString(IDS_TRANSFER_RATE_LABEL));
//Spin off the background thread which will do the actual downloading
m_pThread = AfxBeginThread(_DownloadThread, this, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
if (m_pThread == NULL)
{
TRACE(_T("Failed to create download thread, dialog is aborting\n"));
EndDialog(IDCANCEL);
return TRUE;
}
m_pThread->m_bAutoDelete = FALSE;
m_pThread->ResumeThread();
return TRUE;
}
UINT AFX_CDECL CHttpDownloadDlg::_DownloadThread(LPVOID pParam)
{
DbgSetThreadName("HttpDownload");
InitThreadLocale();
//Convert from the SDK world to the C++ world
CHttpDownloadDlg* pDlg = (CHttpDownloadDlg*) pParam;
ASSERT(pDlg);
ASSERT(pDlg->IsKindOf(RUNTIME_CLASS(CHttpDownloadDlg)));
pDlg->DownloadThread();
return 0;
}
void CHttpDownloadDlg::SetPercentage(int nPercentage)
{
//Change the caption text
CString sPercentage;
sPercentage.Format(_T("%d"), nPercentage);
CString sCaption;
sCaption.Format(GetResString(IDS_HTTPDOWNLOAD_PERCENTAGE), sPercentage, m_sFilename);
SetWindowText(sCaption);
}
void CHttpDownloadDlg::SetProgressRange(DWORD dwFileSize)
{
m_ctrlProgress.SetRange(0, (short)((dwFileSize+512)/1024));
}
void CHttpDownloadDlg::SetProgress(DWORD dwBytesRead)
{
m_ctrlProgress.SetPos(dwBytesRead/1024);
}
void CHttpDownloadDlg::SetTimeLeft(DWORD dwSecondsLeft, DWORD dwBytesRead, DWORD dwFileSize)
{
CString sOf;
sOf.Format(GetResString(IDS_HTTPDOWNLOAD_OF), CastItoXBytes((uint64)dwBytesRead, false, false), CastItoXBytes((uint64)dwFileSize, false, false));
CString sTimeLeft;
sTimeLeft.Format(GetResString(IDS_HTTPDOWNLOAD_TIMELEFT), CastSecondsToHM(dwSecondsLeft), sOf);
m_ctrlTimeLeft.SetWindowText(sTimeLeft);
}
void CHttpDownloadDlg::SetStatus(const CString& sCaption)
{
m_ctrlStatus.SetWindowText(sCaption);
}
void CHttpDownloadDlg::SetStatus(CString nID, const CString& lpsz1)
{
CString sStatus;
sStatus.Format(nID, lpsz1);
SetStatus(sStatus);
}
void CHttpDownloadDlg::SetTransferRate(double KbPerSecond)
{
CString sRate;
sRate.Format( _T("%s"), CastItoXBytes(KbPerSecond, true, true));
m_ctrlTransferRate.SetWindowText(sRate);
}
void CHttpDownloadDlg::PlayAnimation()
{
m_ctrlAnimate.Play(0, (UINT)-1, (UINT)-1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -