www.pudn.com > VOBSUB.rar > subresyncDlg.cpp


// subresyncDlg.cpp : implementation file 
// 
 
#include "stdafx.h" 
 
#include  
 
#include  
#include  
 
#include  
 
#include "subresync.h" 
#include "subresyncDlg.h" 
#include "../vobsub/vobsub.h" 
#include "resource.h" 
 
#include  
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
// CAboutDlg dialog used for App About 
 
class CAboutDlg : public CDialog 
{ 
public: 
	CAboutDlg(); 
 
// Dialog Data 
	//{{AFX_DATA(CAboutDlg) 
	enum { IDD = IDD_ABOUTBOX }; 
	//}}AFX_DATA 
 
	// ClassWizard generated virtual function overrides 
	//{{AFX_VIRTUAL(CAboutDlg) 
	protected: 
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support 
	//}}AFX_VIRTUAL 
 
// Implementation 
protected: 
	//{{AFX_MSG(CAboutDlg) 
	afx_msg void OnHomepagebtn(); 
	afx_msg void OnBugreportbtn(); 
	//}}AFX_MSG 
	DECLARE_MESSAGE_MAP() 
}; 
 
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) 
{ 
	//{{AFX_DATA_INIT(CAboutDlg) 
	//}}AFX_DATA_INIT 
} 
 
void CAboutDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CAboutDlg) 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) 
	//{{AFX_MSG_MAP(CAboutDlg) 
	ON_BN_CLICKED(IDC_HOMEPAGEBTN, OnHomepagebtn) 
	ON_BN_CLICKED(IDC_BUGREPORTBTN, OnBugreportbtn) 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
void CAboutDlg::OnHomepagebtn()  
{ 
	CString cmd(_T("http://vobsub.edensrising.com")); 
	ShellExecute(m_hWnd, _T("open"), cmd, NULL, NULL, SW_SHOWNORMAL); 
} 
 
void CAboutDlg::OnBugreportbtn()  
{ 
	CString cmd(_T("mailto:gabest@freemail.hu")); 
	ShellExecute(m_hWnd, _T("open"), cmd, NULL, NULL, SW_SHOWNORMAL); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CSubresyncDlg dialog 
 
CSubresyncDlg::CSubresyncDlg(CString fn, CWnd* pParent /*=NULL*/) 
	: CDialog(CSubresyncDlg::IDD, pParent) 
	, m_fn(fn) 
	, m_fRender(FALSE) 
	, m_fUnlink(FALSE) 
{ 
	//{{AFX_DATA_INIT(CSubresyncDlg) 
	//}}AFX_DATA_INIT 
 
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
 
	m_fps = 25.000; 
 
	m_curSegmRect = CRect(0, 0, 0, 0); 
 
	m_orgwin = m_orgcli = CSize(0, 0); 
 
	m_subimgperc = 100; 
 
	m_scalex = m_scaley = 1; 
 
	m_fSizing = false; 
 
	m_mode = NONE; 
 
	m_fOCRing = false; 
 
	if(m_od.IsValid()) 
	{ 
		FILE* f = _tfopen(_T("ENGLISH.WDC"), _T("r")); 
		if(f) 
		{ 
			m_od.SetLanguage(1, "."); 
			fclose(f); 
		} 
	} 
} 
 
CSubresyncDlg::~CSubresyncDlg() 
{ 
	m_subdc.DeleteDC(); 
	m_subimg.DeleteObject(); 
	FreeCharImgList(); 
} 
 
void CSubresyncDlg::DoDataExchange(CDataExchange* pDX) 
{ 
	CDialog::DoDataExchange(pDX); 
	//{{AFX_DATA_MAP(CSubresyncDlg) 
	DDX_Control(pDX, IDC_LIST1, m_list); 
	DDX_Control(pDX, IDC_SAVEBTN, m_saveasbtn); 
	DDX_Control(pDX, IDC_RESET, m_resetbtn); 
	DDX_Control(pDX, IDC_EDITSUB, m_editbtn); 
	DDX_Control(pDX, IDOK, m_exitbtn); 
	DDX_Check(pDX, IDC_CHECK1, m_fRender); 
	DDX_Control(pDX, IDC_CHECK1, m_previewchk); 
	DDX_Check(pDX, IDC_CHECK2, m_fUnlink); 
	DDX_Control(pDX, IDC_CHECK2, m_unlinkchk); 
	DDX_Control(pDX, IDC_COMBO1, m_vslangs); 
	//}}AFX_DATA_MAP 
} 
 
BEGIN_MESSAGE_MAP(CSubresyncDlg, CDialog) 
	//{{AFX_MSG_MAP(CSubresyncDlg) 
	ON_WM_SYSCOMMAND() 
	ON_WM_PAINT() 
	ON_WM_QUERYDRAGICON() 
	ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST1, OnEndlabeleditList1) 
	ON_NOTIFY(NM_RCLICK, IDC_LIST1, OnRclickList1) 
	ON_BN_CLICKED(IDC_OPENBTN, OnOpen) 
	ON_BN_CLICKED(IDC_RESET, OnReset) 
	ON_BN_CLICKED(IDC_SAVEBTN, OnSave) 
	ON_WM_DROPFILES() 
	ON_NOTIFY(NM_DBLCLK, IDC_LIST1, OnNMDblclkList1) 
	ON_BN_CLICKED(IDC_EDITSUB, OnBnClickedEditsub) 
	ON_WM_SIZE() 
	ON_WM_GETMINMAXINFO() 
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, OnLvnItemchangedList1) 
	ON_BN_CLICKED(IDC_CHECK1, OnBnClickedCheck1) 
	ON_NOTIFY(NM_CLICK, IDC_LIST1, OnNMClickList1) 
	ON_WM_LBUTTONDOWN() 
	ON_WM_NCHITTEST() 
	ON_WM_ERASEBKGND() 
	ON_BN_CLICKED(IDC_CHECK2, OnBnClickedCheck2) 
	ON_CBN_SELCHANGE(IDC_COMBO1, OnCbnSelchangeCombo1) 
	ON_NOTIFY(LVN_KEYDOWN, IDC_LIST1, OnLvnKeydownList1) 
	ON_WM_MOUSEMOVE() 
	ON_WM_LBUTTONUP() 
	ON_WM_MOUSEWHEEL() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CSubresyncDlg message handlers 
 
enum  
{ 
	// TEXTSUB 
	COL_START=0, COL_END, COL_PREVSTART, COL_PREVEND, COL_TEXT, COL_STYLE, COL_FONT, COL_CHARSET, COL_LAYER, COL_ACTOR, COL_EFFECT, 
	// VOBSUB 
	/* ........... same as TEXTSUB ............. */	  COL_VOBID=COL_TEXT, COL_CELLID, COL_FORCED, 
	// OCR 
	COL_LETTERS=0, COL_WIDTH, COL_HEIGHT, COL_ALIGNMENT 
}; 
 
BOOL CSubresyncDlg::OnInitDialog() 
{ 
	CDialog::OnInitDialog(); 
 
	// Add "About..." menu item to system menu. 
 
	// IDM_ABOUTBOX must be in the system command range. 
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); 
	ASSERT(IDM_ABOUTBOX < 0xF000); 
 
	CMenu* pSysMenu = GetSystemMenu(FALSE); 
	if (pSysMenu != NULL) 
	{ 
		CString strAboutMenu; 
		strAboutMenu.LoadString(IDS_ABOUTBOX); 
		if (!strAboutMenu.IsEmpty()) 
		{ 
			pSysMenu->AppendMenu(MF_SEPARATOR); 
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); 
		} 
	} 
 
	SetIcon(m_hIcon, TRUE);			// Set big icon 
	SetIcon(m_hIcon, FALSE);		// Set small icon 
	 
	// TODO: Add extra initialization here 
 
	m_icons.Create(IDB_BITMAP1, 13, 3, 0xffffff); 
	m_list.SetImageList(&m_icons, LVSIL_SMALL); 
	SetWindowLong(m_list.m_hWnd, DWL_USER, GetWindowLong(m_list.m_hWnd, DWL_USER)|LBS_WANTKEYBOARDINPUT); 
 
	CRect rect; 
	GetWindowRect(&rect); 
	m_orgwin = rect.Size(); 
	GetClientRect(&rect); 
	m_orgcli = rect.Size(); 
 
	m_saveasbtn.EnableWindow(FALSE); 
	m_resetbtn.EnableWindow(FALSE); 
	m_previewchk.EnableWindow(FALSE); 
	m_unlinkchk.EnableWindow(FALSE); 
 
	if(m_fn.GetLength() > 4)  
	{ 
		if(!m_fn.Right(4).CompareNoCase(_T(".idx")) || !m_fn.Right(4).CompareNoCase(_T(".vsocr")))  
		{ 
			Open(m_fn); 
		} 
		else  
		{ 
			OnOpen(); // will ask additional info 
		} 
	} 
	else  
	{ 
		m_fn.Empty(); 
	} 
 
	return TRUE;  // return TRUE  unless you set the focus to a control 
} 
 
void CSubresyncDlg::OnSysCommand(UINT nID, LPARAM lParam) 
{ 
	if ((nID & 0xFFF0) == IDM_ABOUTBOX) 
	{ 
		CAboutDlg dlgAbout; 
		dlgAbout.DoModal(); 
	} 
	else 
	{ 
		CDialog::OnSysCommand(nID, lParam); 
	} 
} 
 
// If you add a minimize button to your dialog, you will need the code below 
//  to draw the icon.  For MFC applications using the document/view model, 
//  this is automatically done for you by the framework. 
 
