/*
* (C) 2009-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 "MultiFiles.h"
IMPLEMENT_DYNAMIC(CMultiFiles, CObject)
CMultiFiles::CMultiFiles()
: m_hFile(INVALID_HANDLE_VALUE)
, m_llTotalLength(0)
, m_nCurPart(-1)
, m_pCurrentPTSOffset(nullptr)
{
}
void CMultiFiles::Reset()
{
m_strFiles.RemoveAll();
m_FilesSize.RemoveAll();
m_rtPtsOffsets.RemoveAll();
m_llTotalLength = 0;
}
BOOL CMultiFiles::Open(LPCTSTR lpszFileName, UINT nOpenFlags)
{
Reset();
m_strFiles.Add(lpszFileName);
return OpenPart(0);
}
BOOL CMultiFiles::OpenFiles(CAtlList& files, UINT nOpenFlags)
{
POSITION pos = files.GetHeadPosition();
LARGE_INTEGER llSize;
int nPos = 0;
REFERENCE_TIME rtDur = 0;
Reset();
while (pos) {
CHdmvClipInfo::PlaylistItem& s = files.GetNext(pos);
m_strFiles.Add(s.m_strFileName);
if (!OpenPart(nPos)) {
return false;
}
llSize.QuadPart = 0;
GetFileSizeEx(m_hFile, &llSize);
m_llTotalLength += llSize.QuadPart;
m_FilesSize.Add(llSize.QuadPart);
m_rtPtsOffsets.Add(rtDur);
rtDur += s.Duration();
nPos++;
}
if (files.GetCount() > 1) {
ClosePart();
}
return TRUE;
}
ULONGLONG CMultiFiles::Seek(LONGLONG lOff, UINT nFrom)
{
LARGE_INTEGER llNewPos;
LARGE_INTEGER llOff;
if (m_strFiles.GetCount() == 1) {
llOff.QuadPart = lOff;
SetFilePointerEx(m_hFile, llOff, &llNewPos, nFrom);
return llNewPos.QuadPart;
} else {
ULONGLONG lAbsolutePos = GetAbsolutePosition(lOff, nFrom);
int nNewPart = 0;
ULONGLONG llSum = 0;
while (m_FilesSize[nNewPart] + llSum <= lAbsolutePos) {
llSum += m_FilesSize[nNewPart];
nNewPart++;
}
OpenPart(nNewPart);
llOff.QuadPart = lAbsolutePos - llSum;
SetFilePointerEx(m_hFile, llOff, &llNewPos, FILE_BEGIN);
return llSum + llNewPos.QuadPart;
}
}
ULONGLONG CMultiFiles::GetAbsolutePosition(LONGLONG lOff, UINT nFrom)
{
LARGE_INTEGER llNoMove = {0, 0};
LARGE_INTEGER llCurPos;
switch (nFrom) {
case begin:
return lOff;
case current:
SetFilePointerEx(m_hFile, llNoMove, &llCurPos, FILE_CURRENT);
return llCurPos.QuadPart + lOff;
case end:
return m_llTotalLength - lOff;
default:
return 0; // just used to quash "not all control paths return a value" warning
}
}
ULONGLONG CMultiFiles::GetLength() const
{
if (m_strFiles.GetCount() == 1) {
LARGE_INTEGER llSize;
GetFileSizeEx(m_hFile, &llSize);
return llSize.QuadPart;
} else {
return m_llTotalLength;
}
}
UINT CMultiFiles::Read(void* lpBuf, UINT nCount)
{
DWORD dwRead;
do {
if (!ReadFile(m_hFile, lpBuf, nCount, &dwRead, nullptr)) {
break;
}
if (dwRead != nCount && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1)) {
OpenPart(m_nCurPart + 1);
lpBuf = (void*)((BYTE*)lpBuf + dwRead);
nCount -= dwRead;
}
} while (nCount != dwRead && (m_nCurPart < 0 || (size_t)m_nCurPart < m_strFiles.GetCount() - 1));
return dwRead;
}
void CMultiFiles::Close()
{
ClosePart();
Reset();
}
CMultiFiles::~CMultiFiles()
{
Close();
}
BOOL CMultiFiles::OpenPart(int nPart)
{
if (m_nCurPart == nPart) {
return TRUE;
} else {
CString fn;
ClosePart();
fn = m_strFiles.GetAt(nPart);
m_hFile = CreateFile(fn, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
if (m_hFile != INVALID_HANDLE_VALUE) {
m_nCurPart = nPart;
if (m_pCurrentPTSOffset != nullptr) {
*m_pCurrentPTSOffset = m_rtPtsOffsets[nPart];
}
}
return (m_hFile != INVALID_HANDLE_VALUE);
}
}
void CMultiFiles::ClosePart()
{
if (m_hFile != INVALID_HANDLE_VALUE) {
CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
m_nCurPart = -1;
}
}