www.pudn.com > src.rar > DirectVobSub.cpp


#include "stdafx.h" 
#include "resource.h" 
#include "Main.h" 
#include "DirectVobSub.h" 
 
CDirectVobSub::CDirectVobSub() : CPersistStream(NULL, NULL) 
{ 
	AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
 
	BYTE* pData; 
	UINT nSize; 
 
	m_iSelectedLanguage = -1; 
	m_fHideSubtitles = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_HIDE), 0); 
	m_fDoPreBuffering = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_DOPREBUFFERING), 1); 
	m_fOverridePlacement = !!theApp.GetProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_OVERRIDEPLACEMENT), 0); 
	m_PlacementXperc = theApp.GetProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_XPERC), 50); 
	m_PlacementYperc = theApp.GetProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_YPERC), 90); 
	m_fBufferVobSub = !!theApp.GetProfileInt(ResStr(IDS_R_VOBSUB), ResStr(IDS_RV_BUFFER), 1); 
	m_fOnlyShowForcedVobSubs = !!theApp.GetProfileInt(ResStr(IDS_R_VOBSUB), ResStr(IDS_RV_ONLYSHOWFORCEDSUBS), 0); 
	m_fPolygonize = !!theApp.GetProfileInt(ResStr(IDS_R_VOBSUB), ResStr(IDS_RV_POLYGONIZE), 0); 
	// m_lf = ; // we set this later 
	m_TextColor = theApp.GetProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_COLOR), 0xffffff); 
	m_fShadow = !!theApp.GetProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_SHADOW), 1); 
	m_fOutline = !!theApp.GetProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_OUTLINE), 1); 
	m_fAdvancedRenderer = !!theApp.GetProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_ADVANCEDRENDERER), 1); 
	m_fFlipPicture = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_FLIPPICTURE), 0); 
	m_fFlipSubtitles = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_FLIPSUBTITLES), 0); 
	m_fOSD = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SHOWOSDSTATS), 0); 
	m_fSaveFullPath = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SAVEFULLPATH), 0); 
	m_nReloaderDisableCount = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_DISABLERELOADER), 0) ? 1 : 0; 
	m_SubtitleDelay = theApp.GetProfileInt(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_SUBTITLEDELAY), 0); 
	m_SubtitleSpeedMul = theApp.GetProfileInt(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_SUBTITLESPEEDMUL), 1000); 
	m_SubtitleSpeedDiv = theApp.GetProfileInt(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_SUBTITLESPEEDDIV), 1000); 
	m_fMediaFPSEnabled = !!theApp.GetProfileInt(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_MEDIAFPSENABLED), 0); 
	pData = NULL; 
	if(theApp.GetProfileBinary(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_MEDIAFPS), &pData, &nSize) && pData) 
	{ 
		if(nSize != sizeof(m_MediaFPS)) m_MediaFPS = 25.0; 
		else memcpy(&m_MediaFPS, pData, sizeof(m_MediaFPS)); 
		delete [] pData; 
	} 
	m_ZoomRect.left = m_ZoomRect.top = 0; 
	m_ZoomRect.right = m_ZoomRect.bottom = 1; 
 
	memset(&m_lf, 0, sizeof(m_lf)); 
	m_lf.lfCharSet = DEFAULT_CHARSET; 
	m_lf.lfOutPrecision = OUT_CHARACTER_PRECIS; 
	m_lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; 
	m_lf.lfQuality = ANTIALIASED_QUALITY; 
	HDC hdc = ::GetDC(NULL); 
	m_lf.lfHeight = -MulDiv(16, GetDeviceCaps(hdc, LOGPIXELSY), 72); 
	::ReleaseDC(NULL, hdc); 
	m_lf.lfWeight = FW_BOLD; 
	_tcscpy(m_lf.lfFaceName, _T("Arial")); 
 
	pData = NULL; 
	theApp.GetProfileBinary(ResStr(IDS_R_TEXT), ResStr(IDS_RT_LOGFONT), &pData, &nSize); 
	if(pData) 
	{ 
		CString face; 
 
		if(nSize == sizeof(LOGFONTA)) face = ((LOGFONTA*)pData)->lfFaceName; 
		else if(nSize == sizeof(LOGFONTW)) face = ((LOGFONTW*)pData)->lfFaceName; 
 
		if(!face.IsEmpty())  
		{ 
			memcpy(&m_lf, pData, sizeof(LOGFONTA)-LF_FACESIZE); 
			_tcsncpy(m_lf.lfFaceName, face, LF_FACESIZE); 
		} 
 
		delete [] pData; 
	} 
 
	m_fForced = false; 
} 
 
