crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> Странная работа QSettings с QTextCodec и BOM, нормально работает только с ASCII и utf8
kin63camapa
  опции профиля:
сообщение 9.12.2014, 18:41
Сообщение #1


Студент
*

Группа: Участник
Сообщений: 32
Регистрация: 21.8.2010
Пользователь №: 1976

Спасибо сказали: 0 раз(а)




Репутация:   1  


Столкнулся со странным поведением QSettings на юникоде, если файл в ascii все ok, cp1251 не детектит, но какбэ и не обязан. Но вот если файл в юникоде парсер делает вид что в файле пусто allKeys().size==0. Сначала думал что он bom не распознаёт, сделал костыль
Раскрывающийся текст

QString Parser::codecDetect(QString file)
{
    QFile fl(file);
    if (!fl.open(QFile::ReadOnly))
    {
        qDebug() << QString("Can not open file %1").arg(file));
        return "default";
    }
    QByteArray bom = fl.read(4);
    if ( bom.contains("\xEF\xBB\xBF")) return "UTF-8";
    //if ( bom.contains("\016\376\377")) return "SCSU";
    //if ( bom.contains("\335\163\146\163")) return "UTF-8-EBCDIC";
    if ( bom.contains("\376\377")) return "UTF-16BE";
    if ( bom.contains("\377\376")) return "UTF-16LE";
    return "Windows-1251";
}
//дальше по коду
    QSettings infoTxt(file,QSettings::IniFormat);
    QString codec = codecDetect(file);
    qDebug() << QString("Detect codec %1").arg(codec));
    infoTxt.setIniCodec(QTextCodec::codecForName(codec.toAscii()));


Костыль дал нормальную работу только на utf-8 на UTF-16LE и UTF-16BE QSettings говорит что нет никаких значений у тя в файле, иди лесом.
Думаю дай хоть гляну что ему нужно на вход подсовывать:
#include <QtCore>

int main(int argc, char *argv[])
{
    QSettings s("blah-blah.txt",QSettings::IniFormat);
    s.setIniCodec(QTextCodec::codecForName("UTF-16BE"));
    s.setValue("Test","Test");
    s.sync();

    QSettings b("blah-blah.txt",QSettings::IniFormat);
    b.setIniCodec(QTextCodec::codecForName("UTF-16BE"));
    qDebug() << b.value("Test").toString();
    return 0;
}

На выхлопе:
Запускается C:\tmp\test-build-desktop-Qt_4_7_4_for_Desktop_-_MinGW_4_4__Qt_SDK_______\release\test.exe...
Qt: Untested Windows version 6.2 detected!
"T?e?s?t"
C:\tmp\test-build-desktop-Qt_4_7_4_for_Desktop_-_MinGW_4_4__Qt_SDK_______\release\test.exe завершился с кодом 0

Но и это ещё не все, в созданном файле вообще черт пойми какая кодировка притом без BOM
5B 47 65 6E 65 72 61 6C 5D 0D 0A 54 65 73 74 3D FE FF 00 54 FE FF 00 65 FE FF 00 73 FE FF 00 74 0D 0A

Собственно вопрос чо делать та?
зы и если кто знает как заставить QSettings работать с UTF-7, UTF-8-EBCDIC и SCSU поделитесь, о-о-о-очень надо

Сообщение отредактировал kin63camapa - 9.12.2014, 18:58
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 9.12.2014, 20:07
Сообщение #2


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9669
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Меня реализация QSettings бесит давно и основательно.
Всё что нужно было сделать это конструктор:
QSettings ( const QIODevice & iodevice, QObject * parent = 0 )
вместо
QSettings ( const QString & fileName, Format format, QObject * parent = 0 )

тогда мы могли бы читать файл в QBuffer предварительно преобразовав кодировку (но внутрянка получается сложнее, поэтому делать так троли не стали).

Выход из положения - зарегистрировать свой формат, через
registerFormat()

по сути создаёшь две функции, чтения и записи из/в файла и регистрируешь их связывая с условным форматом.
В функция чтения/записи реализуешь механизм перекодирования.
В общем-то не сложно и можно эту кухню вынести в отдельную пару .cpp/.h

Сообщение отредактировал Litkevich Yuriy - 9.12.2014, 20:09
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
lanz
  опции профиля:
сообщение 9.12.2014, 20:29
Сообщение #3


Старейший участник
****

Группа: Участник
Сообщений: 690
Регистрация: 28.12.2012
Пользователь №: 3660

Спасибо сказали: 113 раз(а)




Репутация:   8  


