// wxMsgCatalogFile corresponds to one disk-file message catalog.
//
// This is a "low-level" class and is used only by wxMsgCatalog
+// NOTE: for the documentation of the binary catalog (.MO) files refer to
+// the GNU gettext manual:
+// http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html
// ----------------------------------------------------------------------------
WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash);
// load the catalog from disk (szDirPrefix corresponds to language)
bool Load(const wxString& szDirPrefix, const wxString& szName,
- wxPluralFormsCalculatorPtr& rPluralFormsCalculator);
+ wxPluralFormsCalculatorPtr& rPluralFormsCalculator);
// fills the hash with string-translation pairs
- void FillHash(wxMessagesHash& hash,
- const wxString& msgIdCharset,
- bool convertEncoding) const;
+ bool FillHash(wxMessagesHash& hash,
+ const wxString& msgIdCharset,
+ bool convertEncoding) const;
// return the charset of the strings in this catalog or empty string if
// none/unknown
// plural forms formula from it:
const char* headerData = StringAtOfs(m_pOrigTable, 0);
- if (headerData && headerData[0] == 0)
+ if ( headerData && headerData[0] == '\0' )
{
// Extract the charset:
- wxString header = wxString::FromAscii(StringAtOfs(m_pTransTable, 0));
- int begin = header.Find(wxS("Content-Type: text/plain; charset="));
- if (begin != wxNOT_FOUND)
+ const char * const header = StringAtOfs(m_pTransTable, 0);
+ const char *
+ cset = strstr(header, "Content-Type: text/plain; charset=");
+ if ( cset )
{
- begin += 34; //strlen("Content-Type: text/plain; charset=")
- size_t end = header.find('\n', begin);
- if (end != size_t(-1))
+ cset += 34; // strlen("Content-Type: text/plain; charset=")
+
+ const char * const csetEnd = strchr(cset, '\n');
+ if ( csetEnd )
{
- m_charset.assign(header, begin, end - begin);
- if (m_charset == wxS("CHARSET"))
+ m_charset = wxString(cset, csetEnd - cset);
+ if ( m_charset == wxS("CHARSET") )
{
// "CHARSET" is not valid charset, but lazy translator
- m_charset.Clear();
+ m_charset.empty();
}
}
}
// else: incorrectly filled Content-Type header
// Extract plural forms:
- begin = header.Find(wxS("Plural-Forms:"));
- if (begin != wxNOT_FOUND)
+ const char * plurals = strstr(header, "Plural-Forms:");
+ if ( plurals )
{
- begin += 13;
- size_t end = header.find('\n', begin);
- if (end != size_t(-1))
+ plurals += 13; // strlen("Plural-Forms:")
+ const char * const pluralsEnd = strchr(plurals, '\n');
+ if ( pluralsEnd )
{
- wxString pfs(header, begin, end - begin);
- wxPluralFormsCalculator* pCalculator = wxPluralFormsCalculator
- ::make(pfs.ToAscii());
- if (pCalculator != 0)
+ const size_t pluralsLen = pluralsEnd - plurals;
+ wxCharBuffer buf(pluralsLen);
+ strncpy(buf.data(), plurals, pluralsLen);
+ wxPluralFormsCalculator * const
+ pCalculator = wxPluralFormsCalculator::make(buf);
+ if ( pCalculator )
{
rPluralFormsCalculator.reset(pCalculator);
}
else
{
- wxLogVerbose(_("Cannot parse Plural-Forms:'%s'"), pfs.c_str());
+ wxLogVerbose(_("Failed to parse Plural-Forms: '%s'"),
+ buf.data());
}
}
}
- if (rPluralFormsCalculator.get() == NULL)
- {
+
+ if ( !rPluralFormsCalculator.get() )
rPluralFormsCalculator.reset(wxPluralFormsCalculator::make());
- }
}
// everything is fine
return true;
}
-void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
+bool wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
const wxString& msgIdCharset,
bool convertEncoding) const
{
for (size_t32 i = 0; i < m_numStrings; i++)
{
const char *data = StringAtOfs(m_pOrigTable, i);
+ if (!data)
+ return false; // may happen for invalid MO files
wxString msgid;
#if wxUSE_UNICODE
#endif // wxUSE_UNICODE
data = StringAtOfs(m_pTransTable, i);
+ if (!data)
+ return false; // may happen for invalid MO files
+
size_t length = Swap(m_pTransTable[i].nLen);
size_t offset = 0;
size_t index = 0;
}
// skip this string
- offset += strlen(str) + 1;
+ // IMPORTANT: accesses to the 'data' pointer are valid only for
+ // the first 'length+1' bytes (GNU specs says that the
+ // final NUL is not counted in length); using wxStrnlen()
+ // we make sure we don't access memory beyond the valid range
+ // (which otherwise may happen for invalid MO files):
+ offset += wxStrnlen(str, length - offset) + 1;
++index;
}
}
delete sourceConv;
delete inputConvPtr;
#endif // wxUSE_WCHAR_T
+
+ return true;
}
if ( !file.Load(dirPrefix, name, m_pluralFormsCalculator) )
return false;
- file.FillHash(m_messages, msgIdCharset, bConvertEncoding);
+ if ( !file.FillHash(m_messages, msgIdCharset, bConvertEncoding) )
+ return false;
#if !wxUSE_UNICODE
// we should use a conversion compatible with the message catalog encoding
// the environment variables (in most cases this won't work, but I was
// out of ideas)
char *lang = getenv( "LC_ALL");
- char *dot = lang ? strchr(lang, '.') : (char *)NULL;
+ char *dot = lang ? strchr(lang, '.') : NULL;
if (!dot)
{
lang = getenv( "LC_CTYPE" );
const wxString& msgIdCharset)
{
- wxCHECK_MSG( IsOk(), false, "must initialize catalog first" );
+ wxCHECK_MSG( !m_strShort.empty(), false, "must initialize catalog first" );
// It is OK to not load catalog if the msgid language and m_language match,