CDirectVobSub::~CDirectVobSub() 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
} 
 
STDMETHODIMP CDirectVobSub::get_FileName(WCHAR* fn) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(!fn) return E_POINTER; 
 
#ifdef UNICODE 
	wcscpy(fn, m_FileName); 
#else 
	mbstowcs(fn, m_FileName, m_FileName.GetLength()+1); 
#endif 
 
    return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_FileName(WCHAR* fn) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(!fn) return E_POINTER; 
 
	CString tmp = fn; 
	if(!m_FileName.Left(m_FileName.ReverseFind('.')+1).CompareNoCase(tmp.Left(tmp.ReverseFind('.')+1))) return S_FALSE; 
 
#ifdef UNICODE 
	m_FileName = fn; 
#else 
	CHARSETINFO cs={0}; 
	::TranslateCharsetInfo((DWORD *)DEFAULT_CHARSET, &cs, TCI_SRCCHARSET); 
	CHAR* buff = m_FileName.GetBuffer(MAX_PATH*2); 
	int len = WideCharToMultiByte(cs.ciACP/*CP_OEMCP*/, NULL, fn, -1, buff, MAX_PATH*2, NULL, NULL); 
	m_FileName.ReleaseBuffer(len+1); 
#endif 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_LanguageCount(int* nLangs) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	return nLangs ? *nLangs = 0, S_OK : E_POINTER; 
} 
 
STDMETHODIMP CDirectVobSub::get_LanguageName(int iLanguage, WCHAR** ppName) 
{ 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_SelectedLanguage(int* iSelected) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	return iSelected ? *iSelected = m_iSelectedLanguage, S_OK : E_POINTER; 
} 
 
STDMETHODIMP CDirectVobSub::put_SelectedLanguage(int iSelected) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_iSelectedLanguage == iSelected) return S_FALSE; 
 
	int nCount; 
	if(FAILED(get_LanguageCount(&nCount)) 
	|| iSelected < 0  
	|| iSelected >= nCount)  
		return E_FAIL; 
 
	m_iSelectedLanguage = iSelected; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_HideSubtitles(bool* fHideSubtitles) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	return fHideSubtitles ? *fHideSubtitles = m_fHideSubtitles, S_OK : E_POINTER; 
} 
 
STDMETHODIMP CDirectVobSub::put_HideSubtitles(bool fHideSubtitles) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_fHideSubtitles == fHideSubtitles) return S_FALSE; 
 
	m_fHideSubtitles = fHideSubtitles; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_PreBuffering(bool* fDoPreBuffering) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	return fDoPreBuffering ? *fDoPreBuffering = m_fDoPreBuffering, S_OK : E_POINTER; 
} 
 
