Russian Qt Forum

Программирование => С/C++ => Тема начата: Пантер от Декабрь 25, 2012, 13:49



Название: Как избежать краша в libjpeg при открытии некорректного файла?
Отправлено: Пантер от Декабрь 25, 2012, 13:49
Вот код:

Код
C++ (Qt)
static void error_exit (j_common_ptr cinfo)
{
Q_UNUSED (cinfo)
qDebug() << Q_FUNC_INFO;
}
 
static void output_message (j_common_ptr cinfo)
{
Q_UNUSED (cinfo)
qDebug() << Q_FUNC_INFO;
}
 
static void emit_message (j_common_ptr cinfo, int msg_level)
{
Q_UNUSED (cinfo)
Q_UNUSED (msg_level)
qDebug() << Q_FUNC_INFO;
}
 
static void format_message (j_common_ptr cinfo, char *buffer)
{
Q_UNUSED (cinfo)
Q_UNUSED (buffer)
qDebug() << Q_FUNC_INFO;
}
 
static void reset_error_mgr (j_common_ptr cinfo)
{
qDebug() << Q_FUNC_INFO;
cinfo->err->num_warnings = 0;
cinfo->err->msg_code = 0;
}
 

Код
C++ (Qt)
bool JpegFormat::load (const QByteArray &data, const QSize &size)
{
Q_UNUSED (size)
qDebug() << Q_FUNC_INFO;
 
jpeg_decompress_struct decompressStruct;
jpeg_error_mgr error;
 
decompressStruct.err = jpeg_std_error (&error);
jpeg_CreateDecompress (&decompressStruct,
       JPEG_LIB_VERSION,
sizeof (decompressStruct));
error.error_exit = error_exit;
error.emit_message = emit_message;
error.output_message = output_message;
error.format_message = format_message;
error.reset_error_mgr = reset_error_mgr;
 
auto inBuf = reinterpret_cast<const unsigned char *> (data.constData());
jpeg_mem_src (&decompressStruct,
const_cast<unsigned char *> (inBuf),
data.size());
 
if (jpeg_read_header (&decompressStruct, true) != JPEG_HEADER_OK) {
jpeg_destroy_decompress (&decompressStruct);
return false;
}
 
decompressStruct.out_color_space = JCS_GRAYSCALE;
jpeg_start_decompress (&decompressStruct);
 
size_ = QSize (decompressStruct.image_width, decompressStruct.image_height);
data_.fill (0,
decompressStruct.image_width * decompressStruct.image_height
  );
auto outBuf = reinterpret_cast<unsigned char *> (data_.data());
 
while (decompressStruct.output_scanline < decompressStruct.image_height) {
jpeg_read_scanlines (&decompressStruct, &outBuf, 1);
outBuf += decompressStruct.image_width;
}
 
jpeg_finish_decompress (&decompressStruct);
jpeg_destroy_decompress (&decompressStruct);
 
return true;
}
 

В jpeg_start_decompress происходит падение, как этого избежать? Файл во вложении.


Название: Re: Как избежать краша в libjpeg при открытии некорректного файла?
Отправлено: ecspertiza от Декабрь 25, 2012, 14:24
честно скажу что с libjpeg ни разу не работал, но вот в голову такая мысль пришла, а что если проверять файл на наличие

0xFFD8 и 0xFFD9 - стало быть начало и конец jpg файла ? Хотя может есть более верное решение  :-\
 


Название: Re: Как избежать краша в libjpeg при открытии некорректного файла?
Отправлено: Пантер от Декабрь 25, 2012, 14:27
jpeg_read_header нормально отрабатывает, значит, хидер корректен, по идее.


Название: Re: Как избежать краша в libjpeg при открытии некорректного файла?
Отправлено: xokc от Декабрь 25, 2012, 14:44
А как падения избежать-то хочется? Что бы написало "вы подсунули плохой JPEG" и продолжало ждать нормального JPEG или всё же пыталось бы распаковать хоть что-то из битого JPEG?


Название: Re: Как избежать краша в libjpeg при открытии некорректного файла?
Отправлено: Пантер от Декабрь 25, 2012, 14:46
Первый вариант. То есть, просто должно сказать, что файл не корректен.


Название: Re: Как избежать краша в libjpeg при открытии некорректного файла?
Отправлено: xokc от Декабрь 25, 2012, 16:00
Тогда, видимо, надо почитать документацию на libjpeg в разделе Error handling.


Название: Re: Как избежать краша в libjpeg при открытии некорр
Отправлено: Пантер от Декабрь 26, 2012, 10:58
Решение подсказано на linux.org.ru
Код
C++ (Qt)
struct JpegError : public jpeg_error_mgr {
jmp_buf jmpBuffer;
};
 
static void error_exit (j_common_ptr cinfo)
{
JpegError *error = static_cast<JpegError *> (cinfo->err);
longjmp (error->jmpBuffer, 1);
}
//-------------------------------
bool JpegFormat::load (const QByteArray &data, const QSize &size)
{
Q_UNUSED (size)
 
jpeg_decompress_struct decompressStruct;
JpegError error;
 
decompressStruct.err = jpeg_std_error (&error);
 
error.error_exit = error_exit;
 
#if 0
error.emit_message = emit_message;
error.output_message = output_message;
error.format_message = format_message;
error.reset_error_mgr = reset_error_mgr;
#endif //0
 
if (!setjmp (error.jmpBuffer)) {
jpeg_CreateDecompress (&decompressStruct,
  JPEG_LIB_VERSION,
  sizeof (decompressStruct)
 );
 
auto inBuf = reinterpret_cast<const unsigned char *> (data.constData());
jpeg_mem_src (&decompressStruct,
 const_cast<unsigned char *> (inBuf),
 data.size());
 
if (jpeg_read_header (&decompressStruct, true) != JPEG_HEADER_OK) {
jpeg_destroy_decompress (&decompressStruct);
return false;
}
 
decompressStruct.out_color_space = JCS_GRAYSCALE;
jpeg_start_decompress (&decompressStruct);
 
size_ = QSize (decompressStruct.image_width, decompressStruct.image_height);
data_.fill (0,
decompressStruct.image_width * decompressStruct.image_height
  );
auto outBuf = reinterpret_cast<unsigned char *> (data_.data());
 
while (decompressStruct.output_scanline < decompressStruct.image_height) {
jpeg_read_scanlines (&decompressStruct, &outBuf, 1);
outBuf += decompressStruct.image_width;
}
 
jpeg_finish_decompress (&decompressStruct);
jpeg_destroy_decompress (&decompressStruct);
}
 
 
return !data_.isEmpty ();
}