/*
* (C) 2003-2006 Gabest
* (C) 2006-2013 see Authors.txt
*
* This file is part of MPC-HC.
*
* MPC-HC 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 3 of the License, or
* (at your option) any later version.
*
* MPC-HC 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, see .
*
*/
#include "stdafx.h"
#include "AsyncReader.h"
#include
#include
#include "../../../DSUtil/DSUtil.h"
//
// CAsyncFileReader
//
CAsyncFileReader::CAsyncFileReader(CString fn, HRESULT& hr)
: CUnknown(NAME("CAsyncFileReader"), nullptr, &hr)
, m_len((ULONGLONG) - 1)
, m_hBreakEvent(nullptr)
, m_lOsError(0)
{
hr = Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) {
m_len = GetLength();
}
}
CAsyncFileReader::CAsyncFileReader(CAtlList& Items, HRESULT& hr)
: CUnknown(NAME("CAsyncFileReader"), nullptr, &hr)
, m_len((ULONGLONG) - 1)
, m_hBreakEvent(nullptr)
, m_lOsError(0)
{
hr = OpenFiles(Items, modeRead | shareDenyNone | typeBinary | osSequentialScan) ? S_OK : E_FAIL;
if (SUCCEEDED(hr)) {
m_len = GetLength();
}
}
STDMETHODIMP CAsyncFileReader::NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
CheckPointer(ppv, E_POINTER);
return
QI(IAsyncReader)
QI(ISyncReader)
QI(IFileHandle)
__super::NonDelegatingQueryInterface(riid, ppv);
}
// IAsyncReader
STDMETHODIMP CAsyncFileReader::SyncRead(LONGLONG llPosition, LONG lLength, BYTE* pBuffer)
{
do {
try {
if ((ULONGLONG)llPosition + lLength > GetLength()) {
return E_FAIL; // strange, but the Seek below can return llPosition even if the file is not that big (?)
}
if ((ULONGLONG)llPosition != Seek(llPosition, begin)) {
return E_FAIL;
}
if ((UINT)lLength < Read(pBuffer, lLength)) {
return E_FAIL;
}
#if 0 // def DEBUG
static __int64 s_total = 0, s_laststoppos = 0;
s_total += lLength;
if (s_laststoppos > llPosition) {
TRACE(_T("[%I64d - %I64d] %d (%I64d)\n"), llPosition, llPosition + lLength, lLength, s_total);
}
s_laststoppos = llPosition + lLength;
#endif
return S_OK;
} catch (CFileException* e) {
m_lOsError = e->m_lOsError;
e->Delete();
Sleep(1);
CString fn = m_strFileName;
try {
Close();
} catch (CFileException* fe) {
fe->Delete();
}
try {
Open(fn, modeRead | shareDenyNone | typeBinary | osSequentialScan);
} catch (CFileException* fe) {
fe->Delete();
}
m_strFileName = fn;
}
} while (m_hBreakEvent && WaitForSingleObject(m_hBreakEvent, 0) == WAIT_TIMEOUT);
return E_FAIL;
}
STDMETHODIMP CAsyncFileReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable)
{
LONGLONG len = m_len >= 0 ? m_len : GetLength();
if (pTotal) {
*pTotal = len;
}
if (pAvailable) {
*pAvailable = len;
}
return S_OK;
}
// IFileHandle
STDMETHODIMP_(HANDLE) CAsyncFileReader::GetFileHandle()
{
return m_hFile;
}
STDMETHODIMP_(LPCTSTR) CAsyncFileReader::GetFileName()
{
return m_nCurPart != -1 ? m_strFiles[m_nCurPart] : m_strFiles[0];
}
//
// CAsyncUrlReader
//
CAsyncUrlReader::CAsyncUrlReader(CString url, HRESULT& hr)
: CAsyncFileReader(url, hr)
{
if (SUCCEEDED(hr)) {
return;
}
m_url = url;
if (CAMThread::Create()) {
CallWorker(CMD_INIT);
}
hr = Open(m_fn, modeRead | shareDenyRead | typeBinary | osSequentialScan) ? S_OK : E_FAIL;
m_len = (ULONGLONG) - 1; // force GetLength() return actual length always
}
CAsyncUrlReader::~CAsyncUrlReader()
{
if (ThreadExists()) {
CallWorker(CMD_EXIT);
}
if (!m_fn.IsEmpty()) {
CMultiFiles::Close();
DeleteFile(m_fn);
}
}
// IAsyncReader
STDMETHODIMP CAsyncUrlReader::Length(LONGLONG* pTotal, LONGLONG* pAvailable)
{
if (pTotal) {
*pTotal = 0;
}
return __super::Length(nullptr, pAvailable);
}
// CAMThread
DWORD CAsyncUrlReader::ThreadProc()
{
AfxSocketInit(nullptr);
DWORD cmd = GetRequest();
if (cmd != CMD_INIT) {
Reply((DWORD)E_FAIL);
return (DWORD) - 1;
}
try {
CInternetSession is;
CAutoPtr fin(is.OpenURL(m_url, 1, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_CACHE_WRITE));
TCHAR path[MAX_PATH], fn[MAX_PATH];
CFile fout;
if (GetTempPath(MAX_PATH, path) && GetTempFileName(path, _T("mpc_http"), 0, fn)
&& fout.Open(fn, modeCreate | modeWrite | shareDenyWrite | typeBinary)) {
m_fn = fn;
char buff[1024];
int len = fin->Read(buff, sizeof(buff));
if (len > 0) {
fout.Write(buff, len);
}
Reply(S_OK);
while (!CheckRequest(&cmd)) {
int len2 = fin->Read(buff, sizeof(buff));
if (len2 > 0) {
fout.Write(buff, len2);
}
}
} else {
Reply((DWORD)E_FAIL);
}
fin->Close(); // must close it because the destructor doesn't seem to do it and we will get an exception when "is" is destroying
} catch (CInternetException* ie) {
ie->Delete();
Reply((DWORD)E_FAIL);
}
//
cmd = GetRequest();
ASSERT(cmd == CMD_EXIT);
Reply(S_OK);
//
m_hThread = nullptr;
return S_OK;
}