Index: src/rc2lng/rc.cpp
===================================================================
diff -u
--- src/rc2lng/rc.cpp	(revision 0)
+++ src/rc2lng/rc.cpp	(revision 2f3512c2df187a16a62c131d69bcddc06d671ed7)
@@ -0,0 +1,579 @@
+#include "stdafx.h"
+#include <vector>
+#include <map>
+#include <functional>
+#include <algorithm>
+#include "rc.h"
+#include "../libicpf/exception.h"
+#include "../libicpf/crc32.h"
+
+#define MAX_LINE 65536
+
+CRCFile::CRCFile() :
+	m_pszBuffer(new TCHAR[MAX_LINE])
+{
+	AddInitialValues();
+}
+
+CRCFile::~CRCFile()
+{
+	delete [] m_pszBuffer;
+}
+
+void CRCFile::ReadRC(PCTSTR pszFilename)
+{
+	// read file
+	CRCFile::ReadFile(pszFilename, m_vInRCFile, false);
+
+	// and process it
+	ProcessRCFile();
+}
+
+void CRCFile::ReadResourceIDs(PCTSTR pszFile)
+{
+	std::vector<CString> vLines;
+	CRCFile::ReadFile(pszFile, vLines, false);
+
+	long lLineNo = 0;
+	CString str, str2;
+	for(std::vector<CString>::iterator itLine = vLines.begin(); itLine != vLines.end(); ++itLine)
+	{
+		str = (*itLine);
+		str.TrimLeft(_T(" \t"));
+		if (str.Left(7) == _T("#define"))
+		{
+			str=str.Mid(8);
+			int iPos=str.FindOneOf(_T(" \t"));
+			str2=str.Left(iPos);
+			str=str.Mid(iPos);
+			str.TrimLeft(_T(" \t"));
+			str.TrimRight(_T(" \t\r\n"));
+
+			int iID;
+			if(str.Find(_T("x")) != -1)
+			{
+				// hex2dec
+				if(_stscanf(str, _T("%lx"), &iID) != 1)
+					THROW(icpf::exception::format(TSTRFMT _T("(%ld) : Error: Cannot parse hex number in line:\n") TSTRFMT, pszFile, lLineNo, m_pszBuffer), 0, 0, 0);
+			}
+			else
+				iID=_ttoi(str);
+
+			m_mapNameToID.insert(std::map<CString, UINT>::value_type(str2, iID));
+		}
+
+		++lLineNo;
+	}
+}
+
+void CRCFile::WriteRC(PCTSTR pszFilename)
+{
+	CRCFile::WriteFile(pszFilename, m_vOutRCFile, false);
+}
+
+void CRCFile::WriteLang(PCTSTR pszFilename, PCTSTR pszHeaderFile)
+{
+	// write header file to the output file
+	std::vector<CString> vData;
+	CRCFile::ReadFile(pszHeaderFile, vData, true);
+
+	// append the translation
+	CString str;
+	for(group_map::iterator itGroup = m_mapOutputLanguage.begin(); itGroup != m_mapOutputLanguage.end(); ++itGroup)
+	{
+		// write section header
+		AddTranslationLine(eLine_Group, (*itGroup).first, NULL, vData);
+
+		// and key=value assignment
+		element_map& rElementMap = (*itGroup).second;
+		for(element_map::iterator itElement = rElementMap.begin(); itElement != rElementMap.end(); ++itElement)
+		{
+			AddTranslationLine(eLine_Translation, (*itElement).first, (*itElement).second, vData);
+		}
+	}
+
+	CRCFile::WriteFile(pszFilename, vData, true);
+}
+
+void CRCFile::Clear()
+{
+	m_vInRCFile.clear();
+	m_vOutRCFile.clear();
+	m_mapNameToID.clear();
+	m_mapOutputLanguage.clear();
+
+	AddInitialValues();
+}
+
+void CRCFile::AddInitialValues()
+{
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDOK")), 1));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDCANCEL")), 2));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDABORT")), 3));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDRETRY")), 4));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDIGNORE")), 5));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDYES")), 6));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDNO")), 7));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDCLOSE")), 8));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDHELP")), 9));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDTRYAGAIN")), 10));
+	m_mapNameToID.insert(std::map<CString, UINT>::value_type(CString(_T("IDCONTINUE")), 11));
+}
+
+int CRCFile::GetCommasCount(const CString& str)
+{
+	int cnt=0;
+	bool bInside=false;
+	for (int i=0;i<str.GetLength();i++)
+	{
+		if (str[i] == _T('\"'))
+			bInside=!bInside;
+
+		if (!bInside && str[i] == _T(','))
+			cnt++;
+	}
+
+	return cnt;
+}
+
+void CRCFile::AddTranslationLine(ELineType eLineType, UINT uiID, PCTSTR pszText, std::vector<CString>& vLines)
+{
+	switch(eLineType)
+	{
+	case eLine_Group:
+		{
+			CString str;
+			str.Format(_T("[") UIFMT _T("]"), uiID);
+			vLines.push_back(_T(""));
+			vLines.push_back(str);
+			break;
+		}
+	case eLine_Translation:
+		{
+			if(!pszText)
+				THROW(_T("Error: Invalid string."), 0, 0, 0);
+			if(pszText[0] != _T('\0'))
+			{
+				CString str;
+				str.Format(UIFMT _T("[") UIXFMT _T("]=") TSTRFMT, uiID, icpf::crc32((const byte_t*)pszText, _tcslen(pszText)*sizeof(TCHAR)), pszText);
+				vLines.push_back(str);
+			}
+			break;
+		}
+	default:
+		{
+			_ASSERTE(FALSE);
+			THROW(_T("Error: Unknown line type."), 0, 0, 0);
+		}
+	}
+}
+
+void CRCFile::ReadFile(PCTSTR pszFile, std::vector<CString>& rLines, bool bUnicode)
+{
+	// load file
+	FILE* pFile = _tfopen(pszFile, bUnicode ? _T("rb") : _T("rt"));
+	if(!pFile)
+		THROW(icpf::exception::format(_T("Error: Cannot open file: ") TSTRFMT, pszFile), 0, errno, 0);
+
+	CString str;
+	while(_fgetts(str.GetBufferSetLength(MAX_LINE), MAX_LINE, pFile))
+	{
+		str.ReleaseBuffer();
+		str.TrimRight(_T("\r\n"));
+		rLines.push_back(str);
+	}
+	str.ReleaseBuffer();
+
+	fclose(pFile);
+}
+
+void CRCFile::WriteFile(PCTSTR pszFile, const std::vector<CString>& rLines, bool bUnicode)
+{
+	FILE* pFile = _tfopen(pszFile, bUnicode ? _T("wb") : _T("wt"));
+	if(!pFile)
+		THROW(icpf::exception::format(_T("Error: Cannot open file: ") TSTRFMT _T(" for writing."), pszFile), 0, errno, 0);
+
+	for (std::vector<CString>::const_iterator it=rLines.begin();it != rLines.end();it++)
+	{
+		CString str = (*it);
+		str += _T("\r\n");
+		if(_fputts((PCTSTR)str, pFile) < 0)
+			THROW(icpf::exception::format(_T("Cannot write data to file ") TSTRFMT, pszFile), 0, errno, 0);
+	}
+
+	fclose(pFile);
+}
+
+void CRCFile::ProcessMenu(UINT uiMenuID, std::vector<CString>::iterator *init)
+{
+	element_map* pElementMap = GetElementMap(uiMenuID);
+	if(!pElementMap)
+		return;
+
+	CString str;
+	for (;(*init) != m_vInRCFile.end();(*init)++)
+	{
+		str=**init;
+		str.TrimLeft(_T(" "));
+		str.TrimRight(_T(" "));
+
+		// check for exit
+		if ( str == _T("END") )
+		{
+			// add the line to the outrc wo changes
+			m_vOutRCFile.push_back(**init);
+			return;
+		}
+		else if (str.Left(5) == _T("POPUP")) // if that is the popup string - call the function once more
+		{
+			// add the line to the outrc with changes - replace string inside "" with P
+			str=**init;
+
+			// processing menuitem - find the text
+			int iPos=str.Find(_T("\""), 0);
+			CString strText;
+			if (iPos != -1)
+			{
+				strText=str.Mid(iPos+1);
+				int iPos2=strText.Find(_T("\""));
+				if (iPos2 != -1)
+					strText=strText.Left(iPos2);
+			}
+
+			// now find the | that separates the text from the pseudo-ID
+			int iBar=strText.ReverseFind(_T('|'));
+			if (iBar != -1)
+			{
+				// there is a text with an ID
+				CString strID=strText.Mid(iBar+1);
+				strText=strText.Left(iBar);
+
+				// put the id and text in the translation file
+				// find the equiv for the id
+				UINT uiID = GetResourceID(strID);
+				pElementMap->insert(std::make_pair(uiID, strText));
+
+				// put the found ID as output text
+				CString out;
+				out.Format(_T("\"%lu\""), uiID);
+				str=str.Left(iPos)+out;
+			}
+			else
+			{
+				// no pseudoID in menu name
+				str=str.Left(iPos)+_T("\"P\"");
+			}
+
+			m_vOutRCFile.push_back(str);
+
+			(*init)++;
+			ProcessMenu(uiMenuID, init);
+		}
+		else
+		{
+			// if the line has MENUITEM
+			if (str.Left(8) == _T("MENUITEM") && str.Right(9) != _T("SEPARATOR"))
+			{
+				// restore original
+				str=**init;
+
+				// check if there is any text after the comma
+				int iPos=str.Find(_T(","), 0);
+				CString strTest=str.Mid(iPos);
+				strTest.TrimLeft(_T(" ,\t\r\n"));
+				if (strTest.IsEmpty())
+				{
+					(*init)++;
+
+					CString tmp=**init;
+					tmp.Trim(_T(" ,\t\r\n"));
+					str+=tmp;
+				}
+
+				// processing menuitem - find the text
+				iPos=str.Find(_T("\""), 0);
+				CString strText;
+				if (iPos != -1)
+				{
+					strText=str.Mid(iPos+1);
+					int iPos2=strText.Find(_T("\""));
+					if (iPos2 != -1)
+						strText=strText.Left(iPos2);
+				}
+
+				// find the ID
+				iPos=str.Find(_T(","), 0);
+				CString strID;
+				if (iPos != -1)
+				{
+					strID=str.Mid(iPos+1);
+					int iPos2=strID.Find(_T(","), 0);
+					if (iPos2 != -1)
+						strID=strID.Left(iPos2);
+				}
+				strID.TrimLeft(_T(" \t"));
+				strID.TrimRight(_T(" \t"));
+
+				// find the equiv for the id
+				UINT uiID = GetResourceID(strID);
+				pElementMap->insert(std::make_pair(uiID, strText));
+				CString out = str;
+				//				out=**init;
+				out.Replace(_T("\"")+strText+_T("\""), _T("\"i\""));
+				m_vOutRCFile.push_back(out);
+			}
+			else
+				m_vOutRCFile.push_back(**init);
+		}
+	}
+}
+
+void CRCFile::ProcessDialog(UINT uiDialogID, std::vector<CString>::iterator *init)
+{
+	element_map* pElementMap = GetElementMap(uiDialogID);
+	if(!pElementMap)
+		return;
+
+	CString str;
+	for (;(*init) != m_vInRCFile.end();(*init)++)
+	{
+		str=**init;
+		str.TrimLeft(_T(" "));
+		str.TrimRight(_T(" "));
+
+		// check for exit
+		if ( str == _T("END") )
+		{
+			// add the line to the outrc wo changes
+			m_vOutRCFile.push_back(**init);
+			return;
+		}
+		else if ( str.Left(7) == _T("CAPTION") )
+		{
+			// read the caption
+			CString strText=str.Mid(7);
+			strText.TrimLeft(_T(" \t\""));
+			strText.TrimRight(_T(" \t\""));
+
+			pElementMap->insert(std::make_pair(0, strText));
+
+			// save to rc wo title
+			str=**init;
+			str.Replace(_T("\"")+strText+_T("\""), _T("\"\""));
+			m_vOutRCFile.push_back(str);
+		}
+		else if ( str.Left(5) == _T("LTEXT") || str.Left(5) == _T("CTEXT") || str.Left(5) == _T("RTEXT") || str.Left(13) == _T("DEFPUSHBUTTON") || str.Left(10) == _T("PUSHBUTTON") || str.Left(7) == _T("CONTROL") || str.Left(8) == _T("GROUPBOX") )
+		{
+			// needed only 2 commas (outside the '\"')
+			if ( GetCommasCount(str) < 3 )
+				str+=*((*init)+1);
+
+			// the first thing after LTEXT(and other) is the caption
+			CString strText;
+			bool bControl = false;
+
+			if (str.Left(5) == _T("LTEXT") || str.Left(5) == _T("CTEXT") || str.Left(5) == _T("RTEXT"))
+				str=str.Mid(5);
+			else if (str.Left(13) == _T("DEFPUSHBUTTON"))
+				str=str.Mid(13);
+			else if (str.Left(10) == _T("PUSHBUTTON"))
+				str=str.Mid(10);
+			else if (str.Left(7) == _T("CONTROL"))
+			{
+				bControl = true;
+				str=str.Mid(7);
+			}
+			else if (str.Left(8) == _T("GROUPBOX"))
+				str=str.Mid(8);
+
+			str=str.Mid(str.Find(_T("\""))+1);
+			int iPos=str.Find(_T("\""), 0);
+			if (iPos != -1)
+				strText=str.Left(iPos);
+			else
+				THROW(_T("Error: cannot find a comma in processed text"), 0, 0, 0);
+
+			str = str.Mid(iPos+1);
+
+			// after the first comma there is an ID
+			iPos=str.Find(_T(","), 0);
+			CString strID;
+			if (iPos != -1)
+			{
+				str=str.Mid(iPos+1);
+				iPos=str.Find(_T(","), 0);
+				if (iPos != -1)
+					strID=str.Left(iPos);
+				else
+					THROW(_T("Error: cannot find a comma in processed text"), 0, 0, 0);
+
+				strID.TrimLeft(_T(" \t"));
+				strID.TrimRight(_T(" \t"));
+			}
+			else
+				THROW(_T("Error: cannot find a comma in processed text"), 0, 0, 0);
+
+			bool bSkip = false;
+			if(bControl)
+			{
+				str = str.Mid(iPos+1);
+				iPos = str.Find(_T(","), 0);
+				if(iPos == -1)
+					THROW(_T("Error: cannot find a comma in processed text"), 0, 0, 0);
+
+				CString strType = str.Left(iPos);
+				strType.Trim(_T("\""));
+				if(strType == _T("SysListView32") || strType == _T("msctls_progress32") ||
+					strType == _T("ComboBoxEx32") || strType == _T("msctls_updown32") ||
+					strType == _T("SysDateTimePick32"))
+				{
+					bSkip = true;
+				}
+			}
+
+			if(!bSkip)
+			{
+				// find id
+				UINT uiID = GetResourceID(strID);
+				CString out;
+				pElementMap->insert(std::make_pair(uiID, strText));
+			}
+
+			// now add the data to output rc
+			str=**init;
+			str.Replace(_T("\"")+strText+_T("\""), _T("\"\""));
+
+			m_vOutRCFile.push_back(str);
+		}
+		else
+			m_vOutRCFile.push_back(**init);
+	}
+}
+
+void CRCFile::ProcessStringTable(UINT uiStringGroupID, std::vector<CString>::iterator *init)
+{
+	element_map* pElementMap = GetElementMap(uiStringGroupID);
+	if(!pElementMap)
+		return;
+
+	CString str;
+	for (;(*init) != m_vInRCFile.end();(*init)++)
+	{
+		str=**init;
+		str.TrimLeft(_T(" "));
+		str.TrimRight(_T(" "));
+
+		if ( str == _T("END") )
+			return;
+		else if ( str != _T("BEGIN") )
+		{
+			// the first stuff is ID, the second is text
+			int iPos=str.Find(_T("\""), 0);
+			if (iPos == -1)
+			{
+				(*init)++;
+				str+=**init;
+				iPos=str.Find(_T("\""), 0);
+			}
+
+			if (iPos != -1)
+			{
+				CString strID=str.Left(iPos);
+				strID.TrimRight(_T(" \"\t\n\r"));
+
+				CString strText=str.Mid(iPos+1);
+				strText.Replace(_T("\"\""), _T("\""));
+				strText=strText.Left(strText.ReverseFind(_T('\"')));
+
+				UINT uiID = GetResourceID(strID);
+				pElementMap->insert(std::make_pair(uiID, strText));
+
+				str=**init;
+				str.Replace(_T("\"")+strText+_T("\""), _T("\"\""));
+			}
+		}
+	}
+}
+
+bool CRCFile::ProcessRCFile()
+{
+	int iPos;
+	CString strData;
+	std::vector<CString> vStrTable;
+	for (std::vector<CString>::iterator it=m_vInRCFile.begin();it != m_vInRCFile.end();it++)
+	{
+		if ( (iPos=it->Find(_T(" MENU "))) != -1 )
+		{
+			// add the line to the output rc with no change
+			m_vOutRCFile.push_back(*it);
+
+			UINT uiID = GetResourceID(it->Left(iPos));
+
+			// begin enumerating items
+			it++;
+
+			// process the menu
+			ProcessMenu(uiID, &it);
+		}
+		else if ( (iPos=it->Find(_T(" DIALOGEX "))) != -1)
+		{
+			// add the line to the output rc with no change
+			m_vOutRCFile.push_back(*it);
+
+			UINT uiID = GetResourceID(it->Left(iPos));
+			// begin processing dialog template
+			it++;
+			ProcessDialog(uiID, &it);
+		}
+		else if ( (iPos=it->Find(_T("STRINGTABLE "))) != -1)
+		{
+			// begin of the string table
+			it++;
+			ProcessStringTable(0, &it);
+		}
+		else
+			m_vOutRCFile.push_back(*it);
+	}
+
+	return true;
+}
+
+CRCFile::element_map* CRCFile::GetElementMap(UINT uiGroup)
+{
+	// insert menu if does not exist
+	element_map* pElementMap = NULL;
+	group_map::iterator itGroup = m_mapOutputLanguage.find(uiGroup);
+	if(itGroup == m_mapOutputLanguage.end())
+	{
+		std::pair<group_map::iterator, bool> pairGroup = m_mapOutputLanguage.insert(std::make_pair(uiGroup, element_map()));
+		if(!pairGroup.second)
+		{
+			_ASSERTE(false);
+			return NULL;
+		}
+
+		pElementMap = &(*(pairGroup.first)).second;
+	}
+	else
+		pElementMap = &((*itGroup).second);
+
+	if(!pElementMap)
+	{
+		_ASSERTE(false);
+		return NULL;
+	}
+
+	return pElementMap;
+}
+
+UINT CRCFile::GetResourceID(PCTSTR pszID)
+{
+	std::map<CString, UINT>::iterator mit = m_mapNameToID.find(pszID);
+	if (mit != m_mapNameToID.end())
+		return (*mit).second;
+	else
+	{
+		_ASSERTE(false);
+		THROW(icpf::exception::format(_T("Error: Cannot find resource identifier ") TSTRFMT, pszID), 0, 0, 0);
+	}
+}
Index: src/rc2lng/rc.h
===================================================================
diff -u
--- src/rc2lng/rc.h	(revision 0)
+++ src/rc2lng/rc.h	(revision 2f3512c2df187a16a62c131d69bcddc06d671ed7)
@@ -0,0 +1,56 @@
+#ifndef __RC_H__
+#define __RC_H__
+
+class CRCFile
+{
+private:
+	typedef std::map<UINT, CString> element_map;
+	typedef std::map<UINT, element_map> group_map;
+
+	enum ELineType
+	{
+		eLine_Group,
+		eLine_Translation
+	};
+public:
+	CRCFile();
+	~CRCFile();
+
+	void ReadRC(PCTSTR pszFilename);
+	void ReadResourceIDs(PCTSTR pszFilename);
+
+	void WriteRC(PCTSTR pszFilename);
+	void WriteLang(PCTSTR pszFilename, PCTSTR pszHeaderFile);
+
+	void Clear();
+
+protected:
+	// Adds initial values to the maps
+	void AddInitialValues();
+
+	static int GetCommasCount(const CString& str);
+
+	static void WriteFile(PCTSTR pszFile, const std::vector<CString>& rLines, bool bUnicode);
+	static void ReadFile(PCTSTR pszFile, std::vector<CString>& rLines, bool bUnicode);
+
+	void AddTranslationLine(ELineType eLineType, UINT uiID, PCTSTR pszText, std::vector<CString>& vLines);
+
+	bool ProcessRCFile();
+	void ProcessMenu(UINT uiMenuID, std::vector<CString>::iterator *init);
+	void ProcessDialog(UINT uiDialogID, std::vector<CString>::iterator *init);
+	void ProcessStringTable(UINT uiStringGroupID, std::vector<CString>::iterator *init);
+
+	element_map* GetElementMap(UINT uiGroup);
+	UINT GetResourceID(PCTSTR pszID);
+
+protected:
+	std::map<CString, UINT> m_mapNameToID;		// resource name to resource id
+	std::vector<CString> m_vInRCFile;			// lines from rc file
+	std::vector<CString> m_vOutRCFile;			// lines to write to rc file
+
+	group_map m_mapOutputLanguage;	// section_id->element_id->string
+//	std::vector<CString> m_vOutputLanguage;		// lines of the language file to be written
+	TCHAR* m_pszBuffer;
+};
+
+#endif
Index: src/rc2lng/rc2lng.cpp
===================================================================
diff -u -rbee51aca3d5d9b67ecac4f528a3203738cc63455 -r2f3512c2df187a16a62c131d69bcddc06d671ed7
--- src/rc2lng/rc2lng.cpp	(.../rc2lng.cpp)	(revision bee51aca3d5d9b67ecac4f528a3203738cc63455)
+++ src/rc2lng/rc2lng.cpp	(.../rc2lng.cpp)	(revision 2f3512c2df187a16a62c131d69bcddc06d671ed7)
@@ -1,9 +1,11 @@
-// CHExe2Lng.cpp : Defines the entry point for the console application.
+// rc2lng.cpp : Defines the entry point for the console application.
 //
 
 #include "stdafx.h"
 #include "rc2lng.h"
 #include "conio.h"