void CSubresyncDlg::OnPaint()  
{ 
	if (IsIconic()) 
	{ 
		CPaintDC dc(this); // device context for painting 
 
		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); 
 
		// Center icon in client rectangle 
		int cxIcon = GetSystemMetrics(SM_CXICON); 
		int cyIcon = GetSystemMetrics(SM_CYICON); 
		CRect rect; 
		GetClientRect(&rect); 
		int x = (rect.Width() - cxIcon + 1) / 2; 
		int y = (rect.Height() - cyIcon + 1) / 2; 
 
		// Draw the icon 
		dc.DrawIcon(x, y, m_hIcon); 
	} 
	else 
	{ 
		CPaintDC dc(this); // device context for painting 
 
		if((m_fRender || m_fOCRing) && GetImageOfSelected() && !m_subimgrect.IsRectEmpty()) 
		{ 
			BITMAP bm; 
			m_subimg.GetBitmap(&bm); 
 
			CRect r = m_subimgrect; 
 
			r.DeflateRect(2, 2, 2, 2); 
 
			CBitmap* oldbm = m_subdc.SelectObject(&m_subimg); 
 
			dc.StretchBlt( 
				r.left, r.top, 
				r.Width(), r.Height(), 
				&m_subdc,  
				0, 0, bm.bmWidth, bm.bmHeight,  
				SRCCOPY); 
 
			m_subdc.SelectObject(oldbm); 
 
			r.InflateRect(2, 2, 2, 2); 
 
			dc.DrawEdge(r, EDGE_RAISED, BF_RECT); 
 
			if(!m_curSegmRect.IsRectEmpty()) 
			{ 
				double rx = 1.0 * r.Width() / bm.bmWidth; 
				double ry = 1.0 * r.Height() / bm.bmHeight; 
 
				r = CRect( 
					r.left + (int)(rx*m_curSegmRect.left), 
					r.top + (int)(ry*m_curSegmRect.top), 
					r.left + (int)(rx*(m_curSegmRect.right+1)), 
					r.top + (int)(ry*(m_curSegmRect.bottom+1))); 
 
				CBrush br(0x0000ff); 
 
				r.InflateRect(1, 1, 3, 3); 
				r &= m_subimgrect; 
				dc.FrameRect(&r, &br); 
				r.InflateRect(1, 1, 1, 1); 
				r &= m_subimgrect; 
				dc.FrameRect(&r, &br); 
			} 
		} 
 
		CDialog::OnPaint(); 
	} 
} 
 
HCURSOR CSubresyncDlg::OnQueryDragIcon() 
{ 
	return (HCURSOR) m_hIcon; 
} 
 
void CSubresyncDlg::OnEndlabeleditList1(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; 
 
	*pResult = FALSE; 
 
	if(pDispInfo->item.pszText) 
	{ 
		if(m_mode == VOBSUB || m_mode == TEXTSUB) 
		{ 
			int sign = 1, h, m, s, ms; 
 
			int n = _stscanf(pDispInfo->item.pszText, _T("%d:%d:%d.%d"), &h, &m, &s, &ms); 
 
			h = abs(h); 
 
			if(n == 4 
			&& 0 <= h && h < 24  
			&& 0 <= m && m < 60  
			&& 0 <= s && s < 60  
			&& 0 <= ms && ms < 1000) 
			{ 
				CString str(pDispInfo->item.pszText); 
				str.TrimLeft();	str.TrimRight(); 
				if(str.GetLength() > 0 && str[0] == '-') sign = -1; 
				_tcscpy(pDispInfo->item.pszText, str); 
 
				SubTime& st = m_subtimes[pDispInfo->item.iItem]; 
				st.newstart = sign*(h*60*60*1000+m*60*1000+s*1000+ms); 
				st.newend = st.newstart + (st.orgend - st.orgstart); 
 
				SetChecked(pDispInfo->item.iItem, true); 
 
				UpdatePreview(); 
 
				*pResult = TRUE; 
 
				return; 
			} 
 
			CString err1 = _T("Please try to concentrate!\n"),  
				err2 = _T("The correct time format is [-]hh:mm:ss.ms\n(e.g. 01:23:45.678)");  
 
			AfxMessageBox((!(rand()%20)?err1:_T("")) + err2); 
		} 
		else if(m_mode == OCR) 
		{ 
			if(_tcslen(pDispInfo->item.pszText) > 0) 
			{ 
				m_cilist.GetAt((POSITION)pDispInfo->item.lParam)->m_str = pDispInfo->item.pszText; 
				*pResult = TRUE; 
			} 
		} 
	} 
} 
 
void CSubresyncDlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult)  
{ 
	LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pNMHDR; 
 
	if(m_mode == VOBSUB || m_mode == TEXTSUB) 
	{ 
		if(lpnmlv->iItem >= 0 && lpnmlv->iSubItem == 0) 
		{ 
			UpdateData(); 
 
			CRect r; 
			m_list.GetItemRect(lpnmlv->iItem, r, LVIR_ICON); 
			if(!m_fUnlink && m_subtimes[lpnmlv->iItem].fChecked && r.PtInRect(lpnmlv->ptAction)) 
			{ 
				m_subtimes[lpnmlv->iItem].chkmode = (m_subtimes[lpnmlv->iItem].chkmode+1)%3; 
				SetChecked(lpnmlv->iItem, m_subtimes[lpnmlv->iItem].fChecked); 
			} 
			else 
			{ 
				SetChecked(lpnmlv->iItem, !GetChecked(lpnmlv->iItem)); 
			} 
 
			UpdatePreview(); 
		} 
	} 
	else if(m_mode == OCR) 
	{ 
		if(lpnmlv->iItem >= 0 && lpnmlv->iSubItem == 0) 
		{ 
			CRect r; 
			if(m_list.GetItemRect(lpnmlv->iItem, r, LVIR_SELECTBOUNDS) && r.PtInRect(lpnmlv->ptAction)) 
			{ 
				CMenu popup; 
				popup.CreatePopupMenu(); 
				popup.AppendMenu(MF_STRING|MF_ENABLED, 1, _T("&Rename")); 
				popup.AppendMenu(MF_STRING|MF_ENABLED, 2, _T("&Delete")); 
				CPoint p(lpnmlv->ptAction); 
				m_list.ClientToScreen(&p); 
				switch(popup.TrackPopupMenu(TPM_LEFTBUTTON|TPM_RETURNCMD, p.x, p.y, this)) 
				{ 
				case 1:   
					m_list.SetFocus(); 
					m_list.EditLabel(lpnmlv->iItem); 
					break; 
				case 2:  
					{ 
						LRESULT Result; 
						NMLVKEYDOWN LVKeyDown; 
						LVKeyDown.wVKey = VK_DELETE; 
						OnLvnKeydownList1((NMHDR*)&LVKeyDown, &Result); 
					} 
					break; 
				default:  
					break; 
				} 
			} 
		} 
	} 
	 
	*pResult = 0; 
} 
 
void CSubresyncDlg::OnNMClickList1(NMHDR *pNMHDR, LRESULT *pResult) 
{ 
	RearrangeControls(); 
 
	*pResult = 0; 
} 
 
void CSubresyncDlg::OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult) 
{ 
	LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pNMHDR; 
 
	if(m_mode == TEXTSUB) OnBnClickedEditsub(); 
 
	*pResult = 0; 
} 
 
void CSubresyncDlg::OnBnClickedEditsub() 
{ 
	if(m_mode == TEXTSUB)  
	{ 
		CUIntArray elems; 
 
		POSITION pos = m_list.GetFirstSelectedItemPosition(); 
		while(pos) elems.Add(m_list.GetNextSelectedItem(pos)); 
 
		m_rts.ConfigDlg(&elems, m_hWnd); 
 
		UpdateStrings(); 
 
		RearrangeControls(); 
	} 
	else if(m_mode == VOBSUB || m_mode == OCR) 
	{ 
		if(m_list.GetSelectedCount() > 0) 
		{ 
			POSITION pos = m_list.GetFirstSelectedItemPosition(); 
			if(pos)  
			{ 
				m_list.SetFocus(); 
				m_list.EditLabel(m_list.GetNextSelectedItem(pos)); 
			} 
		} 
	} 
} 
 
void CSubresyncDlg::OnReset()  
{ 
	m_list.DeleteAllItems(); 
 
	if(m_mode == VOBSUB || m_mode == TEXTSUB)  
	{ 
		TCHAR buff[32]; 
 
		for(int i = 0, j = m_rts.GetSize(); i < j; i++) 
		{ 
			m_subtimes[i].newstart = m_subtimes[i].orgstart; 
			m_subtimes[i].newend = m_subtimes[i].orgend; 
			m_subtimes[i].fChecked = false; 
			m_subtimes[i].chkmode = 0; 
 
			FormatTime(i, buff, 0, false); 
			m_list.InsertItem(i, buff, COL_START); 
			FormatTime(i, buff, 0, true); 
			m_list.SetItemText(i, COL_END, buff); 
 
			SetChecked(i, false); 
		} 
 
		UpdatePreview(); 
	} 
 
	UpdateStrings(); 
} 
 
void CSubresyncDlg::OnBnClickedCheck2() 
{ 
	UpdateData(); 
 
	if(m_mode == VOBSUB || m_mode == TEXTSUB)  
	{ 
		for(int i = 0, j = m_rts.GetSize(); i < j; i++) 
		{ 
			m_rts[i].start = m_subtimes[i].orgstart; 
			m_rts[i].end = m_subtimes[i].orgend; 
		} 
 
		m_rts.Sort(!!m_fUnlink); 
 
		for(i = 0, j = m_rts.GetSize(); i < j; i++) 
		{ 
			m_subtimes[i].orgstart = m_rts[i].start; 
			m_subtimes[i].orgend = m_rts[i].end; 
		} 
	} 
	else if(m_mode == OCR) 
	{ 
		// TODO 
	} 
 
	OnReset(); 
} 
 
