]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/strconv.cpp
removed the strange __WXMSW__ test in AddFile(bitmap) -- why should this function...
[wxWidgets.git] / src / common / strconv.cpp
index b6c3ca3545c1748d3896775a7a744aa4cd527ed2..31dc602f35926d94fb5b16170627c31441da8991 100644 (file)
@@ -160,11 +160,15 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen,
                   const char *src, size_t srcLen) const
 {
     // although new conversion classes are supposed to implement this function
                   const char *src, size_t srcLen) const
 {
     // although new conversion classes are supposed to implement this function
-    // directly, the existins ones only implement the old MB2WC() and so, to
+    // directly, the existing ones only implement the old MB2WC() and so, to
     // avoid to have to rewrite all conversion classes at once, we provide a
     // default (but not efficient) implementation of this one in terms of the
     // old function by copying the input to ensure that it's NUL-terminated and
     // then using MB2WC() to convert it
     // avoid to have to rewrite all conversion classes at once, we provide a
     // default (but not efficient) implementation of this one in terms of the
     // old function by copying the input to ensure that it's NUL-terminated and
     // then using MB2WC() to convert it
+    //
+    // moreover, some conversion classes simply can't implement ToWChar()
+    // directly, the primary example is wxConvLibc: mbstowcs() only handles
+    // NUL-terminated strings
 
     // the number of chars [which would be] written to dst [if it were not NULL]
     size_t dstWritten = 0;
 
     // the number of chars [which would be] written to dst [if it were not NULL]
     size_t dstWritten = 0;
@@ -205,6 +209,21 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen,
         srcEnd = NULL;
     }
 
         srcEnd = NULL;
     }
 
+    // the idea of this code is straightforward: it converts a NUL-terminated
+    // chunk of the string during each iteration and updates the output buffer
+    // with the result
+    //
+    // all the complication come from the fact that this function, for
+    // historical reasons, must behave in 2 subtly different ways when it's
+    // called with a fixed number of characters and when it's called for the
+    // entire NUL-terminated string: in the former case (srcEnd == NULL) we
+    // must count all characters we convert, NUL or not; but in the latter we
+    // do not count the trailing NUL -- but still count all the NULs inside the
+    // string
+    //
+    // so for the (simple) former case we just always count the trailing NUL,
+    // but for the latter we need to wait until we see if there is going to be
+    // another loop iteration and only count it then
     for ( ;; )
     {
         // try to convert the current chunk
     for ( ;; )
     {
         // try to convert the current chunk
@@ -212,11 +231,11 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen,
         if ( lenChunk == wxCONV_FAILED )
             return wxCONV_FAILED;
 
         if ( lenChunk == wxCONV_FAILED )
             return wxCONV_FAILED;
 
-        lenChunk++; // for the L'\0' at the end of this chunk
-
         dstWritten += lenChunk;
         dstWritten += lenChunk;
+        if ( !srcEnd )
+            dstWritten++;
 
 
-        if ( lenChunk == 1 )
+        if ( !lenChunk )
         {
             // nothing left in the input string, conversion succeeded
             break;
         {
             // nothing left in the input string, conversion succeeded
             break;
@@ -227,10 +246,13 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen,
             if ( dstWritten > dstLen )
                 return wxCONV_FAILED;
 
             if ( dstWritten > dstLen )
                 return wxCONV_FAILED;
 
-            if ( MB2WC(dst, src, lenChunk) == wxCONV_FAILED )
+            // +1 is for trailing NUL
+            if ( MB2WC(dst, src, lenChunk + 1) == wxCONV_FAILED )
                 return wxCONV_FAILED;
 
             dst += lenChunk;
                 return wxCONV_FAILED;
 
             dst += lenChunk;
+            if ( !srcEnd )
+                dst++;
         }
 
         if ( !srcEnd )
         }
 
         if ( !srcEnd )
@@ -254,9 +276,19 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen,
 
         // note that ">=" (and not just "==") is needed here as the terminator
         // we skipped just above could be inside or just after the buffer
 
         // note that ">=" (and not just "==") is needed here as the terminator
         // we skipped just above could be inside or just after the buffer
-        // delimited by inEnd
+        // delimited by srcEnd
         if ( src >= srcEnd )
             break;
         if ( src >= srcEnd )
             break;
+
+        // if we got here then this wasn't the last chunk in this string and
+        // hence we must count an extra char for L'\0' even when converting a
+        // fixed number of characters
+        if ( srcEnd )
+        {
+            dstWritten++;
+            if ( dst )
+                dst++;
+        }
     }
 
     return dstWritten;
     }
 
     return dstWritten;
