1/* setupdialog : converts a RAW image file into the c structure that the
2 * kernel panic ui system expects.
3 *
4 * to build: cc -o setupdialog setupdialog.c
5*/
6
7#include <stdio.h>
8#include <sys/types.h>
9#include <fcntl.h>
10
11#define RUN_MAX 32767
12
13void create_numbers_file( FILE *stream, char *outfile );
14unsigned int encode_rle(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, unsigned char value);
15
16void
17usage(void) {
18    printf("\nusage: setupdialog -i <image file> -oi <image output> -n <numbers file> -on <numbers output>\n");
19
20    printf("\nYou can supply a panic image file, a numbers file, or both. Input files\n");
21    printf("must be in RAW format where each pixel is represented by an index into the\n");
22    printf("MacOS X system CLUT. The first %d bytes must be the width, height, and depth\n", 3 * sizeof(short));
23    printf("(in that order, %d bytes each).\n", sizeof(short));
24
25    printf("\nThe output files are generated C structures in the format the panic ui code\n");
26    printf("expects (default output files are panic_image.c and rendered_numbers.c).\n\n");
27}
28
29int
30main( int argc, char *argv[] )
31{
32    int		next;
33    char 	*file = NULL, *ptr, *out = NULL, *numsfile = NULL, *numsout = NULL;
34    FILE *	stream, *out_stream;
35    int *	data;
36    short 	width = 0, height = 0, depth = 0;
37    char	word[2];
38    char	byte;
39    unsigned int i, pixels, filePos;
40    int		err;
41    unsigned char *fileArr;
42    unsigned char nextP;
43    unsigned int count;
44    int currP;
45    int fd;
46    int pairs_this_line;
47
48
49    // pull apart the arguments
50    for( next = 1; next < argc; next++ )
51    {
52        if (strcmp(argv[next], "-i") == 0) // image file (RAW/PICT?)
53            file = argv[++next];
54        else if (strcmp(argv[next], "-n") == 0) // numbers/chars image file (RAW)
55            numsfile = argv[++next];
56        else if (strcmp(argv[next], "-oi") == 0) // output file for image
57            out = argv[++next];
58        else if (strcmp(argv[next], "-on") == 0) // output file for numbers
59            numsout = argv[++next];
60
61	/* perhaps we should just let the user specify the W/H rather than require the header */
62	/*
63        else if (strcmp(argv[next], "-w") == 0) // image width (pixels)
64            width = strtoul(argv[++next], &ptr, 0);
65        else if (strcmp(argv[next], "-h") == 0) // image height (pixels)
66            width = strtoul(argv[++next], &ptr, 0);
67	*/
68    }
69
70    if (!(numsfile || file)) {
71	usage();
72	exit(1);
73    }
74
75    if (!numsfile) {
76	printf("\nNo numbers file to process\n");
77    } else {
78        stream = fopen(numsfile, "r");
79        if (!stream) {
80            printf("bad nums infile.. bailing.\n");
81            exit(1);
82        }
83        create_numbers_file( stream, numsout );
84        fclose(stream);
85    }
86
87    if( file == NULL) {
88        printf("\nNo image file to process\n");
89        exit(1);
90    }
91
92    stream = fopen(file, "r");
93    if (!stream) {
94        printf("bad infile.. bailing.\n");
95        exit(1);
96    }
97
98    printf("\nReading image file...\n");
99
100    fread((void *) &width, sizeof(short), 1, stream);
101    printf("got width: %d\n", width);
102    fread((void *) &height, sizeof(short), 1, stream);
103    printf("got height: %d\n", height);
104    fread((void *) &depth, sizeof(short), 1, stream);
105    printf("got depth: %d\n", depth);
106
107    if (!(width && height && depth)) {
108	printf("Invalid image file header (width, height, or depth is 0)\n");
109	exit(1);
110    }
111
112    pixels = width * height;
113
114    if (!(fileArr = (unsigned char *) malloc(pixels))) {
115	printf("couldn't malloc fileArr (%d pixels)... bailing.\n", pixels);
116	exit(1);
117    }
118
119    currP = -1;
120    count = 0;
121    filePos = 0; // position in the file we're writing out
122
123    for (i=0; i < pixels; i++) {
124        nextP = fgetc(stream);
125        count++;
126        if (nextP == currP) {
127            if (count >= RUN_MAX) {
128                    filePos += encode_rle(fileArr, filePos, count, (unsigned char) currP);
129                    count = 0;
130                    currP = -1;
131            }
132        } else {
133            if (currP != -1) {
134                filePos += encode_rle(fileArr, filePos, count-1, (unsigned char) currP);
135            }
136            currP = nextP; // start a new run
137            count = 1;
138        }
139    }
140
141    // write out any run that was in progress
142    if (count > 0) {
143        filePos += encode_rle(fileArr, filePos, count, (unsigned char) currP);
144    }
145
146    fclose( stream );
147
148    // now, generate the c file
149
150    if ( out == NULL)
151        out = "panic_image.c";
152    out_stream = fopen(out, "w");
153
154    if(out_stream == NULL) {
155        printf("couldn't open out file.. bailing\n");
156        exit(1);
157    }
158
159    pairs_this_line = 0;
160
161    fprintf( out_stream, "/* generated c file */\n\n");
162    fprintf( out_stream, "static const struct {\n");
163    fprintf( out_stream, "  unsigned int 	 pd_width;\n");
164    fprintf( out_stream, "  unsigned int 	 pd_height;\n");
165    fprintf( out_stream, "  unsigned int 	 bytes_per_pixel; /* 1: CLUT, 3:RGB, 4:RGBA */\n");
166    fprintf( out_stream, "  unsigned char	 image_pixel_data[%#4.2x];\n", (filePos));
167
168    fprintf( out_stream, "} panic_dialog = {\n");
169    fprintf( out_stream, "\t%d, ", width);		/* panic dialog x */
170    fprintf( out_stream, "%d, ", height);		/* panic dialog y */
171    fprintf( out_stream, "1,\n");			/* bytes per pixel */
172
173    for( i=0; i < filePos;) {
174    	fprintf( out_stream, "0x%.2x,0x%.2x", fileArr[i], fileArr[i+1]);
175	i+=2;
176        pairs_this_line++;
177
178        // if the first byte had a leading 1, this is a 3-byte encoding
179        if ((fileArr[i-2] >> 7) == 1) {
180            fprintf( out_stream, ",0x%.2x", fileArr[i++]);
181	    pairs_this_line++;
182        }
183
184        if (i >= filePos) // this is the last element
185            fprintf( out_stream, "\n};");
186        else fprintf( out_stream, ", ");
187
188        if(pairs_this_line > 8) {
189            fprintf( out_stream, "\n");
190            pairs_this_line = 0;
191        }
192    }
193
194
195  fclose( out_stream );
196
197  return 0;
198}
199
200
201/* Each number/char (0-f) has its own row in the pixmap array.
202    When done, these rows each contain an RLE character.
203    The image file is read row by row, so the individual characters
204    must be constructed in the same way. The numPos array tracks the
205    current position in each character's RLE array.
206    */
207void
208create_numbers_file( FILE *stream, char *outfile )
209{
210    int		err;
211    short	height, depth, totalwidth;
212    int		numbers = 17;
213    int         width[17] = {9,7,8,6,9,7,8,7,8,7,10,7,9,10,7,6,4};
214    int		numPos[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
215
216    int **pixmap;
217    int		row, col, item, line=0, currWidth;
218    int nextP, currP;
219    int count, currNum;
220
221    FILE	*out_stream;
222
223    printf("\nReading numbers file...\n");
224    fread((void *) &totalwidth, sizeof(short), 1, stream);
225    printf("got width: %d\n", totalwidth);
226    fread((void *) &height, sizeof(short), 1, stream);
227    printf("got height: %d\n", height);
228    fread((void *) &depth, sizeof(short), 1, stream);
229    printf("got depth: %d\n", depth);
230
231    if (!(width && height && depth)) {
232	printf("Invalid numbers file header (width, height, or depth is 0)\n");
233	return;
234    }
235
236    // allocate array to hold each number's RLE encoding (20 = 2xwidest width[i] value, 17 = num chars)
237    pixmap = (int **) malloc( 17 * sizeof(int *) );
238    for( item=0; item<17; item++)
239        pixmap[item] = (int *) malloc( 2*width[item]*height*sizeof(int) );
240
241    currP = -1;
242    count = 0;
243    currWidth = 0;
244    currNum = 0;
245
246    for( row=0; row < height; row++) {
247        for( item=0; item < numbers; item++) {
248            count = 0;
249            currP = -1; // start each character fresh
250            for( col=0; col < width[item]; col++) {
251                nextP = fgetc( stream );
252                if( nextP == currP) {
253                    if( count == 127) { // probably never executed given the small widths
254                        pixmap[item][numPos[item]] = count;
255                        pixmap[item][numPos[item]+1] = currP;
256                        numPos[item]+=2;
257                        count = 0;
258                        currP = -1;
259                    } else count++; // add one to the current run
260                } else {
261                    if( currP != -1) {
262                        pixmap[item][numPos[item]] = count; // currP was the end of the run
263                        pixmap[item][numPos[item]+1] = currP;
264                        numPos[item]+=2;
265                    }
266                    currP = nextP; // start a new run
267                    count = 1;
268                }
269            }
270            // write out any run that was in progress
271            if( count > 0) {
272                pixmap[item][numPos[item]] = count;
273                pixmap[item][numPos[item]+1] = currP;
274                numPos[item]+=2;
275            }
276        }
277    }
278
279    // now, generate the c file
280
281    if ( outfile == NULL)
282        outfile = "rendered_numbers.c";
283    out_stream = fopen(outfile, "w");
284
285    if(out_stream == NULL) {
286        printf("couldn't open numbers outfile.. bailing\n");
287        exit(1);
288    }
289
290    fprintf( out_stream, " /* generated c file */\n\n");
291
292    // iterate through all the numbers/chars
293    for( item=0; item<numbers; item++)
294    {
295        fprintf( out_stream, "static const struct {\n");
296        fprintf( out_stream, "  unsigned int 	 num_w;\n");
297        fprintf( out_stream, "  unsigned int 	 num_h;\n");
298        fprintf( out_stream, "  unsigned char	 num_pixel_data[%#4.2x];\n", numPos[item]); // num elems
299        item == 16 ? fprintf( out_stream, "} num_colon = {\n") : fprintf( out_stream, "} num_%x = {\n", item);
300        fprintf( out_stream, "/* w */ %d,\n", width[item]);
301        fprintf( out_stream, "/* h */ %d,\n", height);
302        fprintf( out_stream, "/* pixel_data */ \n");
303
304        for( col = 0; col < numPos[item];)
305        {
306            fprintf( out_stream, "0x%.2x,0x%.2x", pixmap[item][col], pixmap[item][col+1]);
307            if (col == (numPos[item] - 2)) // this is the last element
308                fprintf( out_stream, "\n};\n\n");
309            else fprintf( out_stream, ", ");
310
311            line+=pixmap[item][col];
312            if( line >= width[item]) {
313                fprintf( out_stream, "\n");
314                line = 0;
315            }
316            col+=2;
317        }
318    }
319
320  fclose( out_stream );
321}
322
323
324/* 	encode_rle applies a "modified-RLE encoding to a given image. The encoding works as follows:
325
326        The quantity and value will be described by either two or three bytes. If the
327        most significant bit of the first byte is a 0, then the next seven bits are
328        the quantity (run-length) and the following 8 bits are the value (index into
329        a clut, in this case). If the msb of the first byte is a 1, then the next 15 bits
330        are the quantity and the following 8 are the value. Visually, the two possible
331        encodings are: (q = quantity, v = value)
332
333          Byte 1			   Byte 2		        Byte 3
334  case 1: [ 0 q6 q5 q4 q3 q2 q1 q0 ]       [ v7 v6 v5 v4 v3 v2 v1 v0 ]  [ ]
335  case 2: [ 1 q14 q13 q12 a11 q10 q9 q8 ]  [ q7 q6 q5 q4 q3 q2 q1 q0 ]  [ v7 v6 v5 v4 v3 v2 v1 v0 ]
336*/
337
338
339unsigned int
340encode_rle(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, unsigned char value)
341{
342    unsigned char single_mask = 0x00;
343    unsigned char double_mask = 0x80;
344    unsigned char slots_used = 0;
345
346    if (quantity < 128) {
347        fileArr[filePos] = single_mask | quantity;
348        slots_used = 1;
349    } else {
350        fileArr[filePos] = double_mask | (quantity >> 8); // high 7 bits (plus mask)
351        fileArr[filePos+1] = (unsigned char) quantity; // low 8 bits
352        slots_used = 2;
353    }
354
355    fileArr[filePos+slots_used] = value;
356    slots_used++;
357
358    return slots_used;
359}
360