void CSubresyncDlg::OnLvnKeydownList1(NMHDR *pNMHDR, LRESULT *pResult) 
{ 
	LPNMLVKEYDOWN pLVKeyDown = reinterpret_cast(pNMHDR); 
 
	if(pLVKeyDown->wVKey == VK_DELETE && m_list.GetSelectedCount() > 0)  
	{ 
		if(m_mode == OCR 
			&& AfxMessageBox(_T("Are you sure you want to delete the selected entries?"), MB_YESNO|MB_DEFBUTTON2) == IDYES) 
		{ 
			CList items; 
 
			POSITION pos = m_list.GetFirstSelectedItemPosition(); 
			while(pos) items.AddHead(m_list.GetNextSelectedItem(pos)); 
 
			pos = items.GetHeadPosition(); 
			while(pos)  
			{ 
				int item = items.GetNext(pos); 
 
				POSITION cipos = (POSITION)m_list.GetItemData(item); 
				delete m_cilist.GetAt(cipos); 
				m_cilist.RemoveAt(cipos); 
 
				m_list.DeleteItem(item); 
			} 
 
			RearrangeControls(); 
		} 
	} 
 
	*pResult = 0; 
} 
 
void CSubresyncDlg::UpdatePreview() 
{ 
	UpdateData(); 
 
	if(m_mode == VOBSUB || m_mode == TEXTSUB)  
	{ 
		if(m_fUnlink) 
		{ 
			for(int i = 0, j = m_rts.GetSize(); i < j; i++) 
			{ 
				if(GetChecked(i)) 
				{ 
					m_rts[i].start = m_subtimes[i].newstart; 
					m_rts[i].end = m_subtimes[i].newend; 
				} 
				else 
				{ 
					m_rts[i].start = m_subtimes[i].orgstart; 
					m_rts[i].end = m_subtimes[i].orgend; 
				} 
			} 
		} 
		else 
		{ 
			CArray  checked; 
 
			for(int i = 0, j = m_rts.GetSize(); i < j;) 
			{ 
				checked.RemoveAll(); 
 
				int start = i; 
 
				for(int end = i; end < j; end++) 
				{ 
					if(m_subtimes[end].fChecked) 
					{ 
						if(m_subtimes[end].chkmode == 1 && end > start) {break;} 
						checked.Add(end); 
						if(m_subtimes[end].chkmode == 2) {end++; break;} 
					} 
				} 
 
				if(checked.GetSize() == 0) 
				{ 
					for(; start < end; start++)  
					{ 
						m_rts[start].start = m_subtimes[start].orgstart; 
						m_rts[start].end = m_subtimes[start].orgend; 
					} 
				} 
				else if(checked.GetSize() == 1) 
				{ 
					int k = checked[0]; 
					 
					int dt = m_subtimes[k].newstart - m_subtimes[k].orgstart; 
 
					for(int l = start; l < k; l++)  
					{ 
						m_rts[l].start = m_subtimes[l].orgstart + dt; 
						m_rts[l].end = m_subtimes[l].orgend + dt; 
					} 
 
					m_rts[l].start = m_subtimes[l].newstart; 
					m_rts[l].end = m_subtimes[l].newend; 
 
					for(l++; l < end; l++)  
					{ 
						m_rts[l].start = m_subtimes[l].orgstart + dt; 
						m_rts[l].end = m_subtimes[l].orgend + dt; 
					} 
				} 
				else if(checked.GetSize() >= 2) 
				{ 
					int i0, i1, ti0, ds; 
					double m = 0; 
 
					for(int k = 0, l = checked.GetSize()-1; k < l; k++) 
					{ 
						i0 = checked[k]; 
						i1 = checked[k+1]; 
						 
						ti0 = m_subtimes[i0].orgstart; 
						ds = m_subtimes[i1].orgstart - ti0; 
						 
						if(ds == 0) 
						{ 
							for(; start < i1; start++) 
							{ 
								m_rts[start].start = ti0; 
								m_rts[start].end = ti0 + (m_subtimes[start].orgend - m_subtimes[start].orgstart); 
							} 
						} 
						else 
						{ 
							m = double(m_subtimes[i1].newstart - m_subtimes[i0].newstart) / ds; 
 
							for(; start < i1; start++)  
							{ 
								m_rts[start].start = int((m_subtimes[start].orgstart - ti0)*m + m_subtimes[i0].newstart); 
								m_rts[start].end = m_rts[start].start + int((m_subtimes[start].orgend - m_subtimes[start].orgstart)*m); 
							} 
						} 
					} 
 
					if(ds == 0) 
					{ 
						for(; start < end; start++)  
						{ 
							m_rts[start].start = ti0; 
							m_rts[start].end = ti0 + (m_subtimes[start].orgend - m_subtimes[start].orgstart); 
						} 
					} 
					else 
					{ 
						for(; start < end; start++) 
						{ 
							m_rts[start].start = int((m_subtimes[start].orgstart - ti0)*m + m_subtimes[i0].newstart); 
							m_rts[start].end = m_rts[start].start + int((m_subtimes[start].orgend - m_subtimes[start].orgstart)*m); 
						} 
					} 
				} 
 
				i = end; 
			} 
		} 
 
		UpdateData(); 
		m_rts.CreateSegments(); 
 
		for(int i = 0, j = m_rts.GetSize(); i < j; i++) 
		{ 
			TCHAR buff[32]; 
			FormatTime(i, buff, 2, false); 
			m_list.SetItemText(i, COL_PREVSTART, buff); 
			FormatTime(i, buff, 2, true); 
			m_list.SetItemText(i, COL_PREVEND, buff); 
		} 
	} 
} 
 
static int CALLBACK MyCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) 
{ 
	CList * cilist = (CList *)lParamSort; 
	return _tcscmp(cilist->GetAt((POSITION)lParam1)->m_str, cilist->GetAt((POSITION)lParam2)->m_str); 
} 
 
void CSubresyncDlg::UpdateStrings() 
{ 
	if(m_mode == TEXTSUB) 
	{ 
		CString str; 
 
		for(int i = 0, j = m_rts.GetSize(); i < j; i++) 
		{ 
			m_list.SetItemText(i, COL_TEXT, m_rts.GetStr(i)); 
			m_list.SetItemText(i, COL_STYLE, m_rts[i].style); 
			STSStyle* s = m_rts.GetStyle(i); 
			m_list.SetItemText(i, COL_FONT, s->fontName); 
			str.Format(_T("%d"), s->charSet); 
			m_list.SetItemText(i, COL_CHARSET, str); 
			str.Format(_T("%d"), m_rts[i].layer); 
			m_list.SetItemText(i, COL_LAYER, str); 
			m_list.SetItemText(i, COL_ACTOR, m_rts[i].actor); 
			m_list.SetItemText(i, COL_EFFECT, m_rts[i].effect); 
		} 
	} 
	else if(m_mode == VOBSUB) 
	{ 
		CString str; 
 
		for(int i = 0, j = m_rts.GetSize(); i < j; i++) 
		{ 
			int vobid, cellid, forced, c; 
			if(_stscanf(m_rts.GetStr(i), _T("%d%c%d%c%d"), &vobid, &c, &cellid, &c, &forced) != 5) continue; 
			if(vobid < 0) str = _T("Unknown"); 
			else str.Format(_T("%d"), vobid); 
			m_list.SetItemText(i, COL_VOBID, str); 
			if(cellid < 0) str = _T("Unknown"); 
			else str.Format(_T("%d"), cellid); 
			m_list.SetItemText(i, COL_CELLID, str); 
			str = forced?_T("Yes"):_T(""); 
			m_list.SetItemText(i, COL_FORCED, str); 
		}			 
	} 
	else if(m_mode == OCR) 
	{ 
		CString str; 
 
		int i = 0; 
 
		POSITION pos = m_cilist.GetHeadPosition(), tmp; 
		while(pos) 
		{ 
			tmp = pos; 
			CharImg* img = m_cilist.GetNext(pos); 
			m_list.InsertItem(i, img->m_str); // COL_LETTERS 
			m_list.SetItemData(i, (DWORD_PTR)tmp); 
			str.Format(_T("%d"), img->m_w); 
			m_list.SetItemText(i, COL_WIDTH, str); 
			str.Format(_T("%d"), img->m_h); 
			m_list.SetItemText(i, COL_HEIGHT, str); 
			str = img->m_topbottom<0?_T("Top"):img->m_topbottom>0?_T("Bottom"):_T("Center"); 
			m_list.SetItemText(i, COL_ALIGNMENT, str); 
 
			i++; 
		} 
 
		if(!m_fUnlink)  
			m_list.SortItems(MyCompareFunc, (LPARAM)&m_cilist); 
	} 
} 
 
// open/save 
 
void CSubresyncDlg::OnDropFiles(HDROP hDropInfo) 
{ 
	if(DragQueryFile(hDropInfo, 0xffffffff, 0, 0) != 1) return; 
 
	TCHAR buff[MAX_PATH]; 
	DragQueryFile(hDropInfo, 0, buff, MAX_PATH); 
 
	CString fn(buff); 
	CString ext = fn.Mid(fn.ReverseFind('.')+1); 
	ext.MakeLower(); 
 
	if(ext == _T("srt") || ext == _T("sub") || ext == _T("psb")  
	|| ext == _T("smi") || ext == _T("ssa") || ext == _T("ass") 
	|| ext == _T("idx")) 
	{ 
		m_fn = fn; 
		OnOpen(); 
	} 
	else if(ext == _T("vsocr")) 
	{ 
		Open(fn); 
	} 
	else 
	{ 
		m_pDet = NULL; 
 
		BOOL bFoundVideo = FALSE; 
 
		do 
		{ 
			HRESULT hr; 
			if(FAILED(hr = m_pDet.CoCreateInstance(CLSID_MediaDet))) break; 
 
			if(FAILED(hr = m_pDet->put_Filename(_bstr_t(fn)))) break; 
 
			long Streams = 0; 
			if(FAILED(hr = m_pDet->get_OutputStreams(&Streams))) break; 
 
			for(int i = 0 ; i < Streams && !bFoundVideo; i++) 
			{ 
				BOOL bIsVideo = FALSE; 
 
				AM_MEDIA_TYPE Type; 
				memset(&Type, 0, sizeof(Type)); 
 
				if(FAILED(hr = m_pDet->put_CurrentStream(i))) continue; 
 
				if(FAILED(hr = m_pDet->get_StreamMediaType(&Type))) continue; 
 
				if(Type.majortype == MEDIATYPE_Video) bIsVideo = TRUE; 
 
				FreeMediaType(Type); 
 
				if(!bIsVideo) continue; 
 
				bFoundVideo = TRUE; 
			} 
		} 
		while(0); 
 
		if(!bFoundVideo) 
		{ 
			m_pDet = NULL; 
		} 
	} 
} 
 