@@ -269,13 +301,15 @@ wxMBConv::FromWChar(char *dst, size_t dstLen,
     // the number of chars [which would be] written to dst [if it were not NULL]
     size_t dstWritten = 0;
 
     // the number of chars [which would be] written to dst [if it were not NULL]
     size_t dstWritten = 0;
 
+    // if we don't know its length we have no choice but to assume that it is
+    // NUL-terminated (notice that it can still be NUL-terminated even if
+    // explicit length is given but it doesn't change our return value)
+    const bool isNulTerminated = srcLen == wxNO_LEN;
+
     // make a copy of the input string unless it is already properly
     // NUL-terminated
     // make a copy of the input string unless it is already properly
     // NUL-terminated
-    //
-    // if we don't know its length we have no choice but to assume that it is,
-    // indeed, properly terminated
     wxWCharBuffer bufTmp;
     wxWCharBuffer bufTmp;
-    if ( srcLen == wxNO_LEN )
+    if ( isNulTerminated )
     {
         srcLen = wxWcslen(src) + 1;
     }
     {
         srcLen = wxWcslen(src) + 1;
     }
@@ -298,18 +332,21 @@ wxMBConv::FromWChar(char *dst, size_t dstLen,
         if ( lenChunk == wxCONV_FAILED )
             return wxCONV_FAILED;
 
         if ( lenChunk == wxCONV_FAILED )
             return wxCONV_FAILED;
 
-        lenChunk += lenNul;
         dstWritten += lenChunk;
         dstWritten += lenChunk;
+        if ( isNulTerminated )
+            dstWritten += lenNul;
 
         if ( dst )
         {
             if ( dstWritten > dstLen )
                 return wxCONV_FAILED;
 
 
         if ( dst )
         {
             if ( dstWritten > dstLen )
                 return wxCONV_FAILED;
 
-            if ( WC2MB(dst, src, lenChunk) == wxCONV_FAILED )
+            if ( WC2MB(dst, src, lenChunk + lenNul) == wxCONV_FAILED )
                 return wxCONV_FAILED;
 
             dst += lenChunk;
                 return wxCONV_FAILED;
 
             dst += lenChunk;
+            if ( isNulTerminated )
+                dst += lenNul;
         }
     }
 
         }
     }
 
@@ -391,13 +428,19 @@ wxMBConv::cMB2WC(const char *inBuff, size_t inLen, size_t *outLen) const
         // because we want the buffer to always be NUL-terminated, even if the
         // input isn't (as otherwise the caller has no way to know its length)
         wxWCharBuffer wbuf(dstLen);
         // because we want the buffer to always be NUL-terminated, even if the
         // input isn't (as otherwise the caller has no way to know its length)
         wxWCharBuffer wbuf(dstLen);
