#include <FL/Fl.H>
#include "config.h"
#include "Fl_Image_Reader.h"
#include <FL/Fl_ICO_Image.H>
#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
# include <FL/Fl_PNG_Image.H>
#endif
Fl_ICO_Image::Fl_ICO_Image(const char *filename, int id, const unsigned char *data, const size_t datasize)
: Fl_BMP_Image(0,0),
idcount_(0),
icondirentry_(0)
{
Fl_Image_Reader rdr;
int r;
w(0); h(0); d(0); ld(0);
alloc_array = 0;
array = 0;
if (data) {
r = rdr.open(filename, data, datasize);
} else {
r = rdr.open(filename);
}
if (r == -1) {
ld(ERR_FILE_ACCESS);
} else {
load_ico_(rdr, id);
}
}
Fl_ICO_Image::~Fl_ICO_Image() {
delete[] icondirentry_;
}
void Fl_ICO_Image::load_ico_(Fl_Image_Reader &rdr, int id)
{
int pickedID = -1;
if (rdr.read_word() != 0 || rdr.read_word() != 1) {
Fl::error("Fl_ICO_Image: %s is not an ICO file.\n", rdr.name());
ld(ERR_FORMAT);
return;
}
idcount_ = rdr.read_word();
if (idcount() == 0) {
Fl::error("Fl_ICO_Image: %s - no image resources found\n", rdr.name());
ld(ERR_FORMAT);
return;
}
icondirentry_ = new IconDirEntry[idcount()];
for (int i = 0; i < idcount(); ++i) {
icondirentry_[i].bWidth = (int)rdr.read_byte();
icondirentry_[i].bHeight = (int)rdr.read_byte();
icondirentry_[i].bColorCount = (int)rdr.read_byte();
icondirentry_[i].bReserved = (int)rdr.read_byte();
icondirentry_[i].wPlanes = (int)rdr.read_word();
icondirentry_[i].wBitCount = (int)rdr.read_word();
icondirentry_[i].dwBytesInRes = (int)rdr.read_dword();
icondirentry_[i].dwImageOffset = (int)rdr.read_dword();
if (icondirentry_[i].bWidth == 0) icondirentry_[i].bWidth = 256;
if (icondirentry_[i].bHeight == 0) icondirentry_[i].bHeight = 256;
}
if (id <= -2) return;
if (!icondirentry_ || idcount() < 1 || id >= idcount()) {
ld(ERR_FORMAT);
return;
}
if (id == -1) {
int highestRes = 0, bitcount = 0;
for (int i = 0; i < idcount(); ++i) {
int res = icondirentry_[i].bWidth * icondirentry_[i].bHeight;
if (res > highestRes || (res == highestRes && icondirentry_[i].wBitCount > bitcount)) {
highestRes = res;
bitcount = icondirentry_[i].wBitCount;
pickedID = i;
}
}
} else {
pickedID = id;
}
if (pickedID < 0 ||
icondirentry_[pickedID].bWidth <= 0 ||
icondirentry_[pickedID].bHeight <= 0 ||
icondirentry_[pickedID].dwImageOffset <= 0||
icondirentry_[pickedID].dwBytesInRes <= 0)
{
ld(ERR_FORMAT);
return;
}
rdr.seek(icondirentry_[pickedID].dwImageOffset);
uchar b[8];
for (int i=0; i<8; ++i) b[i] = rdr.read_byte();
if (b[0]==0x89 && b[1]=='P' && b[2]=='N' && b[3]=='G' &&
b[4]=='\r' && b[5]=='\n' && b[6]==0x1A && b[7]=='\n')
{
#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
Fl_PNG_Image *png = new Fl_PNG_Image(rdr.name(), icondirentry_[pickedID].dwImageOffset);
int loaded = png ? png->fail() : ERR_FILE_ACCESS;
if (loaded < 0) {
w(0); h(0); d(0);
ld(loaded);
if (png) delete png;
return;
}
w(png->w());
h(png->h());
d(png->d());
array = png->array;
alloc_array = 1;
png->array = NULL;
png->alloc_array = 0;
delete png;
return;
#else
Fl::error("Fl_ICO_Image: %s - cannot decode PNG resource (no libpng support)!\n", rdr.name());
w(0); h(0); d(0);
ld(ERR_FORMAT);
return;
#endif
}
w(icondirentry_[pickedID].bWidth);
h(icondirentry_[pickedID].bHeight);
d(4);
if (((size_t)w()) * h() * d() > max_size()) {
Fl::warning("ICO file \"%s\" is too large!\n", rdr.name());
w(0); h(0); d(0);
ld(ERR_FORMAT);
return;
}
rdr.seek(icondirentry_[pickedID].dwImageOffset);
load_bmp_(rdr, h(), w());
}