enum {EXTSST = EXTIDX+1, EXTSON, EXTWSUB, EXTPASS, EXTVSO}; 
 
typedef struct  
{ 
	DWORD CharSet; // in/out  
	int mode; // in 
	union 
	{ 
		bool fSomethingIsOpened; // in 
		bool fAppend; // out 
	}; 
	int timeoff; // in/out 
	float fps; // out 
} OpenHookData; 
 
UINT CALLBACK OpenHookProc(HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) 
{ 
	switch(uiMsg) 
	{ 
		case WM_COMMAND: 
		{ 
			if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_CHECK1) 
			{ 
				OpenHookData* ohd = (OpenHookData*)((OPENFILENAME*)GetWindowLong(hDlg, GWL_USERDATA))->lCustData; 
 
				bool fAppend = IsDlgButtonChecked(hDlg, IDC_CHECK1) == BST_CHECKED; 
				fAppend = fAppend && (ohd->mode == CSubresyncDlg::TEXTSUB); // no appending time is needed for vsocr 
				EnableWindow(GetDlgItem(hDlg, IDC_EDIT1), fAppend); 
				EnableWindow(GetDlgItem(hDlg, IDC_EDIT2), fAppend); 
				EnableWindow(GetDlgItem(hDlg, IDC_EDIT3), fAppend); 
				EnableWindow(GetDlgItem(hDlg, IDC_EDIT4), fAppend); 
				EnableWindow(GetDlgItem(hDlg, IDC_TIMEFORMATLABEL), fAppend); 
			} 
		} 
 
		break; 
 
		case WM_NOTIFY: 
		{ 
			OPENFILENAME* ofn = ((OFNOTIFY *)lParam)->lpOFN; 
 
			if(((NMHDR *)lParam)->code == CDN_FILEOK) 
			{ 
				OpenHookData* ohd = (OpenHookData*)ofn->lCustData; 
 
				ohd->CharSet = CharSetList[SendMessage(GetDlgItem(hDlg, IDC_COMBO1), CB_GETCURSEL, 0, 0)]; 
				ohd->fAppend = IsDlgButtonChecked(hDlg, IDC_CHECK1) == BST_CHECKED; 
				 
				if(ohd->fAppend) 
				{ 
					TCHAR hhb[10], mmb[10], ssb[10], msb[10]; 
					GetWindowText(GetDlgItem(hDlg, IDC_EDIT1), hhb, 10); 
					GetWindowText(GetDlgItem(hDlg, IDC_EDIT2), mmb, 10); 
					GetWindowText(GetDlgItem(hDlg, IDC_EDIT3), ssb, 10); 
					GetWindowText(GetDlgItem(hDlg, IDC_EDIT4), msb, 10); 
 
					int hh, mm, ss, ms; 
 
					if(_stscanf(hhb, _T("%d"), &hh) 
					+ _stscanf(mmb, _T("%d"), &mm) 
					+ _stscanf(ssb, _T("%d"), &ss) 
					+ _stscanf(msb, _T("%d"), &ms) != 4) 
					{ 
						ohd->fAppend = false; 
					} 
					else if(mm >= 0 && mm < 60 && ss >= 0 && ss < 60 && ms >= 0 && ms < 1000) 
					{ 
						int sign = 1; 
						if(hh < 0) {sign = -1; hh = -hh;} 
 
						ohd->timeoff = ((((hh*60+mm)*60+ss)*1000)+ms)*sign; 
					} 
				} 
 
				TCHAR buff[256]; 
				GetWindowText(GetDlgItem(hDlg, IDC_COMBO2), buff, 256); 
				if(_stscanf(buff, _T("%f"), &ohd->fps) != 1) ohd->fps = 25; 
			} 
			else if(((NMHDR *)lParam)->code == CDN_SELCHANGE) 
			{ 
				OpenHookData* ohd = (OpenHookData*)ofn->lCustData; 
 
				TCHAR fn[MAX_PATH]; 
 
				if(SendMessage(GetParent(hDlg), CDM_GETFILEPATH, (WPARAM)MAX_PATH, (LPARAM)fn) > 0) 
				{ 
					FILE* f = _tfopen(fn, _T("rb")); 
					if(f) 
					{ 
						CString tmp(fn), ext = tmp.Mid(tmp.ReverseFind('.')+1); 
 
						bool fVobSubIdx = !ext.CompareNoCase(_T("idx")); 
 
						bool fVobSubSub = false; 
 
						if(!ext.CompareNoCase(_T("sub"))) 
						{ 
							uint dw; 
							fread(&dw, 4, 1, f); 
 
							fVobSubSub = (dw == 0xba010000); 
						} 
 
						fclose(f); 
 
						EnableWindow(GetDlgItem(hDlg, IDC_COMBO1), fVobSubSub ? FALSE : TRUE); 
 
						bool fCanAppend =  
							(ohd->mode == CSubresyncDlg::TEXTSUB && ext.CompareNoCase(_T("vsocr"))  
								|| ohd->mode == CSubresyncDlg::OCR && !ext.CompareNoCase(_T("vsocr"))) 
							&& ohd->fSomethingIsOpened && !fVobSubIdx && !fVobSubSub; 
 
						EnableWindow(GetDlgItem(hDlg, IDC_CHECK1), fCanAppend ? TRUE : FALSE); 
						fCanAppend = fCanAppend && (ohd->mode == CSubresyncDlg::TEXTSUB); // no appending time is needed for vsocr 
						EnableWindow(GetDlgItem(hDlg, IDC_AT), fCanAppend ? TRUE : FALSE); 
						EnableWindow(GetDlgItem(hDlg, IDC_EDIT1), fCanAppend ? TRUE : FALSE); 
						EnableWindow(GetDlgItem(hDlg, IDC_EDIT2), fCanAppend ? TRUE : FALSE); 
						EnableWindow(GetDlgItem(hDlg, IDC_EDIT3), fCanAppend ? TRUE : FALSE); 
						EnableWindow(GetDlgItem(hDlg, IDC_EDIT4), fCanAppend ? TRUE : FALSE); 
						EnableWindow(GetDlgItem(hDlg, IDC_TIMEFORMATLABEL), fCanAppend ? TRUE : FALSE); 
					} 
					else 
					{ 
						EnableWindow(GetDlgItem(hDlg, IDC_COMBO1), FALSE); 
					} 
				} 
			} 
		} 
 
		break; 
 
		case WM_INITDIALOG: 
		{ 
			SetWindowLong(hDlg, GWL_USERDATA, lParam); 
 
			OPENFILENAME* ofn = (OPENFILENAME*)lParam; 
			OpenHookData* ohd = (OpenHookData*)ofn->lCustData; 
 
			EnableWindow(GetDlgItem(hDlg, IDC_COMBO1), FALSE); 
 
			EnableWindow(GetDlgItem(hDlg, IDC_CHECK1), FALSE); 
			EnableWindow(GetDlgItem(hDlg, IDC_AT), FALSE); 
			EnableWindow(GetDlgItem(hDlg, IDC_EDIT1), FALSE); 
			EnableWindow(GetDlgItem(hDlg, IDC_EDIT2), FALSE); 
			EnableWindow(GetDlgItem(hDlg, IDC_EDIT3), FALSE); 
			EnableWindow(GetDlgItem(hDlg, IDC_EDIT4), FALSE); 
			EnableWindow(GetDlgItem(hDlg, IDC_TIMEFORMATLABEL), FALSE); 
 
			CString tmp; 
			tmp.Format(_T("%03d"), ohd->timeoff%1000); ohd->timeoff /= 1000; 
			SetWindowText(GetDlgItem(hDlg, IDC_EDIT4), tmp); 
			tmp.Format(_T("%02d"), ohd->timeoff%60); ohd->timeoff /= 60; 
			SetWindowText(GetDlgItem(hDlg, IDC_EDIT3), tmp); 
			tmp.Format(_T("%02d"), ohd->timeoff%60); ohd->timeoff /= 60; 
			SetWindowText(GetDlgItem(hDlg, IDC_EDIT2), tmp); 
			tmp.Format(_T("%d"), ohd->timeoff); 
			SetWindowText(GetDlgItem(hDlg, IDC_EDIT1), tmp); 
 
			for(int i = 0; i < CharSetLen; i++) 
			{ 
				SendMessage(GetDlgItem(hDlg, IDC_COMBO1), CB_ADDSTRING, 0, (LONG)CharSetNames[i]); 
				 
				if(CharSetList[i] == ohd->CharSet)  
					SendMessage(GetDlgItem(hDlg, IDC_COMBO1), CB_SETCURSEL, i, 0); 
			} 
 
			TCHAR fpsvalues[][7] = {_T("23.976"), _T("24"), _T("25"), _T("29.97"), _T("30")}; 
			for(i = 0; i < 5; i++) 
				SendMessage(GetDlgItem(hDlg, IDC_COMBO2), CB_ADDSTRING, 0, (LONG)fpsvalues[i]); 
			SendMessage(GetDlgItem(hDlg, IDC_COMBO2), CB_SETCURSEL, 2, 0); 
 
			break; 
		} 
		 
		default:; 
	} 
 
	return FALSE; 
} 
 