-        wbuf.data()[dstLen - 1] = L'\0';
+        wbuf.data()[dstLen] = L'\0';
         if ( ToWChar(wbuf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED )
         {
             if ( outLen )
             {
                 *outLen = dstLen;
         if ( ToWChar(wbuf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED )
         {
             if ( outLen )
             {
                 *outLen = dstLen;
-                if ( wbuf[dstLen - 1] == L'\0' )
+
+                // we also need to handle NUL-terminated input strings
+                // specially: for them the output is the length of the string
+                // excluding the trailing NUL, however if we're asked to
+                // convert a specific number of characters we return the length
+                // of the resulting output even if it's NUL-terminated
+                if ( inLen == wxNO_LEN )
                     (*outLen)--;
             }
 
                     (*outLen)--;
             }
 
@@ -429,11 +472,10 @@ wxMBConv::cWC2MB(const wchar_t *inBuff, size_t inLen, size_t *outLen) const
             {
                 *outLen = dstLen;
 
             {
                 *outLen = dstLen;
 
-                if ( dstLen >= nulLen &&
-                        !NotAllNULs(buf.data() + dstLen - nulLen, nulLen) )
+                if ( inLen == wxNO_LEN )
                 {
                 {
-                    // in this case the output is NUL-terminated and we're not
-                    // supposed to count NUL
+                    // in this case both input and output are NUL-terminated
+                    // and we're not supposed to count NUL
                     *outLen -= nulLen;
                 }
             }
                     *outLen -= nulLen;
                 }
             }
@@ -523,14 +565,14 @@ static const unsigned char utf7unb64[] =
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 };
 
 size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen,
                              const char *src, size_t srcLen) const
 {
     DecoderState stateOrig,
 };
 
 size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen,
                              const char *src, size_t srcLen) const
 {
     DecoderState stateOrig,
-         *statePtr;
+                *statePtr;
     if ( srcLen == wxNO_LEN )
     {
         // convert the entire string, up to and including the trailing NUL
     if ( srcLen == wxNO_LEN )
     {
         // convert the entire string, up to and including the trailing NUL
@@ -567,7 +609,20 @@ size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen,
             const unsigned char dc = utf7unb64[cc];
             if ( dc == 0xff )
             {
             const unsigned char dc = utf7unb64[cc];
             if ( dc == 0xff )
             {
-                // end of encoded part
+                // end of encoded part, check that nothing was left: there can
+                // be up to 4 bits of 0 padding but nothing else (we also need
+                // to check isLSB as we count bits modulo 8 while a valid UTF-7
+                // encoded sequence must contain an integral number of UTF-16
+                // characters)
+                if ( state.isLSB || state.bit > 4 ||
+                        (state.accum & ((1 << state.bit) - 1)) )
+                {
+                    if ( !len )
+                        state = stateOrig;
+
+                    return wxCONV_FAILED;
+                }
+
                 state.ToDirect();
 
                 // re-parse this character normally below unless it's '-' which
                 state.ToDirect();
 
                 // re-parse this character normally below unless it's '-' which
@@ -611,9 +666,6 @@ size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen,
             // start of an encoded segment?
             if ( cc == '+' )
             {
             // start of an encoded segment?
             if ( cc == '+' )
             {
-                if ( src == srcEnd )
-                    return wxCONV_FAILED; // can't have '+' at the end
-
                 if ( *src == '-' )
                 {
                     // just the encoded plus sign, don't switch to shifted mode
                 if ( *src == '-' )
                 {
                     // just the encoded plus sign, don't switch to shifted mode
@@ -622,7 +674,15 @@ size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen,
                     len++;
                     src++;
                 }
                     len++;
                     src++;
                 }
-                else
+                else if ( utf7unb64[(unsigned)*src] == 0xff )
+                {
+                    // empty encoded chunks are not allowed
+                    if ( !len )
+                        state = stateOrig;
+
+                    return wxCONV_FAILED;
+                }
+                else // base-64 encoded chunk follows
                 {
                     state.ToShifted();
                 }
                 {
                     state.ToShifted();
                 }
@@ -2830,6 +2890,16 @@ wxCSConv::wxCSConv(const wxString& charset)
 
 #if wxUSE_FONTMAP
     m_encoding = wxFontMapperBase::GetEncodingFromName(charset);
 
 #if wxUSE_FONTMAP
     m_encoding = wxFontMapperBase::GetEncodingFromName(charset);
+    if ( m_encoding == wxFONTENCODING_MAX )
+    {
+        // set to unknown/invalid value
+        m_encoding = wxFONTENCODING_SYSTEM;
+    }
+    else if ( m_encoding == wxFONTENCODING_DEFAULT )
+    {
+        // wxFONTENCODING_DEFAULT is same as US-ASCII in this context
+        m_encoding = wxFONTENCODING_ISO8859_1;
+    }
 #else
     m_encoding = wxFONTENCODING_SYSTEM;
 #endif
 #else
     m_encoding = wxFONTENCODING_SYSTEM;
 #endif