From cb4d02b67a13c13064d73c856355c96373524414 Mon Sep 17 00:00:00 2001 From: raspopov Date: Sun, 12 Mar 2017 12:40:31 +0300 Subject: [PATCH] Cosmetic C++11 changes. --- BrowseCtrl.h | 72 ++-- PolangDlg.cpp | 832 +++++++++++++++++++++---------------------- PolangDlg.h | 140 ++++---- Translation.cpp | 924 ++++++++++++++++++++++++------------------------ Translation.h | 214 +++++------ 5 files changed, 1091 insertions(+), 1091 deletions(-) diff --git a/BrowseCtrl.h b/BrowseCtrl.h index 4ce3b5a..a7f551e 100644 --- a/BrowseCtrl.h +++ b/BrowseCtrl.h @@ -1,36 +1,36 @@ -/* - -Polang -Copyright (C) 2017 Nikolay Raspopov - -This program 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. - -This program 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 . - -*/ - -#pragma once - -// CBrowseCtrl - -class CBrowseCtrl : public CMFCEditBrowseCtrl -{ - DECLARE_DYNAMIC(CBrowseCtrl) - -public: - CBrowseCtrl() {} - -protected: - afx_msg void OnDropFiles( HDROP hDropInfo ); - - DECLARE_MESSAGE_MAP() -}; +/* + +Polang +Copyright (C) 2017 Nikolay Raspopov + +This program 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. + +This program 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 . + +*/ + +#pragma once + +// CBrowseCtrl + +class CBrowseCtrl : public CMFCEditBrowseCtrl +{ + DECLARE_DYNAMIC(CBrowseCtrl) + +public: + inline CBrowseCtrl() = default; + +protected: + afx_msg void OnDropFiles( HDROP hDropInfo ); + + DECLARE_MESSAGE_MAP() +}; diff --git a/PolangDlg.cpp b/PolangDlg.cpp index c3c874b..ca16763 100644 --- a/PolangDlg.cpp +++ b/PolangDlg.cpp @@ -1,416 +1,416 @@ -/* - -Polang -Copyright (C) 2017 Nikolay Raspopov - -This program 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. - -This program 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 "Polang.h" -#include "PolangDlg.h" -#include "Translation.h" - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - -#define SETTINGS _T("Settings") -#define VAL_OPTIONS _T("Options") -#define VAL_ENGLISH _T("EnglishPath") -#define VAL_LANG _T("LangPath") -#define VAL_PO _T("PoPath") -#define VAL_POT _T("PotPath") -#define VAL_WINDOW _T("Window") - -// CPolangDlg dialog - -CPolangDlg::CPolangDlg(CWnd* pParent /*=NULL*/) - : CDialogEx ( IDD_POLANG_DIALOG, pParent ) - , m_hIcon ( theApp.LoadIcon( IDR_MAINFRAME ) ) - , m_nOptions ( theApp.GetProfileInt( SETTINGS, VAL_OPTIONS, OPT_POT ) ) - , m_nOptionsLast ( OPT_NULL ) -{ -} - -void CPolangDlg::DoDataExchange(CDataExchange* pDX) -{ - __super::DoDataExchange( pDX ); - - DDX_Control( pDX, IDC_1_FILE, m_wnd1File ); - DDX_Control( pDX, IDC_2_FILE, m_wnd2File ); - DDX_Control( pDX, IDC_3_FILE, m_wnd3File ); - - DDX_Control( pDX, IDC_1_TITLE, m_wnd1Title ); - DDX_Control( pDX, IDC_2_TITLE, m_wnd2Title ); - DDX_Control( pDX, IDC_3_TITLE, m_wnd3Title ); - - DDX_Control( pDX, IDC_1_OPEN, m_wnd1Open ); - DDX_Control( pDX, IDC_2_OPEN, m_wnd2Open ); - DDX_Control( pDX, IDC_3_OPEN, m_wnd3Open ); - - DDX_Radio( pDX, IDC_RADIO1, m_nOptions ); -} - -void CPolangDlg::UpdateInterface(int nOptions) -{ - CString s1Filename, s2Filename, s3Filename; - m_wnd1File.GetWindowText( s1Filename ); - m_wnd2File.GetWindowText( s2Filename ); - m_wnd3File.GetWindowText( s3Filename ); - - // Save previous - CString str; - switch ( m_nOptionsLast ) - { - case OPT_NULL: - break; - - case OPT_POT: - theApp.WriteProfileString( SETTINGS, VAL_ENGLISH, s1Filename ); - theApp.WriteProfileString( SETTINGS, VAL_POT, s2Filename ); - break; - - case OPT_PO: - theApp.WriteProfileString( SETTINGS, VAL_ENGLISH, s1Filename ); - theApp.WriteProfileString( SETTINGS, VAL_LANG, s2Filename ); - theApp.WriteProfileString( SETTINGS, VAL_PO, s3Filename ); - break; - - case OPT_LANG: - theApp.WriteProfileString( SETTINGS, VAL_PO, s1Filename ); - theApp.WriteProfileString( SETTINGS, VAL_LANG, s2Filename ); - break; - } - - switch ( nOptions ) - { - case OPT_NULL: - break; - - case OPT_POT: - // Input - m_wnd1Title.SetWindowText( LoadString( IDS_ENGLISH_TITLE ) ); - m_wnd1File.EnableFileBrowseButton( _T("lang"), LoadString( IDS_LANG_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST ); - s1Filename = theApp.GetProfileString( SETTINGS, VAL_ENGLISH ); - m_wnd1File.SetWindowText( s1Filename ); - m_wnd1File.SetCueBanner( _T("en_US.lang") ); - // Output - m_wnd2Title.SetWindowText( LoadString( IDS_POT_TITLE ) ); - m_wnd2File.EnableFileBrowseButton( _T("pot"), LoadString( IDS_POEDIT_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT ); - s2Filename = theApp.GetProfileString( SETTINGS, VAL_POT ); - if ( s2Filename.IsEmpty() && ! s1Filename.IsEmpty() ) - s2Filename = s1Filename.Left( (int)( PathFindExtension( (LPCTSTR)s1Filename ) - (LPCTSTR)s1Filename ) + 1 ) + _T("pot"); - m_wnd2File.SetWindowText( s2Filename ); - m_wnd2File.SetCueBanner( _T("en_US.pot") ); - // Disabled - m_wnd3Title.SetWindowText( _T("") ); - m_wnd3File.EnableWindow( FALSE ); - m_wnd3File.SetWindowText( _T("") ); - m_wnd3File.SetCueBanner( _T("") ); - m_wnd3Open.EnableWindow( FALSE ); - break; - - case OPT_PO: - // Input - m_wnd1Title.SetWindowText( LoadString( IDS_ENGLISH_TITLE ) ); - m_wnd1File.EnableFileBrowseButton( _T("lang"), LoadString( IDS_LANG_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST ); - s1Filename = theApp.GetProfileString( SETTINGS, VAL_ENGLISH ); - m_wnd1File.SetWindowText( s1Filename ); - m_wnd1File.SetCueBanner( _T("en_US.lang") ); - // Input - m_wnd2Title.SetWindowText( LoadString( IDS_LANG_TITLE ) ); - m_wnd2File.EnableFileBrowseButton( _T("lang"), LoadString( IDS_LANG_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST ); - s2Filename = theApp.GetProfileString( SETTINGS, VAL_LANG ); - m_wnd2File.SetWindowText( s2Filename ); - m_wnd2File.SetCueBanner( _T("ru_RU.lang") ); - // Output - m_wnd3Title.SetWindowText( LoadString( IDS_PO_TITLE ) ); - m_wnd3File.EnableWindow(); - m_wnd3File.EnableFileBrowseButton( _T("po"), LoadString( IDS_POEDIT_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT ); - s3Filename = theApp.GetProfileString( SETTINGS, VAL_PO ); - if ( s3Filename.IsEmpty() && ! s2Filename.IsEmpty() ) - s3Filename = s2Filename.Left( (int)( PathFindExtension( (LPCTSTR)s2Filename ) - (LPCTSTR)s2Filename ) + 1 ) + _T("po"); - m_wnd3File.SetWindowText( s3Filename ); - m_wnd3File.SetCueBanner( _T("ru_RU.po") ); - m_wnd3Open.EnableWindow(); - break; - - case OPT_LANG: - // Input - m_wnd1Title.SetWindowText( LoadString( IDS_PO_TITLE ) ); - m_wnd1File.EnableFileBrowseButton( _T("po"), LoadString( IDS_POEDIT_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST ); - s1Filename = theApp.GetProfileString( SETTINGS, VAL_PO ); - m_wnd1File.SetWindowText( s1Filename ); - m_wnd1File.SetCueBanner( _T("ru_RU.po") ); - // Output - m_wnd2Title.SetWindowText( LoadString( IDS_LANG_TITLE ) ); - m_wnd2File.EnableFileBrowseButton( _T("lang"), LoadString( IDS_LANG_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT ); - s2Filename = theApp.GetProfileString( SETTINGS, VAL_LANG ); - if ( s2Filename.IsEmpty() && ! s1Filename.IsEmpty() ) - s2Filename = s1Filename.Left( (int)( PathFindExtension( (LPCTSTR)s1Filename ) - (LPCTSTR)s1Filename ) + 1 ) + _T("lang"); - m_wnd2File.SetWindowText( s2Filename ); - m_wnd2File.SetCueBanner( _T("ru_RU.lang") ); - // Disabled - m_wnd3Title.SetWindowText( _T("") ); - m_wnd3File.EnableWindow( FALSE ); - m_wnd3File.SetWindowText( _T("") ); - m_wnd3File.SetCueBanner( _T("") ); - m_wnd3Open.EnableWindow( FALSE ); - break; - } - - if ( nOptions != OPT_NULL ) - { - theApp.WriteProfileInt( SETTINGS, VAL_OPTIONS, nOptions ); - } - - m_nOptionsLast = nOptions; -} - -BEGIN_MESSAGE_MAP(CPolangDlg, CDialogEx) - ON_WM_PAINT() - ON_WM_GETMINMAXINFO() - ON_WM_QUERYDRAGICON() - ON_BN_CLICKED( IDC_RADIO1, &CPolangDlg::OnBnClickedRadio ) - ON_BN_CLICKED( IDC_RADIO2, &CPolangDlg::OnBnClickedRadio ) - ON_BN_CLICKED( IDC_RADIO3, &CPolangDlg::OnBnClickedRadio ) - ON_WM_DESTROY() - ON_BN_CLICKED( IDC_1_OPEN, &CPolangDlg::OnBnClicked1Open ) - ON_BN_CLICKED( IDC_2_OPEN, &CPolangDlg::OnBnClicked2Open ) - ON_BN_CLICKED( IDC_3_OPEN, &CPolangDlg::OnBnClicked3Open ) -END_MESSAGE_MAP() - -// CPolangDlg message handlers - -BOOL CPolangDlg::OnInitDialog() -{ - __super::OnInitDialog(); - - GetWindowRect( m_rcInitial ); - - SetIcon( m_hIcon, TRUE ); // Set big icon - SetIcon( m_hIcon, FALSE ); // Set small icon - - UpdateInterface( m_nOptions ); - - CAutoVectorPtr< WINDOWPLACEMENT> pl; - UINT len = 0; - theApp.GetProfileBinary( SETTINGS, VAL_WINDOW, (LPBYTE*)&pl, &len ); - if ( len == sizeof( WINDOWPLACEMENT ) ) - { - SetWindowPlacement( pl ); - } - - return TRUE; // return TRUE unless you set the focus to a control -} - -// 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 CPolangDlg::OnPaint() -{ - if ( IsIconic() ) - { - CPaintDC dc( this ); // device context for painting - - SendMessage( WM_ICONERASEBKGND, reinterpret_cast< WPARAM >( dc.GetSafeHdc() ), 0 ); - - // Center icon in client rectangle - CRect rect; - GetClientRect(&rect); - int x = ( rect.Width() - GetSystemMetrics( SM_CXICON ) + 1 ) / 2; - int y = ( rect.Height() - GetSystemMetrics( SM_CYICON ) + 1 ) / 2; - - // Draw the icon - dc.DrawIcon( x, y, m_hIcon ); - } - else - __super::OnPaint(); -} - -void CPolangDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI) -{ - __super::OnGetMinMaxInfo( lpMMI ); - - lpMMI->ptMinTrackSize.x = m_rcInitial.Width(); - lpMMI->ptMinTrackSize.y = m_rcInitial.Height(); -} - -HCURSOR CPolangDlg::OnQueryDragIcon() -{ - return static_cast< HCURSOR >( m_hIcon ); -} - -void CPolangDlg::OnOK() -{ - CWaitCursor wc; - - UpdateData(); - - CString s1Filename, s2Filename, s3Filename; - m_wnd1File.GetWindowText( s1Filename ); - m_wnd2File.GetWindowText( s2Filename ); - m_wnd3File.GetWindowText( s3Filename ); - - CTranslation translations; - switch ( m_nOptions ) - { - case OPT_POT: - // en_US.lang + en_US.pot - if ( s1Filename.IsEmpty() || s2Filename.IsEmpty() || GetFileAttributes( s1Filename ) == INVALID_FILE_ATTRIBUTES ) - { - AfxMessageBox( IDS_MSG_NO_FILE, MB_OK | MB_ICONEXCLAMATION ); - return; - } - - if ( ! translations.LoadLang( s1Filename ) ) - { - AfxMessageBox( IDS_MSG_ENGLISH_ERROR, MB_OK | MB_ICONEXCLAMATION ); - return; - } - - if ( ! translations.SavePo( s2Filename ) ) - { - AfxMessageBox( IDS_MSG_PO_SAVE_ERROR, MB_OK | MB_ICONEXCLAMATION ); - return; - } - - if ( AfxMessageBox( IDS_MSG_PO_SAVE_OK, MB_YESNO | MB_ICONQUESTION ) == IDYES ) - { - ShellExecute( GetSafeHwnd(), NULL, s2Filename, NULL, NULL, SW_NORMAL ); - } - break; - - case OPT_PO: - // en_US.lang + Local.lang -> Local.po - if ( s1Filename.IsEmpty() || s3Filename.IsEmpty() || GetFileAttributes( s1Filename ) == INVALID_FILE_ATTRIBUTES ) - { - AfxMessageBox( IDS_MSG_NO_FILE, MB_OK | MB_ICONEXCLAMATION ); - return; - } - - if ( ! translations.LoadLang( s1Filename ) ) - { - AfxMessageBox( IDS_MSG_ENGLISH_ERROR, MB_OK | MB_ICONEXCLAMATION ); - return; - } - - if ( ! s2Filename.IsEmpty() ) - { - if ( ! translations.LoadLang( s2Filename, true ) ) - { - AfxMessageBox( IDS_MSG_LANG_ERROR, MB_OK | MB_ICONEXCLAMATION ); - return; - } - } - - if ( ! translations.SavePo( s3Filename ) ) - { - AfxMessageBox( IDS_MSG_PO_SAVE_ERROR, MB_OK | MB_ICONEXCLAMATION ); - return; - } - - if ( AfxMessageBox( IDS_MSG_PO_SAVE_OK, MB_YESNO | MB_ICONQUESTION ) == IDYES ) - { - ShellExecute( GetSafeHwnd(), NULL, s3Filename, NULL, NULL, SW_NORMAL ); - } - break; - - case OPT_LANG: - // Local.po -> Local.lang - if ( s1Filename.IsEmpty() || s2Filename.IsEmpty() || GetFileAttributes( s1Filename ) == INVALID_FILE_ATTRIBUTES ) - { - AfxMessageBox( IDS_MSG_NO_FILE, MB_OK | MB_ICONEXCLAMATION ); - return; - } - - if ( ! translations.LoadPo( s1Filename ) ) - { - AfxMessageBox( IDS_MSG_PO_LOAD_ERROR, MB_OK | MB_ICONEXCLAMATION ); - return; - } - - if ( ! translations.SaveLang( s2Filename ) ) - { - AfxMessageBox( IDS_MSG_LANG_SAVE_ERROR, MB_OK | MB_ICONEXCLAMATION ); - return; - } - - if ( AfxMessageBox( IDS_MSG_LANG_SAVE_OK, MB_YESNO | MB_ICONQUESTION ) == IDYES ) - { - ShellExecute( GetSafeHwnd(), NULL, s2Filename, NULL, NULL, SW_NORMAL ); - } - break; - } -} - -void CPolangDlg::OnBnClickedRadio() -{ - UpdateData(); - - UpdateInterface( m_nOptions ); -} - -void CPolangDlg::OnDestroy() -{ - UpdateInterface( OPT_NULL ); - - WINDOWPLACEMENT pl = { sizeof( WINDOWPLACEMENT ) }; - GetWindowPlacement( &pl ); - theApp.WriteProfileBinary( SETTINGS, VAL_WINDOW, (LPBYTE)&pl, sizeof( WINDOWPLACEMENT ) ); - - __super::OnDestroy(); -} - -void CPolangDlg::OnBnClicked1Open() -{ - CWaitCursor wc; - - UpdateData(); - - UpdateInterface( m_nOptions ); - - CString sFilename; - m_wnd1File.GetWindowText( sFilename ); - ShellExecute( GetSafeHwnd(), NULL, sFilename, NULL, NULL, SW_NORMAL ); -} - -void CPolangDlg::OnBnClicked2Open() -{ - CWaitCursor wc; - - UpdateData(); - - UpdateInterface( m_nOptions ); - - CString sFilename; - m_wnd2File.GetWindowText( sFilename ); - ShellExecute( GetSafeHwnd(), NULL, sFilename, NULL, NULL, SW_NORMAL ); -} - -void CPolangDlg::OnBnClicked3Open() -{ - CWaitCursor wc; - - UpdateData(); - - UpdateInterface( m_nOptions ); - - CString sFilename; - m_wnd3File.GetWindowText( sFilename ); - ShellExecute( GetSafeHwnd(), NULL, sFilename, NULL, NULL, SW_NORMAL ); -} +/* + +Polang +Copyright (C) 2017 Nikolay Raspopov + +This program 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. + +This program 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 "Polang.h" +#include "PolangDlg.h" +#include "Translation.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +#define SETTINGS _T("Settings") +#define VAL_OPTIONS _T("Options") +#define VAL_ENGLISH _T("EnglishPath") +#define VAL_LANG _T("LangPath") +#define VAL_PO _T("PoPath") +#define VAL_POT _T("PotPath") +#define VAL_WINDOW _T("Window") + +// CPolangDlg dialog + +CPolangDlg::CPolangDlg(CWnd* pParent /*=NULL*/) + : CDialogEx ( IDD_POLANG_DIALOG, pParent ) + , m_hIcon ( theApp.LoadIcon( IDR_MAINFRAME ) ) + , m_nOptions ( theApp.GetProfileInt( SETTINGS, VAL_OPTIONS, OPT_POT ) ) + , m_nOptionsLast ( OPT_NULL ) +{ +} + +void CPolangDlg::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange( pDX ); + + DDX_Control( pDX, IDC_1_FILE, m_wnd1File ); + DDX_Control( pDX, IDC_2_FILE, m_wnd2File ); + DDX_Control( pDX, IDC_3_FILE, m_wnd3File ); + + DDX_Control( pDX, IDC_1_TITLE, m_wnd1Title ); + DDX_Control( pDX, IDC_2_TITLE, m_wnd2Title ); + DDX_Control( pDX, IDC_3_TITLE, m_wnd3Title ); + + DDX_Control( pDX, IDC_1_OPEN, m_wnd1Open ); + DDX_Control( pDX, IDC_2_OPEN, m_wnd2Open ); + DDX_Control( pDX, IDC_3_OPEN, m_wnd3Open ); + + DDX_Radio( pDX, IDC_RADIO1, m_nOptions ); +} + +void CPolangDlg::UpdateInterface(int nOptions) +{ + CString s1Filename, s2Filename, s3Filename; + m_wnd1File.GetWindowText( s1Filename ); + m_wnd2File.GetWindowText( s2Filename ); + m_wnd3File.GetWindowText( s3Filename ); + + // Save previous + CString str; + switch ( m_nOptionsLast ) + { + case OPT_NULL: + break; + + case OPT_POT: + theApp.WriteProfileString( SETTINGS, VAL_ENGLISH, s1Filename ); + theApp.WriteProfileString( SETTINGS, VAL_POT, s2Filename ); + break; + + case OPT_PO: + theApp.WriteProfileString( SETTINGS, VAL_ENGLISH, s1Filename ); + theApp.WriteProfileString( SETTINGS, VAL_LANG, s2Filename ); + theApp.WriteProfileString( SETTINGS, VAL_PO, s3Filename ); + break; + + case OPT_LANG: + theApp.WriteProfileString( SETTINGS, VAL_PO, s1Filename ); + theApp.WriteProfileString( SETTINGS, VAL_LANG, s2Filename ); + break; + } + + switch ( nOptions ) + { + case OPT_NULL: + break; + + case OPT_POT: + // Input + m_wnd1Title.SetWindowText( LoadString( IDS_ENGLISH_TITLE ) ); + m_wnd1File.EnableFileBrowseButton( _T("lang"), LoadString( IDS_LANG_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST ); + s1Filename = theApp.GetProfileString( SETTINGS, VAL_ENGLISH ); + m_wnd1File.SetWindowText( s1Filename ); + m_wnd1File.SetCueBanner( _T("en_US.lang") ); + // Output + m_wnd2Title.SetWindowText( LoadString( IDS_POT_TITLE ) ); + m_wnd2File.EnableFileBrowseButton( _T("pot"), LoadString( IDS_POEDIT_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT ); + s2Filename = theApp.GetProfileString( SETTINGS, VAL_POT ); + if ( s2Filename.IsEmpty() && ! s1Filename.IsEmpty() ) + s2Filename = s1Filename.Left( (int)( PathFindExtension( (LPCTSTR)s1Filename ) - (LPCTSTR)s1Filename ) + 1 ) + _T("pot"); + m_wnd2File.SetWindowText( s2Filename ); + m_wnd2File.SetCueBanner( _T("en_US.pot") ); + // Disabled + m_wnd3Title.SetWindowText( _T("") ); + m_wnd3File.EnableWindow( FALSE ); + m_wnd3File.SetWindowText( _T("") ); + m_wnd3File.SetCueBanner( _T("") ); + m_wnd3Open.EnableWindow( FALSE ); + break; + + case OPT_PO: + // Input + m_wnd1Title.SetWindowText( LoadString( IDS_ENGLISH_TITLE ) ); + m_wnd1File.EnableFileBrowseButton( _T("lang"), LoadString( IDS_LANG_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST ); + s1Filename = theApp.GetProfileString( SETTINGS, VAL_ENGLISH ); + m_wnd1File.SetWindowText( s1Filename ); + m_wnd1File.SetCueBanner( _T("en_US.lang") ); + // Input + m_wnd2Title.SetWindowText( LoadString( IDS_LANG_TITLE ) ); + m_wnd2File.EnableFileBrowseButton( _T("lang"), LoadString( IDS_LANG_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST ); + s2Filename = theApp.GetProfileString( SETTINGS, VAL_LANG ); + m_wnd2File.SetWindowText( s2Filename ); + m_wnd2File.SetCueBanner( _T("ru_RU.lang") ); + // Output + m_wnd3Title.SetWindowText( LoadString( IDS_PO_TITLE ) ); + m_wnd3File.EnableWindow(); + m_wnd3File.EnableFileBrowseButton( _T("po"), LoadString( IDS_POEDIT_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT ); + s3Filename = theApp.GetProfileString( SETTINGS, VAL_PO ); + if ( s3Filename.IsEmpty() && ! s2Filename.IsEmpty() ) + s3Filename = s2Filename.Left( (int)( PathFindExtension( (LPCTSTR)s2Filename ) - (LPCTSTR)s2Filename ) + 1 ) + _T("po"); + m_wnd3File.SetWindowText( s3Filename ); + m_wnd3File.SetCueBanner( _T("ru_RU.po") ); + m_wnd3Open.EnableWindow(); + break; + + case OPT_LANG: + // Input + m_wnd1Title.SetWindowText( LoadString( IDS_PO_TITLE ) ); + m_wnd1File.EnableFileBrowseButton( _T("po"), LoadString( IDS_POEDIT_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST ); + s1Filename = theApp.GetProfileString( SETTINGS, VAL_PO ); + m_wnd1File.SetWindowText( s1Filename ); + m_wnd1File.SetCueBanner( _T("ru_RU.po") ); + // Output + m_wnd2Title.SetWindowText( LoadString( IDS_LANG_TITLE ) ); + m_wnd2File.EnableFileBrowseButton( _T("lang"), LoadString( IDS_LANG_FILES ), OFN_EXPLORER | OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT ); + s2Filename = theApp.GetProfileString( SETTINGS, VAL_LANG ); + if ( s2Filename.IsEmpty() && ! s1Filename.IsEmpty() ) + s2Filename = s1Filename.Left( (int)( PathFindExtension( (LPCTSTR)s1Filename ) - (LPCTSTR)s1Filename ) + 1 ) + _T("lang"); + m_wnd2File.SetWindowText( s2Filename ); + m_wnd2File.SetCueBanner( _T("ru_RU.lang") ); + // Disabled + m_wnd3Title.SetWindowText( _T("") ); + m_wnd3File.EnableWindow( FALSE ); + m_wnd3File.SetWindowText( _T("") ); + m_wnd3File.SetCueBanner( _T("") ); + m_wnd3Open.EnableWindow( FALSE ); + break; + } + + if ( nOptions != OPT_NULL ) + { + theApp.WriteProfileInt( SETTINGS, VAL_OPTIONS, nOptions ); + } + + m_nOptionsLast = nOptions; +} + +BEGIN_MESSAGE_MAP(CPolangDlg, CDialogEx) + ON_WM_PAINT() + ON_WM_GETMINMAXINFO() + ON_WM_QUERYDRAGICON() + ON_BN_CLICKED( IDC_RADIO1, &CPolangDlg::OnBnClickedRadio ) + ON_BN_CLICKED( IDC_RADIO2, &CPolangDlg::OnBnClickedRadio ) + ON_BN_CLICKED( IDC_RADIO3, &CPolangDlg::OnBnClickedRadio ) + ON_WM_DESTROY() + ON_BN_CLICKED( IDC_1_OPEN, &CPolangDlg::OnBnClicked1Open ) + ON_BN_CLICKED( IDC_2_OPEN, &CPolangDlg::OnBnClicked2Open ) + ON_BN_CLICKED( IDC_3_OPEN, &CPolangDlg::OnBnClicked3Open ) +END_MESSAGE_MAP() + +// CPolangDlg message handlers + +BOOL CPolangDlg::OnInitDialog() +{ + __super::OnInitDialog(); + + GetWindowRect( m_rcInitial ); + + SetIcon( m_hIcon, TRUE ); // Set big icon + SetIcon( m_hIcon, FALSE ); // Set small icon + + UpdateInterface( m_nOptions ); + + CAutoVectorPtr< WINDOWPLACEMENT> pl; + UINT len = 0; + theApp.GetProfileBinary( SETTINGS, VAL_WINDOW, (LPBYTE*)&pl, &len ); + if ( len == sizeof( WINDOWPLACEMENT ) ) + { + SetWindowPlacement( pl ); + } + + return TRUE; // return TRUE unless you set the focus to a control +} + +// 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 CPolangDlg::OnPaint() +{ + if ( IsIconic() ) + { + CPaintDC dc( this ); // device context for painting + + SendMessage( WM_ICONERASEBKGND, reinterpret_cast< WPARAM >( dc.GetSafeHdc() ), 0 ); + + // Center icon in client rectangle + CRect rect; + GetClientRect(&rect); + int x = ( rect.Width() - GetSystemMetrics( SM_CXICON ) + 1 ) / 2; + int y = ( rect.Height() - GetSystemMetrics( SM_CYICON ) + 1 ) / 2; + + // Draw the icon + dc.DrawIcon( x, y, m_hIcon ); + } + else + __super::OnPaint(); +} + +void CPolangDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI) +{ + __super::OnGetMinMaxInfo( lpMMI ); + + lpMMI->ptMinTrackSize.x = m_rcInitial.Width(); + lpMMI->ptMinTrackSize.y = m_rcInitial.Height(); +} + +HCURSOR CPolangDlg::OnQueryDragIcon() +{ + return static_cast< HCURSOR >( m_hIcon ); +} + +void CPolangDlg::OnOK() +{ + CWaitCursor wc; + + UpdateData(); + + CString s1Filename, s2Filename, s3Filename; + m_wnd1File.GetWindowText( s1Filename ); + m_wnd2File.GetWindowText( s2Filename ); + m_wnd3File.GetWindowText( s3Filename ); + + CTranslation translations; + switch ( m_nOptions ) + { + case OPT_POT: + // en_US.lang + en_US.pot + if ( s1Filename.IsEmpty() || s2Filename.IsEmpty() || GetFileAttributes( s1Filename ) == INVALID_FILE_ATTRIBUTES ) + { + AfxMessageBox( IDS_MSG_NO_FILE, MB_OK | MB_ICONEXCLAMATION ); + return; + } + + if ( ! translations.LoadLang( s1Filename ) ) + { + AfxMessageBox( IDS_MSG_ENGLISH_ERROR, MB_OK | MB_ICONEXCLAMATION ); + return; + } + + if ( ! translations.SavePo( s2Filename ) ) + { + AfxMessageBox( IDS_MSG_PO_SAVE_ERROR, MB_OK | MB_ICONEXCLAMATION ); + return; + } + + if ( AfxMessageBox( IDS_MSG_PO_SAVE_OK, MB_YESNO | MB_ICONQUESTION ) == IDYES ) + { + ShellExecute( GetSafeHwnd(), nullptr, s2Filename, nullptr, nullptr, SW_NORMAL ); + } + break; + + case OPT_PO: + // en_US.lang + Local.lang -> Local.po + if ( s1Filename.IsEmpty() || s3Filename.IsEmpty() || GetFileAttributes( s1Filename ) == INVALID_FILE_ATTRIBUTES ) + { + AfxMessageBox( IDS_MSG_NO_FILE, MB_OK | MB_ICONEXCLAMATION ); + return; + } + + if ( ! translations.LoadLang( s1Filename ) ) + { + AfxMessageBox( IDS_MSG_ENGLISH_ERROR, MB_OK | MB_ICONEXCLAMATION ); + return; + } + + if ( ! s2Filename.IsEmpty() ) + { + if ( ! translations.LoadLang( s2Filename, true ) ) + { + AfxMessageBox( IDS_MSG_LANG_ERROR, MB_OK | MB_ICONEXCLAMATION ); + return; + } + } + + if ( ! translations.SavePo( s3Filename ) ) + { + AfxMessageBox( IDS_MSG_PO_SAVE_ERROR, MB_OK | MB_ICONEXCLAMATION ); + return; + } + + if ( AfxMessageBox( IDS_MSG_PO_SAVE_OK, MB_YESNO | MB_ICONQUESTION ) == IDYES ) + { + ShellExecute( GetSafeHwnd(), nullptr, s3Filename, nullptr, nullptr, SW_NORMAL ); + } + break; + + case OPT_LANG: + // Local.po -> Local.lang + if ( s1Filename.IsEmpty() || s2Filename.IsEmpty() || GetFileAttributes( s1Filename ) == INVALID_FILE_ATTRIBUTES ) + { + AfxMessageBox( IDS_MSG_NO_FILE, MB_OK | MB_ICONEXCLAMATION ); + return; + } + + if ( ! translations.LoadPo( s1Filename ) ) + { + AfxMessageBox( IDS_MSG_PO_LOAD_ERROR, MB_OK | MB_ICONEXCLAMATION ); + return; + } + + if ( ! translations.SaveLang( s2Filename ) ) + { + AfxMessageBox( IDS_MSG_LANG_SAVE_ERROR, MB_OK | MB_ICONEXCLAMATION ); + return; + } + + if ( AfxMessageBox( IDS_MSG_LANG_SAVE_OK, MB_YESNO | MB_ICONQUESTION ) == IDYES ) + { + ShellExecute( GetSafeHwnd(), nullptr, s2Filename, nullptr, nullptr, SW_NORMAL ); + } + break; + } +} + +void CPolangDlg::OnBnClickedRadio() +{ + UpdateData(); + + UpdateInterface( m_nOptions ); +} + +void CPolangDlg::OnDestroy() +{ + UpdateInterface( OPT_NULL ); + + WINDOWPLACEMENT pl = { sizeof( WINDOWPLACEMENT ) }; + GetWindowPlacement( &pl ); + theApp.WriteProfileBinary( SETTINGS, VAL_WINDOW, (LPBYTE)&pl, sizeof( WINDOWPLACEMENT ) ); + + __super::OnDestroy(); +} + +void CPolangDlg::OnBnClicked1Open() +{ + CWaitCursor wc; + + UpdateData(); + + UpdateInterface( m_nOptions ); + + CString sFilename; + m_wnd1File.GetWindowText( sFilename ); + ShellExecute( GetSafeHwnd(), nullptr, sFilename, nullptr, nullptr, SW_NORMAL ); +} + +void CPolangDlg::OnBnClicked2Open() +{ + CWaitCursor wc; + + UpdateData(); + + UpdateInterface( m_nOptions ); + + CString sFilename; + m_wnd2File.GetWindowText( sFilename ); + ShellExecute( GetSafeHwnd(), nullptr, sFilename, nullptr, nullptr, SW_NORMAL ); +} + +void CPolangDlg::OnBnClicked3Open() +{ + CWaitCursor wc; + + UpdateData(); + + UpdateInterface( m_nOptions ); + + CString sFilename; + m_wnd3File.GetWindowText( sFilename ); + ShellExecute( GetSafeHwnd(), nullptr, sFilename, nullptr, nullptr, SW_NORMAL ); +} diff --git a/PolangDlg.h b/PolangDlg.h index 5916513..f4e7b26 100644 --- a/PolangDlg.h +++ b/PolangDlg.h @@ -1,70 +1,70 @@ -/* - -Polang -Copyright (C) 2017 Nikolay Raspopov - -This program 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. - -This program 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 . - -*/ - -#pragma once - -#include "BrowseCtrl.h" - - -// CPolangDlg dialog - -class CPolangDlg : public CDialogEx -{ -public: - CPolangDlg(CWnd* pParent = NULL); // standard constructor - -// Dialog Data -#ifdef AFX_DESIGN_TIME - enum { IDD = IDD_POLANG_DIALOG }; -#endif - -protected: - enum { OPT_NULL = -1, OPT_POT = 0, OPT_PO = 1, OPT_LANG = 2 }; - - HICON m_hIcon; - CBrowseCtrl m_wnd1File; - CBrowseCtrl m_wnd2File; - CBrowseCtrl m_wnd3File; - CStatic m_wnd1Title; - CStatic m_wnd2Title; - CStatic m_wnd3Title; - CButton m_wnd1Open; - CButton m_wnd2Open; - CButton m_wnd3Open; - int m_nOptions, m_nOptionsLast; - CRect m_rcInitial; - - void UpdateInterface(int nOptions); - - virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support - virtual BOOL OnInitDialog(); - virtual void OnOK(); - - afx_msg void OnPaint(); - afx_msg HCURSOR OnQueryDragIcon(); - afx_msg void OnBnClickedRadio(); - afx_msg void OnDestroy(); - afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI); - afx_msg void OnBnClicked1Open(); - afx_msg void OnBnClicked2Open(); - afx_msg void OnBnClicked3Open(); - - DECLARE_MESSAGE_MAP() -}; +/* + +Polang +Copyright (C) 2017 Nikolay Raspopov + +This program 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. + +This program 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 . + +*/ + +#pragma once + +#include "BrowseCtrl.h" + + +// CPolangDlg dialog + +class CPolangDlg : public CDialogEx +{ +public: + CPolangDlg(CWnd* pParent = nullptr); // standard constructor + +// Dialog Data +#ifdef AFX_DESIGN_TIME + enum { IDD = IDD_POLANG_DIALOG }; +#endif + +protected: + enum { OPT_NULL = -1, OPT_POT = 0, OPT_PO = 1, OPT_LANG = 2 }; + + HICON m_hIcon; + CBrowseCtrl m_wnd1File; + CBrowseCtrl m_wnd2File; + CBrowseCtrl m_wnd3File; + CStatic m_wnd1Title; + CStatic m_wnd2Title; + CStatic m_wnd3Title; + CButton m_wnd1Open; + CButton m_wnd2Open; + CButton m_wnd3Open; + int m_nOptions, m_nOptionsLast; + CRect m_rcInitial; + + void UpdateInterface(int nOptions); + + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + virtual BOOL OnInitDialog(); + virtual void OnOK(); + + afx_msg void OnPaint(); + afx_msg HCURSOR OnQueryDragIcon(); + afx_msg void OnBnClickedRadio(); + afx_msg void OnDestroy(); + afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI); + afx_msg void OnBnClicked1Open(); + afx_msg void OnBnClicked2Open(); + afx_msg void OnBnClicked3Open(); + + DECLARE_MESSAGE_MAP() +}; diff --git a/Translation.cpp b/Translation.cpp index f2052a1..784ac9e 100644 --- a/Translation.cpp +++ b/Translation.cpp @@ -1,462 +1,462 @@ -/* - -Polang -Copyright (C) 2017 Nikolay Raspopov - -This program 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. - -This program 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 "Translation.h" - -void CTranslation::SetAt(const CStringList& lIds, const CString& sMsgid) -{ - for ( POSITION pos = lIds.GetHeadPosition(); pos; ) - { - SetAt( lIds.GetNext( pos ), sMsgid ); - } -} - -void CTranslation::SetAt(const CString& sId, const CString& sMsgid) -{ - CTrans trans; - if ( m_MsgidToTrans.Lookup( sMsgid, trans ) ) - { - // Add new ID to existing Msgid - if ( ! trans.m_sId.Find( sId ) ) - { - trans.m_sId.AddTail( sId ); - m_MsgidToTrans.SetAt( sMsgid, trans ); - } - else - TRACE( "Duplicate id: %s\n", (LPCSTR)CT2A( sId ) ); - } - else - { - // Add new MsgId - m_MsgidToTrans.SetAt( sMsgid, CTrans( sId ) ); - } - m_IdToMsgid.SetAt( sId, sMsgid ); -} - -void CTranslation::Add(const CString& sId, const CString& sMsgstr) -{ - CString sMsgid; - if ( m_IdToMsgid.Lookup( sId, sMsgid ) ) - { - CTrans trans; - if ( m_MsgidToTrans.Lookup( sMsgid, trans ) ) - { - trans.m_sMsgstr = sMsgstr; - m_MsgidToTrans.SetAt( sMsgid, trans ); - } - } -} - -void CTranslation::Add(const CStringList& lIds, const CString& sMsgstr) -{ - for ( POSITION pos = lIds.GetHeadPosition(); pos; ) - { - Add( lIds.GetNext( pos ), sMsgstr ); - } -} - -CStringA CTranslation::UTF8Encode(__in_bcount(nInput) LPCWSTR psInput, __in int nInput) -{ - CStringA strUTF8; - int nUTF8 = ::WideCharToMultiByte( CP_UTF8, 0, psInput, nInput, strUTF8.GetBuffer( nInput * 4 + 1 ), nInput * 4 + 1, NULL, NULL ); - if ( nUTF8 == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER ) - { - nUTF8 = ::WideCharToMultiByte( CP_UTF8, 0, psInput, nInput, NULL, 0, NULL, NULL ); - nUTF8 = ::WideCharToMultiByte( CP_UTF8, 0, psInput, nInput, strUTF8.GetBuffer( nUTF8 ), nUTF8, NULL, NULL ); - } - strUTF8.ReleaseBuffer( nUTF8 ); - return strUTF8; -} - -CStringA CTranslation::UTF8Encode(__in const CStringW& strInput) -{ - return UTF8Encode( strInput, strInput.GetLength() ); -} - -CString CTranslation::Escape(__in CString str) -{ - str.Replace( _T("\""), _T("\\\"") ); - str.Replace( _T("\t"), _T("\\t") ); - str.Replace( _T("\n"), _T("\\n") ); - str.Remove( _T('\r') ); - return str; -} - -CString CTranslation::Decode(__in CString str) -{ - CString tmp; - LPTSTR dst = tmp.GetBuffer( str.GetLength() + 1 ); - for ( LPCTSTR src = str; *src; src++ ) - { - if ( *src == _T('\\') ) - { - switch ( *(src + 1) ) - { - case _T('\\'): - *dst++ = _T('\\'); - src++; - break; - - case _T('r'): - *dst++ = _T('\r'); - src++; - break; - - case _T('n'): - *dst++ = _T('\n'); - src++; - break; - - case _T('t'): - *dst++ = _T('\t'); - src++; - break; - - case _T('\"'): - *dst++ = _T('\"'); - src++; - break; - - default: - *dst++ = *src; - } - } - else - *dst++ = *src; - } - *dst = 0; - tmp.ReleaseBuffer(); - return tmp; -} - -bool CTranslation::LoadPoFromString(const CString& sContent) -{ - bool bRet = true; - - CStringList lRef; // #: - CString sString, sOriginalLine; - enum - { - mode_start, mode_ref, mode_msgid, mode_msgstr - } - mode = mode_start; - - int nLine = 1; - for ( int curPos = 0; bRet; ++nLine ) - { - CString sLine = sContent.Tokenize( _T("\n"), curPos ); - if ( sLine.IsEmpty() ) - break; - - sOriginalLine = sLine; - sLine.Trim(); - - switch ( sLine[ 0 ] ) - { - case _T('#'): - if ( mode != mode_ref && mode != mode_start && mode != mode_msgstr ) - { - TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); - bRet = false; - break; - } - if ( sLine[ 1 ] == ':' ) - { - // Ref - switch ( mode ) - { - case mode_msgstr: - // Save previous string - if ( ! lRef.IsEmpty() && ! sString.IsEmpty() ) - Add( lRef, Decode( sString ) ); - sString.Empty(); - lRef.RemoveAll(); - mode = mode_ref; - break; - - case mode_ref: - for ( int nRefPos = 0; ; ) - { - const CString sRef = sString.Tokenize( _T( " " ), nRefPos ); - if ( sRef.IsEmpty() ) - break; - lRef.AddTail( sRef ); - } - sString.Empty(); - break; - } - - if ( ! sString.IsEmpty() ) - sString += " "; - sString += sLine.Mid( 2 ).Trim(); - } - // else Comments - break; - - case _T('M'): - case _T('m'): - if ( ( mode == mode_start || mode == mode_ref ) && _tcsncicmp( sLine, _T("msgid \""), 7 ) == 0 ) - { - // ID - for ( int nRefPos = 0; ; ) - { - const CString sRef = sString.Tokenize( _T( " " ), nRefPos ); - if ( sRef.IsEmpty() ) - break; - lRef.AddTail( sRef ); - } - sString.Empty(); - - sLine = sLine.Mid( 6, sLine.GetLength() - 6 ); - mode = mode_msgid; - } - else if ( mode == mode_msgid && _tcsncicmp( sLine, _T("msgstr \""), 8 ) == 0 ) - { - // Translation - if ( ! lRef.IsEmpty() && ! sString.IsEmpty() ) - SetAt( lRef, Decode( sString ) ); - - sString.Empty(); - - sLine = sLine.Mid( 7, sLine.GetLength() - 7 ); - mode = mode_msgstr; - } - else - { - // Unknown string - TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); - bRet = false; - break; - } - - case _T('\"'): - if ( mode != mode_msgid && mode != mode_msgstr ) - { - TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); - bRet = false; - break; - } - if ( sLine[ sLine.GetLength() - 1 ] == _T('\"') ) - { - // String continue - sString += sLine.Mid( 1, sLine.GetLength() - 2 ); - } - else - { - // Unknown string - TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); - bRet = false; - break; - } - break; - - default: - // Empty or unknown lines - ; - } - } // while - - if ( bRet && mode != mode_msgstr ) - { - // Unknown string - TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); - bRet = false; - } - - if ( bRet ) - { - // Save last string - if ( ! lRef.IsEmpty() && ! sString.IsEmpty() ) - Add( lRef, Decode( sString ) ); - } - - return bRet; -} - -bool CTranslation::LoadPo(const CString& sFilename) -{ - bool bResult = false; - - // Open input file - FILE* fileIn = NULL; - if ( _tfopen_s( &fileIn, _T("\\\\?\\") + sFilename, _T("rt,ccs=UTF-8") ) == 0 && fileIn ) - { - CString sFile; - - while( ! feof( fileIn ) ) - { - CString sLine; - if ( ! _fgetts( sLine.GetBuffer( 1024 ), 1024, fileIn ) ) - { - sLine.ReleaseBuffer( 0 ); - break; - } - sLine.ReleaseBuffer(); - - sFile.Append( sLine ); - } - - bResult = LoadPoFromString( sFile ); - - fclose( fileIn ); - } - - return bResult; -} - -bool CTranslation::LoadLang(const CString& sFilename, bool bMsgstr) -{ - bool bResult = false; - - // Open input file - FILE* fileIn = NULL; - if ( _tfopen_s( &fileIn, _T("\\\\?\\") + sFilename, _T("rt,ccs=UTF-8") ) == 0 && fileIn ) - { - while( ! feof( fileIn ) ) - { - CString sLine; - if ( ! _fgetts( sLine.GetBuffer( 1024 ), 1024, fileIn ) ) - { - sLine.ReleaseBuffer( 0 ); - break; - } - sLine.ReleaseBuffer(); - - sLine.TrimLeft(); - sLine.TrimRight( _T("\r\n") ); - - if ( sLine.IsEmpty() ) - // Skip empty line - continue; - - if ( sLine.GetAt( 0 ) == _T('#') ) - // Skip comments - continue; - - // "key=value" - const int nSplit = sLine.Find( _T('=') ); - if ( nSplit > 0 ) - { - const CString sId = sLine.Left( nSplit ).Trim(); - const CString sMsgid = sLine.Mid( nSplit + 1 ); - - if ( bMsgstr ) - Add( sId, sMsgid ); - else - SetAt( sId, sMsgid ); - - bResult = true; - } - } - - fclose( fileIn ); - } - - return bResult; -} - -bool CTranslation::SavePo(const CString& sFilename) const -{ - bool bResult = false; - - // Backup old output file - CopyFile( _T("\\\\?\\") + sFilename, _T("\\\\?\\") + sFilename + _T(".bak"), FALSE ); - - // Create output file - FILE* fileOut = NULL; - if ( _tfopen_s( &fileOut, _T("\\\\?\\") + sFilename, _T("wb") ) == 0 && fileOut ) - { - // Header - fputs( - "msgid \"\"\n" - "msgstr \"\"\n" - "\"Project-Id-Version: \\n\"\n" - "\"POT-Creation-Date: \\n\"\n" - "\"PO-Revision-Date: \\n\"\n" - "\"Last-Translator: \\n\"\n" - "\"Language-Team: \\n\"\n" - "\"MIME-Version: 1.0\\n\"\n" - "\"Content-Type: text/plain; charset=UTF-8\\n\"\n" - "\"Content-Transfer-Encoding: 8bit\\n\"\n" - "\"X-Poedit-SourceCharset: UTF-8\\n\"\n", fileOut ); - - for ( POSITION pos = GetHeadPosition(); pos; ) - { - CString sMsgid; - CTrans trans; - GetNext( pos, trans, sMsgid ); - - fputs( "\n#:" + UTF8Encode( trans.GetId() ) + "\n", fileOut ); - fputs( "msgid \"" + UTF8Encode( Escape( sMsgid ) ) + "\"\n", fileOut ); - fputs( "msgstr \"" + UTF8Encode( Escape( trans.m_sMsgstr ) ) + "\"\n", fileOut ); - } - - bResult = true; - - fclose( fileOut ); - } - - return bResult; -} - -bool CTranslation::SaveLang(const CString& sFilename) const -{ - bool bResult = false; - - // Sort output strings excluding empty ones - CRBMap < CString, int > out; - for ( POSITION posT = GetHeadPosition(); posT; ) - { - CString sMsgid; - CTrans trans; - GetNext( posT, trans, sMsgid ); - - for ( POSITION posI = trans.m_sId.GetHeadPosition(); posI; ) - { - const CString sId = trans.m_sId.GetNext( posI ); - if ( ! trans.m_sMsgstr.IsEmpty() ) - { - CString str = trans.m_sMsgstr; - str.Replace( _T("\n"), _T("\\n") ); - out.SetAt( sId + _T("=") + str, 0 ); - } - } - } - - // Backup old output file - CopyFile( _T("\\\\?\\") + sFilename, _T("\\\\?\\") + sFilename + _T(".bak"), FALSE ); - - // Create output file - FILE* fileOut = NULL; - if ( _tfopen_s( &fileOut, _T("\\\\?\\") + sFilename, _T("wb") ) == 0 && fileOut ) - { - for ( POSITION pos = out.GetHeadPosition(); pos; ) - { - fputs( UTF8Encode( out.GetNextKey( pos ) ) + "\n", fileOut ); - } - - bResult = true; - - fclose( fileOut ); - } - - return bResult; -} +/* + +Polang +Copyright (C) 2017 Nikolay Raspopov + +This program 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. + +This program 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 "Translation.h" + +void CTranslation::SetAt(const CStringList& lIds, const CString& sMsgid) +{ + for ( POSITION pos = lIds.GetHeadPosition(); pos; ) + { + SetAt( lIds.GetNext( pos ), sMsgid ); + } +} + +void CTranslation::SetAt(const CString& sId, const CString& sMsgid) +{ + CTrans trans; + if ( m_MsgidToTrans.Lookup( sMsgid, trans ) ) + { + // Add new ID to existing Msgid + if ( ! trans.m_sId.Find( sId ) ) + { + trans.m_sId.AddTail( sId ); + m_MsgidToTrans.SetAt( sMsgid, trans ); + } + else + TRACE( "Duplicate id: %s\n", (LPCSTR)CT2A( sId ) ); + } + else + { + // Add new MsgId + m_MsgidToTrans.SetAt( sMsgid, CTrans( sId ) ); + } + m_IdToMsgid.SetAt( sId, sMsgid ); +} + +void CTranslation::Add(const CString& sId, const CString& sMsgstr) +{ + CString sMsgid; + if ( m_IdToMsgid.Lookup( sId, sMsgid ) ) + { + CTrans trans; + if ( m_MsgidToTrans.Lookup( sMsgid, trans ) ) + { + trans.m_sMsgstr = sMsgstr; + m_MsgidToTrans.SetAt( sMsgid, trans ); + } + } +} + +void CTranslation::Add(const CStringList& lIds, const CString& sMsgstr) +{ + for ( POSITION pos = lIds.GetHeadPosition(); pos; ) + { + Add( lIds.GetNext( pos ), sMsgstr ); + } +} + +CStringA CTranslation::UTF8Encode(__in_bcount(nInput) LPCWSTR psInput, __in int nInput) +{ + CStringA strUTF8; + int nUTF8 = ::WideCharToMultiByte( CP_UTF8, 0, psInput, nInput, strUTF8.GetBuffer( nInput * 4 + 1 ), nInput * 4 + 1, nullptr, nullptr ); + if ( nUTF8 == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER ) + { + nUTF8 = ::WideCharToMultiByte( CP_UTF8, 0, psInput, nInput, nullptr, 0, nullptr, nullptr ); + nUTF8 = ::WideCharToMultiByte( CP_UTF8, 0, psInput, nInput, strUTF8.GetBuffer( nUTF8 ), nUTF8, nullptr, nullptr ); + } + strUTF8.ReleaseBuffer( nUTF8 ); + return strUTF8; +} + +CStringA CTranslation::UTF8Encode(__in const CStringW& strInput) +{ + return UTF8Encode( strInput, strInput.GetLength() ); +} + +CString CTranslation::Escape(__in CString str) +{ + str.Replace( _T("\""), _T("\\\"") ); + str.Replace( _T("\t"), _T("\\t") ); + str.Replace( _T("\n"), _T("\\n") ); + str.Remove( _T('\r') ); + return str; +} + +CString CTranslation::Decode(__in CString str) +{ + CString tmp; + LPTSTR dst = tmp.GetBuffer( str.GetLength() + 1 ); + for ( LPCTSTR src = str; *src; src++ ) + { + if ( *src == _T('\\') ) + { + switch ( *(src + 1) ) + { + case _T('\\'): + *dst++ = _T('\\'); + src++; + break; + + case _T('r'): + *dst++ = _T('\r'); + src++; + break; + + case _T('n'): + *dst++ = _T('\n'); + src++; + break; + + case _T('t'): + *dst++ = _T('\t'); + src++; + break; + + case _T('\"'): + *dst++ = _T('\"'); + src++; + break; + + default: + *dst++ = *src; + } + } + else + *dst++ = *src; + } + *dst = 0; + tmp.ReleaseBuffer(); + return tmp; +} + +bool CTranslation::LoadPoFromString(const CString& sContent) +{ + bool bRet = true; + + CStringList lRef; // #: + CString sString, sOriginalLine; + enum + { + mode_start, mode_ref, mode_msgid, mode_msgstr + } + mode = mode_start; + + int nLine = 1; + for ( int curPos = 0; bRet; ++nLine ) + { + CString sLine = sContent.Tokenize( _T("\n"), curPos ); + if ( sLine.IsEmpty() ) + break; + + sOriginalLine = sLine; + sLine.Trim(); + + switch ( sLine[ 0 ] ) + { + case _T('#'): + if ( mode != mode_ref && mode != mode_start && mode != mode_msgstr ) + { + TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); + bRet = false; + break; + } + if ( sLine[ 1 ] == ':' ) + { + // Ref + switch ( mode ) + { + case mode_msgstr: + // Save previous string + if ( ! lRef.IsEmpty() && ! sString.IsEmpty() ) + Add( lRef, Decode( sString ) ); + sString.Empty(); + lRef.RemoveAll(); + mode = mode_ref; + break; + + case mode_ref: + for ( int nRefPos = 0; ; ) + { + const CString sRef = sString.Tokenize( _T( " " ), nRefPos ); + if ( sRef.IsEmpty() ) + break; + lRef.AddTail( sRef ); + } + sString.Empty(); + break; + } + + if ( ! sString.IsEmpty() ) + sString += " "; + sString += sLine.Mid( 2 ).Trim(); + } + // else Comments + break; + + case _T('M'): + case _T('m'): + if ( ( mode == mode_start || mode == mode_ref ) && _tcsncicmp( sLine, _T("msgid \""), 7 ) == 0 ) + { + // ID + for ( int nRefPos = 0; ; ) + { + const CString sRef = sString.Tokenize( _T( " " ), nRefPos ); + if ( sRef.IsEmpty() ) + break; + lRef.AddTail( sRef ); + } + sString.Empty(); + + sLine = sLine.Mid( 6, sLine.GetLength() - 6 ); + mode = mode_msgid; + } + else if ( mode == mode_msgid && _tcsncicmp( sLine, _T("msgstr \""), 8 ) == 0 ) + { + // Translation + if ( ! lRef.IsEmpty() && ! sString.IsEmpty() ) + SetAt( lRef, Decode( sString ) ); + + sString.Empty(); + + sLine = sLine.Mid( 7, sLine.GetLength() - 7 ); + mode = mode_msgstr; + } + else + { + // Unknown string + TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); + bRet = false; + break; + } + + case _T('\"'): + if ( mode != mode_msgid && mode != mode_msgstr ) + { + TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); + bRet = false; + break; + } + if ( sLine[ sLine.GetLength() - 1 ] == _T('\"') ) + { + // String continue + sString += sLine.Mid( 1, sLine.GetLength() - 2 ); + } + else + { + // Unknown string + TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); + bRet = false; + break; + } + break; + + default: + // Empty or unknown lines + ; + } + } // while + + if ( bRet && mode != mode_msgstr ) + { + // Unknown string + TRACE( "Invalid .po-line #%d: %s\n", nLine, (LPCSTR)CT2A( sOriginalLine ) ); + bRet = false; + } + + if ( bRet ) + { + // Save last string + if ( ! lRef.IsEmpty() && ! sString.IsEmpty() ) + Add( lRef, Decode( sString ) ); + } + + return bRet; +} + +bool CTranslation::LoadPo(const CString& sFilename) +{ + bool bResult = false; + + // Open input file + FILE* fileIn = nullptr; + if ( _tfopen_s( &fileIn, _T("\\\\?\\") + sFilename, _T("rt,ccs=UTF-8") ) == 0 && fileIn ) + { + CString sFile; + + while( ! feof( fileIn ) ) + { + CString sLine; + if ( ! _fgetts( sLine.GetBuffer( 1024 ), 1024, fileIn ) ) + { + sLine.ReleaseBuffer( 0 ); + break; + } + sLine.ReleaseBuffer(); + + sFile.Append( sLine ); + } + + bResult = LoadPoFromString( sFile ); + + fclose( fileIn ); + } + + return bResult; +} + +bool CTranslation::LoadLang(const CString& sFilename, bool bMsgstr) +{ + bool bResult = false; + + // Open input file + FILE* fileIn = nullptr; + if ( _tfopen_s( &fileIn, _T("\\\\?\\") + sFilename, _T("rt,ccs=UTF-8") ) == 0 && fileIn ) + { + while( ! feof( fileIn ) ) + { + CString sLine; + if ( ! _fgetts( sLine.GetBuffer( 1024 ), 1024, fileIn ) ) + { + sLine.ReleaseBuffer( 0 ); + break; + } + sLine.ReleaseBuffer(); + + sLine.TrimLeft(); + sLine.TrimRight( _T("\r\n") ); + + if ( sLine.IsEmpty() ) + // Skip empty line + continue; + + if ( sLine.GetAt( 0 ) == _T('#') ) + // Skip comments + continue; + + // "key=value" + const int nSplit = sLine.Find( _T('=') ); + if ( nSplit > 0 ) + { + const CString sId = sLine.Left( nSplit ).Trim(); + const CString sMsgid = sLine.Mid( nSplit + 1 ); + + if ( bMsgstr ) + Add( sId, sMsgid ); + else + SetAt( sId, sMsgid ); + + bResult = true; + } + } + + fclose( fileIn ); + } + + return bResult; +} + +bool CTranslation::SavePo(const CString& sFilename) const +{ + bool bResult = false; + + // Backup old output file + CopyFile( _T("\\\\?\\") + sFilename, _T("\\\\?\\") + sFilename + _T(".bak"), FALSE ); + + // Create output file + FILE* fileOut = nullptr; + if ( _tfopen_s( &fileOut, _T("\\\\?\\") + sFilename, _T("wb") ) == 0 && fileOut ) + { + // Header + fputs( + "msgid \"\"\n" + "msgstr \"\"\n" + "\"Project-Id-Version: \\n\"\n" + "\"POT-Creation-Date: \\n\"\n" + "\"PO-Revision-Date: \\n\"\n" + "\"Last-Translator: \\n\"\n" + "\"Language-Team: \\n\"\n" + "\"MIME-Version: 1.0\\n\"\n" + "\"Content-Type: text/plain; charset=UTF-8\\n\"\n" + "\"Content-Transfer-Encoding: 8bit\\n\"\n" + "\"X-Poedit-SourceCharset: UTF-8\\n\"\n", fileOut ); + + for ( POSITION pos = GetHeadPosition(); pos; ) + { + CString sMsgid; + CTrans trans; + GetNext( pos, trans, sMsgid ); + + fputs( "\n#:" + UTF8Encode( trans.GetId() ) + "\n", fileOut ); + fputs( "msgid \"" + UTF8Encode( Escape( sMsgid ) ) + "\"\n", fileOut ); + fputs( "msgstr \"" + UTF8Encode( Escape( trans.m_sMsgstr ) ) + "\"\n", fileOut ); + } + + bResult = true; + + fclose( fileOut ); + } + + return bResult; +} + +bool CTranslation::SaveLang(const CString& sFilename) const +{ + bool bResult = false; + + // Sort output strings excluding empty ones + CRBMap < CString, int > out; + for ( POSITION posT = GetHeadPosition(); posT; ) + { + CString sMsgid; + CTrans trans; + GetNext( posT, trans, sMsgid ); + + for ( POSITION posI = trans.m_sId.GetHeadPosition(); posI; ) + { + const CString sId = trans.m_sId.GetNext( posI ); + if ( ! trans.m_sMsgstr.IsEmpty() ) + { + CString str = trans.m_sMsgstr; + str.Replace( _T("\n"), _T("\\n") ); + out.SetAt( sId + _T("=") + str, 0 ); + } + } + } + + // Backup old output file + CopyFile( _T("\\\\?\\") + sFilename, _T("\\\\?\\") + sFilename + _T(".bak"), FALSE ); + + // Create output file + FILE* fileOut = nullptr; + if ( _tfopen_s( &fileOut, _T("\\\\?\\") + sFilename, _T("wb") ) == 0 && fileOut ) + { + for ( POSITION pos = out.GetHeadPosition(); pos; ) + { + fputs( UTF8Encode( out.GetNextKey( pos ) ) + "\n", fileOut ); + } + + bResult = true; + + fclose( fileOut ); + } + + return bResult; +} diff --git a/Translation.h b/Translation.h index 24a6d05..b6e887f 100644 --- a/Translation.h +++ b/Translation.h @@ -1,107 +1,107 @@ -/* - -Polang -Copyright (C) 2017 Nikolay Raspopov - -This program 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. - -This program 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 . - -*/ - -#pragma once - - -class CTrans -{ -public: - inline CTrans() {} - - inline CTrans(const CString& sId) - { - m_sId.AddTail( sId ); - } - - inline CTrans(const CTrans& it) - { - for ( POSITION pos = it.m_sId.GetHeadPosition(); pos; ) - { - m_sId.AddTail( it.m_sId.GetNext( pos ) ); - } - m_sMsgstr = it.m_sMsgstr; - } - - inline CTrans& operator=(const CTrans& it) - { - m_sId.RemoveAll(); - for ( POSITION pos = it.m_sId.GetHeadPosition(); pos; ) - { - m_sId.AddTail( it.m_sId.GetNext( pos ) ); - } - m_sMsgstr = it.m_sMsgstr; - return *this; - } - - inline CString GetId() const - { - CString sId; - for ( POSITION pos = m_sId.GetHeadPosition(); pos; ) - { - sId += _T(" ") + m_sId.GetNext( pos ); - } - return sId; - } - - CStringList m_sId; - CString m_sMsgstr; -}; - - -class CTranslation -{ -public: - inline CTranslation() {} - - inline POSITION GetHeadPosition() const - { - return m_MsgidToTrans.GetHeadPosition(); - } - - inline void GetNext(POSITION& pos, CTrans& trans, CString& sMsgid) const - { - m_MsgidToTrans.GetNextAssoc( pos, sMsgid, trans ); - } - - // Add English - void SetAt(const CString& sId, const CString& sMsgid); - void SetAt(const CStringList& lIds, const CString& sMsgid); - - // Add localization - void Add(const CString& sId, const CString& sMsgstr); - void Add(const CStringList& lIds, const CString& sMsgstr); - - bool LoadPo(const CString& sFilename); - bool LoadLang(const CString& sFilename, bool bMsgstr = false); - bool SavePo(const CString& sFilename) const; - bool SaveLang(const CString& sFilename) const; - -private: - CRBMap < CString, CTrans > m_MsgidToTrans; - CRBMap < CString, CString > m_IdToMsgid; - - bool LoadPoFromString(const CString& sContent); - - static CStringA UTF8Encode(__in_bcount(nInput) LPCWSTR psInput, __in int nInput); - static CStringA UTF8Encode(__in const CStringW& strInput); - static CString Decode(__in CString str); - static CString Escape(__in CString str); -}; +/* + +Polang +Copyright (C) 2017 Nikolay Raspopov + +This program 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. + +This program 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 . + +*/ + +#pragma once + + +class CTrans +{ +public: + inline CTrans() = default; + + inline CTrans(const CString& sId) + { + m_sId.AddTail( sId ); + } + + inline CTrans(const CTrans& it) + { + for ( POSITION pos = it.m_sId.GetHeadPosition(); pos; ) + { + m_sId.AddTail( it.m_sId.GetNext( pos ) ); + } + m_sMsgstr = it.m_sMsgstr; + } + + inline CTrans& operator=(const CTrans& it) + { + m_sId.RemoveAll(); + for ( POSITION pos = it.m_sId.GetHeadPosition(); pos; ) + { + m_sId.AddTail( it.m_sId.GetNext( pos ) ); + } + m_sMsgstr = it.m_sMsgstr; + return *this; + } + + inline CString GetId() const + { + CString sId; + for ( POSITION pos = m_sId.GetHeadPosition(); pos; ) + { + sId += _T(" ") + m_sId.GetNext( pos ); + } + return sId; + } + + CStringList m_sId; + CString m_sMsgstr; +}; + + +class CTranslation +{ +public: + inline CTranslation() = default; + + inline POSITION GetHeadPosition() const + { + return m_MsgidToTrans.GetHeadPosition(); + } + + inline void GetNext(POSITION& pos, CTrans& trans, CString& sMsgid) const + { + m_MsgidToTrans.GetNextAssoc( pos, sMsgid, trans ); + } + + // Add English + void SetAt(const CString& sId, const CString& sMsgid); + void SetAt(const CStringList& lIds, const CString& sMsgid); + + // Add localization + void Add(const CString& sId, const CString& sMsgstr); + void Add(const CStringList& lIds, const CString& sMsgstr); + + bool LoadPo(const CString& sFilename); + bool LoadLang(const CString& sFilename, bool bMsgstr = false); + bool SavePo(const CString& sFilename) const; + bool SaveLang(const CString& sFilename) const; + +private: + CRBMap < CString, CTrans > m_MsgidToTrans; + CRBMap < CString, CString > m_IdToMsgid; + + bool LoadPoFromString(const CString& sContent); + + static CStringA UTF8Encode(__in_bcount(nInput) LPCWSTR psInput, __in int nInput); + static CStringA UTF8Encode(__in const CStringW& strInput); + static CString Decode(__in CString str); + static CString Escape(__in CString str); +};