Если посмотреть в исходники, то видно что кодек используется только для кодировки значений ключей
    static void iniEscapedKey(const QString &key, QByteArray &result);
    static bool iniUnescapedKey(const QByteArray &key, int from, int to, QString &result);
    static void iniEscapedString(const QString &str, QByteArray &result, QTextCodec *codec);
    static void iniEscapedStringList(const QStringList &strs, QByteArray &result, QTextCodec *codec);

Сами ключи кодируются вот так:
Раскрывающийся текст
void QSettingsPrivate::iniEscapedKey(const QString &key, QByteArray &result)
{
    result.reserve(result.length() + key.length() * 3 / 2);
    for (int i = 0; i < key.size(); ++i) {
        uint ch = key.at(i).unicode();

        if (ch == '/') {
            result += '\\';
        } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')
                || ch == '_' || ch == '-' || ch == '.') {
            result += (char)ch;
        } else if (ch <= 0xFF) {
            result += '%';
            result += hexDigits[ch / 16];
            result += hexDigits[ch % 16];
        } else {
            result += "%U";
            QByteArray hexCode;
            for (int i = 0; i < 4; ++i) {
                hexCode.prepend(hexDigits[ch % 16]);
                ch >>= 4;
            }
            result += hexCode;
        }
    }
}


Так что никак. UTF-8 работает постольку-поскольку его кодировка совпадает с ASCII.
Вообще:
Цитата
Following the philosophy that we should be liberal in what we accept and conservative in what we generate, QSettings will accept Latin-1 encoded INI files, but generate pure ASCII files, where non-ASCII values are encoded using standard INI escape sequences. To make the INI files more readable (but potentially less compatible), call setIniCodec().


Самый близкий workaround:
    QSettings s("blah-blah.txt", QSettings::IniFormat);
    QTextCodec * tc = QTextCodec::codecForName("UTF16-BE");
    s.setValue("Test", tc->fromUnicode( "Test" ) );
    s.sync();

    QSettings b("blah-blah.txt",QSettings::IniFormat);
    QString str = tc->toUnicode( b.value("Test").toByteArray() );

    qDebug() << str;


Цитата
Всё что нужно было сделать это конструктор:
QSettings ( const QIODevice & iodevice, QObject * parent = 0 )
вместо
QSettings ( const QString & fileName, Format format, QObject * parent = 0 )

А как тогда в реестр сохранять? И вообще AppData и т.п. разруливать?
QSettings мне как раз нравится тем, что можно завести его и не париться.
Но для общего инструмента чтения INI файлов он конечно не очень.

Сообщение отредактировал lanz - 9.12.2014, 20:31
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kin63camapa
  опции профиля:
сообщение 9.12.2014, 22:16
Сообщение #4


Студент
*

Группа: Участник
Сообщений: 32
Регистрация: 21.8.2010
Пользователь №: 1976

Спасибо сказали: 0 раз(а)




Репутация:   1  


:blink: Троли шо курили? Получается часть файла одной кодировкой пишется часть другой... убится об моник.
А ещё с дуру надеялся что он bom сам определяет или даже 8 бит как-нить логически.
Цитата(lanz @ 9.12.2014, 21:29) *
Самый близкий workaround:

это для примера, в проекте ровно наоборот парсится туева хуча сторонних файлов и понасохранять могли в чем угодно, ессно ни одному идиоту не пришло в голову сохранять файло так как это qt делает без bom или кодировку посреди файла менять... щас вот ещё думаю как KOI и 866 детектить парочка таких уже попалась и, цуко, везде кирилица.
Цитата(lanz @ 9.12.2014, 21:29) *
А как тогда в реестр сохранять? И вообще AppData и т.п. разруливать?
QSettings мне как раз нравится тем, что можно завести его и не париться.
Но для общего инструмента чтения INI файлов он конечно не очень.

Можно просто как нить перегрузить конструктор именно для ини форматата хочешь отдал на откупут тулкиту, хочешь вызвал конкретный конструктор, запхнул туда кодек, имя файла, можно ещё флаги добавить мол игнорим пробелы или нет и т.д. и хоть черта лысого туда записывай, а то блин и инструмент есть и пользы NULL хоть прям сам все кодировки реализуй и собственный ini парсер...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Iron Bug
  опции профиля:
сообщение 10.12.2014, 10:06
Сообщение #5


Профессионал
*****

Группа: Модератор
Сообщений: 1611
Регистрация: 6.2.2009
Из: Yekaterinburg
Пользователь №: 533

Спасибо сказали: 219 раз(а)




Репутация:   12  


это совершенно нормально. потому что для параметров программист должен сам выбирать нужную ему кодировку. и вполне возможно, что параметры могут оказаться в разных кодировках. иначе будет ненужное ограничение для разработчиков.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 29.3.2024, 14:15