GIFTranslator: try hard to not throw an exception

... by calling new(std::nothrow)

Also try really hard not to leak any memory in the process.

Lots of error checking added to check if reads and writes fail
returning B_IO_ERROR and if initialization fails returning B_NO_MEMORY
This commit is contained in:
John Scipione
2014-03-06 16:48:48 -05:00
parent 33ef87cd9e
commit 78bfaa98e1
4 changed files with 199 additions and 41 deletions
+6 -1
View File
@@ -22,6 +22,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <syslog.h> #include <syslog.h>
#include <new>
#include <ByteOrder.h> #include <ByteOrder.h>
#include <InterfaceDefs.h> #include <InterfaceDefs.h>
#include <TranslatorFormats.h> #include <TranslatorFormats.h>
@@ -139,7 +141,10 @@ GIFLoad::ReadGIFHeader()
fWidth = header[6] + (header[7] << 8); fWidth = header[6] + (header[7] << 8);
fHeight = header[8] + (header[9] << 8); fHeight = header[8] + (header[9] << 8);
fPalette = new LoadPalette(); fPalette = new(std::nothrow) LoadPalette();
if (fPalette == NULL)
return false;
// Global palette // Global palette
if (header[10] & GIF_LOCALCOLORMAP) { if (header[10] & GIF_LOCALCOLORMAP) {
fPalette->size_in_bits = (header[10] & 0x07) + 1; fPalette->size_in_bits = (header[10] & 0x07) + 1;
+174 -30
View File
@@ -24,6 +24,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <syslog.h> #include <syslog.h>
#include <new>
#include "GIFPrivate.h" #include "GIFPrivate.h"
@@ -58,13 +60,21 @@ GIFSave::GIFSave(BBitmap* bitmap, BPositionIO* output,
} }
fatalerror = false; fatalerror = false;
if (fSettings->SetGetInt32(GIF_SETTING_PALETTE_MODE) == OPTIMAL_PALETTE) if (fSettings->SetGetInt32(GIF_SETTING_PALETTE_MODE) == OPTIMAL_PALETTE) {
palette = new SavePalette(bitmap, palette = new(std::nothrow) SavePalette(bitmap,
fSettings->SetGetInt32(GIF_SETTING_PALETTE_SIZE)); fSettings->SetGetInt32(GIF_SETTING_PALETTE_SIZE));
else } else {
palette = new SavePalette( palette = new(std::nothrow) SavePalette(
fSettings->SetGetInt32(GIF_SETTING_PALETTE_MODE)); fSettings->SetGetInt32(GIF_SETTING_PALETTE_MODE));
}
if (palette == NULL) {
fatalerror = true;
return;
}
if (!palette->IsValid()) { if (!palette->IsValid()) {
delete palette;
fatalerror = true; fatalerror = true;
return; return;
} }
@@ -80,13 +90,33 @@ GIFSave::GIFSave(BBitmap* bitmap, BPositionIO* output,
if (debug) if (debug)
syslog(LOG_INFO, "GIFSave::GIFSave() - Using dithering\n"); syslog(LOG_INFO, "GIFSave::GIFSave() - Using dithering\n");
red_error = new int32[width + 2]; red_error = new(std::nothrow) int32[width + 2];
if (red_error == NULL) {
delete palette;
fatalerror = true;
return;
}
red_error = &red_error[1]; red_error = &red_error[1];
// Allow index of -1 too // Allow index of -1 too
green_error = new int32[width + 2];
green_error = new(std::nothrow) int32[width + 2];
if (green_error == NULL) {
delete palette;
delete[] red_error;
fatalerror = true;
return;
}
green_error = &green_error[1]; green_error = &green_error[1];
// Allow index of -1 too // Allow index of -1 too
blue_error = new int32[width + 2];
blue_error = new(std::nothrow) int32[width + 2];
if (blue_error == NULL) {
delete palette;
delete[] red_error;
delete[] green_error;
fatalerror = true;
return;
}
blue_error = &blue_error[1]; blue_error = &blue_error[1];
// Allow index of -1 too // Allow index of -1 too
@@ -151,11 +181,29 @@ GIFSave::GIFSave(BBitmap* bitmap, BPositionIO* output,
this->output = output; this->output = output;
this->bitmap = bitmap; this->bitmap = bitmap;
WriteGIFHeader();
if (WriteGIFHeader() != B_OK) {
delete palette;
delete[] red_error;
delete[] green_error;
delete[] blue_error;
fatalerror = true;
return;
}
if (debug) if (debug)
syslog(LOG_INFO, "GIFSave::GIFSave() - Wrote gif header\n"); syslog(LOG_INFO, "GIFSave::GIFSave() - Wrote gif header\n");
hash = new SFHash(1 << 16); hash = new(std::nothrow) SFHash(1 << 16);
if (hash == NULL) {
delete palette;
delete[] red_error;
delete[] green_error;
delete[] blue_error;
fatalerror = true;
return;
}
WriteGIFControlBlock(); WriteGIFControlBlock();
if (debug) if (debug)
syslog(LOG_INFO, "GIFSave::GIFSave() - Wrote gif control block\n"); syslog(LOG_INFO, "GIFSave::GIFSave() - Wrote gif control block\n");
@@ -188,7 +236,7 @@ GIFSave::~GIFSave()
} }
void status_t
GIFSave::WriteGIFHeader() GIFSave::WriteGIFHeader()
{ {
// Standard header // Standard header
@@ -200,19 +248,28 @@ GIFSave::WriteGIFHeader()
header[9] = (height & 0xff00) >> 8; header[9] = (height & 0xff00) >> 8;
header[10] = 0xf0 | (palette->SizeInBits() - 1); header[10] = 0xf0 | (palette->SizeInBits() - 1);
header[11] = palette->BackgroundIndex(); header[11] = palette->BackgroundIndex();
output->Write(header, 13); if (output->Write(header, 13) < 0)
return B_IO_ERROR;
// global palette // global palette
int size = (1 << palette->SizeInBits()) * 3; int size = (1 << palette->SizeInBits()) * 3;
uint8* buffer = new uint8[size];
// can't be bigger than this // can't be bigger than this
uint8* buffer = new(std::nothrow) uint8[size];
if (buffer == NULL)
return B_NO_MEMORY;
palette->GetColors(buffer, size); palette->GetColors(buffer, size);
output->Write(buffer, size); if (output->Write(buffer, size) < 0) {
delete[] buffer;
return B_IO_ERROR;
}
delete[] buffer; delete[] buffer;
return B_OK;
} }
void status_t
GIFSave::WriteGIFControlBlock() GIFSave::WriteGIFControlBlock()
{ {
unsigned char b[8] = { unsigned char b[8] = {
@@ -223,11 +280,11 @@ GIFSave::WriteGIFControlBlock()
b[3] = b[3] | 1; b[3] = b[3] | 1;
b[6] = palette->TransparentIndex(); b[6] = palette->TransparentIndex();
} }
output->Write(b, 8); return output->Write(b, 8) < 0 ? B_IO_ERROR : B_OK;
} }
void status_t
GIFSave::WriteGIFImageHeader() GIFSave::WriteGIFImageHeader()
{ {
unsigned char header[10]; unsigned char header[10];
@@ -245,21 +302,55 @@ GIFSave::WriteGIFImageHeader()
else else
header[9] = BLOCK_TERMINATOR; header[9] = BLOCK_TERMINATOR;
output->Write(header, 10); return output->Write(header, 10) < 0 ? B_IO_ERROR : B_OK;
} }
void status_t
GIFSave::WriteGIFImageData() GIFSave::WriteGIFImageData()
{ {
InitFrame(); InitFrame();
status_t result = B_OK;
code_value = (short*)malloc(HASHSIZE * 2); code_value = (short*)malloc(HASHSIZE * 2);
if (code_value == NULL)
return B_NO_MEMORY;
prefix_code = (short*)malloc(HASHSIZE * 2); prefix_code = (short*)malloc(HASHSIZE * 2);
if (prefix_code == NULL) {
free(code_value);
return B_NO_MEMORY;
}
append_char = (unsigned char*)malloc(HASHSIZE); append_char = (unsigned char*)malloc(HASHSIZE);
if (append_char == NULL) {
free(code_value);
free(prefix_code);
return B_NO_MEMORY;
}
ResetHashtable(); ResetHashtable();
output->Write(&code_size, 1); if (output->Write(&code_size, 1) < 0) {
OutputCode(clear_code, BITS); free(code_value);
free(prefix_code);
free(append_char);
return B_IO_ERROR;
}
result = OutputCode(clear_code, BITS);
if (result != B_OK) {
free(code_value);
free(prefix_code);
free(append_char);
return B_IO_ERROR;
}
string_code = NextPixel(0); string_code = NextPixel(0);
int area = height * width; int area = height * width;
@@ -270,12 +361,27 @@ GIFSave::WriteGIFImageData()
string_code = y; string_code = y;
else { else {
AddToHashtable(string_code, character); AddToHashtable(string_code, character);
OutputCode(string_code, BITS); result = OutputCode(string_code, BITS);
if (result != B_OK) {
free(code_value);
free(prefix_code);
free(append_char);
return B_IO_ERROR;
}
if (next_code > max_code) { if (next_code > max_code) {
BITS++; BITS++;
if (BITS > LZ_MAX_BITS) { if (BITS > LZ_MAX_BITS) {
OutputCode(clear_code, LZ_MAX_BITS); result = OutputCode(clear_code, LZ_MAX_BITS);
if (result != B_OK) {
free(code_value);
free(prefix_code);
free(append_char);
return B_IO_ERROR;
}
BITS = code_size + 1; BITS = code_size + 1;
ResetHashtable(); ResetHashtable();
next_code = clear_code + 1; next_code = clear_code + 1;
@@ -288,22 +394,55 @@ GIFSave::WriteGIFImageData()
} }
} }
OutputCode(string_code, BITS); result = OutputCode(string_code, BITS);
OutputCode(end_code, BITS); if (result != B_OK) {
OutputCode(0, BITS, true); free(code_value);
free(prefix_code);
free(append_char);
return B_IO_ERROR;
}
result = OutputCode(end_code, BITS);
if (result != B_OK) {
free(code_value);
free(prefix_code);
free(append_char);
return B_IO_ERROR;
}
result = OutputCode(0, BITS, true);
if (result != B_OK) {
free(code_value);
free(prefix_code);
free(append_char);
return B_IO_ERROR;
}
char t = BLOCK_TERMINATOR; char t = BLOCK_TERMINATOR;
output->Write(&t, 1); if (output->Write(&t, 1) < 0) {
free(code_value);
free(prefix_code);
free(append_char);
return B_IO_ERROR;
}
free(code_value); free(code_value);
free(prefix_code); free(prefix_code);
free(append_char); free(append_char);
return result;
} }
void status_t
GIFSave::OutputCode(short code, int BITS, bool flush) GIFSave::OutputCode(short code, int BITS, bool flush)
{ {
if (!flush) { if (!flush) {
bit_buffer |= (unsigned int) code << bit_count; bit_buffer |= (unsigned int)code << bit_count;
bit_count += BITS; bit_count += BITS;
while (bit_count >= 8) { while (bit_count >= 8) {
byte_buffer[byte_count + 1] = (unsigned char)(bit_buffer & 0xff); byte_buffer[byte_count + 1] = (unsigned char)(bit_buffer & 0xff);
@@ -313,7 +452,9 @@ GIFSave::OutputCode(short code, int BITS, bool flush)
} }
if (byte_count >= 255) { if (byte_count >= 255) {
byte_buffer[0] = 255; byte_buffer[0] = 255;
output->Write(byte_buffer, 256); if (output->Write(byte_buffer, 256) < 0)
return B_IO_ERROR;
if (byte_count == 256) { if (byte_count == 256) {
byte_buffer[1] = byte_buffer[256]; byte_buffer[1] = byte_buffer[256];
byte_count = 1; byte_count = 1;
@@ -331,9 +472,12 @@ GIFSave::OutputCode(short code, int BITS, bool flush)
} }
if (byte_count > 0) { if (byte_count > 0) {
byte_buffer[0] = (unsigned char)byte_count; byte_buffer[0] = (unsigned char)byte_count;
output->Write(byte_buffer, byte_count + 1); if (output->Write(byte_buffer, byte_count + 1) < 0)
return B_IO_ERROR;
} }
} }
return B_OK;
} }
+5 -5
View File
@@ -44,11 +44,11 @@ public:
bool fatalerror; bool fatalerror;
private: private:
void WriteGIFHeader(); status_t WriteGIFHeader();
void WriteGIFControlBlock(); status_t WriteGIFControlBlock();
void WriteGIFImageHeader(); status_t WriteGIFImageHeader();
void WriteGIFImageData(); status_t WriteGIFImageData();
void OutputCode(short code, int BITS, status_t OutputCode(short code, int BITS,
bool flush = false); bool flush = false);
unsigned char NextPixel(int pixel); unsigned char NextPixel(int pixel);
+14 -5
View File
@@ -265,7 +265,13 @@ GIFTranslator::DerivedTranslate(BPositionIO* inSource,
if (result != B_OK) if (result != B_OK)
return result; return result;
GIFSave* gifSave = new GIFSave(bitmap, outDestination, fSettings); GIFSave* gifSave = new(std::nothrow) GIFSave(bitmap, outDestination,
fSettings);
if (gifSave == NULL) {
delete bitmap;
return B_NO_MEMORY;
}
if (gifSave->fatalerror) { if (gifSave->fatalerror) {
delete gifSave; delete gifSave;
delete bitmap; delete bitmap;
@@ -275,7 +281,10 @@ GIFTranslator::DerivedTranslate(BPositionIO* inSource,
delete bitmap; delete bitmap;
} else { } else {
// GIF to BBitmap // GIF to BBitmap
GIFLoad* gifLoad = new GIFLoad(inSource, outDestination); GIFLoad* gifLoad = new(std::nothrow) GIFLoad(inSource, outDestination);
if (gifLoad == NULL)
return B_NO_MEMORY;
if (gifLoad->fatalerror) { if (gifLoad->fatalerror) {
delete gifLoad; delete gifLoad;
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -296,7 +305,7 @@ BTranslator*
make_nth_translator(int32 n, image_id you, uint32 flags, ...) make_nth_translator(int32 n, image_id you, uint32 flags, ...)
{ {
if (n == 0) if (n == 0)
return new GIFTranslator(); return new(std::nothrow) GIFTranslator();
return NULL; return NULL;
} }
@@ -324,7 +333,7 @@ GIFTranslator::~GIFTranslator()
BView* BView*
GIFTranslator::NewConfigView(TranslatorSettings* settings) GIFTranslator::NewConfigView(TranslatorSettings* settings)
{ {
return new GIFView(settings); return new(std::nothrow) GIFView(settings);
} }
@@ -332,7 +341,7 @@ int
main() main()
{ {
BApplication app("application/x-vnd.Haiku-GIFTranslator"); BApplication app("application/x-vnd.Haiku-GIFTranslator");
status_t result = LaunchTranslatorWindow(new GIFTranslator, status_t result = LaunchTranslatorWindow(new(std::nothrow) GIFTranslator,
B_TRANSLATE("GIF Settings"), kRectView); B_TRANSLATE("GIF Settings"), kRectView);
if (result == B_OK) { if (result == B_OK) {
app.Run(); app.Run();