void CSubresyncDlg::OnOpen()  
{ 
	static TCHAR BASED_CODE szFilter[] = _T("Supported files (idx,srt,sub,smi,psb,ssa,ass,vsocr)|*.idx;*.srt;*.sub;*.smi;*.psb;*.ssa;*.ass;*.vsocr;||"); 
 
	CFileDialog fd(TRUE, NULL, m_fn,  
		OFN_EXPLORER | OFN_ENABLESIZING | OFN_HIDEREADONLY | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK,  
		szFilter, this); 
 
	fd.m_ofn.hInstance = AfxGetResourceHandle(); 
	fd.m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_OPENTMPLT); 
	fd.m_ofn.lpfnHook = OpenHookProc; 
 
	OpenHookData ohd; 
	ohd.CharSet = DEFAULT_CHARSET; 
	ohd.fSomethingIsOpened = !m_fn.IsEmpty(); 
	ohd.mode = m_mode; 
	ohd.timeoff = !m_fn.IsEmpty() && m_mode == TEXTSUB && m_rts.GetSize() > 0 
		? m_rts.TranslateEnd(m_rts.GetSize()-1, m_fps) 
		: 0; 
	fd.m_ofn.lCustData = (DWORD)&ohd; 
 
	if(fd.DoModal() != IDOK) return; 
 
	if(!ohd.fAppend) ohd.timeoff = 0; 
 
	m_fps = ohd.fps; 
 
	m_CharSet = ohd.CharSet; 
 
	Open(fd.GetPathName(), ohd.CharSet, ohd.fAppend, ohd.timeoff); 
} 
 
bool CSubresyncDlg::Open(CString fn, int CharSet /*= DEFAULT_CHARSET*/, bool fAppend /*= false*/, int timeoff /*= 0*/) 
{ 
	if(!m_subimgrect.IsRectEmpty()) InvalidateRect(m_subimgrect); 
	m_subimgrect.SetRectEmpty(); 
 
	CSimpleTextSubtitle sts; 
	if(sts.Open(fn, CharSet)) 
	{ 
		m_mode = TEXTSUB; 
		m_fn = fn; 
 
		sts.ConvertToTimeBased(m_fps); 
 
		if(fAppend) m_rts.Append(sts, timeoff); 
		else m_rts = sts; 
 
		m_rts.Sort(!!m_fUnlink); 
 
#ifndef UNICODE 
		if(!m_rts.IsEntryUnicode(0)) 
		{ 
			CFont* f = m_list.GetFont(); 
			LOGFONT lf; 
			f->GetLogFont(&lf); 
			lf.lfCharSet = m_rts.GetCharSet(0); 
			m_font.DeleteObject(); 
			m_font.CreateFontIndirect(&lf); 
			m_list.SetFont(&m_font); 
		} 
#endif 
		for(int i = 0, j = m_list.GetHeaderCtrl()->GetItemCount(); i < j; i++) m_list.DeleteColumn(0); 
 
		m_list.InsertColumn(COL_START, _T("Time"), LVCFMT_LEFT, 90); 
		m_list.InsertColumn(COL_END, _T("End"), LVCFMT_LEFT, 4); 
		m_list.InsertColumn(COL_PREVSTART, _T("Preview"), LVCFMT_LEFT, 80); 
		m_list.InsertColumn(COL_PREVEND, _T("End"), LVCFMT_LEFT, 4); 
		m_list.InsertColumn(COL_TEXT, _T("Text"), LVCFMT_LEFT, 275); 
		m_list.InsertColumn(COL_STYLE, _T("Style"), LVCFMT_LEFT, 80); 
		m_list.InsertColumn(COL_FONT, _T("Font"), LVCFMT_LEFT, 80); 
		m_list.InsertColumn(COL_CHARSET, _T("CharSet"), LVCFMT_LEFT, 80); 
		m_list.InsertColumn(COL_LAYER, _T("Layer"), LVCFMT_LEFT, 80); 
		m_list.InsertColumn(COL_ACTOR, _T("Actor"), LVCFMT_LEFT, 80); 
		m_list.InsertColumn(COL_EFFECT, _T("Effect"), LVCFMT_LEFT, 80); 
	} 
	else if(!fn.Mid(fn.ReverseFind('.')+1).CompareNoCase(_T("vsocr"))) // it is important to check for .vsocr _before_ vobsub, since m_file.Open() will reset m_file and we can't keep it if the user selects IDYES 
	{ 
		if(!fAppend) FreeCharImgList(); 
 
		FILE* f = _tfopen(fn, _T("rb")); 
		if(!f) return(false); 
		while(1) 
		{ 
			int c = fgetc(f); 
			if(c == EOF) break; 
			ungetc(c, f); 
			m_cilist.AddTail(new CharImg(f)); 
			CharImg* ci = m_cilist.GetTail(); 
			if(!ci || !ci->m_w || !ci->m_h || !ci->m_p) {delete ci; m_cilist.RemoveTail();} 
		} 
		fclose(f); 
		 
		if(m_mode == VOBSUB  
			&& AfxMessageBox(_T("Keep the already opened vobsub subtitle?"), MB_YESNO|MB_ICONQUESTION) == IDYES) 
		{ 
			RearrangeControls(); 
			return(true); 
		} 
		else 
		{ 
			m_mode = OCR; 
			m_fn = fn; 
		} 
 
		m_subimgidx = -1; 
 
		for(int i = 0, j = m_list.GetHeaderCtrl()->GetItemCount(); i < j; i++) m_list.DeleteColumn(0); 
 
		m_list.InsertColumn(COL_LETTERS, _T("Letter(s)"), LVCFMT_LEFT, 60); 
		m_list.InsertColumn(COL_WIDTH, _T("Width"), LVCFMT_CENTER, 60); 
		m_list.InsertColumn(COL_HEIGHT, _T("Height"), LVCFMT_CENTER, 60); 
		m_list.InsertColumn(COL_ALIGNMENT, _T("Alignment"), LVCFMT_CENTER, 70); 
	} 
	else if(fn.Find('.') >= 0 && m_file.Open(fn.Left(fn.ReverseFind('.')), false)) 
	{ 
		m_mode = VOBSUB; 
		m_fn = fn.Left(fn.ReverseFind('.')); 
 
		CArray & sub = m_file.m_subidx[m_file.GetLangIdx()]; 
 
		m_rts.Empty(); 
 
		for(int i = 0, j = sub.GetSize(); i < j; i++) 
		{ 
			CString str; 
			str.Format(_T("%d,%d,%d"), sub[i].vobid, sub[i].cellid, m_file.IsForcedSub(i)); 
			m_rts.Add(str, (int)sub[i].timestamp, (int)sub[i].timestamp); 
		} 
 
		m_rts.CreateDefaultStyle(CharSet, false); 
		m_rts.SetStylesToUnicode(false); 
 
		m_file.SetOnlyShowForcedSubs(false); 
 
		m_subimgidx = -1; 
 
		for(i = 0, j = m_list.GetHeaderCtrl()->GetItemCount(); i < j; i++)  
			m_list.DeleteColumn(0); 
 
		m_list.InsertColumn(COL_START, _T("Time"), LVCFMT_LEFT, 90); 
		m_list.InsertColumn(COL_END, _T("End"), LVCFMT_LEFT, 4); 
		m_list.InsertColumn(COL_PREVSTART, _T("Preview"), LVCFMT_LEFT, 80); 
		m_list.InsertColumn(COL_PREVEND, _T("End"), LVCFMT_LEFT, 4); 
		m_list.InsertColumn(COL_VOBID, _T("Vob ID"), LVCFMT_CENTER, 60); 
		m_list.InsertColumn(COL_CELLID, _T("Cell ID"), LVCFMT_CENTER, 60); 
		m_list.InsertColumn(COL_FORCED, _T("Forced"), LVCFMT_CENTER, 60); 
 
		SetupLangCombo(); 
	} 
	else 
	{ 
		m_fn.Empty(); 
		m_mode = NONE; 
	} 
 
	if(m_mode == VOBSUB || m_mode == TEXTSUB) 
	{ 
		m_subtimes.SetSize(m_rts.GetSize()); 
 
		for(int i = 0, j = m_rts.GetSize(); i < j; i++) 
		{ 
			m_subtimes[i].orgstart = m_rts[i].start; 
			m_subtimes[i].orgend = m_rts[i].end; 
		} 
	} 
 
	m_saveasbtn.EnableWindow(m_mode != NONE); 
	m_resetbtn.EnableWindow(m_mode == TEXTSUB || m_mode == VOBSUB); 
	m_editbtn.ShowWindow(m_mode == TEXTSUB || m_mode == OCR ? SW_SHOW : SW_HIDE); 
	m_editbtn.EnableWindow(m_mode != NONE); 
	m_vslangs.ShowWindow(m_mode == VOBSUB ? SW_SHOW : SW_HIDE); 
	m_previewchk.EnableWindow(m_mode != NONE); 
	m_unlinkchk.EnableWindow(m_mode == TEXTSUB || m_mode == VOBSUB || m_mode == OCR); 
 
	CString wndtitle(_T("Subresync")); 
	if(!m_fn.IsEmpty()) wndtitle += CString(_T(" - (")) + fn + ')'; 
	SetWindowText(wndtitle); 
 
	m_fRender = true; 
	UpdateData(FALSE); 
 
	OnReset(); 
 
	RearrangeControls(); 
 
	return(m_mode != NONE); 
} 
 
void CSubresyncDlg::SetupLangCombo() 
{ 
	if(m_mode == VOBSUB) 
	{ 
		m_vslangs.ResetContent(); 
 
		CString s, s2; 
		ushort id; 
		int	num; 
 
		for(int i = 0, j = m_file.GetLangCount(); i < j; i++) 
		{ 
			num = m_file.GetLangInfo(i, s, &id); 
			if(id == '--' && num > 0) s = _T("(Unknown)"); 
			else if(id != '--' && num == 0) s += _T(" (empty)"); 
			s2.Format(_T("%02d - %s"), i, s); 
			m_vslangs.AddString(s2); 
		} 
 
		if(j > 0) m_vslangs.SetCurSel(m_file.GetLangIdx()); 
	} 
} 
 
