]> git.tdb.fi Git - libs/gui.git/blobdiff - source/graphics/devil/devilloader.cpp
Add some state checking to ImageLoader
[libs/gui.git] / source / graphics / devil / devilloader.cpp
index 23b04b32d64819bd839bc317ad3c81995c866d53..423b108a5bf6ad13d960099c03070cfe2e30b96b 100644 (file)
@@ -1,4 +1,5 @@
 #include <algorithm>
+#include <msp/strings/format.h>
 #include <IL/il.h>
 #include "devilloader.h"
 
@@ -6,90 +7,65 @@ using namespace std;
 
 namespace {
 
-struct IOContext
-{
-       Msp::IO::Base *io;
-       char *buffer;
-       unsigned buf_fill;
-       unsigned buf_max;
-       unsigned position;
-};
-
 unsigned char eof(void *handle)
 {
-       return reinterpret_cast<IOContext *>(handle)->io->eof();
+       return reinterpret_cast<Msp::IO::Seekable *>(handle)->eof();
 }
 
 int get(void *handle)
 {
-       IOContext *ctx = reinterpret_cast<IOContext *>(handle);
-       if(ctx->position<ctx->buf_fill)
-               return ctx->buffer[ctx->position++];
-       else
-       {
-               char c = ctx->io->get();
-               if(ctx->position<ctx->buf_max)
-                       ctx->buffer[ctx->position] = c;
-               ++ctx->position;
-               return c;
-       }
+       return reinterpret_cast<Msp::IO::Seekable *>(handle)->get();
 }
 
 int read(void *buf, unsigned size, unsigned count, void *handle)
 {
-       IOContext *ctx = reinterpret_cast<IOContext *>(handle);
+       Msp::IO::Seekable *io = reinterpret_cast<Msp::IO::Seekable *>(handle);
        char *cbuf = reinterpret_cast<char *>(buf);
-       unsigned len = size*count;
-       unsigned ret = 0;
-
-       if(ctx->position<ctx->buf_fill)
-       {
-               unsigned copy_len = min(ctx->buf_fill-ctx->position, len);
-               copy(ctx->buffer+ctx->position, ctx->buffer+ctx->position+copy_len, cbuf);
-               ctx->position += copy_len;
-               ret += copy_len;
-               cbuf += copy_len;
-               len -= copy_len;
-       }
-
-       if(len)
+       unsigned i = 0;
+       for(; i<count; ++i)
        {
-               unsigned read_len = ctx->io->read(cbuf, len);
-               if(ctx->position<ctx->buf_max)
-               {
-                       unsigned copy_len = min(ctx->buf_max-ctx->position, read_len);
-                       copy(cbuf, cbuf+copy_len, ctx->buffer+ctx->position);
-                       ctx->buf_fill += copy_len;
-               }
-               ret += read_len;
-               ctx->position += read_len;
+               unsigned len = io->read(cbuf, size);
+               cbuf += size;
+               if(len<size)
+                       break;
        }
-
-       return ret;
+       return i;
 }
 
-int seek(void *handle, int offset, int type)
+int seek(void *handle, int offset, int il_type)
 {
-       IOContext *ctx = reinterpret_cast<IOContext *>(handle);
-
-       unsigned new_pos = ctx->position;
-       if(type==IL_SEEK_SET)
-               new_pos = offset;
-       else if(type==IL_SEEK_CUR)
-               new_pos += offset;
+       Msp::IO::SeekType type;
+       if(il_type==IL_SEEK_SET)
+               type = Msp::IO::S_BEG;
+       else if(il_type==IL_SEEK_CUR)
+               type = Msp::IO::S_CUR;
+       else if(il_type==IL_SEEK_END)
+               type = Msp::IO::S_END;
        else
                return -1;
 
-       if(new_pos>ctx->buf_fill)
-               new_pos = ctx->buf_fill;
-       ctx->position = new_pos;
+       reinterpret_cast<Msp::IO::Seekable *>(handle)->seek(offset, type);
 
        return 0;
 }
 
 int tell(void *handle)
 {
-       return reinterpret_cast<IOContext *>(handle)->position;
+       return reinterpret_cast<Msp::IO::Seekable *>(handle)->tell();
+}
+
+std::string error_string(ILenum err)
+{
+       switch(err)
+       {
+       case IL_FORMAT_NOT_SUPPORTED: return "Format not supported";
+       case IL_INTERNAL_ERROR: return "DevIL internal error";
+       case IL_INVALID_FILE_HEADER: return "Invalid file header";
+       case IL_FILE_READ_ERROR: return "File read error";
+       case IL_LIB_PNG_ERROR: return "LibPNG error";
+       case IL_LIB_JPEG_ERROR: return "LibJPEG error";
+       default: return Msp::format("Unknown error (%04X)", err);
+       }
 }
 
 } // namespace
@@ -98,9 +74,8 @@ int tell(void *handle)
 namespace Msp {
 namespace Graphics {
 
-DevilLoader::DevilLoader(IO::Base &i, const string &s):
-       io(i),
-       signature(s)
+DevilLoader::DevilLoader(IO::Seekable &i):
+       io(i)
 {
        static bool il_init_done = false;
 
@@ -126,20 +101,14 @@ bool DevilLoader::detect(const string &sig)
        return type!=IL_TYPE_UNKNOWN;
 }
 
-void DevilLoader::load(Image::Data &data)
+void DevilLoader::load_(Image::Data &data)
 {
-       IOContext ctx;
-       ctx.io = &io;
-       char buffer[4096];
-       ctx.buffer = buffer;
-       ctx.buf_max = sizeof(buffer);
-       copy(signature.begin(), signature.end(), buffer);
-       ctx.buf_fill = signature.size();
-       ctx.position = 0;
-
        ilSetRead(0, 0, eof, get, read, seek, tell);
        ilBindImage(id);
-       ilLoadF(IL_TYPE_UNKNOWN, &ctx);
+
+       ilGetError();
+       if(!ilLoadF(IL_TYPE_UNKNOWN, &io))
+               throw bad_image_data(error_string(ilGetError()));
 
        switch(ilGetInteger(IL_IMAGE_FORMAT))
        {
@@ -155,10 +124,11 @@ void DevilLoader::load(Image::Data &data)
 
        data.width = ilGetInteger(IL_IMAGE_WIDTH);
        data.height = ilGetInteger(IL_IMAGE_HEIGHT);
-       unsigned data_size = data.width*data.height*ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
-       data.data = new char[data_size];
+       data.stride = data.width*ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL);
+       unsigned data_size = data.stride*data.height;
+       data.pixels = new char[data_size];
        ILubyte *il_data = ilGetData();
-       copy(il_data, il_data+data_size, data.data);
+       copy(il_data, il_data+data_size, data.pixels);
 
        ilBindImage(0);
        ilResetRead();