STDMETHODIMP CDirectVobSub::put_PreBuffering(bool fDoPreBuffering) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_fDoPreBuffering == fDoPreBuffering) return S_FALSE; 
 
	m_fDoPreBuffering = fDoPreBuffering; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_Placement(bool* fOverridePlacement, int* xperc, int* yperc) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(fOverridePlacement) *fOverridePlacement = m_fOverridePlacement; 
	if(xperc) *xperc = m_PlacementXperc; 
	if(yperc) *yperc = m_PlacementYperc; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_Placement(bool fOverridePlacement, int xperc, int yperc) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_fOverridePlacement == fOverridePlacement && m_PlacementXperc == xperc && m_PlacementYperc == yperc) return S_FALSE; 
 
	m_fOverridePlacement = fOverridePlacement; 
	m_PlacementXperc = xperc; 
	m_PlacementYperc = yperc; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_VobSubSettings(bool* fBuffer, bool* fOnlyShowForcedSubs, bool* fPolygonize) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(fBuffer) *fBuffer = m_fBufferVobSub; 
	if(fOnlyShowForcedSubs) *fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs; 
	if(fPolygonize) *fPolygonize = m_fPolygonize; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_VobSubSettings(bool fBuffer, bool fOnlyShowForcedSubs, bool fPolygonize) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_fBufferVobSub == fBuffer && m_fOnlyShowForcedVobSubs == fOnlyShowForcedSubs && m_fPolygonize == fPolygonize) return S_FALSE; 
 
	m_fBufferVobSub = fBuffer; 
	m_fOnlyShowForcedVobSubs = fOnlyShowForcedSubs; 
	m_fPolygonize = fPolygonize; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_TextSettings(void* lf, int lflen, COLORREF* color, bool* fShadow, bool* fOutline, bool* fAdvancedRenderer) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(lf)  
	{ 
		if(lflen != sizeof(LOGFONTA) && lflen != sizeof(LOGFONTW)) return E_INVALIDARG; 
 
		memcpy(lf, &m_lf, sizeof(LOGFONT)-sizeof(m_lf.lfFaceName)); 
 
		if(lflen == sizeof(LOGFONTA)) 
		{ 
#ifdef UNICODE 
			wcstombs(((LOGFONTA*)lf)->lfFaceName, m_lf.lfFaceName, wcslen(m_lf.lfFaceName)+1); 
#else 
			strcpy(((LOGFONTA*)lf)->lfFaceName, m_lf.lfFaceName); 
#endif 
		} 
		else if(lflen == sizeof(LOGFONTW)) 
		{ 
#ifdef UNICODE 
			wcscpy(((LOGFONTW*)lf)->lfFaceName, m_lf.lfFaceName); 
#else 
			mbstowcs(((LOGFONTW*)lf)->lfFaceName, m_lf.lfFaceName, strlen(m_lf.lfFaceName)+1); 
#endif 
		} 
	} 
 
	if(color) *color = m_TextColor; 
	if(fShadow) *fShadow = m_fShadow; 
	if(fOutline) *fOutline = m_fOutline; 
	if(fAdvancedRenderer) *fAdvancedRenderer = m_fAdvancedRenderer; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_TextSettings(void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(((LOGFONT*)lf)->lfHeight > 0) 
	{ 
		HDC hdc = ::GetDC(0); 
		((LOGFONT*)lf)->lfHeight = -MulDiv(((LOGFONT*)lf)->lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72); 
		ReleaseDC(0, hdc); 
	} 
 
	if(m_TextColor == color && m_fShadow == fShadow && m_fOutline == fOutline && m_fAdvancedRenderer == fAdvancedRenderer) 
	{ 
		if(!memcmp(lf, &m_lf, sizeof(LOGFONT)-sizeof(m_lf.lfFaceName))) 
		{ 
			TCHAR facename[sizeof(m_lf.lfFaceName)]; 
 
			if(lflen == sizeof(LOGFONTA)) 
			{ 
	#ifdef UNICODE 
				mbstowcs(facename, ((LOGFONTA*)lf)->lfFaceName, strlen(((LOGFONTA*)lf)->lfFaceName)+1); 
				if(!wcscmp(facename, m_lf.lfFaceName)) return S_FALSE; 
	#else 
				if(!strcmp(m_lf.lfFaceName, ((LOGFONTA*)lf)->lfFaceName)) return S_FALSE; 
	#endif 
			} 
			else if(lflen == sizeof(LOGFONTW)) 
			{ 
	#ifdef UNICODE 
				if(!wcscmp(m_lf.lfFaceName, ((LOGFONTW*)lf)->lfFaceName)) return S_FALSE; 
	#else 
				wcstombs(facename, ((LOGFONTW*)lf)->lfFaceName, wcslen(((LOGFONTW*)lf)->lfFaceName)+1); 
				if(!strcmp(facename, m_lf.lfFaceName)) return S_FALSE; 
	#endif 
			} 
		} 
	} 
 
	if(lf)  
	{ 
		if(lflen != sizeof(LOGFONTA) && lflen != sizeof(LOGFONTW)) return E_INVALIDARG; 
 
		memcpy(&m_lf, lf, sizeof(LOGFONT)-sizeof(m_lf.lfFaceName)); 
 
		if(lflen == sizeof(LOGFONTA)) 
		{ 
#ifdef UNICODE 
		    mbstowcs(m_lf.lfFaceName, ((LOGFONTA*)lf)->lfFaceName, strlen(((LOGFONTA*)lf)->lfFaceName)+1); 
#else 
		    strcpy(m_lf.lfFaceName, ((LOGFONTA*)lf)->lfFaceName); 
#endif 
		} 
		else if(lflen == sizeof(LOGFONTW)) 
		{ 
#ifdef UNICODE 
		    wcscpy(m_lf.lfFaceName, ((LOGFONTW*)lf)->lfFaceName); 
#else 
		    wcstombs(m_lf.lfFaceName, ((LOGFONTW*)lf)->lfFaceName, wcslen(((LOGFONTW*)lf)->lfFaceName)+1); 
#endif 
		} 
	} 
	 
	m_TextColor = color; 
	m_fShadow = fShadow; 
	m_fOutline = fOutline; 
	m_fAdvancedRenderer = fAdvancedRenderer; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_Flip(bool* fPicture, bool* fSubtitles) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(fPicture) *fPicture = m_fFlipPicture; 
	if(fSubtitles) *fSubtitles = m_fFlipSubtitles; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_Flip(bool fPicture, bool fSubtitles) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_fFlipPicture == fPicture && m_fFlipSubtitles == fSubtitles) return S_FALSE; 
 
	m_fFlipPicture = fPicture; 
	m_fFlipSubtitles = fSubtitles; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_OSD(bool* fOSD) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	return fOSD ? *fOSD = m_fOSD, S_OK : E_POINTER; 
} 
 