void CSubresyncDlg::OnCbnSelchangeCombo1() 
{ 
	if(m_mode != VOBSUB) return; 
 
	m_file.SetLangIdx(m_vslangs.GetCurSel()); 
 
	CArray & sub = m_file.m_subidx[m_file.GetLangIdx()]; 
 
	CString lang; 
	m_file.GetLangInfo(m_file.GetLangIdx(), lang); 
	m_file.GetLangAlt(m_file.GetLangIdx(), lang); 
 
	m_rts.Empty(); 
 
	for(int i = 0, j = sub.GetSize(); i < j; i++) 
	{ 
		CString str; 
		str.Format(_T("%s - Vob %02d Cell %02d"), lang, sub[i].vobid, sub[i].cellid); 
		m_rts.Add(str, (int)sub[i].timestamp, (int)sub[i].timestamp); 
	} 
 
	m_rts.CreateDefaultStyle(m_CharSet, false); 
	m_rts.SetStylesToUnicode(false); 
 
	m_subimgidx = -1; 
 
	m_subtimes.SetSize(m_rts.GetSize()); 
 
	for(i = 0, j = m_rts.GetSize(); i < j; i++) 
	{ 
		m_subtimes[i].orgstart = m_rts[i].start; 
		m_subtimes[i].orgend = m_rts[i].end; 
	} 
 
	OnReset(); 
 
	RearrangeControls(); 
} 
 
typedef struct  
{ 
	int mode; // in/out 
	bool fUnicode; // out 
	bool fClearImgLetterDb; // out 
	bool fOcrDll; // in/out 
} SaveHookData; 
 
UINT CALLBACK SaveHookProc(HWND hDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) 
{ 
	switch(uiMsg) 
	{ 
		case WM_NOTIFY: 
		{ 
			OPENFILENAME* ofn = ((OFNOTIFY *)lParam)->lpOFN; 
 
			if(((NMHDR *)lParam)->code == CDN_FILEOK) 
			{ 
				SaveHookData* shd = (SaveHookData*)ofn->lCustData; 
 
				shd->fUnicode = (ofn->nFilterIndex == EXTIDX+1) ? false : IsDlgButtonChecked(hDlg, IDC_CHECK1) == BST_CHECKED; 
				shd->fClearImgLetterDb = IsDlgButtonChecked(hDlg, IDC_CHECK2) == BST_CHECKED; 
				shd->fOcrDll = IsDlgButtonChecked(hDlg, IDC_OCRDLL) == BST_CHECKED; 
 
				AfxGetApp()->WriteProfileInt( 
					CString(MAKEINTRESOURCE(IDS_R_GENERAL)), CString(MAKEINTRESOURCE(IDS_RG_SPACESENS)),  
					SendMessage(GetDlgItem(hDlg, IDC_SLIDER1), TBM_GETPOS, 0, 0)); 
			} 
			else if(((NMHDR *)lParam)->code == CDN_TYPECHANGE) 
			{ 
				SaveHookData* shd = (SaveHookData*)ofn->lCustData; 
				int idx = ((OFNOTIFY*)lParam)->lpOFN->nFilterIndex-1; 
 
				BOOL uenable = (idx < EXTIDX || idx == EXTPASS) ? TRUE : FALSE; 
				BOOL ocrenable = (idx < EXTIDX && shd->mode == CSubresyncDlg::VOBSUB) ? TRUE : FALSE; 
#ifndef UNICODE 
				uenable = FALSE; 
#endif 
				EnableWindow(GetDlgItem(hDlg, IDC_CHECK1), uenable); 
				EnableWindow(GetDlgItem(hDlg, IDC_STATIC4), uenable); 
 
				EnableWindow(GetDlgItem(hDlg, IDC_CHECK2), ocrenable); 
				EnableWindow(GetDlgItem(hDlg, IDC_SLIDER1), ocrenable); 
				EnableWindow(GetDlgItem(hDlg, IDC_STATIC1), ocrenable); 
				EnableWindow(GetDlgItem(hDlg, IDC_STATIC2), ocrenable); 
				EnableWindow(GetDlgItem(hDlg, IDC_STATIC3), ocrenable); 
				EnableWindow(GetDlgItem(hDlg, IDC_OCRDLL), ocrenable); 
			} 
		} 
 
		break; 
 
		case WM_INITDIALOG: 
		{ 
			SetWindowLong(hDlg, GWL_USERDATA, lParam); 
 
			OPENFILENAME* ofn = (OPENFILENAME*)lParam; 
			SaveHookData* shd = (SaveHookData*)ofn->lCustData; 
 
			BOOL uenable = shd->mode == CSubresyncDlg::TEXTSUB ? TRUE : FALSE; 
#ifndef UNICODE 
			uenable = FALSE; 
#endif 
			EnableWindow(GetDlgItem(hDlg, IDC_CHECK1), uenable); 
			EnableWindow(GetDlgItem(hDlg, IDC_STATIC4), uenable); 
			CheckDlgButton(hDlg, IDC_CHECK1, shd->fUnicode ? BST_CHECKED : BST_UNCHECKED); 
 
			CString General(MAKEINTRESOURCE(IDS_R_GENERAL)); 
			CString SpaceSensitivity(MAKEINTRESOURCE(IDS_RG_SPACESENS)); 
 
			CheckDlgButton(hDlg, IDC_CHECK2, shd->fClearImgLetterDb ? BST_CHECKED : BST_UNCHECKED); 
			SendMessage(GetDlgItem(hDlg, IDC_SLIDER1), TBM_SETPOS, TRUE, AfxGetApp()->GetProfileInt(General, SpaceSensitivity, 35)); 
 
			EnableWindow(GetDlgItem(hDlg, IDC_CHECK2), shd->mode == CSubresyncDlg::VOBSUB); 
			EnableWindow(GetDlgItem(hDlg, IDC_SLIDER1), shd->mode == CSubresyncDlg::VOBSUB); 
			EnableWindow(GetDlgItem(hDlg, IDC_STATIC1), shd->mode == CSubresyncDlg::VOBSUB); 
			EnableWindow(GetDlgItem(hDlg, IDC_STATIC2), shd->mode == CSubresyncDlg::VOBSUB); 
			EnableWindow(GetDlgItem(hDlg, IDC_STATIC3), shd->mode == CSubresyncDlg::VOBSUB); 
 
			ShowWindow(GetDlgItem(hDlg, IDC_OCRDLL), shd->fOcrDll?SW_SHOW:SW_HIDE); 
			EnableWindow(GetDlgItem(hDlg, IDC_OCRDLL), shd->mode == CSubresyncDlg::VOBSUB); 
						 
			break; 
		} 
 
		default:; 
	} 
 
	return FALSE; 
} 
 
void CSubresyncDlg::OnSave()  
{ 
	if(m_mode == NONE) return; 
 
	CString filter; 
 
	if(m_mode == TEXTSUB || m_mode == VOBSUB)  
	{ 
		filter += _T("Subripper (*.srt)|*.srt|"); 
		filter += _T("Microdvd (*.sub)|*.sub|"); 
		filter += _T("Sami (*.smi)|*.smi|"); 
		filter += _T("Psb (*.psb)|*.psb|"); 
		filter += _T("Sub Station Alpha (*.ssa)|*.ssa|"); 
		filter += _T("Advanced Sub Station Alpha (*.ass)|*.ass|"); 
	} 
 
	if(m_mode == VOBSUB)  
	{ 
		filter += _T("VobSub (*.idx, *.sub)|*.idx;*.sub|"); 
		filter += _T("Scenarist (*.sst)|*.sst|"); 
		filter += _T("DVDMaestro (*.son)|*.son|"); 
		filter += _T("WinSubMux (*.sub)|*.sub|"); 
		filter += _T("Polygonized (*.ass)|*.ass|"); 
	} 
 
	if((m_mode == VOBSUB && m_cilist.GetCount() > 0) || m_mode == OCR) 
	{ 
		filter += _T("VobSub OCR file (*.vsocr)|*.vsocr|"); 
	} 
 
	filter += _T("|"); 
 
	CString ext = m_fn.Mid(m_fn.ReverseFind('.')+1); 
	ext.MakeLower(); 
	int textidx = ext == _T("srt") ? EXTSRT 
				: ext == _T("sub") ? EXTSUB 
				: ext == _T("smi") ? EXTSMI 
				: ext == _T("psb") ? EXTPSB 
				: ext == _T("ssa") ? EXTSSA 
				: ext == _T("ass") ? EXTASS 
				: EXTSRT; 
 
	CFileDialog fd(FALSE, NULL, m_fn,  
		OFN_EXPLORER|OFN_ENABLESIZING|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST|OFN_ENABLETEMPLATE|OFN_ENABLEHOOK 
		, filter, this); 
 
	SaveHookData shd; 
	shd.mode = m_mode; 
	shd.fUnicode = (m_mode == TEXTSUB || m_mode == VOBSUB) ? m_rts.IsEntryUnicode(0) : false; 
	shd.fClearImgLetterDb = false; 
	shd.fOcrDll = m_od.IsValid(); 
 
	fd.m_ofn.hInstance = AfxGetResourceHandle(); 
	fd.m_ofn.lpTemplateName = MAKEINTRESOURCE(IDD_SAVEASTMPLT); 
	fd.m_ofn.lpfnHook = SaveHookProc; 
	fd.m_ofn.lCustData = (LONG)&shd; 
	fd.m_ofn.nFilterIndex = (m_mode == VOBSUB ? EXTIDX : m_mode == TEXTSUB ? textidx : 0)+1; 
 
	if(fd.DoModal() != IDOK) return; 
 
	fd.m_ofn.nFilterIndex--; 
 
	Save(fd.GetPathName(), fd.m_ofn.nFilterIndex, shd.fUnicode, shd.fClearImgLetterDb, shd.fOcrDll); 
} 
 
