2015-09-16 2 views
1

При анализе содержимого wchar_t на платформе win32, quickxml может вызывать исключение parse_error. Содержание:rapidxml throws exception on wchar_t content

<xml att='最好' />

Вот мой код тестирования:

/* 
* @file : TestRapidXmlBug.cpp 
* @author: shilyx 
* @date : 2015-09-16 11:02:22.886 
* @note : Generated by SlxTemplates 
*/ 

#include <Windows.h> 
#include "rapidxml.hpp" 
#include <iostream> 
#include <string> 

using namespace std; 
using namespace rapidxml; 

int main(int argc, char *argv[]) 
{ 
    // data block 
    unsigned char szData[] = { 
     0x3C, 0x00, 0x78, 0x00, 0x6D, 0x00, 0x6C, 0x00, 0x20, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x3D, 
     0x00, 0x27, 0x00, 0x00, 0x67, 0x7D, 0x59, 0x27, 0x00, 0x20, 0x00, 0x2F, 0x00, 0x3E, 0x00, 0x00, 0x00}; 

    // uft8 string 
    char szDataUtf8[sizeof(szData) * 10] = ""; 

    // ucs2 string 
    wchar_t *szDataUcs2 = (wchar_t *)szData; 

    WideCharToMultiByte(CP_UTF8, 0, szDataUcs2, -1, szDataUtf8, sizeof(szDataUtf8), NULL, NULL); 

    try 
    { 
     xml_document<wchar_t> xml; 

     cout<<"-------------------------wchar_t"<<endl; 
     xml.parse<0>(szDataUcs2); // will throw parse_error 
     cout<<"success"<<endl; 
    } 
    catch (parse_error &ex) 
    { 
     cout<<"exception: "<<ex.what()<<endl; 
     cout<<"failled"<<endl; 
    } 

    try 
    { 
     xml_document<char> xml; 

     cout<<"-------------------------char"<<endl; 
     xml.parse<0>(szDataUtf8); // will not throw any exception 
     cout<<"success"<<endl; 
    } 
    catch (parse_error &ex) 
    { 
     cout<<ex.what()<<endl; 
     cout<<"failled"<<endl; 
    } 

    return 0; 
} 

Это выбросит исключение по адресу:

 // Make sure that end quote is present 
     if (*text != quote) 
      RAPIDXML_PARSE_ERROR("expected ' or \"", text); 
     ++text;  // Skip quote 

Причиной может быть:

// Skip characters until predicate evaluates to true 
template<class StopPred, int Flags> 
static void skip(Ch *&text) 
{ 
    Ch *tmp = text; 
    while (StopPred::test(*tmp)) 
     ++tmp; 
    text = tmp; 
} 

В StopPred :: Функциональный тест:

// Detect attribute value character 
template<Ch Quote> 
struct attribute_value_pure_pred 
{ 
    static unsigned char test(Ch ch) 
    { 
     if (Quote == Ch('\'')) 
      return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast<unsigned char>(ch)]; 
     if (Quote == Ch('\"')) 
      return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast<unsigned char>(ch)]; 
     return 0;  // Should never be executed, to avoid warnings on Comeau 
    } 
}; 

static_cast изменяет wchar_t (0x6700) к беззнаковым символам (0x00), операция пропуска остановлена.


Это ошибка? или неправильно использовать quickxml с wchar_t? Дата последнего обновления rapidxml - 2013-04-26, я думаю, он должен быть достаточно стабильным.

ответ

1

Rapidxml не поддерживает полностью UTF-16, UTF-32 или другие широкие кодировки.

Текущая версия не полностью поддерживает UTF-16 или UTF-32, поэтому использование широких символов несколько недееспособно. Тем не менее, он должен успешно разбирать строки wchar_t, содержащие UTF-16 или UTF-32, если соответствие данных соответствует характеристикам машины.

Как вы уже видели, интересное совпадение характера 0x6700, когда преобразуется в unsigned char для внутреннего табличного rapidxml является 0, который не является допустимым символом атрибута и поэтому завершает синтаксический анализ. Я полагаю, что в документации должно быть разъяснено, что частичная поддержка широкого кодирования доступна с оговоркой, что вы не используете кодовые точки вне базовой латинской и латинской-1 (то есть U + 0000 ~ U + 00FF).

Решение заключается в использовании UTF-8 вместо этого.

+0

Спасибо, но здесь я не могу использовать utf-8. Я обнаружил, что нет проблем с rapidxml.hpp в boost, возможно, я должен выбрать эту версию. Благодарю. – shilyx

+0

@shilyx Я сомневаюсь, что что-то изменит, насколько я могу сказать, что boost_tree использует quickxml под капотом. – user657267