STDMETHODIMP CDirectVobSub::put_OSD(bool fOSD) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_fOSD == fOSD) return S_FALSE; 
 
	m_fOSD = fOSD; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_SaveFullPath(bool* fSaveFullPath) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	return fSaveFullPath ? *fSaveFullPath = m_fSaveFullPath, S_OK : E_POINTER; 
} 
 
STDMETHODIMP CDirectVobSub::put_SaveFullPath(bool fSaveFullPath) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_fSaveFullPath == fSaveFullPath) return S_FALSE; 
 
	m_fSaveFullPath = fSaveFullPath; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_SubtitleTiming(int* delay, int* speedmul, int* speeddiv) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(delay) *delay = m_SubtitleDelay; 
	if(speedmul) *speedmul = m_SubtitleSpeedMul; 
	if(speeddiv) *speeddiv = m_SubtitleSpeedDiv; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_SubtitleTiming(int delay, int speedmul, int speeddiv) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_SubtitleDelay == delay && m_SubtitleSpeedMul == speedmul && m_SubtitleSpeedDiv == speeddiv) return S_FALSE; 
 
	m_SubtitleDelay = delay; 
	m_SubtitleSpeedMul = speedmul; 
	if(speeddiv > 0) m_SubtitleSpeedDiv = speeddiv; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_MediaFPS(bool* fEnabled, double* fps) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(fEnabled) *fEnabled = m_fMediaFPSEnabled; 
	if(fps) *fps = m_MediaFPS; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_MediaFPS(bool fEnabled, double fps) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(m_fMediaFPSEnabled == fEnabled && m_MediaFPS == fps) return S_FALSE; 
 
	m_fMediaFPSEnabled = fEnabled; 
	if(fps > 0) m_MediaFPS = fps; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_ZoomRect(NORMALIZEDRECT* rect) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(!rect) return E_POINTER; 
 
	*rect = m_ZoomRect; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_ZoomRect(NORMALIZEDRECT* rect) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(!rect) return E_POINTER; 
 
	if(!memcmp(&m_ZoomRect, rect, sizeof(m_ZoomRect))) return S_FALSE; 
 
	m_ZoomRect = *rect; 
 
	SetDirty(TRUE); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::UpdateRegistry() 
{ 
	AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
 
	CAutoLock cAutoLock(&m_propsLock); 
 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_HIDE), m_fHideSubtitles); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_DOPREBUFFERING), m_fDoPreBuffering); 
	theApp.WriteProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_OVERRIDEPLACEMENT), m_fOverridePlacement); 
	theApp.WriteProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_XPERC), m_PlacementXperc); 
	theApp.WriteProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_YPERC), m_PlacementYperc); 
	theApp.WriteProfileInt(ResStr(IDS_R_VOBSUB), ResStr(IDS_RV_BUFFER), m_fBufferVobSub); 
	theApp.WriteProfileInt(ResStr(IDS_R_VOBSUB), ResStr(IDS_RV_ONLYSHOWFORCEDSUBS), m_fOnlyShowForcedVobSubs); 
	theApp.WriteProfileInt(ResStr(IDS_R_VOBSUB), ResStr(IDS_RV_POLYGONIZE), m_fPolygonize); 
	theApp.WriteProfileBinary(ResStr(IDS_R_TEXT), ResStr(IDS_RT_LOGFONT), (BYTE*)&m_lf, sizeof(LOGFONT)); 
	theApp.WriteProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_COLOR), *((unsigned int*)&m_TextColor)); 
	theApp.WriteProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_SHADOW), m_fShadow); 
	theApp.WriteProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_OUTLINE), m_fOutline); 
	theApp.WriteProfileInt(ResStr(IDS_R_TEXT), ResStr(IDS_RT_ADVANCEDRENDERER), m_fAdvancedRenderer); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_FLIPPICTURE), m_fFlipPicture); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_FLIPSUBTITLES), m_fFlipSubtitles); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SHOWOSDSTATS), m_fOSD); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SAVEFULLPATH), m_fSaveFullPath); 
	theApp.WriteProfileInt(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_SUBTITLEDELAY), m_SubtitleDelay); 
	theApp.WriteProfileInt(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_SUBTITLESPEEDMUL), m_SubtitleSpeedMul); 
	theApp.WriteProfileInt(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_SUBTITLESPEEDDIV), m_SubtitleSpeedDiv); 
	theApp.WriteProfileInt(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_MEDIAFPSENABLED), m_fMediaFPSEnabled); 
	theApp.WriteProfileBinary(ResStr(IDS_R_TIMING), ResStr(IDS_RTM_MEDIAFPS), (BYTE*)&m_MediaFPS, sizeof(m_MediaFPS)); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::HasConfigDialog(int iSelected) 
{ 
	return E_NOTIMPL; 
} 
 
