Index: src/libictranslate/ResourceManager.cpp =================================================================== diff -u -N -r945fdda3ea66a8ce8a09ee9307b04c3d79d518b3 -r8443d0d98d380facaf07b540c8d98da08365b816 --- src/libictranslate/ResourceManager.cpp (.../ResourceManager.cpp) (revision 945fdda3ea66a8ce8a09ee9307b04c3d79d518b3) +++ src/libictranslate/ResourceManager.cpp (.../ResourceManager.cpp) (revision 8443d0d98d380facaf07b540c8d98da08365b816) @@ -1,1076 +1,1076 @@ -/*************************************************************************** -* Copyright (C) 2001-2008 by J�zef Starosczyk * -* ixen@copyhandler.com * -* * -* This program is free software; you can redistribute it and/or modify * -* it under the terms of the GNU Library General Public License * -* (version 2) as published by the Free Software Foundation; * -* * -* 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 Library General Public * -* License along with this program; if not, write to the * -* Free Software Foundation, Inc., * -* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * -***************************************************************************/ -#include "stdafx.h" -#include "ResourceManager.h" -#include "../libicpf/exception.h" -#include "../libicpf/cfg.h" -#include "../libicpf/crc32.h" -#include -#include - -#ifdef _DEBUG -#define new DEBUG_NEW -#endif - -BEGIN_ICTRANSLATE_NAMESPACE - -#define EMPTY_STRING _t("") - -CFormat::CFormat(const tchar_t* pszFormat) : - m_strText(pszFormat) -{ -} - -CFormat::~CFormat() -{ -} - -void CFormat::SetFormat(const tchar_t* pszFormat) -{ - m_strText = pszFormat; -} - -CFormat& CFormat::SetParam(PCTSTR pszName, PCTSTR pszText) -{ - assert(pszName); - if(!pszName) - return *this; - - size_t stLen = _tcslen(pszName); - tstring_t::size_type stPos = 0; - while((stPos = m_strText.find(pszName)) != tstring_t::npos) - { - m_strText.replace(stPos, stLen, pszText); - } - - return *this; -} - -CFormat& CFormat::SetParam(PCTSTR pszName, ull_t ullData) -{ - tchar_t szBuffer[64]; - _sntprintf(szBuffer, 63, ULLFMT, ullData); - szBuffer[63] = _t('\0'); - - return SetParam(pszName, szBuffer); -} - -CFormat& CFormat::SetParam(PCTSTR pszName, ll_t llData) -{ - tchar_t szBuffer[64]; - _sntprintf(szBuffer, 63, LLFMT, llData); - szBuffer[63] = _t('\0'); - - return SetParam(pszName, szBuffer); -} - -CFormat& CFormat::SetParam(PCTSTR pszName, ulong_t ulData) -{ - tchar_t szBuffer[64]; - _sntprintf(szBuffer, 63, ULFMT, ulData); - szBuffer[63] = _t('\0'); - - return SetParam(pszName, szBuffer); -} - -CFormat& CFormat::SetParam(PCTSTR pszName, uint_t uiData) -{ - tchar_t szBuffer[64]; - _sntprintf(szBuffer, 63, UIFMT, uiData); - szBuffer[63] = _t('\0'); - - return SetParam(pszName, szBuffer); -} - -CFormat& CFormat::SetParam(PCTSTR pszName, int_t iData) -{ - tchar_t szBuffer[64]; - _sntprintf(szBuffer, 63, IFMT, iData); - szBuffer[63] = _t('\0'); - - return SetParam(pszName, szBuffer); -} - -CFormat& CFormat::SetParam(PCTSTR pszName, bool bData) -{ - tchar_t szBuffer[64]; - _sntprintf(szBuffer, 63, USFMT, (ushort_t)bData); - szBuffer[63] = _t('\0'); - - return SetParam(pszName, szBuffer); -} - -CTranslationItem::CTranslationItem() : - m_pszText(NULL), - m_uiChecksum(0), - m_stTextLength(0) -{ -} - -CTranslationItem::CTranslationItem(const tchar_t* pszText, uint_t uiChecksum) : - m_pszText(NULL), - m_stTextLength(0), - m_uiChecksum(uiChecksum) -{ - if(pszText) - { - m_stTextLength = _tcslen(pszText); - if(m_stTextLength > 0) - { - m_pszText = new tchar_t[m_stTextLength + 1]; - _tcscpy(m_pszText, pszText); - - UnescapeString(); - } - } -} - -CTranslationItem::~CTranslationItem() -{ - Clear(); -} - -CTranslationItem& CTranslationItem::operator=(const CTranslationItem& rSrc) -{ - if(this != &rSrc) - { - Clear(); - if(rSrc.m_pszText) - { - m_stTextLength = rSrc.m_stTextLength; - if(m_stTextLength > 0) - { - m_pszText = new tchar_t[rSrc.m_stTextLength + 1]; - _tcscpy(m_pszText, rSrc.m_pszText); - } - } - m_uiChecksum = rSrc.m_uiChecksum; - } - - return *this; -} - -void CTranslationItem::Clear() -{ - delete [] m_pszText; - m_pszText = NULL; - m_stTextLength = 0; - m_uiChecksum = 0; -} - -void CTranslationItem::CalculateChecksum() -{ - if(m_pszText) - m_uiChecksum = icpf::crc32((const byte_t*)m_pszText, m_stTextLength*sizeof(tchar_t)); - else - m_uiChecksum = 0; -} - -const tchar_t* CTranslationItem::GetText() const -{ - return m_pszText ? m_pszText : _t(""); -} - -void CTranslationItem::SetText(const tchar_t* pszText, bool bUnescapeString) -{ - delete [] m_pszText; - if(pszText) - { - m_stTextLength = _tcslen(pszText); - if(m_stTextLength > 0) - { - m_pszText = new tchar_t[m_stTextLength + 1]; - _tcscpy(m_pszText, pszText); - if(bUnescapeString) - UnescapeString(); - return; - } - } - - m_pszText = NULL; - m_stTextLength = 0; -} - -void CTranslationItem::UnescapeString() -{ - if(!m_pszText) - return; - - const tchar_t* pszIn = m_pszText; - tchar_t* pszOut = m_pszText; - while (*pszIn != 0) - { - if (*pszIn == _T('\\')) - { - pszIn++; - switch(*pszIn++) - { - case _T('t'): - *pszOut++ = _T('\t'); - break; - case _T('r'): - *pszOut++ = _T('\r'); - break; - case _T('n'): - *pszOut++ = _T('\n'); - break; - default: - *pszOut++ = _T('\\'); - } - } - else - *pszOut++ = *pszIn++; - } - *pszOut = _T('\0'); -} - -CTranslationItem::ECompareResult CTranslationItem::Compare(const CTranslationItem& rReferenceItem) -{ - if(!m_pszText || !rReferenceItem.m_pszText) - return eResult_Invalid; - - if(m_uiChecksum != rReferenceItem.m_uiChecksum) - return eResult_Invalid; - - // space check - if(rReferenceItem.m_pszText[0] == _t(' ') && m_pszText[0] != _t(' ')) - return eResult_ContentWarning; - - size_t stReferenceLen = _tcslen(rReferenceItem.m_pszText); - size_t stOwnLen = _tcslen(m_pszText); - if(stReferenceLen > 0 && stOwnLen > 0 && rReferenceItem.m_pszText[stReferenceLen - 1] == _t(' ') && m_pszText[stOwnLen - 1] != _t(' ')) - return eResult_ContentWarning; - - // formatting strings check - std::set setRefFmt; - if(!rReferenceItem.GetFormatStrings(setRefFmt)) - return eResult_ContentWarning; - - std::set setThisFmt; - if(!GetFormatStrings(setThisFmt)) - return eResult_ContentWarning; - - if(setRefFmt != setThisFmt) - return eResult_ContentWarning; - - return eResult_Valid; -} - -bool CTranslationItem::GetFormatStrings(std::set& setFmtStrings) const -{ - setFmtStrings.clear(); - - const tchar_t* pszData = m_pszText; - const tchar_t* pszNext = NULL; - const size_t stMaxFmt = 256; - tchar_t szFmt[stMaxFmt]; - while((pszData = _tcschr(pszData, _t('%'))) != NULL) - { - pszData++; // it works assuming the string is null-terminated - - // search the end of fmt string - pszNext = pszData; - while(*pszNext && isalpha(*pszNext)) - pszNext++; - - // if we have bigger buffer needs than is available - if(pszNext - pszData >= stMaxFmt) - return false; - - // copy data - _tcsncpy(szFmt, pszData, pszNext - pszData); - szFmt[pszNext - pszData] = _T('\0'); - - setFmtStrings.insert(tstring_t(szFmt)); - } - - return true; -} - -CLangData::CLangData() : - m_pszFilename(NULL), - m_pszLngName(NULL), - m_pszFontFace(NULL), - m_wPointSize(0), - m_pszHelpName(NULL), - m_pszAuthor(NULL), - m_bRTL(false), - m_uiSectionID(0), - m_bUpdating(false), - m_bModified(false) -{ -} - -CLangData::~CLangData() -{ - delete [] m_pszFilename; - delete [] m_pszLngName; - delete [] m_pszFontFace; - delete [] m_pszHelpName; - delete [] m_pszAuthor; -} - -void CLangData::Clear() -{ - delete [] m_pszFilename; - m_pszFilename = NULL; - delete [] m_pszLngName; - m_pszLngName = NULL; - delete [] m_pszFontFace; - m_pszFontFace = NULL; - delete [] m_pszHelpName; - m_pszHelpName = NULL; - delete [] m_pszAuthor; - m_pszAuthor = NULL; - m_bModified = false; - m_bRTL = false; - m_bUpdating = false; - m_uiSectionID = 0; - m_wPointSize = 0; - - m_mapTranslation.clear(); -} - -CLangData::CLangData(const CLangData& ld) : - m_pszFilename(NULL), - m_pszLngName(NULL), - m_pszFontFace(NULL), - m_pszHelpName(NULL), - m_pszAuthor(NULL), - m_bRTL(ld.m_bRTL), - m_bUpdating(ld.m_bUpdating), - m_uiSectionID(ld.m_uiSectionID), - m_wPointSize(ld.m_wPointSize), - m_bModified(false) -{ - SetFilename(ld.GetFilename(true)); - SetLangName(ld.GetLangName()); - SetFontFace(ld.GetFontFace()); - SetPointSize(ld.GetPointSize()); - SetDirection(ld.GetDirection()); - SetHelpName(ld.GetHelpName()); - SetAuthor(ld.GetAuthor()); - - m_mapTranslation.insert(ld.m_mapTranslation.begin(), ld.m_mapTranslation.end()); -} - -CLangData& CLangData::operator=(const CLangData& rSrc) -{ - if(this != &rSrc) - { - SetFilename(rSrc.GetFilename(true)); - SetLangName(rSrc.GetLangName()); - SetFontFace(rSrc.GetFontFace()); - SetPointSize(rSrc.GetPointSize()); - SetDirection(rSrc.GetDirection()); - SetHelpName(rSrc.GetHelpName()); - SetAuthor(rSrc.GetAuthor()); - m_bRTL = rSrc.m_bRTL; - m_bUpdating = rSrc.m_bUpdating; - m_uiSectionID = rSrc.m_uiSectionID; - m_wPointSize = rSrc.m_wPointSize; - m_bModified = false; - - m_mapTranslation.insert(rSrc.m_mapTranslation.begin(), rSrc.m_mapTranslation.end()); - } - - return *this; -} - -bool CLangData::ReadInfo(PCTSTR pszFile) -{ - try - { - Clear(); - - icpf::config cfg(icpf::config::eIni); - const uint_t uiLangName = cfg.register_string(_T("Info/Lang Name"), _t("")); - const uint_t uiFontFace = cfg.register_string(_T("Info/Font Face"), _T("")); - const uint_t uiSize = cfg.register_signed_num(_T("Info/Size"), 0, 0, 0xffff); - const uint_t uiRTL = cfg.register_bool(_T("Info/RTL reading order"), false); - const uint_t uiHelpName = cfg.register_string(_T("Info/Help name"), _T("")); - const uint_t uiAuthor = cfg.register_string(_T("Info/Author"), _T("")); - cfg.read(pszFile); - - const tchar_t* psz = cfg.get_string(uiLangName); - if(!psz || psz[0] == _t('\0')) - return false; - SetLangName(psz); - - psz = cfg.get_string(uiFontFace); - if(!psz || psz[0] == _t('\0')) - return false; - SetFontFace(psz); - - ll_t ll = cfg.get_signed_num(uiSize); - if(ll == 0) - return false; - SetPointSize((WORD)ll); - - SetDirection(cfg.get_bool(uiRTL)); - - psz = cfg.get_string(uiHelpName); - if(!psz || psz[0] == _t('\0')) - return false; - SetHelpName(psz); - - psz = cfg.get_string(uiAuthor); - if(!psz || psz[0] == _t('\0')) - return false; - SetAuthor(psz); - - SetFilename(pszFile); - - m_bModified = false; - - return true; - } - catch(...) - { - return false; - } -} - -void CLangData::EnumAttributesCallback(bool bGroup, const tchar_t* pszName, const tchar_t* pszValue, ptr_t pData) -{ - CLangData* pLangData = (CLangData*)pData; - assert(pLangData); - assert(pszName); - if(!pLangData || !pszName) - return; - - if(bGroup && _tcsicmp(pszName, _t("Info")) == 0) - return; - if(bGroup) - { - // new section - remember in member - pLangData->m_uiSectionID = _ttoi(pszName); - } - else - { - uint_t uiID = 0; - uint_t uiChecksum = 0; - - // parse the pszName to get both the string id and checksum - const tchar_t* pszChecksum = _tcschr(pszName, _T('[')); - if(pszChecksum == NULL) - { - TRACE(_T("Warning! Old-style translation string %s.\n"), pszName); - - int iCount = _stscanf(pszName, UIFMT, &uiID); - if(iCount != 1) - { - TRACE(_T("Warning! Problem retrieving id from string '%s'\n"), pszName); - return; - } - } - else - { - int iCount = _stscanf(pszName, UIFMT _T("[0x%lx]"), &uiID, &uiChecksum); - if(iCount != 2) - { - TRACE(_T("Warning! Problem retrieving id/checksum from string '%s'\n"), pszName); - return; - } - } - - uint_t uiKey = pLangData->m_uiSectionID << 16 | uiID; - translation_map::iterator itTranslation = pLangData->m_mapTranslation.end(); - if(pLangData->m_bUpdating) - { - // check if the checksum exists and matches - itTranslation = pLangData->m_mapTranslation.find(uiKey); - if(itTranslation == pLangData->m_mapTranslation.end()) - { - TRACE(_T("Warning! Superfluous entry %lu in processed language file\n"), uiKey); - return; // entry not found - probably superfluous entry in the language file - } - - if((*itTranslation).second.GetChecksum() != uiChecksum) - { - TRACE(_T("Warning! Invalid checksum for string ID %lu in processed language file\n"), uiKey); - return; // entry has invalid checksum (older version of translation) - } - } - else - { - std::pair pairTranslation = pLangData->m_mapTranslation.insert(translation_map::value_type(uiKey, CTranslationItem())); - itTranslation = pairTranslation.first; - } - - assert(itTranslation != pLangData->m_mapTranslation.end()); - if(itTranslation != pLangData->m_mapTranslation.end()) - { - (*itTranslation).second.SetText(pszValue, true); - if(!pLangData->m_bUpdating) - (*itTranslation).second.SetChecksum(uiChecksum); - } - } -} - -void CLangData::UnescapeString(tchar_t* pszData) -{ - tchar_t* pszOut = pszData; - while (*pszData != 0) - { - if (*pszData == _T('\\')) - { - pszData++; - switch(*pszData++) - { - case _T('t'): - *pszOut++ = _T('\t'); - break; - case _T('r'): - *pszOut++ = _T('\r'); - break; - case _T('n'): - *pszOut++ = _T('\n'); - break; - default: - *pszOut++ = _T('\\'); - } - } - else - *pszOut++ = *pszData++; - } - *pszOut = _T('\0'); - -} - -bool CLangData::ReadTranslation(PCTSTR pszFile, bool bUpdateTranslation) -{ - try - { - if(!bUpdateTranslation) - Clear(); - - // load data from file - icpf::config cfg(icpf::config::eIni); - const uint_t uiLangName = cfg.register_string(_T("Info/Lang Name"), _t("")); - const uint_t uiFontFace = cfg.register_string(_T("Info/Font Face"), _T("")); - const uint_t uiSize = cfg.register_signed_num(_T("Info/Size"), 0, 0, 0xffff); - const uint_t uiRTL = cfg.register_bool(_T("Info/RTL reading order"), false); - const uint_t uiHelpName = cfg.register_string(_T("Info/Help name"), _T("")); - const uint_t uiAuthor = cfg.register_string(_T("Info/Author"), _T("")); - cfg.read(pszFile); - - const tchar_t* psz = cfg.get_string(uiLangName); - if(!psz || psz[0] == _t('\0')) - return false; - SetLangName(psz); - - psz = cfg.get_string(uiFontFace); - if(!psz || psz[0] == _t('\0')) - return false; - SetFontFace(psz); - - ll_t ll = cfg.get_signed_num(uiSize); - if(ll == 0) - return false; - SetPointSize((WORD)ll); - - SetDirection(cfg.get_bool(uiRTL)); - - psz = cfg.get_string(uiHelpName); - if(!psz || psz[0] == _t('\0')) - return false; - SetHelpName(psz); - - psz = cfg.get_string(uiAuthor); - if(!psz || psz[0] == _t('\0')) - return false; - SetAuthor(psz); - - m_bUpdating = bUpdateTranslation; - m_uiSectionID = 0; - if(!cfg.enum_properties(_t("*"), EnumAttributesCallback, this)) - { - m_bUpdating = false; - return false; - } - m_bUpdating = false; - - SetFilename(pszFile); - - m_bModified = false; - - return true; - } - catch(...) - { - return false; - } -} - -void CLangData::WriteTranslation(PCTSTR pszPath) -{ - if(!IsValidDescription()) - THROW(_t("Invalid translation information (author, name or point size)"), 0, 0, 0); - - // real writing - const int iBufferSize = 256; - tchar_t szTemp[iBufferSize]; - - // load data from file - icpf::config cfg(icpf::config::eIni); - cfg.set_string(_t("Info/Lang Name"), m_pszLngName); - cfg.set_string(_T("Info/Font Face"), m_pszFontFace); - cfg.set_string(_T("Info/Size"), _itot(m_wPointSize, szTemp, 10)); - cfg.set_string(_T("Info/RTL reading order"), m_bRTL ? _T("1") : _T("0")); - cfg.set_string(_T("Info/Help name"), m_pszHelpName); - cfg.set_string(_T("Info/Author"), m_pszAuthor); - - tstring_t strText; - for(translation_map::iterator it = m_mapTranslation.begin(); it != m_mapTranslation.end(); it++) - { - uint_t uiKey = (*it).first; - _sntprintf(szTemp, iBufferSize - 1, UIFMT _T("/") UIFMT _T("[") UIXFMT _T("]"), (uiKey >> 16), uiKey & 0x0000ffff, (*it).second.GetChecksum()); - - strText = (*it).second.GetText(); - tstring_t::size_type stPos; - while((stPos = strText.find_first_of(_t("\r\n\t"))) != tstring_t::npos) - { - switch(strText[stPos]) - { - case _t('\r'): - strText.replace(stPos, 1, _t("\\r")); - break; - case _t('\n'): - strText.replace(stPos, 1, _t("\\n")); - break; - case _t('\t'): - strText.replace(stPos, 1, _t("\\t")); - break; - } - } - - cfg.set_string(szTemp, strText.c_str()); - } - - if(pszPath == NULL) - pszPath = m_pszFilename; - else - SetFilename(pszPath); - cfg.write(pszPath); - - m_bModified = false; -} - -PCTSTR CLangData::GetString(WORD wHiID, WORD wLoID) -{ - translation_map::const_iterator it=m_mapTranslation.find((wHiID << 16) | wLoID); - if (it != m_mapTranslation.end()) - return (*it).second.GetText(); - else - return EMPTY_STRING; -} - -void CLangData::EnumStrings(PFNENUMCALLBACK pfnCallback, ptr_t pData) -{ - for(translation_map::const_iterator iterTranslation = m_mapTranslation.begin(); iterTranslation != m_mapTranslation.end(); ++iterTranslation) - { - (*pfnCallback)((*iterTranslation).first, &(*iterTranslation).second, pData); - } -} - -CTranslationItem* CLangData::GetTranslationItem(uint_t uiTranslationKey, bool bCreate) -{ - translation_map::iterator iterTranslation = m_mapTranslation.find(uiTranslationKey); - if(iterTranslation != m_mapTranslation.end()) - return &(*iterTranslation).second; - else - { - if(bCreate) - { - std::pair pairTranslation = m_mapTranslation.insert(std::make_pair(uiTranslationKey, CTranslationItem())); - if(pairTranslation.second) - { - m_bModified = true; - return &(*pairTranslation.first).second; - } - } - } - - return NULL; -} - -bool CLangData::Exists(uint_t uiTranslationKey) const -{ - return m_mapTranslation.find(uiTranslationKey) != m_mapTranslation.end(); -} - -// removes strings that does not exist in the reference translation -void CLangData::CleanupTranslation(const CLangData& rReferenceTranslation) -{ - translation_map::iterator iterTranslation = m_mapTranslation.begin(); - while(iterTranslation != m_mapTranslation.end()) - { - if(!rReferenceTranslation.Exists((*iterTranslation).first)) - { - m_bModified = true; - m_mapTranslation.erase(iterTranslation++); - } - else - ++iterTranslation; - } -} - -void CLangData::SetFilename(PCTSTR psz) -{ - if (m_pszFilename) - delete [] m_pszFilename; - - // copy - m_pszFilename=new TCHAR[_tcslen(psz)+1]; - _tcscpy(m_pszFilename, psz); - - m_bModified = true; -} - -PCTSTR CLangData::GetFilename(bool bFullPath) const -{ - if (bFullPath) - return m_pszFilename; - else - { - if(m_pszFilename) - { - TCHAR *pszFnd=_tcsrchr(m_pszFilename, _T('\\')); - if (pszFnd) - return pszFnd+1; - } - - return m_pszFilename; - } -} - -void CLangData::SetLangName(PCTSTR psz) -{ - if (m_pszLngName) - delete [] m_pszLngName; - m_pszLngName=new TCHAR[_tcslen(psz)+1]; - _tcscpy(m_pszLngName, psz); - m_bModified = true; -} - -void CLangData::SetFontFace(PCTSTR psz) -{ - if (m_pszFontFace) - delete [] m_pszFontFace; - m_pszFontFace=new TCHAR[_tcslen(psz)+1]; - _tcscpy(m_pszFontFace, psz); - m_bModified = true; -} - -void CLangData::SetHelpName(PCTSTR psz) -{ - SetFnameData(&m_pszHelpName, psz); - m_bModified = true; -} - -void CLangData::SetAuthor(PCTSTR psz) -{ - if (m_pszAuthor) - delete [] m_pszAuthor; - m_pszAuthor=new TCHAR[_tcslen(psz)+1]; - _tcscpy(m_pszAuthor, psz); - m_bModified = true; -} - -bool CLangData::IsValidDescription() const -{ - // basic sanity checks - if(!m_pszAuthor || m_pszAuthor[0] == _t('\0') || - !m_pszLngName || m_pszLngName[0] == _t('\0') || - !m_pszFontFace || m_pszFontFace[0] == _t('\0') || - m_wPointSize == 0) - return false; - return true; -} - -void CLangData::SetFnameData(PTSTR *ppszDst, PCTSTR pszSrc) -{ - if (*ppszDst) - delete [] (*ppszDst); - const TCHAR* pszLast=NULL; - if ( (pszLast=_tcsrchr(pszSrc, _T('\\'))) != NULL) - pszLast++; - else - pszLast=pszSrc; - - // copy - *ppszDst=new TCHAR[_tcslen(pszLast)+1]; - _tcscpy(*ppszDst, pszLast); -} - -CResourceManager::CResourceManager() : - m_pfnCallback(NULL), - m_hRes(NULL) -{ - InitializeCriticalSection(&m_cs); -} - -CResourceManager::~CResourceManager() -{ - DeleteCriticalSection(&m_cs); -} - -void CResourceManager::Init(HMODULE hrc) -{ - m_hRes=hrc; -} - -// requires the param with ending '\\' -void CResourceManager::Scan(LPCTSTR pszFolder, vector* pvData) -{ - assert(pszFolder); - assert(pvData); - if(!pszFolder || !pvData) - return; - - TCHAR szPath[_MAX_PATH]; - _tcscpy(szPath, pszFolder); - _tcscat(szPath, _T("*.lng")); - - WIN32_FIND_DATA wfd; - HANDLE hFind=::FindFirstFile(szPath, &wfd); - BOOL bFound=TRUE; - CLangData ld; - while (bFound && hFind != INVALID_HANDLE_VALUE) - { - if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - _tcscpy(szPath, pszFolder); - _tcscat(szPath, wfd.cFileName); - if (ld.ReadInfo(szPath)) - pvData->push_back(ld); - } - - bFound=::FindNextFile(hFind, &wfd); - } - - if (hFind != INVALID_HANDLE_VALUE) - ::FindClose(hFind); -} - -bool CResourceManager::SetLanguage(PCTSTR pszPath) -{ - bool bRet = false; - tchar_t szPath[_MAX_PATH]; - - // parse the path to allow reading the english language first - const tchar_t* pszBaseName = _t("english.lng"); - if(_tcsstr(pszPath, pszBaseName) != NULL) - { - _tcscpy(szPath, pszPath); - pszPath = NULL; - } - else - { - const tchar_t* pszData = _tcsrchr(pszPath, _t('\\')); - if(pszData != NULL) - { - memset(szPath, 0, _MAX_PATH*sizeof(tchar_t)); - _tcsncpy(szPath, pszPath, pszData - pszPath + 1); - szPath[_MAX_PATH - 1] = _T('\0'); - _tcscat(szPath, pszBaseName); - } - else - _tcscpy(szPath, pszPath); - } - - // and load everything - EnterCriticalSection(&m_cs); - try - { - bRet = m_ld.ReadTranslation(szPath); // base language - if(bRet && pszPath) - bRet=m_ld.ReadTranslation(pszPath, true); // real language - } - catch(...) - { - LeaveCriticalSection(&m_cs); - return false; - } - LeaveCriticalSection(&m_cs); - if (!bRet) - return false; - - // update registered dialog boxes - list::iterator it=m_lhDialogs.begin(); - while (it != m_lhDialogs.end()) - { - if (::IsWindow((*it)->m_hWnd)) - (*it)->PostMessage(WM_RMNOTIFY, RMNT_LANGCHANGE, 0); - it++; - } - - // send the notification stuff to the others - if (m_pfnCallback) - (*m_pfnCallback)(RMNT_LANGCHANGE); - - return bRet; -} - -HGLOBAL CResourceManager::LoadResource(LPCTSTR pszType, LPCTSTR pszName) -{ - EnterCriticalSection(&m_cs); - - // find resource - HGLOBAL hRet=NULL; - HRSRC hr=FindResource(m_hRes, pszName, pszType); - if (hr) - hRet=::LoadResource(m_hRes, hr); - - LeaveCriticalSection(&m_cs); - return hRet; -} - -HACCEL CResourceManager::LoadAccelerators(LPCTSTR pszName) -{ - return ::LoadAccelerators(m_hRes, pszName); -} - -HBITMAP CResourceManager::LoadBitmap(LPCTSTR pszName) -{ - return ::LoadBitmap(m_hRes, pszName); -} - -HCURSOR CResourceManager::LoadCursor(LPCTSTR pszName) -{ - return ::LoadCursor(m_hRes, pszName); -} - -HICON CResourceManager::LoadIcon(LPCTSTR pszName) -{ - return ::LoadIcon(m_hRes, pszName); -} - -void CResourceManager::UpdateMenu(HMENU hMenu, WORD wMenuID) -{ - // change the strings inside the menu to the one from txt res file - int iCount=::GetMenuItemCount(hMenu); - MENUITEMINFO mif; - WORD wLoID; - TCHAR szItem[1024]; - memset(szItem, 0, 1024); - for (int i=0;i +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#endif + +BEGIN_ICTRANSLATE_NAMESPACE + +#define EMPTY_STRING _t("") + +CFormat::CFormat(const tchar_t* pszFormat) : + m_strText(pszFormat) +{ +} + +CFormat::~CFormat() +{ +} + +void CFormat::SetFormat(const tchar_t* pszFormat) +{ + m_strText = pszFormat; +} + +CFormat& CFormat::SetParam(PCTSTR pszName, PCTSTR pszText) +{ + assert(pszName); + if(!pszName) + return *this; + + size_t stLen = _tcslen(pszName); + tstring_t::size_type stPos = 0; + while((stPos = m_strText.find(pszName)) != tstring_t::npos) + { + m_strText.replace(stPos, stLen, pszText); + } + + return *this; +} + +CFormat& CFormat::SetParam(PCTSTR pszName, ull_t ullData) +{ + tchar_t szBuffer[64]; + _sntprintf(szBuffer, 63, ULLFMT, ullData); + szBuffer[63] = _t('\0'); + + return SetParam(pszName, szBuffer); +} + +CFormat& CFormat::SetParam(PCTSTR pszName, ll_t llData) +{ + tchar_t szBuffer[64]; + _sntprintf(szBuffer, 63, LLFMT, llData); + szBuffer[63] = _t('\0'); + + return SetParam(pszName, szBuffer); +} + +CFormat& CFormat::SetParam(PCTSTR pszName, ulong_t ulData) +{ + tchar_t szBuffer[64]; + _sntprintf(szBuffer, 63, ULFMT, ulData); + szBuffer[63] = _t('\0'); + + return SetParam(pszName, szBuffer); +} + +CFormat& CFormat::SetParam(PCTSTR pszName, uint_t uiData) +{ + tchar_t szBuffer[64]; + _sntprintf(szBuffer, 63, UIFMT, uiData); + szBuffer[63] = _t('\0'); + + return SetParam(pszName, szBuffer); +} + +CFormat& CFormat::SetParam(PCTSTR pszName, int_t iData) +{ + tchar_t szBuffer[64]; + _sntprintf(szBuffer, 63, IFMT, iData); + szBuffer[63] = _t('\0'); + + return SetParam(pszName, szBuffer); +} + +CFormat& CFormat::SetParam(PCTSTR pszName, bool bData) +{ + tchar_t szBuffer[64]; + _sntprintf(szBuffer, 63, USFMT, (ushort_t)bData); + szBuffer[63] = _t('\0'); + + return SetParam(pszName, szBuffer); +} + +CTranslationItem::CTranslationItem() : + m_pszText(NULL), + m_uiChecksum(0), + m_stTextLength(0) +{ +} + +CTranslationItem::CTranslationItem(const tchar_t* pszText, uint_t uiChecksum) : + m_pszText(NULL), + m_stTextLength(0), + m_uiChecksum(uiChecksum) +{ + if(pszText) + { + m_stTextLength = _tcslen(pszText); + if(m_stTextLength > 0) + { + m_pszText = new tchar_t[m_stTextLength + 1]; + _tcscpy(m_pszText, pszText); + + UnescapeString(); + } + } +} + +CTranslationItem::~CTranslationItem() +{ + Clear(); +} + +CTranslationItem& CTranslationItem::operator=(const CTranslationItem& rSrc) +{ + if(this != &rSrc) + { + Clear(); + if(rSrc.m_pszText) + { + m_stTextLength = rSrc.m_stTextLength; + if(m_stTextLength > 0) + { + m_pszText = new tchar_t[rSrc.m_stTextLength + 1]; + _tcscpy(m_pszText, rSrc.m_pszText); + } + } + m_uiChecksum = rSrc.m_uiChecksum; + } + + return *this; +} + +void CTranslationItem::Clear() +{ + delete [] m_pszText; + m_pszText = NULL; + m_stTextLength = 0; + m_uiChecksum = 0; +} + +void CTranslationItem::CalculateChecksum() +{ + if(m_pszText) + m_uiChecksum = icpf::crc32((const byte_t*)m_pszText, m_stTextLength*sizeof(tchar_t)); + else + m_uiChecksum = 0; +} + +const tchar_t* CTranslationItem::GetText() const +{ + return m_pszText ? m_pszText : _t(""); +} + +void CTranslationItem::SetText(const tchar_t* pszText, bool bUnescapeString) +{ + delete [] m_pszText; + if(pszText) + { + m_stTextLength = _tcslen(pszText); + if(m_stTextLength > 0) + { + m_pszText = new tchar_t[m_stTextLength + 1]; + _tcscpy(m_pszText, pszText); + if(bUnescapeString) + UnescapeString(); + return; + } + } + + m_pszText = NULL; + m_stTextLength = 0; +} + +void CTranslationItem::UnescapeString() +{ + if(!m_pszText) + return; + + const tchar_t* pszIn = m_pszText; + tchar_t* pszOut = m_pszText; + while (*pszIn != 0) + { + if (*pszIn == _T('\\')) + { + pszIn++; + switch(*pszIn++) + { + case _T('t'): + *pszOut++ = _T('\t'); + break; + case _T('r'): + *pszOut++ = _T('\r'); + break; + case _T('n'): + *pszOut++ = _T('\n'); + break; + default: + *pszOut++ = _T('\\'); + } + } + else + *pszOut++ = *pszIn++; + } + *pszOut = _T('\0'); +} + +CTranslationItem::ECompareResult CTranslationItem::Compare(const CTranslationItem& rReferenceItem) +{ + if(!m_pszText || !rReferenceItem.m_pszText) + return eResult_Invalid; + + if(m_uiChecksum != rReferenceItem.m_uiChecksum) + return eResult_Invalid; + + // space check + if(rReferenceItem.m_pszText[0] == _t(' ') && m_pszText[0] != _t(' ')) + return eResult_ContentWarning; + + size_t stReferenceLen = _tcslen(rReferenceItem.m_pszText); + size_t stOwnLen = _tcslen(m_pszText); + if(stReferenceLen > 0 && stOwnLen > 0 && rReferenceItem.m_pszText[stReferenceLen - 1] == _t(' ') && m_pszText[stOwnLen - 1] != _t(' ')) + return eResult_ContentWarning; + + // formatting strings check + std::set setRefFmt; + if(!rReferenceItem.GetFormatStrings(setRefFmt)) + return eResult_ContentWarning; + + std::set setThisFmt; + if(!GetFormatStrings(setThisFmt)) + return eResult_ContentWarning; + + if(setRefFmt != setThisFmt) + return eResult_ContentWarning; + + return eResult_Valid; +} + +bool CTranslationItem::GetFormatStrings(std::set& setFmtStrings) const +{ + setFmtStrings.clear(); + + const tchar_t* pszData = m_pszText; + const tchar_t* pszNext = NULL; + const size_t stMaxFmt = 256; + tchar_t szFmt[stMaxFmt]; + while((pszData = _tcschr(pszData, _t('%'))) != NULL) + { + pszData++; // it works assuming the string is null-terminated + + // search the end of fmt string + pszNext = pszData; + while(*pszNext && isalpha(*pszNext)) + pszNext++; + + // if we have bigger buffer needs than is available + if(pszNext - pszData >= stMaxFmt) + return false; + + // copy data + _tcsncpy(szFmt, pszData, pszNext - pszData); + szFmt[pszNext - pszData] = _T('\0'); + + setFmtStrings.insert(tstring_t(szFmt)); + } + + return true; +} + +CLangData::CLangData() : + m_pszFilename(NULL), + m_pszLngName(NULL), + m_pszFontFace(NULL), + m_wPointSize(0), + m_pszHelpName(NULL), + m_pszAuthor(NULL), + m_bRTL(false), + m_uiSectionID(0), + m_bUpdating(false), + m_bModified(false) +{ +} + +CLangData::~CLangData() +{ + delete [] m_pszFilename; + delete [] m_pszLngName; + delete [] m_pszFontFace; + delete [] m_pszHelpName; + delete [] m_pszAuthor; +} + +void CLangData::Clear() +{ + delete [] m_pszFilename; + m_pszFilename = NULL; + delete [] m_pszLngName; + m_pszLngName = NULL; + delete [] m_pszFontFace; + m_pszFontFace = NULL; + delete [] m_pszHelpName; + m_pszHelpName = NULL; + delete [] m_pszAuthor; + m_pszAuthor = NULL; + m_bModified = false; + m_bRTL = false; + m_bUpdating = false; + m_uiSectionID = 0; + m_wPointSize = 0; + + m_mapTranslation.clear(); +} + +CLangData::CLangData(const CLangData& ld) : + m_pszFilename(NULL), + m_pszLngName(NULL), + m_pszFontFace(NULL), + m_pszHelpName(NULL), + m_pszAuthor(NULL), + m_bRTL(ld.m_bRTL), + m_bUpdating(ld.m_bUpdating), + m_uiSectionID(ld.m_uiSectionID), + m_wPointSize(ld.m_wPointSize), + m_bModified(false) +{ + SetFilename(ld.GetFilename(true)); + SetLangName(ld.GetLangName()); + SetFontFace(ld.GetFontFace()); + SetPointSize(ld.GetPointSize()); + SetDirection(ld.GetDirection()); + SetHelpName(ld.GetHelpName()); + SetAuthor(ld.GetAuthor()); + + m_mapTranslation.insert(ld.m_mapTranslation.begin(), ld.m_mapTranslation.end()); +} + +CLangData& CLangData::operator=(const CLangData& rSrc) +{ + if(this != &rSrc) + { + SetFilename(rSrc.GetFilename(true)); + SetLangName(rSrc.GetLangName()); + SetFontFace(rSrc.GetFontFace()); + SetPointSize(rSrc.GetPointSize()); + SetDirection(rSrc.GetDirection()); + SetHelpName(rSrc.GetHelpName()); + SetAuthor(rSrc.GetAuthor()); + m_bRTL = rSrc.m_bRTL; + m_bUpdating = rSrc.m_bUpdating; + m_uiSectionID = rSrc.m_uiSectionID; + m_wPointSize = rSrc.m_wPointSize; + m_bModified = false; + + m_mapTranslation.insert(rSrc.m_mapTranslation.begin(), rSrc.m_mapTranslation.end()); + } + + return *this; +} + +bool CLangData::ReadInfo(PCTSTR pszFile) +{ + try + { + Clear(); + + icpf::config cfg(icpf::config::eIni); + const uint_t uiLangName = cfg.register_string(_T("Info/Lang Name"), _t("")); + const uint_t uiFontFace = cfg.register_string(_T("Info/Font Face"), _T("")); + const uint_t uiSize = cfg.register_signed_num(_T("Info/Size"), 0, 0, 0xffff); + const uint_t uiRTL = cfg.register_bool(_T("Info/RTL reading order"), false); + const uint_t uiHelpName = cfg.register_string(_T("Info/Help name"), _T("")); + const uint_t uiAuthor = cfg.register_string(_T("Info/Author"), _T("")); + cfg.read(pszFile); + + const tchar_t* psz = cfg.get_string(uiLangName); + if(!psz || psz[0] == _t('\0')) + return false; + SetLangName(psz); + + psz = cfg.get_string(uiFontFace); + if(!psz || psz[0] == _t('\0')) + return false; + SetFontFace(psz); + + ll_t ll = cfg.get_signed_num(uiSize); + if(ll == 0) + return false; + SetPointSize((WORD)ll); + + SetDirection(cfg.get_bool(uiRTL)); + + psz = cfg.get_string(uiHelpName); + if(!psz || psz[0] == _t('\0')) + return false; + SetHelpName(psz); + + psz = cfg.get_string(uiAuthor); + if(!psz || psz[0] == _t('\0')) + return false; + SetAuthor(psz); + + SetFilename(pszFile); + + m_bModified = false; + + return true; + } + catch(...) + { + return false; + } +} + +void CLangData::EnumAttributesCallback(bool bGroup, const tchar_t* pszName, const tchar_t* pszValue, ptr_t pData) +{ + CLangData* pLangData = (CLangData*)pData; + assert(pLangData); + assert(pszName); + if(!pLangData || !pszName) + return; + + if(bGroup && _tcsicmp(pszName, _t("Info")) == 0) + return; + if(bGroup) + { + // new section - remember in member + pLangData->m_uiSectionID = _ttoi(pszName); + } + else + { + uint_t uiID = 0; + uint_t uiChecksum = 0; + + // parse the pszName to get both the string id and checksum + const tchar_t* pszChecksum = _tcschr(pszName, _T('[')); + if(pszChecksum == NULL) + { + TRACE(_T("Warning! Old-style translation string %s.\n"), pszName); + + int iCount = _stscanf(pszName, UIFMT, &uiID); + if(iCount != 1) + { + TRACE(_T("Warning! Problem retrieving id from string '%s'\n"), pszName); + return; + } + } + else + { + int iCount = _stscanf(pszName, UIFMT _T("[0x%lx]"), &uiID, &uiChecksum); + if(iCount != 2) + { + TRACE(_T("Warning! Problem retrieving id/checksum from string '%s'\n"), pszName); + return; + } + } + + uint_t uiKey = pLangData->m_uiSectionID << 16 | uiID; + translation_map::iterator itTranslation = pLangData->m_mapTranslation.end(); + if(pLangData->m_bUpdating) + { + // check if the checksum exists and matches + itTranslation = pLangData->m_mapTranslation.find(uiKey); + if(itTranslation == pLangData->m_mapTranslation.end()) + { + TRACE(_T("Warning! Superfluous entry %lu in processed language file\n"), uiKey); + return; // entry not found - probably superfluous entry in the language file + } + + if((*itTranslation).second.GetChecksum() != uiChecksum) + { + TRACE(_T("Warning! Invalid checksum for string ID %lu in processed language file\n"), uiKey); + return; // entry has invalid checksum (older version of translation) + } + } + else + { + std::pair pairTranslation = pLangData->m_mapTranslation.insert(translation_map::value_type(uiKey, CTranslationItem())); + itTranslation = pairTranslation.first; + } + + assert(itTranslation != pLangData->m_mapTranslation.end()); + if(itTranslation != pLangData->m_mapTranslation.end()) + { + (*itTranslation).second.SetText(pszValue, true); + if(!pLangData->m_bUpdating) + (*itTranslation).second.SetChecksum(uiChecksum); + } + } +} + +void CLangData::UnescapeString(tchar_t* pszData) +{ + tchar_t* pszOut = pszData; + while (*pszData != 0) + { + if (*pszData == _T('\\')) + { + pszData++; + switch(*pszData++) + { + case _T('t'): + *pszOut++ = _T('\t'); + break; + case _T('r'): + *pszOut++ = _T('\r'); + break; + case _T('n'): + *pszOut++ = _T('\n'); + break; + default: + *pszOut++ = _T('\\'); + } + } + else + *pszOut++ = *pszData++; + } + *pszOut = _T('\0'); + +} + +bool CLangData::ReadTranslation(PCTSTR pszFile, bool bUpdateTranslation) +{ + try + { + if(!bUpdateTranslation) + Clear(); + + // load data from file + icpf::config cfg(icpf::config::eIni); + const uint_t uiLangName = cfg.register_string(_T("Info/Lang Name"), _t("")); + const uint_t uiFontFace = cfg.register_string(_T("Info/Font Face"), _T("")); + const uint_t uiSize = cfg.register_signed_num(_T("Info/Size"), 0, 0, 0xffff); + const uint_t uiRTL = cfg.register_bool(_T("Info/RTL reading order"), false); + const uint_t uiHelpName = cfg.register_string(_T("Info/Help name"), _T("")); + const uint_t uiAuthor = cfg.register_string(_T("Info/Author"), _T("")); + cfg.read(pszFile); + + const tchar_t* psz = cfg.get_string(uiLangName); + if(!psz || psz[0] == _t('\0')) + return false; + SetLangName(psz); + + psz = cfg.get_string(uiFontFace); + if(!psz || psz[0] == _t('\0')) + return false; + SetFontFace(psz); + + ll_t ll = cfg.get_signed_num(uiSize); + if(ll == 0) + return false; + SetPointSize((WORD)ll); + + SetDirection(cfg.get_bool(uiRTL)); + + psz = cfg.get_string(uiHelpName); + if(!psz || psz[0] == _t('\0')) + return false; + SetHelpName(psz); + + psz = cfg.get_string(uiAuthor); + if(!psz || psz[0] == _t('\0')) + return false; + SetAuthor(psz); + + m_bUpdating = bUpdateTranslation; + m_uiSectionID = 0; + if(!cfg.enum_properties(_t("*"), EnumAttributesCallback, this)) + { + m_bUpdating = false; + return false; + } + m_bUpdating = false; + + SetFilename(pszFile); + + m_bModified = false; + + return true; + } + catch(...) + { + return false; + } +} + +void CLangData::WriteTranslation(PCTSTR pszPath) +{ + if(!IsValidDescription()) + THROW(_t("Invalid translation information (author, name or point size)"), 0, 0, 0); + + // real writing + const int iBufferSize = 256; + tchar_t szTemp[iBufferSize]; + + // load data from file + icpf::config cfg(icpf::config::eIni); + cfg.set_string(_t("Info/Lang Name"), m_pszLngName); + cfg.set_string(_T("Info/Font Face"), m_pszFontFace); + cfg.set_string(_T("Info/Size"), _itot(m_wPointSize, szTemp, 10)); + cfg.set_string(_T("Info/RTL reading order"), m_bRTL ? _T("1") : _T("0")); + cfg.set_string(_T("Info/Help name"), m_pszHelpName); + cfg.set_string(_T("Info/Author"), m_pszAuthor); + + tstring_t strText; + for(translation_map::iterator it = m_mapTranslation.begin(); it != m_mapTranslation.end(); it++) + { + uint_t uiKey = (*it).first; + _sntprintf(szTemp, iBufferSize - 1, UIFMT _T("/") UIFMT _T("[") UIXFMT _T("]"), (uiKey >> 16), uiKey & 0x0000ffff, (*it).second.GetChecksum()); + + strText = (*it).second.GetText(); + tstring_t::size_type stPos; + while((stPos = strText.find_first_of(_t("\r\n\t"))) != tstring_t::npos) + { + switch(strText[stPos]) + { + case _t('\r'): + strText.replace(stPos, 1, _t("\\r")); + break; + case _t('\n'): + strText.replace(stPos, 1, _t("\\n")); + break; + case _t('\t'): + strText.replace(stPos, 1, _t("\\t")); + break; + } + } + + cfg.set_string(szTemp, strText.c_str()); + } + + if(pszPath == NULL) + pszPath = m_pszFilename; + else + SetFilename(pszPath); + cfg.write(pszPath); + + m_bModified = false; +} + +PCTSTR CLangData::GetString(WORD wHiID, WORD wLoID) +{ + translation_map::const_iterator it=m_mapTranslation.find((wHiID << 16) | wLoID); + if (it != m_mapTranslation.end()) + return (*it).second.GetText(); + else + return EMPTY_STRING; +} + +void CLangData::EnumStrings(PFNENUMCALLBACK pfnCallback, ptr_t pData) +{ + for(translation_map::const_iterator iterTranslation = m_mapTranslation.begin(); iterTranslation != m_mapTranslation.end(); ++iterTranslation) + { + (*pfnCallback)((*iterTranslation).first, &(*iterTranslation).second, pData); + } +} + +CTranslationItem* CLangData::GetTranslationItem(uint_t uiTranslationKey, bool bCreate) +{ + translation_map::iterator iterTranslation = m_mapTranslation.find(uiTranslationKey); + if(iterTranslation != m_mapTranslation.end()) + return &(*iterTranslation).second; + else + { + if(bCreate) + { + std::pair pairTranslation = m_mapTranslation.insert(std::make_pair(uiTranslationKey, CTranslationItem())); + if(pairTranslation.second) + { + m_bModified = true; + return &(*pairTranslation.first).second; + } + } + } + + return NULL; +} + +bool CLangData::Exists(uint_t uiTranslationKey) const +{ + return m_mapTranslation.find(uiTranslationKey) != m_mapTranslation.end(); +} + +// removes strings that does not exist in the reference translation +void CLangData::CleanupTranslation(const CLangData& rReferenceTranslation) +{ + translation_map::iterator iterTranslation = m_mapTranslation.begin(); + while(iterTranslation != m_mapTranslation.end()) + { + if(!rReferenceTranslation.Exists((*iterTranslation).first)) + { + m_bModified = true; + m_mapTranslation.erase(iterTranslation++); + } + else + ++iterTranslation; + } +} + +void CLangData::SetFilename(PCTSTR psz) +{ + if (m_pszFilename) + delete [] m_pszFilename; + + // copy + m_pszFilename=new TCHAR[_tcslen(psz)+1]; + _tcscpy(m_pszFilename, psz); + + m_bModified = true; +} + +PCTSTR CLangData::GetFilename(bool bFullPath) const +{ + if (bFullPath) + return m_pszFilename; + else + { + if(m_pszFilename) + { + TCHAR *pszFnd=_tcsrchr(m_pszFilename, _T('\\')); + if (pszFnd) + return pszFnd+1; + } + + return m_pszFilename; + } +} + +void CLangData::SetLangName(PCTSTR psz) +{ + if (m_pszLngName) + delete [] m_pszLngName; + m_pszLngName=new TCHAR[_tcslen(psz)+1]; + _tcscpy(m_pszLngName, psz); + m_bModified = true; +} + +void CLangData::SetFontFace(PCTSTR psz) +{ + if (m_pszFontFace) + delete [] m_pszFontFace; + m_pszFontFace=new TCHAR[_tcslen(psz)+1]; + _tcscpy(m_pszFontFace, psz); + m_bModified = true; +} + +void CLangData::SetHelpName(PCTSTR psz) +{ + SetFnameData(&m_pszHelpName, psz); + m_bModified = true; +} + +void CLangData::SetAuthor(PCTSTR psz) +{ + if (m_pszAuthor) + delete [] m_pszAuthor; + m_pszAuthor=new TCHAR[_tcslen(psz)+1]; + _tcscpy(m_pszAuthor, psz); + m_bModified = true; +} + +bool CLangData::IsValidDescription() const +{ + // basic sanity checks + if(!m_pszAuthor || m_pszAuthor[0] == _t('\0') || + !m_pszLngName || m_pszLngName[0] == _t('\0') || + !m_pszFontFace || m_pszFontFace[0] == _t('\0') || + m_wPointSize == 0) + return false; + return true; +} + +void CLangData::SetFnameData(PTSTR *ppszDst, PCTSTR pszSrc) +{ + if (*ppszDst) + delete [] (*ppszDst); + const TCHAR* pszLast=NULL; + if ( (pszLast=_tcsrchr(pszSrc, _T('\\'))) != NULL) + pszLast++; + else + pszLast=pszSrc; + + // copy + *ppszDst=new TCHAR[_tcslen(pszLast)+1]; + _tcscpy(*ppszDst, pszLast); +} + +CResourceManager::CResourceManager() : + m_pfnCallback(NULL), + m_hRes(NULL) +{ + InitializeCriticalSection(&m_cs); +} + +CResourceManager::~CResourceManager() +{ + DeleteCriticalSection(&m_cs); +} + +void CResourceManager::Init(HMODULE hrc) +{ + m_hRes=hrc; +} + +// requires the param with ending '\\' +void CResourceManager::Scan(LPCTSTR pszFolder, vector* pvData) +{ + assert(pszFolder); + assert(pvData); + if(!pszFolder || !pvData) + return; + + TCHAR szPath[_MAX_PATH]; + _tcscpy(szPath, pszFolder); + _tcscat(szPath, _T("*.lng")); + + WIN32_FIND_DATA wfd; + HANDLE hFind=::FindFirstFile(szPath, &wfd); + BOOL bFound=TRUE; + CLangData ld; + while (bFound && hFind != INVALID_HANDLE_VALUE) + { + if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + _tcscpy(szPath, pszFolder); + _tcscat(szPath, wfd.cFileName); + if (ld.ReadInfo(szPath)) + pvData->push_back(ld); + } + + bFound=::FindNextFile(hFind, &wfd); + } + + if (hFind != INVALID_HANDLE_VALUE) + ::FindClose(hFind); +} + +bool CResourceManager::SetLanguage(PCTSTR pszPath) +{ + bool bRet = false; + tchar_t szPath[_MAX_PATH]; + + // parse the path to allow reading the english language first + const tchar_t* pszBaseName = _t("english.lng"); + if(_tcsstr(pszPath, pszBaseName) != NULL) + { + _tcscpy(szPath, pszPath); + pszPath = NULL; + } + else + { + const tchar_t* pszData = _tcsrchr(pszPath, _t('\\')); + if(pszData != NULL) + { + memset(szPath, 0, _MAX_PATH*sizeof(tchar_t)); + _tcsncpy(szPath, pszPath, pszData - pszPath + 1); + szPath[_MAX_PATH - 1] = _T('\0'); + _tcscat(szPath, pszBaseName); + } + else + _tcscpy(szPath, pszPath); + } + + // and load everything + EnterCriticalSection(&m_cs); + try + { + bRet = m_ld.ReadTranslation(szPath); // base language + if(bRet && pszPath) + bRet=m_ld.ReadTranslation(pszPath, true); // real language + } + catch(...) + { + LeaveCriticalSection(&m_cs); + return false; + } + LeaveCriticalSection(&m_cs); + if (!bRet) + return false; + + // update registered dialog boxes + list::iterator it=m_lhDialogs.begin(); + while (it != m_lhDialogs.end()) + { + if (::IsWindow((*it)->m_hWnd)) + (*it)->PostMessage(WM_RMNOTIFY, RMNT_LANGCHANGE, 0); + it++; + } + + // send the notification stuff to the others + if (m_pfnCallback) + (*m_pfnCallback)(RMNT_LANGCHANGE); + + return bRet; +} + +HGLOBAL CResourceManager::LoadResource(LPCTSTR pszType, LPCTSTR pszName) +{ + EnterCriticalSection(&m_cs); + + // find resource + HGLOBAL hRet=NULL; + HRSRC hr=FindResource(m_hRes, pszName, pszType); + if (hr) + hRet=::LoadResource(m_hRes, hr); + + LeaveCriticalSection(&m_cs); + return hRet; +} + +HACCEL CResourceManager::LoadAccelerators(LPCTSTR pszName) +{ + return ::LoadAccelerators(m_hRes, pszName); +} + +HBITMAP CResourceManager::LoadBitmap(LPCTSTR pszName) +{ + return ::LoadBitmap(m_hRes, pszName); +} + +HCURSOR CResourceManager::LoadCursor(LPCTSTR pszName) +{ + return ::LoadCursor(m_hRes, pszName); +} + +HICON CResourceManager::LoadIcon(LPCTSTR pszName) +{ + return ::LoadIcon(m_hRes, pszName); +} + +void CResourceManager::UpdateMenu(HMENU hMenu, WORD wMenuID) +{ + // change the strings inside the menu to the one from txt res file + int iCount=::GetMenuItemCount(hMenu); + MENUITEMINFO mif; + WORD wLoID; + TCHAR szItem[1024]; + memset(szItem, 0, 1024); + for (int i=0;i