bool CSubresyncDlg::Save(CString fn, int type, bool fUnicode, bool fClearImgLetterDb, bool fOcrDll) 
{ 
	if(m_mode == TEXTSUB || (m_mode == VOBSUB && (exttype)type < (exttype)EXTVSO)) 
	{ 
		m_savelist.RemoveAll(); 
 
		CSimpleTextSubtitle sts; 
		sts = m_rts; 
		sts.m_mode = TIME; 
		sts.RemoveAll(); 
 
		if(m_list.GetSelectedCount() > 1) 
		{ 
			POSITION pos = m_list.GetFirstSelectedItemPosition(); 
 
			if(m_mode == VOBSUB) 
			{ 
				CArray & sub = m_file.m_subidx[m_file.GetLangIdx()]; 
 
				int size = sub.GetSize(); 
				 
				if(size > 0) 
				{ 
					for(int i = 0; i < size; i++)  
					{ 
						sub[i].timestamp = m_rts[i].start; 
						sub[i].fValid = false; 
					} 
 
					while(pos)  
					{ 
						int i = m_list.GetNextSelectedItem(pos); 
						sub[i].fValid = true; 
						m_savelist.AddTail(i); 
					} 
				} 
			} 
			else if(m_mode == TEXTSUB) 
			{ 
				while(pos)  
				{ 
					int i = m_list.GetNextSelectedItem(pos); 
 
					if(m_rts[i].start < 0) continue; 
 
					STSEntry stse = m_rts[i]; 
					stse.start = m_rts[i].start; 
					stse.end = m_rts[i].end; 
					sts.CSTSArray::Add(stse); 
 
					m_savelist.AddTail(i); 
				} 
			} 
		} 
		else 
		{ 
			if(m_mode == VOBSUB) 
			{ 
				CArray & sub = m_file.m_subidx[m_file.GetLangIdx()]; 
 
				int size = sub.GetSize(); 
				 
				if(size > 0) 
				{ 
					for(int i = 0; i < size; i++)  
					{ 
						sub[i].timestamp = m_rts[i].start; 
						sub[i].fValid = true; 
						m_savelist.AddTail(i); 
					} 
				} 
 
			} 
			else if(m_mode == TEXTSUB) 
			{ 
				for(int i = 0, j = m_list.GetItemCount(); i < j; i++)  
				{ 
					STSEntry stse = m_rts[i]; 
					stse.start = m_rts[i].start; 
					stse.end = m_rts[i].end; 
					sts.CSTSArray::Add(stse); 
 
					m_savelist.AddTail(i); 
				} 
			} 
		} 
 
		if((exttype)type < EXTIDX) 
		{ 
            if(m_mode == VOBSUB && !DoOCR(sts, fClearImgLetterDb, fOcrDll)) return(false); 
 
			return(sts.SaveAs(fn, (exttype)type, m_fps 
#ifdef UNICODE 
				, fUnicode 
#endif 
				)); 
		} 
		else if((exttype)type == EXTIDX) 
		{ 
			return(m_file.SaveAs(fn)); 
		} 
		else if((exttype)type == EXTSST) 
		{ 
			return(m_file.SaveAsBMP(fn, 0)); 
		} 
		else if((exttype)type == EXTSON) 
		{ 
			return(m_file.SaveAsBMP(fn, 1)); 
		} 
		else if((exttype)type == EXTWSUB) 
		{ 
			return(m_file.SaveAsBMP(fn, 2)); 
		} 
		else if((exttype)type == EXTPASS) 
		{ 
			return(m_file.ConvertToSTS(sts) && sts.SaveAs(fn, EXTASS, m_fps 
#ifdef UNICODE 
				, fUnicode 
#endif 
				)); 
		} 
	} 
	else if(m_mode == OCR || (m_mode == VOBSUB && (exttype)type == EXTVSO)) 
	{ 
		if(fn.Mid(fn.ReverseFind('.')+1).CompareNoCase(_T("vsocr"))) fn += _T(".vsocr"); 
 
		FILE* f = _tfopen(fn, _T("wb")); 
		if(f) 
		{ 
			if(m_mode == OCR && m_list.GetSelectedCount() > 1) 
			{ 
				POSITION pos = m_list.GetFirstSelectedItemPosition(); 
				while(pos)  
				{ 
					if(!m_cilist.GetAt((POSITION)m_list.GetItemData(m_list.GetNextSelectedItem(pos)))->Write(f)) break; 
				} 
			} 
			else 
			{ 
				POSITION pos = m_cilist.GetHeadPosition(); 
				while(pos) {if(!m_cilist.GetNext(pos)->Write(f)) break;} 
			} 
 
			fclose(f); 
		} 
 
		return(true); 
	} 
 
	return(false); 
} 
 
/* resizing/moving things */ 
 
void CSubresyncDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI) 
{ 
	lpMMI->ptMinTrackSize.x = m_orgwin.cx - 100; 
	lpMMI->ptMinTrackSize.y = m_orgwin.cy; 
 
	CDialog::OnGetMinMaxInfo(lpMMI); 
} 
 
void CSubresyncDlg::OnSize(UINT nType, int cx, int cy) 
{ 
	CDialog::OnSize(nType, cx, cy); 
 
	if(nType == SIZE_MAXIMIZED || nType == SIZE_RESTORED || nType == SIZE_MAXSHOW) 
	{ 
		RearrangeControls(); 
	} 
} 
 
void CSubresyncDlg::OnLvnItemchangedList1(NMHDR *pNMHDR, LRESULT *pResult) 
{ 
	LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR); 
	if(pNMLV->uNewState & LVIS_SELECTED) RearrangeControls(); 
	*pResult = 0; 
} 
 
void CSubresyncDlg::OnBnClickedCheck1() 
{ 
	RearrangeControls(); 
} 
 
BOOL CSubresyncDlg::OnEraseBkgnd(CDC* pDC) 
{ 
	pDC->ExcludeClipRect(m_subimgrect); 
 
	BOOL ret = CDialog::OnEraseBkgnd(pDC); 
 
	CRgn r; 
	r.CreateRectRgnIndirect(m_subimgrect); 
	pDC->SelectClipRgn(&r, RGN_OR); 
 
	return ret; 
} 
 
void CSubresyncDlg::RearrangeControls() 
{ 
	UpdateData(); 
 
	if(!m_subimgrect.IsRectEmpty()) 
	{ 
		InvalidateRect(m_subimgrect, FALSE); 
	} 
 
	CRect wrect; 
	GetClientRect(wrect); 
 
	CRect lrect; 
	m_list.GetWindowRect(lrect); 
	ScreenToClient(lrect); 
 
	CRect erect; 
	m_exitbtn.GetWindowRect(erect); 
	ScreenToClient(erect); 
 
	int h = 0, w; 
 
	if((m_fRender || m_fOCRing) && m_list.GetSelectedCount() >= 1 && GetImageOfSelected()) 
	{ 
		h = (wrect.Height() - (m_orgcli.cy - 80)) * m_subimgperc/100; 
		h = max(h, 0); 
 
//		h = wrect.Height() - (m_orgcli.cy - 80); 
        w = h * m_scalex / m_scaley; 
 
		if(w > wrect.Width() - 16)  
		{ 
			w = wrect.Width() - 16; 
			h = wrect.Width() * m_scaley / m_scalex; 
		} 
 
		m_subimgrect = CRect( 
			CPoint(wrect.CenterPoint().x - w/2, wrect.bottom - 8 - h), 
			CSize(w, h) 
			); 
	} 
	else 
	{ 
		m_subimgrect.SetRectEmpty(); 
	} 
 
	lrect.bottom = wrect.bottom - 8 - h - (m_subimgrect.IsRectEmpty() ? 0 : 8); 
	lrect.right = wrect.right - 8; 
 
	m_list.MoveWindow(lrect); 
 
	int eheight = erect.Height(); 
	erect.bottom = wrect.bottom - 8 - h - (m_subimgrect.IsRectEmpty() ? 0 : 8); 
	erect.top = erect.bottom - eheight; 
 
	m_exitbtn.MoveWindow(erect); 
 
	if(m_subimgrect.right < m_subimgrect.left || m_subimgrect.bottom < m_subimgrect.top) 
	{ 
		m_subimgrect.SetRectEmpty(); 
	} 
	else 
	{ 
		InvalidateRect(m_subimgrect); 
	} 
} 
 
void CSubresyncDlg::OnLButtonDown(UINT nFlags, CPoint point) 
{ 
	CDialog::OnLButtonDown(nFlags, point); 
 
	if(!m_subimgrect.IsRectEmpty()) 
	{ 
		CRect rect; 
		GetClientRect(rect); 
 
		CRect lrect; 
		m_list.GetWindowRect(lrect); 
		ScreenToClient(&lrect); 
 
		if(rect.PtInRect(point)) 
		{ 
			SetFocus(); 
			return; 
		} 
	} 
 
	PostMessage(WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(point.x, point.y)); 
} 
 
UINT CSubresyncDlg::OnNcHitTest(CPoint point) 
{ 
	UINT nHitTest = CDialog::OnNcHitTest(point); 
 
	if(!m_subimgrect.IsRectEmpty()) 
	{ 
		CRect rect; 
		GetClientRect(rect); 
 
		CRect lrect; 
		m_list.GetWindowRect(lrect); 
		ScreenToClient(&lrect); 
 
		ClientToScreen(rect); 
 
		if(rect.PtInRect(point)) 
		{ 
			return nHitTest; 
		} 
	} 
 
	return (nHitTest == HTCLIENT) ? HTCAPTION : nHitTest; 
} 
 
BOOL CSubresyncDlg::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{ 
	m_subimgperc += 2 * zDelta / WHEEL_DELTA; 
	m_subimgperc = min(max(m_subimgperc, 0), 100); 
	RearrangeControls(); 
	return CDialog::OnMouseWheel(nFlags, zDelta, pt); 
} 
 
/* to prevent exiting on VK_ESCAPE */ 
 
BOOL CSubresyncDlg::PreTranslateMessage(MSG* pMsg) 
{ 
	if(pMsg->message == WM_KEYDOWN && (pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_CANCEL)) 
	{ 
		return TRUE; 
	} 
 
	return CDialog::PreTranslateMessage(pMsg); 
} 
 
/* misc */ 
 
bool CSubresyncDlg::GetChecked(int iItem) 
{ 
	if(iItem < 0 || iItem >= m_rts.GetSize()) return(false); 
 
	return(m_subtimes[iItem].fChecked); 
} 
 
