Ejemplo n.º 1
0
        OSEntry(const TempStringA &Line)
            : m_Valid(false)
        {
            SplitStrByFirstOfA keyAndValue(Line, ConstStringA("= \t"));
            if (!keyAndValue)
                return;

            m_Path = keyAndValue.left;

            for (size_t context = 0;;)
            {
                TempStringA token = FastStringRoutines::GetNextToken<false>(keyAndValue.right, &context);
                if (token.empty())
                    break;
                if (m_Description.empty())
                    m_Description = token;
                else
                {
                    if (token[0] != '/')
                        return;
                    SplitStrByFirstOfA keyAndVal(token.substr(1), ConstStringA("="));
                    if (keyAndVal)
                        m_Properties[keyAndVal.left] = keyAndVal.right;
                    else
                        m_Properties[token.substr(1)] = DynamicStringA();
                }
            }
            if (m_Description.empty())
                return;

            m_OriginalString = Line;
            m_Valid = true;
        }
Ejemplo n.º 2
0
bool LocalizableStringManager::ParseSourceFile( const BazisLib::String &fp )
{
	ManagedPointer<TextANSIFileReader> pRdr = new TextANSIFileReader(new ACFile(fp, FileModes::OpenReadOnly));
	if (!pRdr->Valid())
	{
		_tprintf(_T("ERROR: cannot open %s\n"), fp.c_str());
		return false;
	}
	_tprintf(_T("  %s\n"), Path::GetFileName(fp).c_str());

	bool insideCCommentBlock = false;
	bool insideStringConstant = false;

	unsigned lineNum = 0;

	DynamicString currentDialogID;

	while (!pRdr->IsEOF())
	{
		size_t LocalizationTokenStart = -1;
		enum
		{
			ltUnknown = 0,
			ltTR,
			ltDIALOG,
			ltDLGITEM,
		} localizationTokenType;

		lineNum++;
		DynamicStringA line = pRdr->ReadLine();

		if (line[0] == '#')
			break;
			
		unsigned backslashCount = 0;
		char prevChar = 0, ch = 0;

		size_t lastStringStart = -1, lastStringLen = 0;

		for (size_t i = 0; i < line.length(); i++, prevChar = ch)
		{
			//Even amount of backslashes followed by quotation mark toggles string constant flag (outside comment block)
			//The "/*" and "*/" sequences outside string block change the comment flag.
			//The "//" sequence skips everything till the end of the string
			//At the end of each line inside the string block there should be a backslash
			ch = line[i];

			bool isLastChar = (i == (line.length() - 1));

			if (insideCCommentBlock)
			{
				if ((ch == '/') && (prevChar == '*'))
					insideCCommentBlock = false;
			}
			else	//Outside comment block - detect string literals
			{
				if (ch == '\\')
					backslashCount++;
				else 
				{
					if (((ch == '\"') || (ch == '\'')) && !(backslashCount % 2))
					{
						if (!insideStringConstant)
							lastStringStart = i + 1, lastStringLen = 0;
						else
							lastStringLen = i - lastStringStart;

						insideStringConstant = !insideStringConstant;
					}
					backslashCount = 0;
				}

				if (!insideStringConstant)	//Outside comment and string blocks - check for comment start
				{
					if ((ch == '*') && (prevChar == '/'))
						insideCCommentBlock = true;
					if ((ch == '/') && (prevChar == '/'))
						break;
				}
				else	//Inside string block
				{
					if (isLastChar && (ch != '\\'))
					{
						_tprintf(_T("%s(%d) : error: Unterminated string"), GetFullPath(fp).c_str(), lineNum);
						return false;
					}
				}
			}

			//Here, both insideCCommentBlock and insideStringConstant reflect the real file context. So, let's find "_TR()" and LOCALIZE_DIALOG()/LOCALIZE_DLGITEM()
			if (!insideCCommentBlock && !insideStringConstant)
			{
				if (!IsValidCTokenChar(prevChar))
				{
					size_t newTokenStart = -1;
					size_t remaining = line.length() - i;
					if ((remaining > 4) && (line.substr(i, 3) == "_TR") && !IsValidCTokenChar(line[i + 3]))
						newTokenStart = i + 3, localizationTokenType = ltTR;
					else if ((remaining > 16) && (line.substr(i, 15) == "LOCALIZE_DIALOG") && !IsValidCTokenChar(line[i + 15]))
						newTokenStart = i + 15, localizationTokenType = ltDIALOG;
					else if ((remaining > 17) && (line.substr(i, 16) == "LOCALIZE_DLGITEM") && !IsValidCTokenChar(line[i + 16]))
						newTokenStart = i + 16, localizationTokenType = ltDLGITEM;

					if (newTokenStart != -1)
					{
						if (LocalizationTokenStart != -1)
						{
							_tprintf(_T("%s(%d) : error: Localization token used recursively"), GetFullPath(fp).c_str(), lineNum);
							return false;
						}
						LocalizationTokenStart = newTokenStart;
						
						lastStringStart = -1;
						lastStringLen = 0;
					}

				}
				if (ch == '}')
					currentDialogID.clear();

				if ((ch == ')') && (LocalizationTokenStart != -1))
				{
					size_t tokenParamsStart = line.find_first_not_of(" \t()", LocalizationTokenStart);
					TempStringA tokenParams = line.substr(tokenParamsStart, i - LocalizationTokenStart);
					if (tokenParams.empty())
					{
						_tprintf(_T("%s(%d) : error: Empty localization macro"), GetFullPath(fp).c_str(), lineNum);
						return false;
					}
					if (localizationTokenType == ltTR)
					{
						if ((lastStringStart == -1) || !lastStringLen)
						{
							_tprintf(_T("%s(%d) : error: Invalid _TR() statement - default string not found"), GetFullPath(fp).c_str(), lineNum);
							return false;
						}
						DynamicString lastString = ANSIStringToString(line.substr(lastStringStart, lastStringLen));

						size_t idEnd = tokenParams.find_first_of(" ,");
						DynamicString id = ANSIStringToString(tokenParams.substr(0, (idEnd == -1) ? 0 : idEnd));
						if (id.empty())
						{
							_tprintf(_T("%s(%d) : error: Invalid _TR() statement - cannot determine string ID"), GetFullPath(fp).c_str(), lineNum);
							return false;
						}

						const DynamicString &existingValue = m_Strings[id].Value;
						if (!existingValue.empty() && (existingValue != lastString))
							_tprintf(_T("%s(%d) : warning: %s redefined with different value\n"), GetFullPath(fp).c_str(), lineNum, id.c_str());

						m_Strings[id].Value = lastString;
					}
					else
					{
						_FixedSetOfCharsSplitString<2, TempStringA> params(tokenParams, ", \t");
						if (params.count() < 2)
						{
							_tprintf(_T("%s(%d) : error: Invalid LOCALIZE_xxx() statement - less than 2 arguments\n"), GetFullPath(fp).c_str(), lineNum);
							return false;
						}

						DynamicString stringId = ANSIStringToString(params[0]);
						if (stringId.empty())
						{
							_tprintf(_T("%s(%d) : error: Invalid LOCALIZE_xxx() statement - empty string ID\n"), GetFullPath(fp).c_str(), lineNum);
							return false;
						}

						if (localizationTokenType == ltDIALOG)
						{
							DynamicString dlgID = ANSIStringToString(params[1]);
							if (m_Dialogs.find(dlgID) == m_Dialogs.end())
							{
								_tprintf(_T("%s(%d) : error: Cannot find dialog %s\n"), GetFullPath(fp).c_str(), lineNum, dlgID.c_str());
								return false;
							}
							m_Dialogs[dlgID].Localized = true;
							m_Dialogs[dlgID].LocalizationFileAndLine.Format(_T("%s(%d)"), GetFullPath(fp).c_str(), lineNum);
							m_Strings[stringId].Value = m_Dialogs[dlgID].Caption;
							currentDialogID = dlgID;
						}
						else if (localizationTokenType == ltDLGITEM)
						{
							if (currentDialogID.empty())
							{
								_tprintf(_T("%s(%d) : error: LOCALIZE_DLGITEM() used outside LOCALIZE_DIALOG() block\n"), GetFullPath(fp).c_str(), lineNum);
								return false;
							}
							DynamicString itemID = ANSIStringToString(params[1]);
							std::map<BazisLib::String, DialogMember>::iterator it = m_Dialogs[currentDialogID].DialogMembers.find(itemID);
							if ((stringId == _T("0")) || !stringId.icompare(_T("NULL")))
							{
								it->second.Skipped = true;
								continue;
							}
							if (it == m_Dialogs[currentDialogID].DialogMembers.end())
							{
								_tprintf(_T("%s(%d) : error: %s is not defined in %s\n"), GetFullPath(fp).c_str(), lineNum, itemID.c_str(), currentDialogID.c_str());
								return false;
							}
							m_Strings[stringId].Value = it->second.Name;
							it->second.Localized = true;
						}

					}
					LocalizationTokenStart = -1;
				}
			}
		}

	}
	return true;
}