crossplatform.ru

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

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
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
 
Начать новую тему
Ответов
lanz
  опции профиля:
сообщение 9.12.2014, 20:29
Сообщение #2


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

Группа: Участник
Сообщений: 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
Сообщение #3


Студент
*

Группа: Участник
Сообщений: 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 парсер...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Сообщений в этой теме


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


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


RSS Рейтинг@Mail.ru Текстовая версия Сейчас: 25.4.2025, 11:45