STDMETHODIMP CDirectVobSub::ShowConfigDialog(int iSelected, HWND hWndParent) 
{ 
	return E_NOTIMPL; 
} 
 
STDMETHODIMP CDirectVobSub::IsSubtitleReloaderLocked(bool* fLocked) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(!fLocked) return E_POINTER;  
 
	bool fDisabled; 
	get_SubtitleReloader(&fDisabled); 
 
	*fLocked = fDisabled || m_nReloaderDisableCount > 0; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::LockSubtitleReloader(bool fLock) 
{ 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(fLock) m_nReloaderDisableCount++; 
	else m_nReloaderDisableCount--; 
 
	ASSERT(m_nReloaderDisableCount >= 0); 
	if(m_nReloaderDisableCount < 0) m_nReloaderDisableCount = 0; 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_SubtitleReloader(bool* fDisabled) 
{ 
	AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(fDisabled) *fDisabled = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_DISABLERELOADER), 0); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_SubtitleReloader(bool fDisable) 
{ 
	AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
 
	CAutoLock cAutoLock(&m_propsLock); 
 
	bool b; 
	get_SubtitleReloader(&b); 
	if(b == fDisable) return S_FALSE; 
 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_DISABLERELOADER), fDisable); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_ExtendPicture(int* horizontal, int* vertical, int* resx2, int* resx2minw, int* resx2minh) 
{ 
	AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(horizontal) *horizontal = theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_MOD32FIX), 0) & 1; 
	if(vertical) *vertical = theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_EXTPIC), 1); 
	if(resx2) *resx2 = theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_RESX2), 2) & 3; 
	if(resx2minw) *resx2minw = theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_RESX2MINW), 384); 
	if(resx2minh) *resx2minh = theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_RESX2MINH), 288); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_ExtendPicture(int horizontal, int vertical, int resx2, int resx2minw, int resx2minh) 
{ 
	AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
 
	CAutoLock cAutoLock(&m_propsLock); 
 
	int i[5]; 
	get_ExtendPicture(i, i+1, i+2, i+3, i+4); 
	if(i[0] == horizontal && i[1] == vertical && i[2] == resx2 && i[3] == resx2minw && i[4] == resx2minh) return S_FALSE; 
 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_MOD32FIX), horizontal & 1); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_EXTPIC), vertical); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_RESX2), resx2 & 3); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_RESX2MINW), resx2minw); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_RESX2MINH), resx2minh); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::get_LoadSettings(int* level, bool* fExternalLoad, bool* fWebLoad, bool* fEmbeddedLoad) 
{ 
	AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
 
	CAutoLock cAutoLock(&m_propsLock); 
 
	if(level) *level = theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_LOADLEVEL), 0) & 3; 
	if(fExternalLoad) *fExternalLoad = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_EXTERNALLOAD), 1); 
	if(fWebLoad) *fWebLoad = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_WEBLOAD), 0); 
	if(fEmbeddedLoad) *fEmbeddedLoad = !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_EMBEDDEDLOAD), 1); 
 
	return S_OK; 
} 
 
