Icon for AltKeyQ.
[cake.git] / tools / ilbmtoc / ilbmtoc.c
blobaf03b1977098cf0dc83c82a3ceacfea330f37273
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Tool to convert IFF ILBM images into C source.
7 Lang:
9 */
11 /****************************************************************************************/
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17 #include <memory.h>
19 /****************************************************************************************/
21 #define MAKE_ID(a,b,c,d) (((a)<<24) | ((b)<<16) | ((c)<<8) | ((d)))
23 #define ID_FORM MAKE_ID('F','O','R','M')
24 #define ID_ILBM MAKE_ID('I','L','B','M')
25 #define ID_CMAP MAKE_ID('C','M','A','P')
26 #define ID_BODY MAKE_ID('B','O','D','Y')
27 #define ID_BMHD MAKE_ID('B','M','H','D')
29 #define CMP_NONE 0
30 #define CMP_BYTERUN1 1
32 #define MSK_HASMASK 1
34 /****************************************************************************************/
36 /* For this tool it does not really matter if the following types
37 have a bigger sizeof() than on Amiga */
39 #ifndef __AROS__
40 typedef unsigned long ULONG;
41 typedef long LONG;
42 typedef unsigned short UWORD;
43 typedef short WORD;
44 typedef short BOOL;
45 typedef unsigned char UBYTE;
46 #else
47 #include <exec/types.h>
48 #endif
50 /****************************************************************************************/
52 struct BitMapHeader
54 UWORD bmh_Width;
55 UWORD bmh_Height;
56 WORD bmh_Left;
57 WORD bmh_Top;
58 UBYTE bmh_Depth;
59 UBYTE bmh_Masking;
60 UBYTE bmh_Compression;
61 UBYTE bmh_Pad;
62 UWORD bmh_Transparent;
63 UBYTE bmh_XAspect;
64 UBYTE bmh_YAspect;
65 WORD bmh_PageWidth;
66 WORD bmh_PageHeight;
69 /****************************************************************************************/
71 static char *filename;
72 static FILE *file;
73 static unsigned char *filebuffer, *body, *planarbuffer, *chunkybuffer;
74 static unsigned char *planarbuffer_packed, *chunkybuffer_packed;
75 static long filesize, bodysize, bodysize_packed;
76 static long filepos;
77 static struct BitMapHeader bmh;
78 static LONG cmapentries, totdepth, bpr;
79 static BOOL have_bmhd, have_cmap, have_body;
80 static UBYTE red[256], green[256], blue[256];
81 static char imagename[1000];
82 static char bigimagename[1000];
84 /****************************************************************************************/
86 static void cleanup(char *msg, int rc)
88 if (msg) fprintf(stderr, "ilbmtoc: %s\n", msg);
90 if (chunkybuffer_packed) free(chunkybuffer_packed);
91 if (planarbuffer_packed) free(planarbuffer_packed);
92 if (chunkybuffer) free(chunkybuffer);
93 if (planarbuffer) free(planarbuffer);
94 if (filebuffer) free(filebuffer);
96 if (file) fclose(file);
98 exit(rc);
101 /****************************************************************************************/
103 static void getarguments(int argc, char **argv)
105 char *imagenamestart, *sp;
106 WORD i;
108 if (argc != 2)
110 fprintf(stderr, "Wrong number of arguments\n");
113 if (argc < 2)
115 cleanup("Usage: ilbmtoc filename", 1);
118 filename = argv[1];
120 if (strlen(filename) >= sizeof(imagename)) cleanup("Filename too long!", 1);
122 imagenamestart = filename;
123 for(;;)
125 sp = strchr(imagenamestart + 1, '/');
126 if (!sp) sp = strchr(imagenamestart + 1, '\\');
127 if (!sp) sp = strchr(imagenamestart + 1, ':');
128 if (!sp) break;
130 imagenamestart = sp + 1;
133 strcpy(imagename, imagenamestart);
134 if ((sp = strchr(imagename, '.'))) *sp = 0;
136 for(i = 0; i < strlen(imagename); i++) bigimagename[i] = toupper(imagename[i]);
139 /****************************************************************************************/
141 static ULONG getlong(void)
143 ULONG ret;
145 if (filepos > filesize - 4) cleanup("Tried to read over file end!", 1);
147 ret = filebuffer[filepos++] * 0x1000000;
148 ret += filebuffer[filepos++] * 0x10000;
149 ret += filebuffer[filepos++] * 0x100;
150 ret += filebuffer[filepos++];
152 return ret;
155 /****************************************************************************************/
157 static UWORD getword(void)
159 UWORD ret;
161 if (filepos > filesize - 2) cleanup("Tried to read over file end!", 1);
163 ret = filebuffer[filepos++] * 0x100;
164 ret += filebuffer[filepos++];
166 return ret;
169 /****************************************************************************************/
171 static UBYTE getbyte(void)
173 ULONG ret;
175 if (filepos > filesize - 1) cleanup("Tried to read over file end!", 1);
176 ret = filebuffer[filepos++];
178 return ret;
181 /****************************************************************************************/
183 static void skipbytes(ULONG howmany)
185 filepos += howmany;
188 /****************************************************************************************/
190 static void openfile(void)
192 file = fopen(filename, "rb");
193 if (!file) cleanup("Can't open file!", 1);
195 fseek(file, 0, SEEK_END);
196 filesize = ftell(file);
198 if (filesize < 12) cleanup("Bad file size!", 1);
200 fprintf(stderr, "Filesize is %d\n", filesize);
202 fseek(file, 0, SEEK_SET);
204 filebuffer = malloc(filesize + 10);
205 if (!filebuffer) cleanup("Memory allocation for file buffer failed!", 1);
207 if (fread(filebuffer, 1, filesize, file) != filesize)
208 cleanup("Error reading file!", 1);
210 fclose(file); file = NULL;
213 /****************************************************************************************/
215 static void checkfile(void)
217 ULONG id;
218 ULONG size;
220 id = getlong();
221 if (id != ID_FORM) cleanup("File is not an IFF file!", 1);
223 size = getlong();
224 if (size != filesize - 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
226 id = getlong();
227 if (id != ID_ILBM) cleanup("File is IFF, but not of type ILBM!", 1);
230 /****************************************************************************************/
232 static void scanfile(void)
234 WORD i;
236 for(;;)
238 ULONG id;
239 ULONG size;
241 id = getlong();
242 size = getlong();
244 fprintf(stderr, "Chunk: %c%c%c%c Size: %d\n", id >> 24, id >> 16, id >> 8, id, size);
246 switch(id)
248 case ID_BMHD:
249 if (size != 20) cleanup("Bad BMHD chunk size!", 1);
251 bmh.bmh_Width = getword();
252 bmh.bmh_Height = getword();
253 bmh.bmh_Left = (WORD)getword();
254 bmh.bmh_Top = (WORD)getword();
255 bmh.bmh_Depth = getbyte();
256 bmh.bmh_Masking = getbyte();
257 bmh.bmh_Compression = getbyte();
258 bmh.bmh_Pad = getbyte();
259 bmh.bmh_Transparent = getword();
260 bmh.bmh_XAspect = getbyte();
261 bmh.bmh_YAspect = getbyte();
262 bmh.bmh_PageWidth = (WORD)getword();
263 bmh.bmh_PageHeight = (WORD)getword();
265 if (bmh.bmh_Depth > 8) cleanup("ILBM file has too many colors!", 1);
266 if ((bmh.bmh_Compression != CMP_NONE) && (bmh.bmh_Compression != CMP_BYTERUN1)) cleanup("Compression method unsupported!", 1);
268 have_bmhd = 1;
270 totdepth = bmh.bmh_Depth + ((bmh.bmh_Masking == MSK_HASMASK) ? 1 : 0);
272 bpr = ((bmh.bmh_Width + 15) & ~15) / 8;
274 fprintf(stderr, "BMHD: %d x %d x %d (%d)\n", bmh.bmh_Width,
275 bmh.bmh_Height,
276 bmh.bmh_Depth,
277 totdepth);
278 break;
280 case ID_CMAP:
281 if (!have_bmhd) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
283 cmapentries = size / 3;
284 if (size & 1) size++;
286 if ((cmapentries < 2) || (cmapentries > 256)) cleanup("CMAP chunk has bad number of entries!", 1);
288 for(i = 0; i < cmapentries; i++)
290 red[i] = getbyte();
291 green[i] = getbyte();
292 blue[i] = getbyte();
293 size -= 3;
296 skipbytes(size);
298 have_cmap = 1;
300 break;
302 case ID_BODY:
303 if (!have_bmhd) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
304 body = &filebuffer[filepos];
305 bodysize = size;
307 if (bmh.bmh_Compression == CMP_NONE)
309 LONG shouldbesize = totdepth * bpr * bmh.bmh_Height;
310 if (bodysize != shouldbesize) cleanup("BODY chunk size seems to be wrong!", 1);
313 have_body = 1;
314 /* Fall through */
316 default:
317 if (size & 1) size++;
318 skipbytes(size);
319 break;
322 if (filepos == filesize) break;
323 if (have_bmhd && have_body && have_cmap) break;
326 if (!have_bmhd) cleanup("BMHD chunk missing!", 1);
327 if (!have_body) cleanup("BODY chunk missing!", 1);
330 /****************************************************************************************/
332 static unsigned char *unpack_byterun1(unsigned char *source, unsigned char *dest, LONG unpackedsize)
334 unsigned char r;
335 signed char c;
337 for(;;)
339 c = (signed char)(*source++);
340 if (c >= 0)
342 while(c-- >= 0)
344 *dest++ = *source++;
345 if (--unpackedsize <= 0) return source;
348 else if (c != -128)
350 c = -c;
351 r = *source++;
353 while(c-- >= 0)
355 *dest++ = r;
356 if (--unpackedsize <= 0) return source;
363 /****************************************************************************************/
365 static BOOL norm1(LONG count, unsigned char **source_backup,
366 unsigned char **dest, LONG *checksize)
368 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
370 while(count >= 0)
372 LONG step = count;
374 if (step > 127) step = 127;
376 *checksize -= step;
377 *checksize -= 2;
379 if (*checksize <= 0) return 0;
381 count -= step;
383 *(*dest)++ = step;
386 while(step-- >= 0)
388 *(*dest)++ = *(*source_backup)++;
391 count--;
395 return 1;
398 static BOOL copy1(unsigned char r, LONG count, unsigned char **dest, LONG *checksize)
400 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
402 while(--count >= 0)
404 LONG step = count;
406 if (step > 127) step = 127;
408 count -= step;
409 step = -step;
410 *checksize -= 2;
411 if (*checksize <= 0) return 0;
413 *(*dest)++ = (unsigned char)step;
414 *(*dest)++ = r;
417 return 1;
420 static BOOL pack_byterun1(unsigned char *source, unsigned char *dest,
421 LONG size, LONG check_size, LONG *packsize)
423 unsigned char *source_backup, *dest_backup;
424 LONG samebytes_counter, samebytes, count;
425 LONG checksize = check_size;
426 unsigned char oldbyte, actbyte;
428 if (checksize < 0) checksize = 0x7FFFFFFF;
430 oldbyte = *source;
431 samebytes_counter = 0;
432 source_backup = source;
433 dest_backup = dest;
435 for(;;)
437 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
438 if (--size < 0) break;
439 actbyte = *source++;
440 if (actbyte == oldbyte)
442 samebytes_counter++;
443 continue;
446 oldbyte = actbyte;
448 samebytes = samebytes_counter;
449 samebytes_counter = 1;
451 if (samebytes < 3) continue;
453 count = (LONG)(source - source_backup - samebytes - 2);
454 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
456 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
458 source_backup = source - 1;
460 //fprintf(stderr, "done\n");
462 if (samebytes_counter >= 3)
464 samebytes = samebytes_counter;
465 count = (LONG)(source - source_backup - samebytes - 1);
466 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
467 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
469 else
471 count = (LONG)(source - source_backup - 1);
472 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
474 //fprintf(stderr, "realdone\n");
476 if (packsize) *packsize = (LONG)(dest - dest_backup);
478 return 1;
481 /****************************************************************************************/
483 static void p2c(unsigned char *source, unsigned char *dest, LONG width, LONG height,
484 LONG totplanes, LONG wantplanes, LONG chunkybpr)
486 LONG alignedwidth, x, y, p, bpr, bpl;
488 alignedwidth = (width + 15) & ~15;
489 bpr = alignedwidth / 8;
490 bpl = bpr * totplanes;
492 for(y = 0; y < height; y++)
494 for(x = 0; x < width; x++)
496 LONG mask = 1 << (7 - (x & 7));
497 LONG offset = x / 8;
498 unsigned char chunkypix = 0;
500 for(p = 0; p < wantplanes; p++)
502 if (source[p * bpr + offset] & mask) chunkypix |= (1 << p);
504 dest[x] = chunkypix;
507 source += bpl;
508 dest += chunkybpr;
514 /****************************************************************************************/
516 static void convertbody(void)
518 LONG unpackedsize = bpr * bmh.bmh_Height * totdepth;
520 planarbuffer = malloc(unpackedsize);
521 if (!planarbuffer) cleanup("Memory allocation for planar buffer failed!", 1);
523 if (bmh.bmh_Compression == CMP_NONE)
525 memcpy(planarbuffer, body, unpackedsize);
527 else
529 unpack_byterun1(body, planarbuffer, unpackedsize);
532 chunkybuffer = malloc(bmh.bmh_Width * bmh.bmh_Height);
533 if (!chunkybuffer) cleanup("Memory allocation for chunky buffer failed!", 1);
535 p2c(planarbuffer,
536 chunkybuffer,
537 bmh.bmh_Width,
538 bmh.bmh_Height,
539 totdepth,
540 bmh.bmh_Depth,
541 bmh.bmh_Width);
544 /****************************************************************************************/
546 static void packdata(void)
548 LONG chunkysize = (LONG)bmh.bmh_Width * (LONG)bmh.bmh_Height;
549 BOOL success;
551 chunkybuffer_packed = malloc(chunkysize);
553 if (!chunkybuffer_packed) cleanup("Memory allocation for packed chunky buffer failed!", 1);
555 fprintf(stderr, "Starting packing\n");
557 success = pack_byterun1(chunkybuffer, chunkybuffer_packed,
558 chunkysize, chunkysize, &bodysize_packed);
560 fprintf(stderr, "Done packing. Success = %d\n", success);
561 if (!success)
563 free(chunkybuffer_packed); chunkybuffer_packed = 0;
567 /****************************************************************************************/
569 static void gensource(void)
571 unsigned char *buffer;
572 LONG i, x, y, buffersize;
574 printf("#include <exec/types.h>\n");
575 printf("\n");
576 printf("#define %s_WIDTH %d\n", bigimagename, bmh.bmh_Width);
577 printf("#define %s_HEIGHT %d\n", bigimagename, bmh.bmh_Height);
578 printf("#define %s_PACKED %d\n", bigimagename, (chunkybuffer_packed || planarbuffer_packed) ? 1 : 0);
579 printf("#define %s_PLANES %d\n", bigimagename, bmh.bmh_Depth);
580 if (have_cmap)
581 printf("#define %s_COLORS %d\n", bigimagename, cmapentries);
583 printf("\n");
585 if (have_cmap)
587 printf("ULONG %s_pal[%d] =\n", imagename, cmapentries);
588 printf("{\n");
589 for(i = 0; i < cmapentries; i++)
591 ULONG col = (((ULONG)red[i]) << 16) +
592 (((ULONG)green[i]) << 8) +
593 ((ULONG)blue[i]);
595 printf(" 0x%06x", col);
596 if (i == cmapentries - 1)
597 printf("\n");
598 else
599 printf(",\n");
601 printf("};\n\n");
605 if (chunkybuffer_packed)
607 buffer = chunkybuffer_packed;
608 buffersize = bodysize_packed;
610 else
612 buffer = chunkybuffer;
613 buffersize = bodysize;
616 printf("UBYTE %s_data[%d] =\n", imagename, buffersize);
617 printf("{");
619 i = 0;
621 for(x = 0; x < buffersize; x++)
623 if ((i++ % 20) == 0) printf("\n ");
624 printf("0x%02x", buffer[x]);
625 if (!(x == buffersize - 1)) printf(",");
628 printf("\n");
629 printf("};\n");
632 /****************************************************************************************/
634 int main(int argc, char **argv)
636 getarguments(argc, argv);
637 openfile();
638 checkfile();
639 scanfile();
640 convertbody();
641 packdata();
642 gensource();
644 cleanup(0, 0);
647 /****************************************************************************************/
648 /****************************************************************************************/
649 /****************************************************************************************/
650 /****************************************************************************************/
651 /****************************************************************************************/