InternetCanonicalizeUrl无法解码变音字母

时间:2014-02-27 11:57:31

标签: c++ windows c++builder urldecode

在将某些字符处理到URL时遇到了很多麻烦,让我们假设我有以下网址:

  

http://localhost/somewere/myLibrary.dll/rest/something?parameter=An%C3%A1lisis

必须转换为:

  

http://localhost/somewere/myLibrary.dll/rest/something?parameter=Análisis

为了处理变音符号的解码,我决定使用InternetCanonicalizeUrl函数,因为我正在处理的应用程序只能在Windows中运行而我不想要要安装其他库,我使用的辅助函数如下:

String DecodeURL(const String &a_URL)
{
    String result;
    unsigned long size = a_reportType.Length() * 2;
    wchar_t *buffer = new wchar_t[size];

    if (InternetCanonicalizeUrlW(a_URL.c_str(), buffer, &size, ICU_DECODE | ICU_NO_ENCODE))
    {
        result = buffer;
    }

   delete [] buffer;
   return result;
}

对于几乎所有通过它的URL都有效,除了变音符号外,我的示例URL解码如下:

  

http://localhost/somewere/myLibrary.dll/rest/something?parameter=Análisis

我正在使用的IDE是CodeGear™C ++Builder®2009(这就是为什么我强制使用String代替std::string),I我还尝试使用AnsiStringchar buffer版本,但结果相同。

有关如何处理此错误的任何提示/替代方法?

提前致谢。

1 个答案:

答案 0 :(得分:3)

InternetCanonicalizeUrl()正在做正确的事情,你只需要考虑它实际上在做什么。

URL不支持Unicode(IRIs),因此必须将Unicode数据字符集编码为字节八位字节,然后根据需要使用%HH序列对这些八位字节进行URL编码。在这种情况下,数据被编码为UTF-8(现在在许多URL中并不常见,但也不能保证),但是InternetCanonicalizeUrl()无法知道因为URL没有描述哪个字符集的语法正在使用。它所能做的只是将%HH序列解码为相关的字节八位字节值,它不能为您解码八位字节。对于Unicode版本,InternetCanonicalizeUrlW()将这些字节值原样返回为wchar_t个元素。但不管怎样,你必须自己对八位字节进行字符串解码才能恢复原始的Unicode数据。

因此,在这种情况下你可以做的是将解码后的数据复制到UTF8String,然后将其作为String分配/返回,以便将其解码为UTF-16。当然,这只适用于UTF-8编码的URL。例如:

String DecodeURL(const String &a_URL)
{
    DWORD size = 0;
    if (!InternetCanonicalizeUrlW(a_URL.c_str(), NULL, &size, ICU_DECODE | ICU_NO_ENCODE))
    {
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
            String buffer;
            buffer.SetLength(size-1);
            if (InternetCanonicalizeUrlW(a_URL.c_str(), buffer.c_str(), &size, ICU_DECODE | ICU_NO_ENCODE))
            {
                UTF8String utf8;
                utf8.SetLength(buffer.Length());
                for (int i = 1; i <= buffer.Length(); ++i)
                    utf8[i] = (char) buffer[i];
                return utf8;
            }
        }
    }

   return String();
}

可替换地:

// encoded URLs are always ASCII, so it is safe
// to pass an encoded URL UnicodeString as an
// AnsiString...
String DecodeURL(const AnsiString &a_URL)
{
    DWORD size = 0;
    if (!InternetCanonicalizeUrlA(a_URL.c_str(), NULL, &size, ICU_DECODE | ICU_NO_ENCODE))
    {
        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
        {
            UTF8String buffer;
            buffer.SetLength(size-1);
            if (InternetCanonicalizeUrlA(a_URL.c_str(), buffer.c_str(), &size, ICU_DECODE | ICU_NO_ENCODE))
            {
                return utf8;
            }
        }
    }

仅供参考,C ++ Builder预装了Indy。 Indy有一个TIdURI类,可以解码URL并考虑字符集,例如:

#include <IdGlobal.hpp>
#include <IdURI.hpp>

String DecodeURL(const String &a_URL)
{ 
    return TIdURI::URLDecode(URL, enUTF8);
}

在任何情况下,您都必须知道用于对URL数据进行编码的字符集。如果不这样做,您所能做的就是解码原始八位字节,然后使用启发式分析来猜测字符集可能是什么,但对于非ASCII和非UTF字符集,这不是100%可靠。