TaggedOpenLibrary constants off by one fix.
[AROS.git] / tools / ilbmtoc / ilbmtoc.c
blobf93b45be9067536466c392c47c36f9ef5b7bfed6
1 /*
2 Copyright © 1995-2010, 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];
83 static BOOL brush2c; // compatibility with brush2c from MUI SDK
84 static BOOL brush2pix; // compatibility with brush2pix from JabberWocky
86 /****************************************************************************************/
88 static void cleanup(char *msg, int rc)
90 if (msg) fprintf(stderr, "ilbmtoc: %s\n", msg);
92 if (chunkybuffer_packed) free(chunkybuffer_packed);
93 if (planarbuffer_packed) free(planarbuffer_packed);
94 if (chunkybuffer) free(chunkybuffer);
95 if (planarbuffer) free(planarbuffer);
96 if (filebuffer) free(filebuffer);
98 if (file) fclose(file);
100 exit(rc);
103 /****************************************************************************************/
105 static void getarguments(int argc, char **argv)
107 char *imagenamestart, *sp;
108 WORD i;
110 if (argc == 3 && !strcasecmp(argv[1], "-b2c"))
112 brush2c = 1;
113 filename = argv[2];
115 else if (argc == 3 && !strcasecmp(argv[1], "-b2p"))
117 brush2pix = 1;
118 filename = argv[2];
120 else if (argc == 2)
122 filename = argv[1];
124 else
126 cleanup("Usage: ilbmtoc [-b2c|-b2p] filename", 1);
129 if (strlen(filename) >= sizeof(imagename)) cleanup("Filename too long!", 1);
131 imagenamestart = filename;
132 for(;;)
134 sp = strchr(imagenamestart + 1, '/');
135 if (!sp) sp = strchr(imagenamestart + 1, '\\');
136 if (!sp) sp = strchr(imagenamestart + 1, ':');
137 if (!sp) break;
139 imagenamestart = sp + 1;
142 strcpy(imagename, imagenamestart);
143 if ((sp = strchr(imagename, '.'))) *sp = 0;
145 for(i = 0; i < strlen(imagename); i++) bigimagename[i] = toupper(imagename[i]);
148 /****************************************************************************************/
150 static ULONG getlong(void)
152 ULONG ret;
154 if (filepos > filesize - 4) cleanup("Tried to read over file end!", 1);
156 ret = filebuffer[filepos++] * 0x1000000;
157 ret += filebuffer[filepos++] * 0x10000;
158 ret += filebuffer[filepos++] * 0x100;
159 ret += filebuffer[filepos++];
161 return ret;
164 /****************************************************************************************/
166 static UWORD getword(void)
168 UWORD ret;
170 if (filepos > filesize - 2) cleanup("Tried to read over file end!", 1);
172 ret = filebuffer[filepos++] * 0x100;
173 ret += filebuffer[filepos++];
175 return ret;
178 /****************************************************************************************/
180 static UBYTE getbyte(void)
182 ULONG ret;
184 if (filepos > filesize - 1) cleanup("Tried to read over file end!", 1);
185 ret = filebuffer[filepos++];
187 return ret;
190 /****************************************************************************************/
192 static void skipbytes(ULONG howmany)
194 filepos += howmany;
197 /****************************************************************************************/
199 static void openfile(void)
201 file = fopen(filename, "rb");
202 if (!file) cleanup("Can't open file!", 1);
204 fseek(file, 0, SEEK_END);
205 filesize = ftell(file);
207 if (filesize < 12) cleanup("Bad file size!", 1);
209 fprintf(stderr, "Filesize is %ld\n", filesize);
211 fseek(file, 0, SEEK_SET);
213 filebuffer = malloc(filesize + 10);
214 if (!filebuffer) cleanup("Memory allocation for file buffer failed!", 1);
216 if (fread(filebuffer, 1, filesize, file) != filesize)
217 cleanup("Error reading file!", 1);
219 fclose(file); file = NULL;
222 /****************************************************************************************/
224 static void checkfile(void)
226 ULONG id;
227 ULONG size;
229 id = getlong();
230 if (id != ID_FORM) cleanup("File is not an IFF file!", 1);
232 size = getlong();
233 if (size != filesize - 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
235 id = getlong();
236 if (id != ID_ILBM) cleanup("File is IFF, but not of type ILBM!", 1);
239 /****************************************************************************************/
241 static void scanfile(void)
243 WORD i;
245 for(;;)
247 ULONG id;
248 ULONG size;
250 id = getlong();
251 size = getlong();
253 /* Cast the IFF identifier to 4 ASCII chars:
254 (Use unsigned as i ANSI-C the cast to signed is implementation-dependent.) */
255 fprintf( stderr, "Chunk: %c%c%c%c Size: %ld\n"
256 , (unsigned char) (id >> 24)
257 , (unsigned char) (id >> 16)
258 , (unsigned char) (id >> 8)
259 , (unsigned char) (id)
260 , size
263 switch(id)
265 case ID_BMHD:
266 if (size != 20) cleanup("Bad BMHD chunk size!", 1);
268 bmh.bmh_Width = getword();
269 bmh.bmh_Height = getword();
270 bmh.bmh_Left = (WORD)getword();
271 bmh.bmh_Top = (WORD)getword();
272 bmh.bmh_Depth = getbyte();
273 bmh.bmh_Masking = getbyte();
274 bmh.bmh_Compression = getbyte();
275 bmh.bmh_Pad = getbyte();
276 bmh.bmh_Transparent = getword();
277 bmh.bmh_XAspect = getbyte();
278 bmh.bmh_YAspect = getbyte();
279 bmh.bmh_PageWidth = (WORD)getword();
280 bmh.bmh_PageHeight = (WORD)getword();
282 if (bmh.bmh_Depth > 8) cleanup("ILBM file has too many colors!", 1);
283 if ((bmh.bmh_Compression != CMP_NONE) && (bmh.bmh_Compression != CMP_BYTERUN1)) cleanup("Compression method unsupported!", 1);
285 have_bmhd = 1;
287 totdepth = bmh.bmh_Depth + ((bmh.bmh_Masking == MSK_HASMASK) ? 1 : 0);
289 bpr = ((bmh.bmh_Width + 15) & ~15) / 8;
291 fprintf(stderr, "BMHD: %d x %d x %d (%ld)\n", bmh.bmh_Width,
292 bmh.bmh_Height,
293 bmh.bmh_Depth,
294 totdepth);
295 break;
297 case ID_CMAP:
298 if (!have_bmhd) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
300 cmapentries = size / 3;
301 if (size & 1) size++;
303 if ((cmapentries < 2) || (cmapentries > 256)) cleanup("CMAP chunk has bad number of entries!", 1);
305 for(i = 0; i < cmapentries; i++)
307 red[i] = getbyte();
308 green[i] = getbyte();
309 blue[i] = getbyte();
310 size -= 3;
313 skipbytes(size);
315 have_cmap = 1;
317 break;
319 case ID_BODY:
320 if (!have_bmhd) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
321 body = &filebuffer[filepos];
322 bodysize = size;
324 if (bmh.bmh_Compression == CMP_NONE)
326 LONG shouldbesize = totdepth * bpr * bmh.bmh_Height;
327 if (bodysize != shouldbesize) cleanup("BODY chunk size seems to be wrong!", 1);
330 have_body = 1;
331 /* Fall through */
333 default:
334 if (size & 1) size++;
335 skipbytes(size);
336 break;
339 if (filepos == filesize) break;
340 if (have_bmhd && have_body && have_cmap) break;
343 if (!have_bmhd) cleanup("BMHD chunk missing!", 1);
344 if (!have_body) cleanup("BODY chunk missing!", 1);
347 /****************************************************************************************/
349 static unsigned char *unpack_byterun1(unsigned char *source, unsigned char *dest, LONG unpackedsize)
351 unsigned char r;
352 signed char c;
354 for(;;)
356 c = (signed char)(*source++);
357 if (c >= 0)
359 while(c-- >= 0)
361 *dest++ = *source++;
362 if (--unpackedsize <= 0) return source;
365 else if (c != -128)
367 c = -c;
368 r = *source++;
370 while(c-- >= 0)
372 *dest++ = r;
373 if (--unpackedsize <= 0) return source;
380 /****************************************************************************************/
382 static BOOL norm1(LONG count, unsigned char **source_backup,
383 unsigned char **dest, LONG *checksize)
385 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
387 while(count >= 0)
389 LONG step = count;
391 if (step > 127) step = 127;
393 *checksize -= step;
394 *checksize -= 2;
396 if (*checksize <= 0) return 0;
398 count -= step;
400 *(*dest)++ = step;
403 while(step-- >= 0)
405 *(*dest)++ = *(*source_backup)++;
408 count--;
412 return 1;
415 static BOOL copy1(unsigned char r, LONG count, unsigned char **dest, LONG *checksize)
417 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
419 while(--count >= 0)
421 LONG step = count;
423 if (step > 127) step = 127;
425 count -= step;
426 step = -step;
427 *checksize -= 2;
428 if (*checksize <= 0) return 0;
430 *(*dest)++ = (unsigned char)step;
431 *(*dest)++ = r;
434 return 1;
437 static BOOL pack_byterun1(unsigned char *source, unsigned char *dest,
438 LONG size, LONG check_size, LONG *packsize)
440 unsigned char *source_backup, *dest_backup;
441 LONG samebytes_counter, samebytes, count;
442 LONG checksize = check_size;
443 unsigned char oldbyte, actbyte;
445 if (checksize < 0) checksize = 0x7FFFFFFF;
447 oldbyte = *source;
448 samebytes_counter = 0;
449 source_backup = source;
450 dest_backup = dest;
452 for(;;)
454 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
455 if (--size < 0) break;
456 actbyte = *source++;
457 if (actbyte == oldbyte)
459 samebytes_counter++;
460 continue;
463 oldbyte = actbyte;
465 samebytes = samebytes_counter;
466 samebytes_counter = 1;
468 if (samebytes < 3) continue;
470 count = (LONG)(source - source_backup - samebytes - 2);
471 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
473 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
475 source_backup = source - 1;
477 //fprintf(stderr, "done\n");
479 if (samebytes_counter >= 3)
481 samebytes = samebytes_counter;
482 count = (LONG)(source - source_backup - samebytes - 1);
483 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
484 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
486 else
488 count = (LONG)(source - source_backup - 1);
489 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
491 //fprintf(stderr, "realdone\n");
493 if (packsize) *packsize = (LONG)(dest - dest_backup);
495 return 1;
498 /****************************************************************************************/
500 static void p2c(unsigned char *source, unsigned char *dest, LONG width, LONG height,
501 LONG totplanes, LONG wantplanes, LONG chunkybpr)
503 LONG alignedwidth, x, y, p, bpr, bpl;
505 alignedwidth = (width + 15) & ~15;
506 bpr = alignedwidth / 8;
507 bpl = bpr * totplanes;
509 for(y = 0; y < height; y++)
511 for(x = 0; x < width; x++)
513 LONG mask = 1 << (7 - (x & 7));
514 LONG offset = x / 8;
515 unsigned char chunkypix = 0;
517 for(p = 0; p < wantplanes; p++)
519 if (source[p * bpr + offset] & mask) chunkypix |= (1 << p);
521 dest[x] = chunkypix;
524 source += bpl;
525 dest += chunkybpr;
531 /****************************************************************************************/
533 static void convertbody(void)
535 LONG unpackedsize = bpr * bmh.bmh_Height * totdepth;
537 planarbuffer = malloc(unpackedsize);
538 if (!planarbuffer) cleanup("Memory allocation for planar buffer failed!", 1);
540 if (bmh.bmh_Compression == CMP_NONE)
542 memcpy(planarbuffer, body, unpackedsize);
544 else
546 unpack_byterun1(body, planarbuffer, unpackedsize);
549 chunkybuffer = malloc(bmh.bmh_Width * bmh.bmh_Height);
550 if (!chunkybuffer) cleanup("Memory allocation for chunky buffer failed!", 1);
552 p2c(planarbuffer,
553 chunkybuffer,
554 bmh.bmh_Width,
555 bmh.bmh_Height,
556 totdepth,
557 bmh.bmh_Depth,
558 bmh.bmh_Width);
561 /****************************************************************************************/
563 static void packdata(void)
565 LONG chunkysize = (LONG)bmh.bmh_Width * (LONG)bmh.bmh_Height;
566 BOOL success;
568 chunkybuffer_packed = malloc(chunkysize);
570 if (!chunkybuffer_packed) cleanup("Memory allocation for packed chunky buffer failed!", 1);
572 fprintf(stderr, "Starting packing\n");
574 success = pack_byterun1(chunkybuffer, chunkybuffer_packed,
575 chunkysize, chunkysize, &bodysize_packed);
577 fprintf(stderr, "Done packing. Success = %d\n", success);
578 if (!success)
580 free(chunkybuffer_packed); chunkybuffer_packed = 0;
584 /****************************************************************************************/
586 static void gensource(void)
588 unsigned char *buffer;
589 LONG i, x, y, buffersize;
591 printf("#include <exec/types.h>\n");
592 printf("\n");
593 printf("#define %s_WIDTH %d\n", bigimagename, bmh.bmh_Width);
594 printf("#define %s_HEIGHT %d\n", bigimagename, bmh.bmh_Height);
595 printf("#define %s_PACKED %d\n", bigimagename, (chunkybuffer_packed || planarbuffer_packed) ? 1 : 0);
596 printf("#define %s_PLANES %d\n", bigimagename, bmh.bmh_Depth);
597 if (have_cmap)
598 printf("#define %s_COLORS %ld\n", bigimagename, cmapentries);
600 printf("\n");
602 if (have_cmap)
604 printf("ULONG %s_pal[%ld] =\n", imagename, cmapentries);
605 printf("{\n");
606 for(i = 0; i < cmapentries; i++)
608 ULONG col = (((ULONG)red[i]) << 16) +
609 (((ULONG)green[i]) << 8) +
610 ((ULONG)blue[i]);
612 printf(" 0x%06lx", col);
613 if (i == cmapentries - 1)
614 printf("\n");
615 else
616 printf(",\n");
618 printf("};\n\n");
622 if (chunkybuffer_packed)
624 buffer = chunkybuffer_packed;
625 buffersize = bodysize_packed;
627 else
629 buffer = chunkybuffer;
630 buffersize = bodysize;
633 printf("UBYTE %s_data[%ld] =\n", imagename, buffersize);
634 printf("{");
636 i = 0;
638 for(x = 0; x < buffersize; x++)
640 if ((i++ % 20) == 0) printf("\n ");
641 printf("0x%02x", buffer[x]);
642 if (!(x == buffersize - 1)) printf(",");
645 printf("\n");
646 printf("};\n");
649 /****************************************************************************************/
651 static void genbrush2csource(void)
653 int i;
655 if (have_cmap)
657 printf("#ifdef USE_%s_COLORS\n", bigimagename);
658 printf("const ULONG %s_colors[%ld] =\n{\n", imagename, cmapentries * 3);
659 for (i = 0; i < cmapentries; i++)
661 printf("\t0x%08lx,0x%08lx,0x%08lx,\n",
662 (long) (red[i] << 24 | red[i] << 16 | red[i] << 8 | red[i]),
663 (long) (green[i] << 24 | green[i] << 16 | green[i] << 8 | green[i]),
664 (long) (blue[i] << 24 | blue[i] << 16 | blue[i] << 8 | blue[i]));
666 printf("};\n");
667 printf("#endif\n\n");
670 if (have_body)
672 printf("#define %s_WIDTH %3d\n", bigimagename, bmh.bmh_Width);
673 printf("#define %s_HEIGHT %3d\n", bigimagename, bmh.bmh_Height);
674 printf("#define %s_DEPTH %3d\n", bigimagename, bmh.bmh_Depth);
675 printf("#define %s_COMPRESSION %3d\n", bigimagename, bmh.bmh_Compression);
676 printf("#define %s_MASKING %3d\n", bigimagename, bmh.bmh_Masking);
677 printf("\n");
679 printf("#ifdef USE_%s_HEADER\n", bigimagename);
680 printf("const struct BitMapHeader %s_header =\n{ %ld,%ld,%ld,%ld,%ld,%ld,%ld,0,%ld,%ld,%ld,%ld,%ld };\n",
681 imagename, (long)bmh.bmh_Width, (long)bmh.bmh_Height, (long)bmh.bmh_Left, (long)bmh.bmh_Top,
682 (long)bmh.bmh_Depth, (long)bmh.bmh_Masking, (long)bmh.bmh_Compression, (long)bmh.bmh_Transparent,
683 (long)bmh.bmh_XAspect, (long)bmh.bmh_YAspect, (long)bmh.bmh_PageWidth, (long)bmh.bmh_PageHeight);
684 printf("#endif\n\n");
686 printf("#ifdef USE_%s_BODY\n", bigimagename);
687 printf("const UBYTE %s_body[%ld] = {\n", imagename, bodysize);
688 for (i = 0; i < bodysize; i++)
690 printf("0x%02lx,", (long)(body[i]));
691 if (!((i + 1) % 15)) printf("\n");
693 printf(" };\n");
694 printf("#endif\n");
698 /****************************************************************************************/
700 static void genbrush2pixsource(void)
702 int i;
704 if (have_cmap)
706 printf("const ULONG %s_colors[%ld] =\n{\n", imagename, cmapentries * 3);
707 for (i = 0; i < cmapentries; i++)
709 printf("\t0x%08lx,0x%08lx,0x%08lx,\n",
710 (long)(red[i] << 24 | red[i] << 16 | red[i] << 8 | red[i]),
711 (long)(green[i] << 24 | green[i] << 16 | green[i] << 8 | green[i]),
712 (long)(blue[i] << 24 | blue[i] << 16 | blue[i] << 8 | blue[i]));
714 printf("};\n\n");
717 if (have_body)
719 printf("#define %s_WIDTH %3d\n", bigimagename, bmh.bmh_Width);
720 printf("#define %s_HEIGHT %3d\n", bigimagename, bmh.bmh_Height);
721 printf("#define %s_DEPTH %3d\n", bigimagename, bmh.bmh_Depth);
722 printf("#define %s_COMPRESSION %3d\n", bigimagename, bmh.bmh_Compression);
723 printf("#define %s_MASKING %3d\n", bigimagename, bmh.bmh_Masking);
724 printf("\n");
726 printf("const UBYTE %s_body[%ld] = {\n", imagename, bodysize);
727 for (i = 0; i < bodysize; i++)
729 printf("0x%02lx,", (long)(body[i]));
730 if (!((i + 1) % 15)) printf("\n");
732 printf(" };\n");
735 if (have_cmap && have_body)
737 printf("\nmuidefpix %s_defpix =\n{\n", imagename);
738 printf("\t%s_body,\n", imagename);
739 printf("\t%s_colors,\n", imagename);
740 printf("\t%s_WIDTH, %s_HEIGHT, %s_DEPTH,\n", bigimagename, bigimagename, bigimagename);
741 printf("\t%s_COMPRESSION, %s_MASKING \n", bigimagename, bigimagename);
742 printf("};\n");
746 /****************************************************************************************/
748 int main(int argc, char **argv)
750 getarguments(argc, argv);
751 openfile();
752 checkfile();
753 scanfile();
755 if (brush2c)
757 genbrush2csource();
759 else if (brush2pix)
761 genbrush2pixsource();
763 else
765 convertbody();
766 packdata();
767 gensource();
770 cleanup(0, 0);
773 /****************************************************************************************/