QBtyeArray QDataStream qCompress в файл с добавлением дополнительных начальных байтов

Программа Qt/C++ имеет функцию, которая записывает данные объектов (_token) в файл следующим образом:

    QFile f( _tokenFile);

    if (!f.open( QIODevice::WriteOnly)) {
        qDebug() << "Unable to open token file for writing" << f.errorString();
        return false;
    }

    QByteArray tokenBa;
    QDataStream ds( &tokenBa, QIODevice::WriteOnly);
    ds << _token;

    tokenBa = qCompress( tokenBa);

    f.write( tokenBa);
    f.close();

_token является экземпляром следующих struct:

struct Token {
    QString accessToken;
    QString refreshToken;
    QString clientSecret;
    QString authCode;
    QTime expiryTime;


    enum AuthState {
        A_Invalid,
        A_RequestAuth,
        A_Authenticated,
    };

    AuthState state;

    Token() : state( A_Invalid) {}

    bool isValid() const {
        if (accessToken.isEmpty() ||
            refreshToken.isEmpty()) {
            return false;
        }
        return true;
    }

    void inValidate() {
        accessToken.clear();
        refreshToken.clear();
        clientSecret.clear();
        authCode.clear();
        expiryTime = QTime();
    }

    void cleanUp() {
        accessToken.clear();
        refreshToken.clear();
        clientSecret.clear();
        authCode.clear();
        expiryTime = QTime();
    }
};

Когда файл сохраняется, в начале у него есть 4 дополнительных байта, которые отображают файл как недопустимый файл zlib.


0000000 0000 5e01 9c78 904d 4f5d 5082 871c fa9f
0000020 353e 25cd 6975 2c2f d563 4c2c 62b8 cad1

Мы видим, что байты 5-6 выше — это 9C 78, что является сигнатурой zlib, но 4 байта перед ними — это проблема.

Чтобы проверить правильность сжатых данных, я делаю следующее:

dd if=file.token bs=1 skip=4 | openssl zlib -d

И это дает ожидаемый результат (для тестирования).

Проблема заключается в том, что приложение считывает эти данные обратно в объект данных:

    QFile f( _tokenFile);

    if (!f.exists()) {
        qDebug() << "Token file doesn't exist"  << f.fileName();
        return false;
    }

    if (!f.open( QIODevice::ReadOnly)) {
        qDebug() << "Unable to open token file for reading" << f.errorString();
        return false;
    }

    QByteArray tokenBa = f.readAll();
    f.close();

    if (tokenBa.isEmpty()) {
        qDebug() << "Token file is empty.";
        return false;
    }

    tokenBa = qUncompress( tokenBa);

    QDataStream ds( &tokenBa, QIODevice::ReadOnly);
    ds >> _token;

Это возвращает null - из-за первых 4 посторонних байтов. Я мог бы добавить некоторый код, чтобы пропустить эти 4 начальных байта, но откуда мне знать, что это всегда будет 4 байта? Вместо этого я хотел бы, чтобы все данные файлов были сжаты zlib.

Мой вопрос заключается в том, как избежать сохранения этих байтов в первую очередь, чтобы при повторном чтении формат был известен как тип zlib?


person TenG    schedule 04.03.2021    source источник


Ответы (1)


Вы не можете избежать их, поскольку они необходимы для qUncompress позже. на:

Примечание. Если вы хотите использовать эту функцию для распаковки внешних данных, сжатых с помощью zlib, вам сначала нужно добавить четырехбайтовый заголовок к массиву байтов, содержащему данные. Заголовок должен содержать ожидаемую длину (в байтах) несжатых данных, выраженную в виде 32-разрядного целого числа без знака с прямым порядком байтов.

person chehrlic    schedule 05.03.2021
comment
Спасибо. Итак, в моем примере первые 4 байта 0000 5e01 должны делать именно это, что вызывает недоумение, почему распаковка не удалась. - person TenG; 05.03.2021
comment
0x5e01 - это 24065 - поэтому ваш файл должен быть размером 24069 байт, а также QByteArray, который вы читаете - так ли это? - person chehrlic; 05.03.2021
comment
Нет. Фактический размер составляет около 240 байт. Возможно проблема в сохранении файла. Я сделаю еще отладку и проверю. - person TenG; 05.03.2021
comment
Затем добавьте оператор отладки, чтобы распечатать размер tokenBA при записи файла. И, возможно, также выведите туда первые 4 байта массива байтов, чтобы увидеть, содержат ли они ожидаемые байты. - person chehrlic; 06.03.2021