+#include "rc.h"
+#include "../libicpf/exception.h"
 
 #pragma warning(disable : 4786)
 
@@ -13,650 +15,44 @@
 static char THIS_FILE[] = __FILE__;
 #endif
 
-CWinApp theApp;
-
-int GetCommasCount(const CString& str)
+int _tmain(int argc, TCHAR* argv[], TCHAR* /*envp*/[])
 {
-	int cnt=0;
-	bool bInside=false;
-	for (int i=0;i<str.GetLength();i++)
-	{
-		if (str[i] == '\"')
-			bInside=!bInside;
-
-		if (!bInside && str[i] == ',')
-			cnt++;
-	}
-
-	return cnt;
-}
-
-bool ReadResourceIDs(PCTSTR pszFile, map<CString, UINT>* pIDs)
-{
-	try
-	{
-		CFile file(pszFile, CFile::modeRead);
-		CArchive ar(&file, CArchive::load);
-		CString str, str2;
-		while(ar.ReadString(str))
-		{
-			if (str.Left(7) == _T("#define"))
-			{
-				str=str.Mid(8);
-				int iPos=str.FindOneOf(" \t");
-				str2=str.Left(iPos);
-				str=str.Mid(iPos);
-				str.TrimLeft(_T(" \t"));
-				str.TrimRight(_T(" \t\r\n"));
-
-				int iID;
-				if (str.Find("x") != -1)
-				{
-					// hex2dec
-					_stscanf(str, "%lx", &iID);
-				}
-				else
-					iID=_ttoi(str);
-				
-				pIDs->insert(map<CString, UINT>::value_type(str2, iID));
-			}
-		}
-		
-		ar.Close();
-		file.Close();
-
-		pIDs->insert(map<CString, UINT>::value_type(CString("IDOK"), 1));
-		pIDs->insert(map<CString, UINT>::value_type(CString("IDCANCEL"), 2));
-	}
-	catch(...)
-	{
-		return false;
-	}
-
-/*	map<CString, UINT>::iterator it=pIDs->begin();
-	while (it != pIDs->end())
-	{
-		cout<<(PCTSTR)(CString)(it->first)<<" = "<<(UINT)(it->second)<<endl;
-		it++;
-	}*/
-
-	return true;
-}
-
-bool UpdateLngHeader(PCTSTR pszFile, vector<CString>* pvData)
-{
-	try
-	{
-		CFile file(pszFile, CFile::modeRead);
-		CArchive ar(&file, CArchive::load);
-		
-		CString str;
-		while (ar.ReadString(str))
-			pvData->push_back(str);
-		
-		ar.Close();
-		file.Close();
-	}
-	catch(...)
-	{
-		return false;
-	}
-	return true;
-}
-
-bool ReadRCFile(PCTSTR pszFile, vector<CString> *pv)
-{
-	try
-	{
-		CFile file(pszFile, CFile::modeRead);
-		CArchive ar(&file, CArchive::load);
-		
-		CString str;
-		while (ar.ReadString(str))
-			pv->push_back(str);
-		
-		ar.Close();
-		file.Close();
-	}
-	catch(...)
-	{
-		return false;
-	}
-	return true;
-}
-
-void ProcessMenu(vector<CString>* pinrc, vector<CString>::iterator *init, map<CString, UINT>* pids, vector<CString>* poutrc, vector<CString>* pol)
-{
-	CString str;
-	map<CString, UINT>::iterator mit;
-	for (;(*init) != pinrc->end();(*init)++)
-	{
-		str=**init;
-		str.TrimLeft(" ");
-		str.TrimRight(" ");
-
-		// check for exit
-		if ( str == "END" )
-		{
-			// add the line to the outrc wo changes
-			poutrc->push_back(**init);
-			return;
-		}
-		else if (str.Left(5) == "POPUP") // if that is the popup string - call the function once more
-		{
-			// add the line to the outrc with changes - replace string inside "" with P
-			str=**init;
-
-			// processing menuitem - find the text
-			int iPos=str.Find("\"", 0);
-			CString strText;
-			if (iPos != -1)
-			{
-				strText=str.Mid(iPos+1);
-				int iPos2=strText.Find("\"");
-				if (iPos2 != -1)
-					strText=strText.Left(iPos2);
-			}
-
-			// now find the | that separates the text from the pseudo-ID
-			int iBar=strText.ReverseFind(_T('|'));
-			if (iBar != -1)
-			{
-				// there is a text with an ID
-				CString strID=strText.Mid(iBar+1);
-				strText=strText.Left(iBar);
-
-				// put the id and text in the translation file
-				// find the equiv for the id
-				mit=pids->find(strID);
-				CString out;
-				if (mit != pids->end())
-				{
-					out.Format("%lu=%s", mit->second, strText);
-					pol->push_back(out);
-
-					// put the found ID as output text
-					out.Format("\"%lu\"", mit->second);
-					str=str.Left(iPos)+out;
-				}
-				else
-				{
-					out.Format("%s=%s", strID, strText);
-					pol->push_back(out);
-
-					// put the ID as output text
-					str=str.Left(iPos)+"\""+strID+"\"";
-				}
-			}
-			else
-			{
-				// no ID
-				str=str.Left(iPos)+"\"P\"";
-			}
-
-			poutrc->push_back(str);
-
-			(*init)++;
-			ProcessMenu(pinrc, init, pids, poutrc, pol);
-		}
-		else
-		{
-			// if the line has MENUITEM
-			if (str.Left(8) == "MENUITEM" && str.Right(9) != "SEPARATOR")
-			{
-				// restore original
-				str=**init;
-
-				// check if there is any text after the comma
-				int iPos=str.Find(",", 0);
-				CString strTest=str.Mid(iPos);
-				strTest.TrimLeft(" ,\t\r\n");
-				if (strTest.IsEmpty())
-				{
-					(*init)++;
-
-					CString tmp=**init;
-					tmp.Trim(" ,\t\r\n");
-					str+=tmp;
-				}
-
-				// processing menuitem - find the text
-				iPos=str.Find("\"", 0);
-				CString strText;
-				if (iPos != -1)
-				{
-					strText=str.Mid(iPos+1);
-					int iPos2=strText.Find("\"");
-					if (iPos2 != -1)
-						strText=strText.Left(iPos2);
-				}
-
-				// find the ID
-				iPos=str.Find(",", 0);
-				CString strID;
-				if (iPos != -1)
-				{
-					strID=str.Mid(iPos+1);
-					int iPos2=strID.Find(",", 0);
-					if (iPos2 != -1)
-						strID=strID.Left(iPos2);
-				}
-				strID.TrimLeft(" \t");
-				strID.TrimRight(" \t");
-
-				// find the equiv for the id
-				mit=pids->find(strID);
-				CString out;
-				if (mit != pids->end())
-				{
-					out.Format("%lu=%s", mit->second, strText);
-					pol->push_back(out);
-				}
-				else
-				{
-					out.Format("%s=%s", strID, strText);
-					pol->push_back(out);
-				}
-//				AfxMessageBox(str);
-				out=str;
-//				out=**init;
-				out.Replace("\""+strText+"\"", "\"i\"");
-				poutrc->push_back(out);
-			}
-			else
-				poutrc->push_back(**init);
-		}
-	}
-}
-
-void ProcessDialog(vector<CString>* pinrc, vector<CString>::iterator *init, map<CString, UINT>* pids, vector<CString>* poutrc, vector<CString>* pol)
-{
-	CString str;
-	map<CString, UINT>::iterator mit;
-	for (;(*init) != pinrc->end();(*init)++)
-	{
-		str=**init;
-		str.TrimLeft(" ");
-		str.TrimRight(" ");
-
-		// check for exit
-		if ( str == "END" )
-		{
-			// add the line to the outrc wo changes
-			poutrc->push_back(**init);
-			return;
-		}
-		else if ( str.Left(7) == "CAPTION" )
-		{
-			// read the caption
-			CString strText=str.Mid(7);
-			strText.TrimLeft(" \t\"");
-			strText.TrimRight(" \t\"");
-
-			pol->push_back("0="+strText);
-
-			// save to rc wo title
-			str=**init;
-			str.Replace("\""+strText+"\"", "\"\"");
-			poutrc->push_back(str);
-		}
-		else if ( str.Left(5) == "LTEXT" || str.Left(5) == "CTEXT" || str.Left(5) == "RTEXT" || str.Left(13) == "DEFPUSHBUTTON" || str.Left(10) == "PUSHBUTTON" || str.Left(7) == "CONTROL" || str.Left(8) == "GROUPBOX" )
-		{
-			// needed only 2 commas (outside the '\"')
-			if ( GetCommasCount(str) < 2 )
-				str+=*((*init)+1);
-
-			// the first thing after LTEXT(and other) is the caption
-			CString strText;
-			
-			if (str.Left(5) == "LTEXT" || str.Left(5) == "CTEXT" || str.Left(5) == "RTEXT")
-				strText=str.Mid(5);
-			else if (str.Left(13) == "DEFPUSHBUTTON")
-				strText=str.Mid(13);
-			else if (str.Left(10) == "PUSHBUTTON")
-				strText=str.Mid(10);
-			else if (str.Left(7) == "CONTROL")
-				strText=str.Mid(7);
-			else if (str.Left(8) == "GROUPBOX")
-				strText=str.Mid(8);
-
-			strText=strText.Mid(strText.Find("\"")+1);
-			int iPos=strText.Find("\"", 0);
-			if (iPos != -1)
-				strText=strText.Left(iPos);
-
-			// after the first comma there is an ID
-			iPos=str.Find(",", 0);
-			CString strID;
-			if (iPos != -1)
-			{
-				strID=str.Mid(iPos+1);
-				iPos=strID.Find(",", 0);
-				if (iPos != -1)
-					strID=strID.Left(iPos);
-				strID.TrimLeft(" \t");
-				strID.TrimRight(" \t");
-			}
-
-			// find id
-			mit=pids->find( strID );
-			CString out;
-			if (mit != pids->end())
-			{
-				// id found
-				if (mit->second != 0)
-				{
-					out.Format("%lu=%s", mit->second, strText);
-					pol->push_back(out);
-				}
-			}
-			else
-			{
-				out.Format("%s=%s", strID, strText);
-				pol->push_back(out);
-			}
-
-			// now add the data to rc
-			str=**init;
-			str.Replace("\""+strText+"\"", "\"\"");
-
-			poutrc->push_back(str);
-		}
-		else
-		{
-			poutrc->push_back(**init);
-		}
-	}
-}
-
-void ProcessStringTable(vector<CString>* pinrc, vector<CString>::iterator *init, map<CString, UINT>* pids, vector<CString>* poutrc, vector<CString>* ptab)
-{
-	map<CString, UINT>::iterator mit;
-	CString str;
-	for (;(*init) != pinrc->end();(*init)++)
-	{
-		str=**init;
-		str.TrimLeft(" ");
-		str.TrimRight(" ");
-
-		if ( str == "END" )
-			return;
-		else if ( str != "BEGIN" )
-		{
-			// the first stuff is ID, the second is text
-			int iPos=str.Find("\"", 0);
-			if (iPos == -1)
-			{
-				(*init)++;
-				str+=**init;
-				iPos=str.Find("\"", 0);
-			}
-
-			if (iPos != -1)
-			{
-				CString strID=str.Left(iPos);
-				strID.TrimRight(" \"\t\n\r");
-
-				CString strText=str.Mid(iPos+1);
-				strText.Replace("\"\"", "\"");
-
-				strText=strText.Left(strText.ReverseFind('\"'));
-
-				mit=pids->find(strID);
-				CString out;
-				if (mit!= pids->end())
-					out.Format("%lu=%s", mit->second, strText);
-				else
-					out.Format("%lu=%s", strID, strText);
-				ptab->push_back(out);
-				str=**init;
-				str.Replace("\""+strText+"\"", "\"\"");
-			}
-		}
-	}
-}
-CString ProcessLine(PCTSTR psz)
-{
-	CString str=psz;
-	str.Replace("\r", "\\r");
-	str.Replace("\n", "\\n");
-	str.Replace("\t", "\\t");
-
-	return str;
-}
-
-bool ProcessRCFile(PCTSTR pszRCPath, vector<CString>* pinrc, map<CString, UINT>* pids, vector<CString>* poutrc, vector<CString>* pol)
-{
-	int iPos;
-	map<CString, UINT>::iterator mit;
-	CString strData;
-	vector<CString> vStrTable;
-	for (vector<CString>::iterator it=pinrc->begin();it != pinrc->end();it++)
-	{
-		if ( (iPos=it->Find(" MENU ")) != -1 )
-		{
-			// retrieve the identifier and add it to the outlng
-			mit=pids->find( it->Left(iPos) );
-			if (mit != pids->end())
-				strData.Format("\r\n# Menu - %s\r\n[%lu]", it->Left(iPos), mit->second);
-			else
-				strData.Format("\r\n# Menu - %s\r\n[%s]", it->Left(iPos), it->Left(iPos));
-
-			pol->push_back(strData);
-
-			// add the line to the output rc with no change
-			poutrc->push_back(*it);
-
-			// begin enumerating items
-			it++;
-			ProcessMenu(pinrc, &it, pids, poutrc, pol);
-		}
-		else if ( (iPos=it->Find(" DIALOGEX ")) != -1)
-		{
-			// find the ID of a dialog box
-			mit=pids->find( it->Left(iPos) );
-			if (mit != pids->end())
-				strData.Format("\r\n# Dialog box - %s\r\n[%lu]", it->Left(iPos), mit->second);
-			else
-				strData.Format("\r\n# Dialog box - %s\r\n[%s]", it->Left(iPos), it->Left(iPos));
-
-			pol->push_back(strData);
-
-			// add the line to the output rc with no change
-			poutrc->push_back(*it);
-
-			// begin processing dialog template
-			it++;
-			ProcessDialog(pinrc, &it, pids, poutrc, pol);
-		}
-		else if ( (iPos=it->Find("STRINGTABLE ")) != -1)
-		{
-			// begin of the string table
-			it++;
-			ProcessStringTable(pinrc, &it, pids, poutrc, &vStrTable);
-		}
-		else if ( (iPos=it->Find(" 25 ")) != -1)
-		{	//pszRCPath
-			CString strID=it->Left(iPos);
-			strID.TrimLeft(" \t\n\r\"");
-			strID.TrimRight(" \t\n\r\"");
-
-			// file name
-			iPos=it->Find("\"");
-			CString strName=it->Mid(iPos+1);
-			strName.TrimRight(" \t\n\r\"");
-			strName.Replace("\\\\", "\\");
-
-			// concat the path
-			CString strPath=pszRCPath;
-			strPath=strPath.Left(strPath.ReverseFind('\\')+1);
-
-			// read the file
-			TCHAR szData[16384];
-			CFile file(strPath+strName, CFile::modeRead);
-			file.Read(szData, 16384);
-			file.Close();
-			CString out=ProcessLine(szData);
-			
-			// add to lang
-			mit=pids->find(strID);
-			CString strLng;
-			if (mit!=pids->end())
-				strLng.Format("%lu=%s", mit->second, out);
-			else
-				strLng.Format("%s=%s", strID, out);
-			vStrTable.push_back(strLng);
-		}
-		else
-		{
-			poutrc->push_back(*it);
-		}
-	}
-
-	if (vStrTable.size() > 0)
-	{
-		// write header
-		pol->push_back(CString("\r\n# String table\r\n[0]"));
-
-		// copy data to the out lng
-		for (vector<CString>::iterator it=vStrTable.begin();it!=vStrTable.end();it++)
-			pol->push_back(*it);
-	}
-
-	return true;
-}
-
-bool WriteFiles(vector<CString>* prc, PCTSTR pszRCFile, vector<CString>* plng, PCTSTR pszLngFile)
-{
-	vector<CString>::iterator it;
-	try
-	{
-		CFile file1(pszRCFile, CFile::modeWrite | CFile::modeCreate);
-		CArchive ar1(&file1, CArchive::store);
-
-		for (it=prc->begin();it != prc->end();it++)
-			ar1.WriteString((*it)+_T("\r\n"));
-
-		ar1.Close();
-		file1.Close();
-		
-		CFile file2(pszLngFile, CFile::modeWrite | CFile::modeCreate);
-		CArchive ar2(&file2, CArchive::store);
-		
-		for (it=plng->begin();it != plng->end();it++)
-			ar2.WriteString((*it)+_T("\r\n"));
-
-		ar2.Close();
-		file2.Close();
-	}
-	catch(...)
-	{
-		return false;
-	}
-	return true;
-}
-
-struct CmpStr : public binary_function <CString, CString, bool>
-{
-      bool operator() (const CString& _Left, const CString& _Right) const
-	  {
-		  CString l=_Left.Left(_Left.Find("="));
-		  CString r=_Right.Left(_Right.Find("="));
-
-		  return (_ttoi(l) <= _ttoi(r));
-	  }
-};
-
-void SortItems(vector<CString>* pv, int iHdrCnt)
-{
-	// find the begin and the end of section
-	vector<CString>::iterator st=pv->begin()+iHdrCnt, en;
-	while (st != pv->end())
-	{
-		for (;st != pv->end();st++)
-		{
-			// find section beginning
-			if (st->Left(3) == "\r\n#" && st->Find("\r\n[") != -1)
-			{
-				st++;
-				break;
-			}
-		}
-		if (st != pv->end())
-		{
-			en=st+1;
-			for (;en != pv->end();en++)
-			{
-				if (en->Left(3) == "\r\n#" && en->Find("\r\n[") != -1)
-					break;
-			}
-				
-			sort(st, en, CmpStr());
-			st=en;
-		}
-	}
-}
-
-int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
-{
 	// initialize MFC and print and error on failure
-	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
+	HMODULE hModule = ::GetModuleHandle(NULL);
+	if(!hModule)
+		return -1;
+	if (!AfxWinInit(hModule, NULL, ::GetCommandLine(), 0))
 	{
 		cerr << _T("Fatal Error: MFC initialization failed") << endl;
 		return 1;
 	}
 
-	// usage - chexe2lng infile.rc resource.h inheader.lng outfile.rc outfile.lng
+	// usage - rc2lng infile.rc resource.h inheader.lng outfile.rc outfile.lng
 	if (argc < 6)
 	{
-		cerr<<_T("Fatal Error: Incorrect numer of params") << endl;
-		cerr << _T("Usage: infile.rc inheader.lng outfile.rc outfile.lng resource.h resource2.h") << endl;
-		return 2;
+		wcerr << _T("Fatal Error: Incorrect numer of params") << endl;
+		wcerr << _T("Usage: infile.rc inheader.lng outfile.rc outfile.lng resource.h resource2.h") << endl;
+		return -1;
 	}
 
-	// open the resource.h file and interprete it
-	map<CString, UINT> mID;
-	for (int i=5;i<argc;i++)
+	CRCFile rcFile;
+
+	try
 	{
-		if (!ReadResourceIDs(argv[i], &mID))
+		for (int i=5;i<argc;i++)
 		{
-			cerr<<"Fatal Error: Cannot read file with resource ID's"<<endl;
-			return 3;
+			rcFile.ReadResourceIDs(argv[i]);
 		}
-	}
+		
+		rcFile.ReadRC(argv[1]);
 
-	// for out .lng - data
-	vector<CString> vOutLang;
-	if (!UpdateLngHeader(argv[2], &vOutLang))
-	{
-		cerr<<"Fatal Error: Cannot read lang header file"<<endl;
-		return 4;
+		rcFile.WriteRC(argv[3]);
+		rcFile.WriteLang(argv[4], argv[2]);
 	}
-	int iHeaderCount=vOutLang.size();
-
-	// out rc file data
-	vector<CString> vRCIn, vRCOut;
-	if (!ReadRCFile(argv[1], &vRCIn))
+	catch(icpf::exception& e)
 	{
-		cerr<<"Fatal Error: Cannot read source RC file"<<endl;
-		return 5;
+		wcerr << e.get_desc() << endl;
+		return -1;
 	}
-
-	if (!ProcessRCFile(argv[1], &vRCIn, &mID, &vRCOut, &vOutLang))
-	{
-		cerr<<"Fatal Error: Cannot process RC file"<<endl;
-		return 6;
-	}
-
-	SortItems(&vOutLang, iHeaderCount);
-
-	if (!WriteFiles(&vRCOut, argv[3], &vOutLang, argv[4]))
-	{
-		cerr<<"Fatal Error: Cannot write output files"<<endl;
-		return 7;
-	}
-
 	return 0;
 }
