]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/intl.cpp
fixing infinite recursion for rotated text, introduced in cleanup r57915
[wxWidgets.git] / src / common / intl.cpp
index 0dc780ac3182bdef22185f0b6cc13cf78635438c..e7ca00816f96ce94e6b21780bb02f6fb77b80823 100644 (file)
@@ -868,6 +868,9 @@ wxPluralFormsCalculator* wxPluralFormsCalculator::make(const char* s)
 // wxMsgCatalogFile corresponds to one disk-file message catalog.
 //
 // This is a "low-level" class and is used only by wxMsgCatalog
 // 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);
 // ----------------------------------------------------------------------------
 
 WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash);
@@ -881,12 +884,12 @@ public:
 
     // load the catalog from disk (szDirPrefix corresponds to language)
     bool Load(const wxString& szDirPrefix, const wxString& szName,
 
     // 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
 
     // 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
 
     // return the charset of the strings in this catalog or empty string if
     // none/unknown
@@ -1304,59 +1307,63 @@ bool wxMsgCatalogFile::Load(const wxString& szDirPrefix, const wxString& szName,
     // plural forms formula from it:
 
     const char* headerData = StringAtOfs(m_pOrigTable, 0);
     // 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:
     {
         // 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
                 {
                     // "CHARSET" is not valid charset, but lazy translator
-                    m_charset.Clear();
+                    m_charset.empty();
                 }
             }
         }
         // else: incorrectly filled Content-Type header
 
         // Extract plural forms:
                 }
             }
         }
         // 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
                 {
                 {
                     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());
             rPluralFormsCalculator.reset(wxPluralFormsCalculator::make());
-        }
     }
 
     // everything is fine
     return true;
 }
 
     }
 
     // everything is fine
     return true;
 }
 
-void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
+bool wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
                                 const wxString& msgIdCharset,
                                 bool convertEncoding) const
 {
                                 const wxString& msgIdCharset,
                                 bool convertEncoding) const
 {
@@ -1444,6 +1451,8 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
     for (size_t32 i = 0; i < m_numStrings; i++)
     {
         const char *data = StringAtOfs(m_pOrigTable, i);
     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
 
         wxString msgid;
 #if wxUSE_UNICODE
@@ -1458,6 +1467,9 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
 #endif // wxUSE_UNICODE
 
         data = StringAtOfs(m_pTransTable, i);
 #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;
         size_t length = Swap(m_pTransTable[i].nLen);
         size_t offset = 0;
         size_t index = 0;
@@ -1488,7 +1500,12 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
             }
 
             // skip this string
             }
 
             // 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;
         }
     }
             ++index;
         }
     }
@@ -1497,6 +1514,8 @@ void wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
     delete sourceConv;
     delete inputConvPtr;
 #endif // wxUSE_WCHAR_T
     delete sourceConv;
     delete inputConvPtr;
 #endif // wxUSE_WCHAR_T
+
+    return true;
 }
 
 
 }
 
 
@@ -1531,7 +1550,8 @@ bool wxMsgCatalog::Load(const wxString& dirPrefix, const wxString& name,
     if ( !file.Load(dirPrefix, name, m_pluralFormsCalculator) )
         return false;
 
     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
 
 #if !wxUSE_UNICODE
     // we should use a conversion compatible with the message catalog encoding
@@ -2573,7 +2593,7 @@ bool wxLocale::AddCatalog(const wxString& szDomain,
                         const wxString& msgIdCharset)
 
 {
                         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,
 
 
     // It is OK to not load catalog if the msgid language and m_language match,