/* $NetBSD: xpm2bootimg.c,v 1.1 1998/09/01 20:04:05 itohy Exp $ */ /* * convert XPM format image to boot title format * * written by Yasha (ITOH Yasufumi), public domain */ #include #include static int opt_ascii; #define IMGWIDTH 56 #define IMGHEIGHT 52 /* if you change this, you must also make changes to the extraction code */ #define VALBIT 2 #define LENBIT 3 #define LENMAX (1< 8 #error too long encoding --- not portable between architectures in this code #endif /* this program may run on cross host, and should be portable */ #ifdef __STDC__ # define PROTO(x) x #else # define PROTO(x) () #endif static void putbyte PROTO((int c)); static void initdot PROTO((void)); static void putrun PROTO((int val, int len)); static void adddot PROTO((int val)); static void flushdot PROTO((void)); static unsigned rgb16b PROTO((int rgb)); static char *destring PROTO((char *str)); static char *getline PROTO((void)); static void error PROTO((char *msg)); int main PROTO((int argc, char *argv[])); static int outbuf; static int bufbits; static int curval; static int curlen; static int obytes; static void putbyte(c) int c; { static unsigned char wbuf; if (c == -1) { if (obytes % 16 && opt_ascii) printf("\n"); if (obytes & 1) { if (opt_ascii) printf("\t.byte\t0x%02x\n", wbuf); else putchar(wbuf); } if (opt_ascii) printf("| compressed image %d bytes\n", obytes); return; } if (obytes % 16 == 0 && opt_ascii) printf("\t.word\t"); obytes++; if (obytes & 1) wbuf = c; else { if (opt_ascii) { if ((obytes >> 1) % 8 != 1) printf(","); printf("0x%04x", (wbuf << 8) | c); } else printf("%c%c", wbuf, c); } if (obytes % 16 == 0 && opt_ascii) printf("\n"); } static void initdot() { outbuf = bufbits = curval = curlen = obytes = 0; } static int put; static void putrun(val, len) int val, len; { /* fprintf(stderr, "val %d, len %d\n", val, len);*/ outbuf <<= VALBIT; outbuf |= val; outbuf <<= LENBIT; outbuf |= len - 1; bufbits += VALBIT + LENBIT; if (bufbits >= 8) { putbyte((unsigned char) (outbuf >> (bufbits - 8))); bufbits -= 8; put = 1; } } static void adddot(val) int val; { if (curval != val) { if (curlen) putrun(curval, curlen); curlen = 0; curval = val; } curlen++; if (curlen == LENMAX) { putrun(val, LENMAX); curlen = 0; } } static void flushdot() { if (curlen) { putrun(curval, curlen); curlen = 0; } if (bufbits) { /* make sure data drain */ put = 0; while (put == 0) putrun(curval, LENMAX); } putbyte(-1); } /* * convert r8g8b8 to g5r5b5i1 */ static unsigned rgb16b(rgb) int rgb; { unsigned r = rgb >> 16, g = (rgb >> 8) & 0xff, b = rgb & 0xff; unsigned rgb16; rgb16 = (g << 8 & 0xf800) | (r << 3 & 0x7c0) | (b >> 2 & 0x3e); /* * v v v v v i i i * valid bits used for I bit */ if ((r & 7) + (g & 7) + (b & 7) >= 11) rgb16 |= 1; return rgb16; } static char * destring(str) char *str; /* must be writable */ { size_t len; char *p; if (*str != '"' || (len = strlen(str)) < 2) return NULL; p = str + len - 1; if (*p == ',') { if (len < 3) return NULL; p--; } if (*p != '"') return NULL; *p = '\0'; return str + 1; } static char *filename; static FILE *infp; static unsigned lineno; static char * getline() { static char buf[256]; char *p; if (!fgets(buf, sizeof buf, infp)) { if (ferror(infp)) { perror(filename); exit(1); } else return NULL; /* end of input */ } lineno++; if (!(p = strchr(buf, '\n'))) { fprintf(stderr, "%s:%d: too long line\n", filename, lineno); exit(1); } *p = '\0'; return buf; } static void error(msg) char *msg; { if (!msg) msg = "format error"; fprintf(stderr, "%s:%d: %s\n", filename, lineno, msg); exit(1); } static struct color { int ch; enum col { COL_BLACK, COL_1, COL_2, COL_WHITE } val; } coltbl[32]; unsigned col1, col2; enum col bitmap[IMGHEIGHT][IMGWIDTH]; int main(argc, argv) int argc; char *argv[]; { char *p; unsigned u, colors, xcol, x; char buf[256]; int in_oc; char *progname = argv[0]; /* * parse arg */ if (argc > 1 && !strcmp(argv[1], "-s")) { /* * -s option: output assembler source * (output binary otherwise) */ opt_ascii = 1; argc--; argv++; } if (argc == 1) { infp = stdin; filename = "stdin"; } else if (argc == 2) { if ((infp = fopen(argv[1], "r")) == NULL) { perror(argv[1]); return 1; } filename = argv[1]; } else { fprintf(stderr, "usage: %s [file.xpm]\n", progname); return 1; } /* * check XPM magic */ if (!(p = getline())) error("short file"); if (strcmp(p, "/* XPM */")) error((char *) NULL); while ((p = getline()) && !(p = destring(p))) ; if (!p) error((char *) NULL); /* * the first string must be * "56 52 5 1 XPMEXT", */ { unsigned w, h, cpp; if (sscanf(p, "%u %u %u %u %s", &w, &h, &colors, &cpp, buf) != 5) error("must be \"56 52 * 1 XPMEXT\""); if (w != IMGWIDTH) error("image width must be 56"); if (h != IMGHEIGHT) error("image height must be 52"); if (cpp != 1) error("chars-per-pixel must be 1"); if (strcmp(buf, "XPMEXT")) error("XPMEXT is required"); } if (colors > sizeof coltbl / sizeof coltbl[0]) error("too many colors"); /* * read colors * ". c #ffffff", */ xcol = 0; for (u = 0; u < colors; u++) { while ((p = getline()) && !(p = destring(p))) ; if (!p) error((char *) NULL); if (sscanf(p, "%c %c %s", buf, buf+1, buf+2) != 3) error((char *) NULL); coltbl[u].ch = buf[0]; if (buf[2] == '#') { int v; if (sscanf(buf+3, "%x", &v) != 1) error((char *) NULL); if (v == 0) coltbl[u].val = COL_BLACK; else if (v == 0xffffff) coltbl[u].val = COL_WHITE; else if (xcol == 0) { coltbl[u].val = COL_1; col1 = rgb16b(v); xcol++; } else if (xcol == 1) { coltbl[u].val = COL_2; col2 = rgb16b(v); xcol++; } else error("too many colors"); } else if (!strcmp(buf+2, "None")) { /* * transparent color is treated as black */ coltbl[u].val = COL_BLACK; } else error("unknown color (symbolic name is not supported)"); } /* * read bitmaps */ for (u = 0; u < IMGHEIGHT; u++) { while ((p = getline()) && !(p = destring(p))) ; if (!p) error((char *) NULL); if (strlen(p) != IMGWIDTH) error((char *) NULL); for (x = 0; x < IMGWIDTH; x++, p++) { unsigned i; for (i = 0; i < colors; i++) if (coltbl[i].ch == *p) goto found_ch; error("unknown character"); found_ch: bitmap[u][x] = coltbl[i].val; } } /* * read XPMEXTs and output copyright string */ in_oc = 0; while ((p = getline()) && *p == '\"') { if (!(p = destring(p))) error((char *) NULL); if (!strcmp(p, "XPMEXT copyright")) in_oc = 1; else if (!strncmp(p, "XPMENDEXT", 3)) break; else if (!strncmp(p, "XPM", 3)) in_oc = 0; else { if (in_oc) { if (opt_ascii) printf("\t.ascii\t\"\\n%s\"\n", p); else printf("\n%s", p); } } } /* terminate string */ if (opt_ascii) printf("\t.byte\t0\n"); else putchar('\0'); /* output color palette */ if (opt_ascii) printf("\t.word\t0x%x,0x%x\n", col1, col2); else printf("%c%c%c%c", col1 >> 8, col1, col2 >> 8, col2); /* * scan bitmap and output */ initdot(); for (u = 0; u < IMGHEIGHT; u++) for (x = 0; x < IMGWIDTH; x++) adddot(bitmap[u][x]); flushdot(); if (opt_ascii) printf("\t.even\n"); return ferror(stdout); }