-
-
Index: src/rc2lng/rc2lng.vc90.vcproj
===================================================================
diff -u -rbee51aca3d5d9b67ecac4f528a3203738cc63455 -r2f3512c2df187a16a62c131d69bcddc06d671ed7
--- src/rc2lng/rc2lng.vc90.vcproj	(.../rc2lng.vc90.vcproj)	(revision bee51aca3d5d9b67ecac4f528a3203738cc63455)
+++ src/rc2lng/rc2lng.vc90.vcproj	(.../rc2lng.vc90.vcproj)	(revision 2f3512c2df187a16a62c131d69bcddc06d671ed7)
@@ -26,7 +26,7 @@
 			ConfigurationType="1"
 			UseOfMFC="2"
 			ATLMinimizesCRunTimeLibraryUsage="false"
-			CharacterSet="2"
+			CharacterSet="1"
 			>
 			<Tool
 				Name="VCPreBuildEventTool"
@@ -113,7 +113,7 @@
 			ConfigurationType="1"
 			UseOfMFC="2"
 			ATLMinimizesCRunTimeLibraryUsage="false"
-			CharacterSet="2"
+			CharacterSet="1"
 			>
 			<Tool
 				Name="VCPreBuildEventTool"
@@ -202,7 +202,7 @@
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
 			UseOfMFC="2"
 			ATLMinimizesCRunTimeLibraryUsage="false"
-			CharacterSet="2"
+			CharacterSet="1"
 			>
 			<Tool
 				Name="VCPreBuildEventTool"
@@ -291,7 +291,7 @@
 			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
 			UseOfMFC="2"
 			ATLMinimizesCRunTimeLibraryUsage="false"
-			CharacterSet="2"
+			CharacterSet="1"
 			>
 			<Tool
 				Name="VCPreBuildEventTool"
@@ -382,6 +382,10 @@
 			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
 			>
 			<File
+				RelativePath=".\rc.cpp"
+				>
+			</File>
+			<File
 				RelativePath="rc2lng.cpp"
 				>
 				<FileConfiguration
@@ -479,6 +483,10 @@
 			Filter="h;hpp;hxx;hm;inl"
 			>
 			<File
+				RelativePath=".\rc.h"
+				>
+			</File>
+			<File
 				RelativePath="rc2lng.h"
 				>
 			</File>