void CSubresyncDlg::SetChecked(int iItem, bool fChecked) 
{ 
	if(iItem < 0 || iItem >= m_rts.GetSize()) return; 
 
	m_subtimes[iItem].fChecked = fChecked; 
 
	int dt = m_subtimes[iItem].newstart - m_subtimes[iItem].orgstart; 
 
	LVITEM lvi; 
	lvi.iItem = iItem; 
	lvi.iSubItem = COL_START; 
	lvi.mask = LVIF_IMAGE; 
 
	if(fChecked) lvi.iImage = m_subtimes[iItem].chkmode + 1; 
	else if(dt) lvi.iImage = m_subtimes[iItem].chkmode + 4; 
	else lvi.iImage = 0; 
 
	m_list.SetItem(&lvi); 
 
	TCHAR buff[32]; 
	FormatTime(iItem, buff, fChecked?1:0, false); 
	m_list.SetItemText(iItem, COL_START, buff); 
	FormatTime(iItem, buff, fChecked?1:0, true); 
	m_list.SetItemText(iItem, COL_END, buff); 
} 
 
void CSubresyncDlg::FormatTime(int iItem, TCHAR* buff, int time, bool fEnd) 
{ 
	int t = !fEnd  
		?(time == 2 ? m_rts[iItem].start 
		: time == 1	? m_subtimes[iItem].newstart  
		: m_subtimes[iItem].orgstart) 
		: (time == 2 ? m_rts[iItem].end 
		: time == 1	? m_subtimes[iItem].newend 
		: m_subtimes[iItem].orgend); 
 
	_stprintf(buff, t >= 0  
					? _T("%02d:%02d:%02d.%03d")  
					: _T("-%02d:%02d:%02d.%03d"),  
		abs(t)/60/60/1000,  
		(abs(t)/60/1000)%60,  
		(abs(t)/1000)%60,  
		abs(t)%1000); 
} 
 
/////////// 
 
static void memsetd(void* dst, unsigned int c, int len) 
{ 
	__asm 
	{ 
		mov eax, c 
		mov ecx, len 
		shr ecx, 2 
		mov edi, dst 
		cld 
		rep stosd 
	} 
} 
 
/////////// 
 
bool CSubresyncDlg::GetImageOfSelected() 
{ 
	if(m_list.GetSelectedCount() >= 1) 
	{ 
		POSITION pos = m_list.GetFirstSelectedItemPosition(); 
 
		if(m_mode == VOBSUB) 
		{ 
			GetVobSubImage(m_list.GetNextSelectedItem(pos)); 
		} 
		else if(m_mode == TEXTSUB) 
		{ 
			BITMAP bm; 
			memset(&bm, 0, sizeof(bm)); 
 
			if(m_subimg.m_hObject != NULL) m_subimg.GetBitmap(&bm); 
 
			int w = m_rts.m_dstScreenSize.cx, h = m_rts.m_dstScreenSize.cy; 
 
			m_scalex = m_rts.m_dstScreenSize.cx; 
			m_scaley = m_rts.m_dstScreenSize.cy; 
 
			if(!m_subimgrect.IsRectEmpty() && !m_fSizing) 
			{ 
				w = max(m_subimgrect.Width()-4, 4); 
				h = max(m_subimgrect.Height()-4, 3); 
			} 
 
			if(bm.bmWidth != w || bm.bmHeight != h) 
			{ 
				m_subimg.DeleteObject(); 
 
				BITMAPV4HEADER bmV4Header; 
 
				bmV4Header.bV4Size = sizeof(BITMAPV4HEADER); 
				bmV4Header.bV4Width = w; 
				bmV4Header.bV4Height = h; 
				bmV4Header.bV4Planes = 1; 
				bmV4Header.bV4BitCount = 32; 
				bmV4Header.bV4V4Compression = BI_RGB; 
 
				HDC hdc = ::GetDC(NULL); 
 
				m_subimg.Attach(CreateDIBSection(hdc, (BITMAPINFO*)&bmV4Header, DIB_RGB_COLORS, NULL, 0, 0)); 
	 
				m_subdc.DeleteDC(); 
				m_subdc.CreateCompatibleDC(CDC::FromHandle(hdc)); 
//				m_subdc.SelectObject(m_subimg); 
 
				::ReleaseDC(NULL, hdc); 
 
				m_rts.Init(CSize(w, h)); 
			} 
 
			m_subimg.GetBitmap(&bm); 
 
			HRESULT hr = E_FAIL; 
 
			do 
			{ 
				if(!m_pDet) break; 
 
				POSITION pos2 = m_list.GetFirstSelectedItemPosition(); 
				double t = 1.0 * m_rts[m_list.GetNextSelectedItem(pos2)].start / 1000; 
 
				long BufferSize; 
 
				hr = m_pDet->GetBitmapBits(t, &BufferSize, NULL, w, h); 
				if(FAILED(hr)) break; 
 
				char* pBuffer = new char[BufferSize]; 
				if(!pBuffer) break; 
 
				hr = m_pDet->GetBitmapBits(t, 0, pBuffer, w, h); 
				if(!FAILED(hr)) 
				{ 
					BITMAPINFOHEADER* pBIH = (BITMAPINFOHEADER*)pBuffer; 
					CBitmap* oldbm = m_subdc.SelectObject(&m_subimg); 
					SetDIBits(m_subdc, m_subimg, 0, h, pBuffer+pBIH->biSize, (BITMAPINFO*)pBIH, DIB_RGB_COLORS); 
					m_subdc.SelectObject(oldbm); 
				} 
 
				delete [] pBuffer; 
			} 
			while(0); 
 
			if(FAILED(hr)) 
			{ 
				w = bm.bmWidthBytes/4; 
				h = bm.bmHeight; 
 
				uint* ptr = (uint*)bm.bmBits; 
 
				for(int j = 0; j < h; j++)  
					for(int i = 0; i < w; i++) 
						*ptr++ = (((j>>4)+(i>>4))&1) == 0 ? 0xa0a0a0 : 0x606060; 
			} 
 
			if(pos) m_rts.Render(bm, m_rts[m_list.GetNextSelectedItem(pos)].start, m_fps); 
		} 
		else if(m_mode == OCR) 
		{ 
			int idx = m_list.GetNextSelectedItem(pos); 
			if(idx == m_subimgidx) return(true); 
 
			CharImg* img = m_cilist.GetAt((POSITION)m_list.GetItemData(idx)); 
			if(!img) return(false); 
 
			m_subimgidx = idx; 
 
			m_scalex = img->m_w; 
			m_scaley = img->m_h; 
 
			m_subimg.DeleteObject(); 
 
			BITMAPV4HEADER bmV4Header; 
			bmV4Header.bV4Size = sizeof(BITMAPV4HEADER); 
			bmV4Header.bV4Width = img->m_w; 
			bmV4Header.bV4Height = -img->m_h; 
			bmV4Header.bV4Planes = 1; 
			bmV4Header.bV4BitCount = 32; 
			bmV4Header.bV4V4Compression = BI_RGB; 
 
			HDC hdc = ::GetDC(NULL); 
 
			m_subimg.Attach(CreateDIBSection(hdc, (BITMAPINFO*)&bmV4Header, DIB_RGB_COLORS, NULL, 0, 0)); 
 
			m_subdc.DeleteDC(); 
			m_subdc.CreateCompatibleDC(CDC::FromHandle(hdc)); 
//			m_subdc.SelectObject(m_subimg); 
 
			::ReleaseDC(NULL, hdc); 
 
			BITMAP bm; 
			m_subimg.GetBitmap(&bm); 
 
			DWORD* dst = (DWORD*)bm.bmBits; 
 
			for(int i = 0, j = img->m_w*img->m_h; i < j; i++, dst++)  
			{ 
				if(img->m_p[i]) 
				{ 
					*dst = 0xffffff; 
				} 
				else 
				{ 
					*dst = (((int)((i/img->m_w)>>3) + ((i%img->m_w)>>3)) & 1) == 0 ? 0xa0a0a0 : 0x606060; 
				} 
			} 
		} 
		else 
		{ 
			m_subimg.DeleteObject(); 
			m_subimgidx = -1; 
		} 
 
		return(true); 
	} 
	 
	return(false); 
} 
 
bool CSubresyncDlg::GetVobSubImage(int idx) 
{ 
	if(m_mode != VOBSUB) return(false); 
 
	if(idx == m_subimgidx) return(true); 
 
	if(!m_file.GetFrame(idx)) return(false); 
 
	m_subimgidx = idx; 
 
	int w = m_file.m_img.rect.Width(), h = m_file.m_img.rect.Height(); 
 
	m_scalex = w; 
	m_scaley = h; 
 
	for(int i = 0, j = w*h; i < j; i++)  
	{ 
		if(!m_file.m_img.lpPixels[i].rgbReserved) 
		{ 
			*((uint*)&m_file.m_img.lpPixels[i]) = (((int)((i/w)>>3) + ((i%w)>>3)) & 1) == 0 ? 0xa0a0a0 : 0x606060; 
		} 
	} 
 
	m_subimg.DeleteObject(); 
 
	BITMAPV4HEADER bmV4Header; 
 
	bmV4Header.bV4Size = sizeof(BITMAPV4HEADER); 
	bmV4Header.bV4Width = w; 
	bmV4Header.bV4Height = -h; 
	bmV4Header.bV4Planes = 1; 
	bmV4Header.bV4BitCount = 32; 
	bmV4Header.bV4V4Compression = BI_RGB; 
 
	HDC hdc = ::GetDC(NULL); 
 
	m_subimg.Attach(CreateDIBSection(hdc, (BITMAPINFO*)&bmV4Header, DIB_RGB_COLORS, NULL, 0, 0)); 
 
	m_subdc.DeleteDC(); 
	m_subdc.CreateCompatibleDC(CDC::FromHandle(hdc)); 
//	m_subdc.SelectObject(m_subimg); 
 
	::ReleaseDC(NULL, hdc); 
 
	BITMAP bm; 
	m_subimg.GetBitmap(&bm); 
 
	memcpy(bm.bmBits, m_file.m_img.lpPixels, bm.bmHeight*bm.bmWidthBytes); 
 
	return(true); 
}