STDMETHODIMP CDirectVobSub::put_LoadSettings(int level, bool fExternalLoad, bool fWebLoad, bool fEmbeddedLoad) 
{ 
	AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
 
	CAutoLock cAutoLock(&m_propsLock); 
 
	int i; 
	bool b[3]; 
	get_LoadSettings(&i, b, b+1, b+2); 
	if(i == level && b[0] == fExternalLoad && b[1] == fWebLoad && b[2] == fEmbeddedLoad) return S_FALSE; 
 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_LOADLEVEL), level & 3); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_EXTERNALLOAD), fExternalLoad); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_WEBLOAD), fWebLoad); 
	theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_EMBEDDEDLOAD), fEmbeddedLoad); 
 
	return S_OK; 
} 
 
// IDirectVobSub2 
 
STDMETHODIMP CDirectVobSub::AdviseSubClock(ISubClock* pSubClock) 
{ 
	m_pSubClock = pSubClock; 
 
	return S_OK; 
} 
 
STDMETHODIMP_(bool) CDirectVobSub::get_Forced() 
{ 
	return m_fForced; 
} 
 
STDMETHODIMP CDirectVobSub::put_Forced(bool fForced) 
{ 
	m_fForced = fForced; 
	return S_OK; 
} 
 
// CPersistStream 
 
DWORD CDirectVobSub::GetSoftwareVersion() 
{ 
	return(0x0223); 
} 
 
#define WRITEVAR(v) if(FAILED(hr = pStream->Write(&(v), sizeof(v), NULL))) break; 
#define WRITEBUFF(v, size) if(FAILED(hr = pStream->Write(v, size, NULL))) break; 
#define READVAR(v) if(FAILED(hr = pStream->Read(&(v), sizeof(v), NULL))) break; 
#define READBUFF(v, size) if(FAILED(hr = pStream->Read(v, size, NULL))) break; 
 
