/*
 * http://www.ruche-home.net/?%A5%D7%A5%ED%A5%B0%A5%E9%A5%DF%A5%F3%A5%B0%2FBMP%A5%D5%A5%A1%A5%A4%A5%EB%BB%C5%CD%CD%2F%A5%D3%A5%C3%A5%C8%A5%D5%A5%A3%A1%BC%A5%EB%A5%C9
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

typedef struct tagBITMAPFILEHEADER {
  unsigned short bfType;
  unsigned long  bfSize;
  unsigned short bfReserved1;
  unsigned short bfReserved2;
  unsigned long  bfOffBits;
} __attribute__((packed)) BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
    unsigned long  biSize;
    long           biWidth;
    long           biHeight;
    unsigned short biPlanes;
    unsigned short biBitCount;
    unsigned long  biCompression;
    unsigned long  biSizeImage;
    long           biXPixPerMeter;
    long           biYPixPerMeter;
    unsigned long  biClrUsed;
    unsigned long  biClrImporant;
} BITMAPINFOHEADER;

typedef struct tagV5INFOHEADER {
    unsigned long redMask;
    unsigned long greenMask;
    unsigned long blueMask;
    unsigned long alphaMask;
    unsigned long clorSpaceType;
    unsigned long readX, redY, redZ;
    unsigned long greenX, greenY, greenZ;
    unsigned long blueX, blueY, blueZ;
    unsigned long redGamma, greenGamma, blueGamma;
    unsigned long sRGBSpaceType;
    unsigned long profileOffset, profileSize;
    unsigned long reserved;
} V5INFOHEADER;

BITMAPFILEHEADER fheader;
BITMAPINFOHEADER iheader;
V5INFOHEADER v5header;

#define	LBSIZE	1024
unsigned char buffer[LBSIZE];

main(int argc, char **argv)
{
    FILE *fp, *ofp;
    int x, y, width, height, nc, nbytes;
    int lw, rval, gval, bval, wval;
    char *cp, *csp;
    char fname[50];
    unsigned char *bp;
    unsigned long *wp;
    unsigned short *imgbuffer, *sp, sval;

    if (argc < 2) {
	fprintf(stderr, "no filename\n");
	exit(1);
    }
    cp = argv[1];
    fp = fopen(cp, "r");
    if (fp == NULL) {
	fprintf(stderr, "can't open %s\n", argv[1]);
	exit(1);
    }
    if (fread(&fheader, sizeof(BITMAPFILEHEADER), 1, fp) != 1) {
	fprintf(stderr, "failed to read file header\n");
	exit(1);
    }
    if (fheader.bfType != 0x4d42) {
	fprintf(stderr, "Bad file type magic.\n");
	exit(1);
    }
    if (fread(&iheader, sizeof(BITMAPINFOHEADER), 1, fp) != 1) {
	fprintf(stderr, "failed to read info header\n");
	exit(1);
    }
    printf("%d X %d (size = %d)\n", iheader.biWidth, iheader.biHeight, iheader.biSize);
    printf("%d bit %d\n", iheader.biBitCount, iheader.biCompression);
    if (iheader.biSize == 124) {
	fread(&v5header, sizeof(V5INFOHEADER), 1, fp);
	printf("redMask: %08x, greenMask: %08x\n",
		v5header.redMask, v5header.greenMask);
	printf("blueMask: %08x, alphaMask: %08x\n",
		v5header.blueMask, v5header.alphaMask);
    }
#ifdef notdef
    if (iheader.biCompression) {
	fprintf(stderr, "I can't handle compressed image.\n");
	exit(1);
    }
#endif
    fseek(fp, sizeof(BITMAPFILEHEADER) + iheader.biSize, SEEK_SET);

    width = iheader.biWidth;
    if (iheader.biBitCount == 32) {
	lw = width * 4;
	nbytes = 4;
    } else {
	lw = (width *3 + 3) >> 2;
	lw <<= 2;
#define	USE_TRI
#ifdef USE_TRI
	nbytes = 4;
#else
	nbytes = 2;
#endif
    }
printf("lw = %d\n", lw);
    if (lw > LBSIZE) {
	fprintf(stderr, "width (%d) too large.\n", width);
	exit(1);
    }
    height = iheader.biHeight;

    imgbuffer = (unsigned short *)malloc(width * nbytes * height);

    csp = strstr(cp, ".bmp");
    if (csp) *csp = 0;
    sprintf(fname, "%s.c", cp);
    ofp = fopen(fname, "w");
    fprintf(ofp, "const UH icon_%s_img[] = {\n");
    sp = imgbuffer;
    for (y = 0; y < height; y++) {
	if (fread(buffer, lw, 1, fp) != 1)
	    break;
	bp = buffer;
	wp = (unsigned long *)buffer;
	for (x = 0; x < width; x++) {
	    if (iheader.biBitCount == 32) {
		*sp++ = (*wp >> 16);
		*sp++ = (*wp & 0xffff);
		wp++;
	    } else {
#ifdef USE_TRI
		bval = (bp[0] >> 2) & 0x3f;
		if (bp[0] & 0x02) bval |= 1;
		gval = (bp[1] >> 2) & 0x3f;
		if (bp[1] & 0x02) gval |= 1;
		rval = (bp[2] >> 2) & 0x3f;
		if (bp[2] & 0x02) rval |= 1;
		bp += 3;
		*sp++ = (rval << 10) | (gval << 4) | (bval >> 2);
		*sp++ = ((bval & 3) << 14);
#else
#define	NEWCODE
#ifdef NEWCODE
		wval = *bp++;
		if ((wval & 0x08) == 0 && (wval & 0x4)) wval += 0x8;
		bval = (wval >> 3) & 0x1f;
		wval = *bp++;
		if ((wval & 0x04) == 0 && (wval & 0x2)) wval += 0x4;
		gval = (wval >> 2) & 0x3f;
		wval = *bp++;
		if ((wval & 0x08) == 0 && (wval & 0x4)) wval += 0x8;
		rval = (wval >> 3) & 0x1f;
#else
		bval = (*bp++ >> 3) & 0x1f;
		gval = (*bp++ >> 2) & 0x3f;
		rval = (*bp++ >> 3) & 0x1f;
#endif	/* NEWCODE */
		*sp++ = (rval << 11) | (gval << 5) | bval;
#endif	/* USE_TRI */
	    }
	}
    }
    if (iheader.biBitCount == 32)
	sp = imgbuffer + width * 2 * (height - 1);
    else
#ifdef USE_TRI
	sp = imgbuffer + width * 2 * (height - 1);
#else
	sp = imgbuffer + width * (height - 1);
#endif
    nc = 0;
    for (y = 0; y < height; y++) {
	for (x = 0; x < width; x++) {
#ifdef USE_TRI
	    fprintf(ofp, "0x%04x,", *sp++);
#else
	    if (iheader.biBitCount == 32) {
		fprintf(ofp, "0x%04x,", *sp++);
		nc++;
	    }
#endif
	    fprintf(ofp, "0x%04x,", *sp++);
	    nc++;
	    if (nc == 8) {
		nc = 0;
		fprintf(ofp, "\n");
	    }
	}
	if (nc) fprintf(ofp, "\n");
	sp -= (width * nbytes);
    }
    fprintf(ofp, "};\n");
    fprintf(ofp, "const struct icon icon_%s = {\n", cp);
    fprintf(ofp, "    %d,\n", iheader.biBitCount);
    fprintf(ofp, "    %d, %d, icon_%s_img };\n", width, height, cp);
    fclose(fp);
    fclose(ofp);
}
