]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libsdl-image/contrib/IMG_lbm.c
update
[l4.git] / l4 / pkg / libsdl-image / contrib / IMG_lbm.c
1 /*
2     SDL_image:  An example image loading library for use with SDL
3     Copyright (C) 1997-2009 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22
23 /* This is a ILBM image file loading framework
24    Load IFF pictures, PBM & ILBM packing methods, with or without stencil
25    Written by Daniel Morais ( Daniel AT Morais DOT com ) in September 2001.
26    24 bits ILBM files support added by Marc Le Douarain (http://www.multimania.com/mavati)
27    in December 2002.
28    EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain
29    (http://www.multimania.com/mavati) in December 2003.
30    Stencil and colorkey fixes by David Raulo (david.raulo AT free DOT fr) in February 2004.
31    Buffer overflow fix in RLE decompression by David Raulo in January 2008.
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 #include "SDL_endian.h"
39 #include "SDL_image.h"
40
41 #ifdef LOAD_LBM
42
43
44 #define MAXCOLORS 256
45
46 /* Structure for an IFF picture ( BMHD = Bitmap Header ) */
47
48 typedef struct
49 {
50     Uint16 w, h;                /* width & height of the bitmap in pixels */
51     Sint16 x, y;                /* screen coordinates of the bitmap */
52     Uint8 planes;               /* number of planes of the bitmap */
53     Uint8 mask;                 /* mask type ( 0 => no mask ) */
54     Uint8 tcomp;                /* compression type */
55     Uint8 pad1;                 /* dummy value, for padding */
56     Uint16 tcolor;              /* transparent color */
57     Uint8 xAspect,              /* pixel aspect ratio */
58           yAspect;
59     Sint16  Lpage;              /* width of the screen in pixels */
60     Sint16  Hpage;              /* height of the screen in pixels */
61 } BMHD;
62
63 int IMG_isLBM( SDL_RWops *src )
64 {
65         int start;
66         int   is_LBM;
67         Uint8 magic[4+4+4];
68
69         if ( !src ) 
70                 return 0;
71         start = SDL_RWtell(src);
72         is_LBM = 0;
73         if ( SDL_RWread( src, magic, sizeof(magic), 1 ) )
74         {
75                 if ( !memcmp( magic, "FORM", 4 ) &&
76                         ( !memcmp( magic + 8, "PBM ", 4 ) ||
77                           !memcmp( magic + 8, "ILBM", 4 ) ) )
78                 {
79                         is_LBM = 1;
80                 }
81         }
82         SDL_RWseek(src, start, RW_SEEK_SET);
83         return( is_LBM );
84 }
85
86 SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
87 {
88         int start;
89         SDL_Surface *Image;
90         Uint8       id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
91         Uint32      size, bytesloaded, nbcolors;
92         Uint32      i, j, bytesperline, nbplanes, stencil, plane, h;
93         Uint32      remainingbytes;
94         Uint32      width;
95         BMHD          bmhd;
96         char        *error;
97         Uint8       flagHAM,flagEHB;
98
99         Image   = NULL;
100         error   = NULL;
101         MiniBuf = NULL;
102
103         if ( !src ) {
104                 /* The error message has been set in SDL_RWFromFile */
105                 return NULL;
106         }
107         start = SDL_RWtell(src);
108
109         if ( !SDL_RWread( src, id, 4, 1 ) )
110         {
111                 error="error reading IFF chunk";
112                 goto done;
113         }
114
115         /* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
116         if ( !SDL_RWread( src, &size, 4, 1 ) )
117         {
118                 error="error reading IFF chunk size";
119                 goto done;
120         }
121
122         /* As size is not used here, no need to swap it */
123
124         if ( memcmp( id, "FORM", 4 ) != 0 )
125         {
126                 error="not a IFF file";
127                 goto done;
128         }
129
130         if ( !SDL_RWread( src, id, 4, 1 ) )
131         {
132                 error="error reading IFF chunk";
133                 goto done;
134         }
135
136         pbm = 0;
137
138         /* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */
139         if ( !memcmp( id, "PBM ", 4 ) ) pbm = 1;
140         else if ( memcmp( id, "ILBM", 4 ) )
141         {
142                 error="not a IFF picture";
143                 goto done;
144         }
145
146         nbcolors = 0;
147
148         memset( &bmhd, 0, sizeof( BMHD ) );
149         flagHAM = 0;
150         flagEHB = 0;
151
152         while ( memcmp( id, "BODY", 4 ) != 0 )
153         {
154                 if ( !SDL_RWread( src, id, 4, 1 ) ) 
155                 {
156                         error="error reading IFF chunk";
157                         goto done;
158                 }
159
160                 if ( !SDL_RWread( src, &size, 4, 1 ) )
161                 {
162                         error="error reading IFF chunk size";
163                         goto done;
164                 }
165
166                 bytesloaded = 0;
167
168                 size = SDL_SwapBE32( size );
169
170                 if ( !memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
171                 {
172                         if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
173                         {
174                                 error="error reading BMHD chunk";
175                                 goto done;
176                         }
177
178                         bytesloaded = sizeof( BMHD );
179
180                         bmhd.w          = SDL_SwapBE16( bmhd.w );
181                         bmhd.h          = SDL_SwapBE16( bmhd.h );
182                         bmhd.x          = SDL_SwapBE16( bmhd.x );
183                         bmhd.y          = SDL_SwapBE16( bmhd.y );
184                         bmhd.tcolor = SDL_SwapBE16( bmhd.tcolor );
185                         bmhd.Lpage      = SDL_SwapBE16( bmhd.Lpage );
186                         bmhd.Hpage      = SDL_SwapBE16( bmhd.Hpage );
187                 }
188
189                 if ( !memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
190                 {
191                         if ( !SDL_RWread( src, &colormap, size, 1 ) )
192                         {
193                                 error="error reading CMAP chunk";
194                                 goto done;
195                         }
196
197                         bytesloaded = size;
198                         nbcolors = size / 3;
199                 }
200
201                 if ( !memcmp( id, "CAMG", 4 ) ) /* Amiga ViewMode  */
202                 {
203                         Uint32 viewmodes;
204                         if ( !SDL_RWread( src, &viewmodes, sizeof(viewmodes), 1 ) )
205                         {
206                                 error="error reading CAMG chunk";
207                                 goto done;
208                         }
209
210                         bytesloaded = size;
211                         viewmodes = SDL_SwapBE32( viewmodes );
212                         if ( viewmodes & 0x0800 )
213                                 flagHAM = 1;
214                         if ( viewmodes & 0x0080 )
215                                 flagEHB = 1;
216                 }
217
218                 if ( memcmp( id, "BODY", 4 ) )
219                 {
220                         if ( size & 1 ) ++size;         /* padding ! */
221                         size -= bytesloaded;
222                         /* skip the remaining bytes of this chunk */
223                         if ( size )     SDL_RWseek( src, size, RW_SEEK_CUR );
224                 }
225         }
226
227         /* compute some usefull values, based on the bitmap header */
228
229         width = ( bmhd.w + 15 ) & 0xFFFFFFF0;  /* Width in pixels modulo 16 */
230
231         bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
232
233         nbplanes = bmhd.planes;
234
235         if ( pbm )                         /* File format : 'Packed Bitmap' */
236         {
237                 bytesperline *= 8;
238                 nbplanes = 1;
239         }
240
241         stencil = (bmhd.mask & 1);   /* There is a mask ( 'stencil' ) */
242
243         /* Allocate memory for a temporary buffer ( used for
244            decompression/deinterleaving ) */
245
246         MiniBuf = (void *)malloc( bytesperline * (nbplanes + stencil) );
247         if ( MiniBuf == NULL )
248         {
249                 error="no enough memory for temporary buffer";
250                 goto done;
251         }
252
253         if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, (bmhd.planes==24 || flagHAM==1)?24:8, 0, 0, 0, 0 ) ) == NULL )
254            goto done;
255
256         if ( bmhd.mask & 2 )               /* There is a transparent color */
257                 SDL_SetColorKey( Image, SDL_SRCCOLORKEY, bmhd.tcolor );
258
259         /* Update palette informations */
260
261         /* There is no palette in 24 bits ILBM file */
262         if ( nbcolors>0 && flagHAM==0 )
263         {
264                 /* FIXME: Should this include the stencil? See comment below */
265                 int nbrcolorsfinal = 1 << (nbplanes + stencil);
266                 ptr = &colormap[0];
267
268                 for ( i=0; i<nbcolors; i++ )
269                 {
270                         Image->format->palette->colors[i].r = *ptr++;
271                         Image->format->palette->colors[i].g = *ptr++;
272                         Image->format->palette->colors[i].b = *ptr++;
273                 }
274
275                 /* Amiga EHB mode (Extra-Half-Bright) */
276                 /* 6 bitplanes mode with a 32 colors palette */
277                 /* The 32 last colors are the same but divided by 2 */
278                 /* Some Amiga pictures save 64 colors with 32 last wrong colors, */
279                 /* they shouldn't !, and here we overwrite these 32 bad colors. */
280                 if ( (nbcolors==32 || flagEHB ) && (1<<bmhd.planes)==64 )
281                 {
282                         nbcolors = 64;
283                         ptr = &colormap[0];
284                         for ( i=32; i<64; i++ )
285                         {
286                                 Image->format->palette->colors[i].r = (*ptr++)/2;
287                                 Image->format->palette->colors[i].g = (*ptr++)/2;
288                                 Image->format->palette->colors[i].b = (*ptr++)/2;
289                         }
290                 }
291
292                 /* If nbcolors < 2^nbplanes, repeat the colormap */
293                 /* This happens when pictures have a stencil mask */
294                 if ( nbrcolorsfinal > (1<<bmhd.planes) ) {
295                         nbrcolorsfinal = (1<<bmhd.planes);
296                 }
297                 for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
298                 {
299                         Image->format->palette->colors[i].r = Image->format->palette->colors[i%nbcolors].r;
300                         Image->format->palette->colors[i].g = Image->format->palette->colors[i%nbcolors].g;
301                         Image->format->palette->colors[i].b = Image->format->palette->colors[i%nbcolors].b;
302                 }
303                 if ( !pbm )
304                         Image->format->palette->ncolors = nbrcolorsfinal;
305         }
306
307         /* Get the bitmap */
308
309         for ( h=0; h < bmhd.h; h++ )
310         {
311                 /* uncompress the datas of each planes */
312
313                 for ( plane=0; plane < (nbplanes+stencil); plane++ )
314                 {
315                         ptr = MiniBuf + ( plane * bytesperline );
316
317                         remainingbytes = bytesperline;
318
319                         if ( bmhd.tcomp == 1 )      /* Datas are compressed */
320                         {
321                                 do
322                                 {
323                                         if ( !SDL_RWread( src, &count, 1, 1 ) )
324                                         {
325                                                 error="error reading BODY chunk";
326                                                 goto done;
327                                         }
328
329                                         if ( count & 0x80 )
330                                         {
331                                                 count ^= 0xFF;
332                                                 count += 2; /* now it */
333
334                                                 if ( ( count > remainingbytes ) || !SDL_RWread( src, &color, 1, 1 ) )
335                                                 {
336                                                         error="error reading BODY chunk";
337                                                         goto done;
338                                                 }
339                                                 memset( ptr, color, count );
340                                         }
341                                         else
342                                         {
343                                                 ++count;
344
345                                                 if ( ( count > remainingbytes ) || !SDL_RWread( src, ptr, count, 1 ) )
346                                                 {
347                                                    error="error reading BODY chunk";
348                                                         goto done;
349                                                 }
350                                         }
351
352                                         ptr += count;
353                                         remainingbytes -= count;
354
355                                 } while ( remainingbytes > 0 );
356                         }
357                         else
358                         {
359                                 if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
360                                 {
361                                         error="error reading BODY chunk";
362                                         goto done;
363                                 }
364                         }
365                 }
366
367                 /* One line has been read, store it ! */
368
369                 ptr = Image->pixels;
370                 if ( nbplanes==24 || flagHAM==1 )
371                         ptr += h * width * 3;
372                 else
373                         ptr += h * width;
374
375                 if ( pbm )                 /* File format : 'Packed Bitmap' */
376                 {
377                    memcpy( ptr, MiniBuf, width );
378                 }
379                 else            /* We have to un-interlace the bits ! */
380                 {
381                         if ( nbplanes!=24 && flagHAM==0 )
382                         {
383                                 size = ( width + 7 ) / 8;
384
385                                 for ( i=0; i < size; i++ )
386                                 {
387                                         memset( ptr, 0, 8 );
388
389                                         for ( plane=0; plane < (nbplanes + stencil); plane++ )
390                                         {
391                                                 color = *( MiniBuf + i + ( plane * bytesperline ) );
392                                                 msk = 0x80;
393
394                                                 for ( j=0; j<8; j++ )
395                                                 {
396                                                         if ( ( plane + j ) <= 7 ) ptr[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j );
397                                                         else                        ptr[j] |= (Uint8)( color & msk ) << ( plane + j - 7 );
398
399                                                         msk >>= 1;
400                                                 }
401                                         }
402                                         ptr += 8;
403                                 }
404                         }
405                         else
406                         {
407                                 Uint32 finalcolor = 0;
408                                 size = ( width + 7 ) / 8;
409                                 /* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
410                                 /* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
411                                 for ( i=0; i<width; i=i+8 )
412                                 {
413                                         Uint8 maskBit = 0x80;
414                                         for ( j=0; j<8; j++ )
415                                         {
416                                                 Uint32 pixelcolor = 0;
417                                                 Uint32 maskColor = 1;
418                                                 Uint8 dataBody;
419                                                 for ( plane=0; plane < nbplanes; plane++ )
420                                                 {
421                                                         dataBody = MiniBuf[ plane*size+i/8 ];
422                                                         if ( dataBody&maskBit )
423                                                                 pixelcolor = pixelcolor | maskColor;
424                                                         maskColor = maskColor<<1;
425                                                 }
426                                                 /* HAM : 12 bits RGB image (4 bits per color component) */
427                                                 /* HAM8 : 18 bits RGB image (6 bits per color component) */
428                                                 if ( flagHAM )
429                                                 {
430                                                         switch( pixelcolor>>(nbplanes-2) )
431                                                         {
432                                                                 case 0: /* take direct color from palette */
433                                                                         finalcolor = colormap[ pixelcolor*3 ] + (colormap[ pixelcolor*3+1 ]<<8) + (colormap[ pixelcolor*3+2 ]<<16);
434                                                                         break;
435                                                                 case 1: /* modify only blue component */
436                                                                         finalcolor = finalcolor&0x00FFFF;
437                                                                         finalcolor = finalcolor | (pixelcolor<<(16+(10-nbplanes)));
438                                                                         break;
439                                                                 case 2: /* modify only red component */
440                                                                         finalcolor = finalcolor&0xFFFF00;
441                                                                         finalcolor = finalcolor | pixelcolor<<(10-nbplanes);
442                                                                         break;
443                                                                 case 3: /* modify only green component */
444                                                                         finalcolor = finalcolor&0xFF00FF;
445                                                                         finalcolor = finalcolor | (pixelcolor<<(8+(10-nbplanes)));
446                                                                         break;
447                                                         }
448                                                 }
449                                                 else
450                                                 {
451                                                         finalcolor = pixelcolor;
452                                                 }
453                                                 if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
454                                                 {
455                                                         *ptr++ = (Uint8)(finalcolor>>16);
456                                                         *ptr++ = (Uint8)(finalcolor>>8);
457                                                         *ptr++ = (Uint8)(finalcolor);
458                                                 }
459                                                 else
460                                                 {
461                                                         *ptr++ = (Uint8)(finalcolor);
462                                                         *ptr++ = (Uint8)(finalcolor>>8);
463                                                         *ptr++ = (Uint8)(finalcolor>>16);
464                                                 }
465
466                                                 maskBit = maskBit>>1;
467                                         }
468                                 }
469                         }
470                 }
471         }
472
473 done:
474
475         if ( MiniBuf ) free( MiniBuf );
476
477         if ( error )
478         {
479                 SDL_RWseek(src, start, RW_SEEK_SET);
480                 if ( Image ) {
481                         SDL_FreeSurface( Image );
482                         Image = NULL;
483                 }
484                 IMG_SetError( error );
485         }
486
487         return( Image );
488 }
489
490 #else /* LOAD_LBM */
491
492 /* See if an image is contained in a data source */
493 int IMG_isLBM(SDL_RWops *src)
494 {
495         return(0);
496 }
497
498 /* Load an IFF type image from an SDL datasource */
499 SDL_Surface *IMG_LoadLBM_RW(SDL_RWops *src)
500 {
501         return(NULL);
502 }
503
504 #endif /* LOAD_LBM */