Я пытаюсь сжать/распаковать QStrings.
Как у меня такая настройка: существует модуль telnet/socket, который считывает информацию с сервера telnet. Затем эти строки отправляются в Javascript (это клиентский клиент, где пользовательский интерфейс реализован в HTML с использованием QWebView и т.д.). Это работает нормально.
Я хотел бы добавить поддержку MCCP (сжатие zlib ввода/вывода).
Я хотел бы, если вообще возможно, предоставить полную поддержку скриптов для приложения (только минимальный C++ код, все остальное реализовано плагинами.)
Я хочу реализовать две функции, compressString и decpressionString:
QString MainWindow::compressString(QString s) {
QByteArray str = s.toLocal8Bit();
int ret,flush;
z_stream strm;
unsigned char out[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm,Z_DEFAULT_COMPRESSION);
if ( ret != Z_OK ) {
return "ERROR: Failed to init z_stream";
}
// do until end of string
do {
strm.avail_in = str.size();
strm.next_in = (unsigned char*)str.data();
strm.avail_out = CHUNK;
strm.next_out = out;
flush = Z_FINISH;
ret = deflate(&strm,flush);
if ( ret == Z_STREAM_ERROR) {
return "ERROR: Z_STREAM_ERROR when deflating.";
}
} while ( flush != Z_FINISH );
deflateEnd(&strm);
return QString( (char *)out );
}
QString MainWindow::decompressString(QString s) {
QByteArray str = s.toLocal8Bit();
int ret,flush;
z_stream strm;
unsigned char out[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if ( ret != Z_OK ) {
return "ERROR: Failed to init z_stream for inflate";
}
// do until end of string
do {
strm.avail_in = str.size();
strm.next_in = (unsigned char*)str.data();
strm.avail_out = CHUNK;
strm.next_out = out;
flush = Z_NO_FLUSH;
ret = inflate(&strm,flush);
if ( ret == Z_STREAM_ERROR) {
return "ERROR: Z_STREAM_ERROR when inflating.";
}
switch( ret ) {
case Z_NEED_DICT:
inflateEnd(&strm);
return "Error: Z_NEED_DICT";
break;
case Z_DATA_ERROR:
inflateEnd(&strm);
return "Error: Z_DATA_ERROR";
break;
case Z_MEM_ERROR:
inflateEnd(&strm);
return "Error: Z_MEM_ERROR";
break;
default:
break;
}
} while ( ret != Z_STREAM_END );
inflateEnd(&strm);
return QString( (char *)out );
}
Речь идет о третьем/четвертом переписывании, которое я пробовал. Метод строки сжатия возвращает это: xóHÍÉÉWÏ/ÊIQ Возможно, это правильно, может быть, нет, не знаю.
Метод decapseString возвращает это: Ошибка: Z_NEED_DICT;
Независимо от того, что я делаю (я пробовал некоторые другие примеры, найденные в Интернете, и при переполнении стека).
Прямо сейчас я просто кормлю строки из JS, в конце концов, мне хотелось бы сжать/распаковать строки, отправленные с сервера telnet, используя telopt 86.
Любые подсказки/указатели будут оценены. Моя цель прямо сейчас состоит в том, чтобы выстроить простой тест на вход/выход.
ОБНОВИТЬ:
После прохождения кода расширения zlib моя проблема здесь:
state->mode = hold & 0x200 ? DICTID : TYPE;
Zlib ожидает какой-то заголовок строки. hold
- это буфер, и DICTID отправит его, чтобы запросить Z_DICT_NEEDED. Это, скорее всего, потому, что заголовок не существует или теряется во время прохождения строки. Если я его взломаю и скажу state->mode = TYPE;
то я получу ошибку данных.
Кроме того, я изменил функцию распаковки следующим образом:
QString MainWindow::decompressString(QString s) {
QByteArray str = s.toLocal8Bit();
unsigned char in[CHUNK];
for ( int i = 0; i < str.size(); i++ ) {
in[i] = (unsigned char)str.at(i);
}
fflush(stdout);
int ret,flush;
z_stream strm;
unsigned char out[CHUNK];
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if ( ret != Z_OK ) {
return "ERROR: Failed to init z_stream for inflate";
}
// do until end of string
do {
strm.avail_in = str.size();
strm.next_in = in;
strm.avail_out = CHUNK;
strm.next_out = out;
flush = Z_NO_FLUSH;
ret = inflate(&strm,flush);
if ( ret == Z_STREAM_ERROR) {
return "ERROR: Z_STREAM_ERROR when inflating.";
}
switch( ret ) {
case Z_NEED_DICT:
inflateEnd(&strm);
return "Error: Z_NEED_DICT";
break;
case Z_DATA_ERROR:
inflateEnd(&strm);
return "Error: Z_DATA_ERROR";
break;
case Z_MEM_ERROR:
inflateEnd(&strm);
return "Error: Z_MEM_ERROR";
break;
default:
break;
}
} while ( ret != Z_STREAM_END );
inflateEnd(&strm);
return QString( (char *)out );
}
Затем, используя printf как на выходе, создаваемом deflate, так и на том, что посылается для раздувания, и данные (шестнадцатеричные значения для каждого символа) кажутся одинаковыми.
По сути, вы не можете.
QStrings "потеряет" некоторые данные. Чтобы выполнить сжатие/декомпрессию с помощью zlib, вам нужно работать с QByteArray, на самом деле, это еще проще, если вы работаете только с строками STL и только конвертируете в QByteArrays, когда вам нужно. Решение, которое я нашел, работает с pantehma.net http://panthema.net/2007/0328-ZLibString.html
Поскольку я читаю сжатые строки из внешнего источника, я просто не конвертирую их в QStrings и обрабатываю сжатие/декомпрессию в слое C и не пытаюсь передать его javascript. Это просто не стоило усилий, чтобы заставить его работать.
Счастливого Рождества тому, кто голосовал по этому вопросу.
(de)compressed
функциях вы используете буферыout
иin
в цикле, не перемещая его. Это перезапишет любые предыдущие данные, если цикл повторяется более одного раза. Может быть, это делается для функции сжатия, и поэтому вы теряете словарь.