HRESULT CDirectVobSub::WriteToStream(IStream* pStream) 
{ 
    CAutoLock cAutolock(&m_propsLock); 
 
	HRESULT hr = E_FAIL; 
 
	CString fn = m_FileName; 
 
	if(!m_fSaveFullPath) 
	{ 
		fn.Replace('\\', '/'); 
		fn = fn.Mid(fn.ReverseFind('/')+1); 
	} 
 
	int len = fn.GetLength(); 
 
	WCHAR tempfn[MAX_PATH]; 
#ifdef UNICODE 
	wcscpy(tempfn, fn); 
#else 
	mbstowcs(tempfn, fn, len+1); 
#endif 
 
	do 
	{ 
		WRITEVAR(len); 
		WRITEBUFF(tempfn, (len+1)*2); 
 
		WRITEVAR(m_fFlipPicture); 
		WRITEVAR(m_fHideSubtitles); 
		WRITEVAR(m_fBufferVobSub); 
		WRITEVAR(m_lf); // TODO 
		WRITEVAR(m_fShadow); 
		WRITEVAR(m_fOutline); 
		WRITEVAR(m_TextColor); 
		WRITEVAR(m_fDoPreBuffering); 
		WRITEVAR(m_fOSD); 
		WRITEVAR(m_fOverridePlacement); 
		WRITEVAR(m_PlacementXperc); 
		WRITEVAR(m_PlacementYperc); 
		WRITEVAR(m_SubtitleDelay); 
		WRITEVAR(m_SubtitleSpeedMul); 
//		WRITEVAR(m_fResX2); 
		WRITEVAR(m_fOnlyShowForcedVobSubs); 
		WRITEVAR(m_SubtitleSpeedDiv); 
		WRITEVAR(m_ZoomRect); 
 
		return(NOERROR); 
	}  
	while(false); 
 
	return(hr); 
} 
 
HRESULT CDirectVobSub::ReadFromStream(IStream* pStream) 
{ 
    CAutoLock cAutolock(&m_propsLock); 
 
	HRESULT hr = E_FAIL; 
 
	int len; 
	char tempfn[MAX_PATH]; 
	WCHAR tempfnw[MAX_PATH]; 
 
	do 
	{ 
		READVAR(len); 
		if(mPS_dwFileVersion >= 0x0207) {READBUFF(tempfnw, (len+1)*2);} 
		else {READBUFF(tempfn, len+1); mbstowcs(tempfnw, tempfn, len+1);} 
 
		READVAR(m_fFlipPicture); 
		READVAR(m_fHideSubtitles); 
		if(mPS_dwFileVersion < 0x0215) {bool m_fDummy; READVAR(m_fDummy);} 
		READVAR(m_fBufferVobSub); 
		READVAR(m_lf); 
		READVAR(m_fShadow); 
 
		// Started version numbering from 1.18. It should  
		// be compatible with older grf's in the future releases. 
 
		if(mPS_dwFileVersion >= 0x0118) READVAR(m_fOutline); 
		if(mPS_dwFileVersion >= 0x0120) READVAR(m_TextColor); 
		if(mPS_dwFileVersion >= 0x0128) READVAR(m_fDoPreBuffering); 
		if(mPS_dwFileVersion >= 0x0201) READVAR(m_fOSD); 
		if(mPS_dwFileVersion >= 0x0203) {READVAR(m_fOverridePlacement); READVAR(m_PlacementXperc); READVAR(m_PlacementYperc);} 
		if(mPS_dwFileVersion >= 0x0207) {READVAR(m_SubtitleDelay); READVAR(m_SubtitleSpeedMul); if(mPS_dwFileVersion < 0x0215) {bool m_fDummy; READVAR(m_fDummy);}} 
		if(mPS_dwFileVersion >= 0x0209) READVAR(m_fOnlyShowForcedVobSubs); 
		if(mPS_dwFileVersion >= 0x0214) READVAR(m_SubtitleSpeedDiv); 
		if(mPS_dwFileVersion >= 0x0215) READVAR(m_ZoomRect); 
 
		put_FileName(tempfnw); 
 
	    return(NOERROR); 
	} 
	while(false); 
 
	return(hr); 
}