1#include "compiler.h"
2
3enum {
4	MODE_GEN_INFO,
5	MODE_GEN_DATA,
6	MODE_GEN_BMP
7};
8
9typedef struct bitmap_s {		/* bitmap description */
10	uint16_t width;
11	uint16_t height;
12	uint8_t	palette[256*3];
13	uint8_t	*data;
14} bitmap_t;
15
16#define DEFAULT_CMAP_SIZE	16	/* size of default color map	*/
17
18void usage(const char *prog)
19{
20	fprintf(stderr, "Usage: %s [--gen-info|--gen-data|--gen-bmp] file\n",
21		prog);
22}
23
24/*
25 * Neutralize little endians.
26 */
27uint16_t le_short(uint16_t x)
28{
29    uint16_t val;
30    uint8_t *p = (uint8_t *)(&x);
31
32    val =  (*p++ & 0xff) << 0;
33    val |= (*p & 0xff) << 8;
34
35    return val;
36}
37
38void skip_bytes (FILE *fp, int n)
39{
40	while (n-- > 0)
41		fgetc (fp);
42}
43
44__attribute__ ((__noreturn__))
45int error (char * msg, FILE *fp)
46{
47	fprintf (stderr, "ERROR: %s\n", msg);
48
49	fclose (fp);
50
51	exit (EXIT_FAILURE);
52}
53
54void gen_info(bitmap_t *b, uint16_t n_colors)
55{
56	printf("/*\n"
57		" * Automatically generated by \"tools/bmp_logo\"\n"
58		" *\n"
59		" * DO NOT EDIT\n"
60		" *\n"
61		" */\n\n\n"
62		"#ifndef __BMP_LOGO_H__\n"
63		"#define __BMP_LOGO_H__\n\n"
64		"#define BMP_LOGO_WIDTH\t\t%d\n"
65		"#define BMP_LOGO_HEIGHT\t\t%d\n"
66		"#define BMP_LOGO_COLORS\t\t%d\n"
67		"#define BMP_LOGO_OFFSET\t\t%d\n\n"
68		"extern unsigned short bmp_logo_palette[];\n"
69		"extern unsigned char bmp_logo_bitmap[];\n\n"
70		"#endif /* __BMP_LOGO_H__ */\n",
71		b->width, b->height, n_colors,
72		DEFAULT_CMAP_SIZE);
73}
74
75int main (int argc, char *argv[])
76{
77	int	mode, i, x;
78	int	size;
79	FILE	*fp;
80	bitmap_t bmp;
81	bitmap_t *b = &bmp;
82	uint16_t data_offset, n_colors, hdr_size;
83
84	if (argc < 3) {
85		usage(argv[0]);
86		exit (EXIT_FAILURE);
87	}
88
89	if (!strcmp(argv[1], "--gen-info"))
90		mode = MODE_GEN_INFO;
91	else if (!strcmp(argv[1], "--gen-data"))
92		mode = MODE_GEN_DATA;
93	else if (!strcmp(argv[1], "--gen-bmp"))
94		mode = MODE_GEN_BMP;
95	else {
96		usage(argv[0]);
97		exit(EXIT_FAILURE);
98	}
99
100	fp = fopen(argv[2], "rb");
101	if (!fp) {
102		perror(argv[2]);
103		exit (EXIT_FAILURE);
104	}
105
106	if (fgetc (fp) != 'B' || fgetc (fp) != 'M')
107		error ("Input file is not a bitmap", fp);
108
109	/*
110	 * read width and height of the image, and the number of colors used;
111	 * ignore the rest
112	 */
113	skip_bytes (fp, 8);
114	if (fread (&data_offset, sizeof (uint16_t), 1, fp) != 1)
115		error ("Couldn't read bitmap data offset", fp);
116	skip_bytes(fp, 2);
117	if (fread(&hdr_size,   sizeof(uint16_t), 1, fp) != 1)
118		error("Couldn't read bitmap header size", fp);
119	if (hdr_size < 40)
120		error("Invalid bitmap header", fp);
121	skip_bytes(fp, 2);
122	if (fread (&b->width,   sizeof (uint16_t), 1, fp) != 1)
123		error ("Couldn't read bitmap width", fp);
124	skip_bytes (fp, 2);
125	if (fread (&b->height,  sizeof (uint16_t), 1, fp) != 1)
126		error ("Couldn't read bitmap height", fp);
127	skip_bytes (fp, 22);
128	if (fread (&n_colors, sizeof (uint16_t), 1, fp) != 1)
129		error ("Couldn't read bitmap colors", fp);
130	skip_bytes(fp, hdr_size - 34);
131
132	/*
133	 * Repair endianess.
134	 */
135	data_offset = le_short(data_offset);
136	b->width = le_short(b->width);
137	b->height = le_short(b->height);
138	n_colors = le_short(n_colors);
139	size = b->width * b->height;
140
141	/* assume we are working with an 8-bit file */
142	if ((n_colors == 0) || (n_colors > 256 - DEFAULT_CMAP_SIZE)) {
143		/* reserve DEFAULT_CMAP_SIZE color map entries for default map */
144		n_colors = 256 - DEFAULT_CMAP_SIZE;
145	}
146
147	if (mode == MODE_GEN_INFO) {
148		gen_info(b, n_colors);
149		goto out;
150	}
151
152	printf("/*\n"
153		" * Automatically generated by \"tools/bmp_logo\"\n"
154		" *\n"
155		" * DO NOT EDIT\n"
156		" *\n"
157		" */\n\n\n"
158		"#ifndef __BMP_LOGO_DATA_H__\n"
159		"#define __BMP_LOGO_DATA_H__\n\n");
160
161	/* read and print the palette information */
162	printf("unsigned short bmp_logo_palette[] = {\n");
163
164	for (i=0; i<n_colors; ++i) {
165		b->palette[(int)(i*3+2)] = fgetc(fp);
166		b->palette[(int)(i*3+1)] = fgetc(fp);
167		b->palette[(int)(i*3+0)] = fgetc(fp);
168		x=fgetc(fp);
169
170		printf ("%s0x0%X%X%X,%s",
171			((i%8) == 0) ? "\t" : "  ",
172			(b->palette[(int)(i*3+0)] >> 4) & 0x0F,
173			(b->palette[(int)(i*3+1)] >> 4) & 0x0F,
174			(b->palette[(int)(i*3+2)] >> 4) & 0x0F,
175			((i%8) == 7) ? "\n" : ""
176		);
177	}
178
179	/* seek to offset indicated by file header */
180	if (mode == MODE_GEN_BMP) {
181		/* copy full bmp file */
182		fseek(fp, 0L, SEEK_END);
183		size = ftell(fp);
184		fseek(fp, 0L, SEEK_SET);
185	} else {
186		fseek(fp, (long)data_offset, SEEK_SET);
187	}
188
189	/* allocate memory */
190	b->data = (uint8_t *)malloc(size);
191	if (!b->data)
192		error("Error allocating memory for file", fp);
193
194	/* read the bitmap; leave room for default color map */
195	printf ("\n");
196	printf ("};\n");
197	printf ("\n");
198	printf("unsigned char bmp_logo_bitmap[] = {\n");
199	if (mode == MODE_GEN_BMP) {
200		/* write full bmp */
201		for (i = 0; i < size; i++)
202			b->data[i] = (uint8_t)fgetc(fp);
203	} else {
204		for (i = (b->height - 1) * b->width; i >= 0; i -= b->width) {
205			for (x = 0; x < b->width; x++) {
206				b->data[i + x] = (uint8_t)fgetc(fp)
207						+ DEFAULT_CMAP_SIZE;
208			}
209		}
210	}
211
212	for (i = 0; i < size; ++i) {
213		if ((i%8) == 0)
214			putchar ('\t');
215		printf ("0x%02X,%c",
216			b->data[i],
217			((i%8) == 7) ? '\n' : ' '
218		);
219	}
220	printf ("\n"
221		"};\n\n"
222		"#endif /* __BMP_LOGO_DATA_H__ */\n"
223	);
224
225out:
226	fclose(fp);
227	return 0;
228}
229