]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/console/panic_ui/setupdialog.c
xnu-792.tar.gz
[apple/xnu.git] / osfmk / console / panic_ui / setupdialog.c
diff --git a/osfmk/console/panic_ui/setupdialog.c b/osfmk/console/panic_ui/setupdialog.c
new file mode 100644 (file)
index 0000000..2d684de
--- /dev/null
@@ -0,0 +1,359 @@
+/* setupdialog : converts a RAW image file into the c structure that the
+ * kernel panic ui system expects.
+ *
+ * to build: cc -o setupdialog setupdialog.c
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+
+#define RUN_MAX 32767
+
+void create_numbers_file( FILE *stream, char *outfile );
+unsigned int encode_rle(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, unsigned char value);
+
+void
+usage(void) {
+    printf("\nusage: setupdialog -i <image file> -oi <image output> -n <numbers file> -on <numbers output>\n");
+    
+    printf("\nYou can supply a panic image file, a numbers file, or both. Input files\n");
+    printf("must be in RAW format where each pixel is represented by an index into the\n");
+    printf("MacOS X system CLUT. The first %d bytes must be the width, height, and depth\n", 3 * sizeof(short));
+    printf("(in that order, %d bytes each).\n", sizeof(short));
+
+    printf("\nThe output files are generated C structures in the format the panic ui code\n");
+    printf("expects (default output files are panic_image.c and rendered_numbers.c).\n\n");
+}
+
+int 
+main( int argc, char *argv[] )
+{
+    int                next;
+    char       *file = NULL, *ptr, *out = NULL, *numsfile = NULL, *numsout = NULL;
+    FILE *     stream, *out_stream;
+    int *      data;
+    short      width = 0, height = 0, depth = 0;
+    char       word[2];
+    char       byte;
+    unsigned int i, pixels, filePos;
+    int                err;
+    unsigned char *fileArr;
+    unsigned char nextP;
+    unsigned int count;
+    int currP;
+    int fd;
+    int pairs_this_line;
+
+
+    // pull apart the arguments
+    for( next = 1; next < argc; next++ )
+    {
+        if (strcmp(argv[next], "-i") == 0) // image file (RAW/PICT?)
+            file = argv[++next];
+        else if (strcmp(argv[next], "-n") == 0) // numbers/chars image file (RAW)
+            numsfile = argv[++next];
+        else if (strcmp(argv[next], "-oi") == 0) // output file for image
+            out = argv[++next];
+        else if (strcmp(argv[next], "-on") == 0) // output file for numbers
+            numsout = argv[++next];
+       
+       /* perhaps we should just let the user specify the W/H rather than require the header */
+       /*
+        else if (strcmp(argv[next], "-w") == 0) // image width (pixels)
+            width = strtoul(argv[++next], &ptr, 0);
+        else if (strcmp(argv[next], "-h") == 0) // image height (pixels)
+            width = strtoul(argv[++next], &ptr, 0);
+       */
+    }
+    
+    if (!(numsfile || file)) {
+       usage();
+       exit(1);
+    }
+
+    if (!numsfile) {
+       printf("\nNo numbers file to process\n");
+    } else {
+        stream = fopen(numsfile, "r");
+        if (!stream) {
+            printf("bad nums infile.. bailing.\n");
+            exit(1);
+        }
+        create_numbers_file( stream, numsout );
+        fclose(stream);
+    }
+    
+    if( file == NULL) {
+        printf("\nNo image file to process\n");
+        exit(1);
+    }
+    
+    stream = fopen(file, "r");
+    if (!stream) {
+        printf("bad infile.. bailing.\n");
+        exit(1);
+    }
+    
+    printf("\nReading image file...\n");
+
+    fread((void *) &width, sizeof(short), 1, stream);
+    printf("got width: %d\n", width);
+    fread((void *) &height, sizeof(short), 1, stream);
+    printf("got height: %d\n", height);
+    fread((void *) &depth, sizeof(short), 1, stream);
+    printf("got depth: %d\n", depth);
+    
+    if (!(width && height && depth)) {
+       printf("Invalid image file header (width, height, or depth is 0)\n");
+       exit(1);
+    }
+
+    pixels = width * height;
+
+    if (!(fileArr = (unsigned char *) malloc(pixels))) {
+       printf("couldn't malloc fileArr (%d pixels)... bailing.\n", pixels);
+       exit(1);
+    }
+    
+    currP = -1;
+    count = 0;
+    filePos = 0; // position in the file we're writing out
+    
+    for (i=0; i < pixels; i++) {
+        nextP = fgetc(stream);
+        count++;
+        if (nextP == currP) {
+            if (count >= RUN_MAX) {
+                    filePos += encode_rle(fileArr, filePos, count, (unsigned char) currP);
+                    count = 0;
+                    currP = -1;
+            } 
+        } else {
+            if (currP != -1) {
+                filePos += encode_rle(fileArr, filePos, count-1, (unsigned char) currP);
+            }
+            currP = nextP; // start a new run
+            count = 1;
+        }
+    }
+    
+    // write out any run that was in progress
+    if (count > 0) {
+        filePos += encode_rle(fileArr, filePos, count, (unsigned char) currP);
+    }  
+    
+    fclose( stream ); 
+
+    // now, generate the c file
+    
+    if ( out == NULL)
+        out = "panic_image.c";
+    out_stream = fopen(out, "w");
+    
+    if(out_stream == NULL) {
+        printf("couldn't open out file.. bailing\n");
+        exit(1);
+    }
+    
+    pairs_this_line = 0;
+    
+    fprintf( out_stream, "/* generated c file */\n\n");
+    fprintf( out_stream, "static const struct {\n");
+    fprintf( out_stream, "  unsigned int        pd_width;\n");
+    fprintf( out_stream, "  unsigned int        pd_height;\n");
+    fprintf( out_stream, "  unsigned int        bytes_per_pixel; /* 1: CLUT, 3:RGB, 4:RGBA */\n");
+    fprintf( out_stream, "  unsigned char       image_pixel_data[%#4.2x];\n", (filePos));
+
+    fprintf( out_stream, "} panic_dialog = {\n");
+    fprintf( out_stream, "\t%d, ", width);             /* panic dialog x */
+    fprintf( out_stream, "%d, ", height);              /* panic dialog y */
+    fprintf( out_stream, "1,\n");                      /* bytes per pixel */
+   
+    for( i=0; i < filePos;) {
+       fprintf( out_stream, "0x%.2x,0x%.2x", fileArr[i], fileArr[i+1]);
+       i+=2;
+        pairs_this_line++;
+        
+        // if the first byte had a leading 1, this is a 3-byte encoding
+        if ((fileArr[i-2] >> 7) == 1) {
+            fprintf( out_stream, ",0x%.2x", fileArr[i++]);
+           pairs_this_line++;
+        }
+        
+        if (i >= filePos) // this is the last element
+            fprintf( out_stream, "\n};");
+        else fprintf( out_stream, ", ");
+       
+        if(pairs_this_line > 8) {
+            fprintf( out_stream, "\n");
+            pairs_this_line = 0;
+        }
+    }
+    
+  
+  fclose( out_stream );
+
+  return 0;
+}
+
+
+/* Each number/char (0-f) has its own row in the pixmap array.
+    When done, these rows each contain an RLE character.
+    The image file is read row by row, so the individual characters
+    must be constructed in the same way. The numPos array tracks the
+    current position in each character's RLE array.
+    */
+void
+create_numbers_file( FILE *stream, char *outfile )
+{
+    int                err;
+    short      height, depth, totalwidth;
+    int                numbers = 17;
+    int         width[17] = {9,7,8,6,9,7,8,7,8,7,10,7,9,10,7,6,4};
+    int                numPos[17] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 
+    
+    int **pixmap;
+    int                row, col, item, line=0, currWidth;
+    int nextP, currP;
+    int count, currNum;
+    
+    FILE       *out_stream;
+
+    printf("\nReading numbers file...\n");
+    fread((void *) &totalwidth, sizeof(short), 1, stream);
+    printf("got width: %d\n", totalwidth);
+    fread((void *) &height, sizeof(short), 1, stream);
+    printf("got height: %d\n", height);
+    fread((void *) &depth, sizeof(short), 1, stream);
+    printf("got depth: %d\n", depth);
+    
+    if (!(width && height && depth)) {
+       printf("Invalid numbers file header (width, height, or depth is 0)\n");
+       return;
+    }
+
+    // allocate array to hold each number's RLE encoding (20 = 2xwidest width[i] value, 17 = num chars)
+    pixmap = (int **) malloc( 17 * sizeof(int *) );
+    for( item=0; item<17; item++)
+        pixmap[item] = (int *) malloc( 2*width[item]*height*sizeof(int) );
+    
+    currP = -1;
+    count = 0;
+    currWidth = 0;
+    currNum = 0;
+    
+    for( row=0; row < height; row++) {
+        for( item=0; item < numbers; item++) {
+            count = 0;
+            currP = -1; // start each character fresh
+            for( col=0; col < width[item]; col++) {
+                nextP = fgetc( stream );
+                if( nextP == currP) {
+                    if( count == 127) { // probably never executed given the small widths
+                        pixmap[item][numPos[item]] = count;
+                        pixmap[item][numPos[item]+1] = currP;
+                        numPos[item]+=2;
+                        count = 0;
+                        currP = -1;
+                    } else count++; // add one to the current run
+                } else {
+                    if( currP != -1) {
+                        pixmap[item][numPos[item]] = count; // currP was the end of the run
+                        pixmap[item][numPos[item]+1] = currP;
+                        numPos[item]+=2;
+                    }
+                    currP = nextP; // start a new run
+                    count = 1;
+                }
+            }  
+            // write out any run that was in progress
+            if( count > 0) {
+                pixmap[item][numPos[item]] = count;
+                pixmap[item][numPos[item]+1] = currP;
+                numPos[item]+=2;
+            }
+        }
+    }
+    
+    // now, generate the c file
+    
+    if ( outfile == NULL)
+        outfile = "rendered_numbers.c";
+    out_stream = fopen(outfile, "w");
+    
+    if(out_stream == NULL) {
+        printf("couldn't open numbers outfile.. bailing\n");
+        exit(1);
+    }
+    
+    fprintf( out_stream, " /* generated c file */\n\n");
+    
+    // iterate through all the numbers/chars
+    for( item=0; item<numbers; item++)
+    {
+        fprintf( out_stream, "static const struct {\n");
+        fprintf( out_stream, "  unsigned int    num_w;\n");
+        fprintf( out_stream, "  unsigned int    num_h;\n");                    
+        fprintf( out_stream, "  unsigned char   num_pixel_data[%#4.2x];\n", numPos[item]); // num elems
+        item == 16 ? fprintf( out_stream, "} num_colon = {\n") : fprintf( out_stream, "} num_%x = {\n", item);
+        fprintf( out_stream, "/* w */ %d,\n", width[item]);
+        fprintf( out_stream, "/* h */ %d,\n", height);
+        fprintf( out_stream, "/* pixel_data */ \n");
+            
+        for( col = 0; col < numPos[item];)
+        {
+            fprintf( out_stream, "0x%.2x,0x%.2x", pixmap[item][col], pixmap[item][col+1]);
+            if (col == (numPos[item] - 2)) // this is the last element
+                fprintf( out_stream, "\n};\n\n");
+            else fprintf( out_stream, ", ");
+            
+            line+=pixmap[item][col];
+            if( line >= width[item]) {
+                fprintf( out_stream, "\n");
+                line = 0;
+            }
+            col+=2;
+        }
+    }
+    
+  fclose( out_stream );
+}
+
+
+/*     encode_rle applies a "modified-RLE encoding to a given image. The encoding works as follows:
+        
+        The quantity and value will be described by either two or three bytes. If the
+        most significant bit of the first byte is a 0, then the next seven bits are
+        the quantity (run-length) and the following 8 bits are the value (index into
+        a clut, in this case). If the msb of the first byte is a 1, then the next 15 bits
+        are the quantity and the following 8 are the value. Visually, the two possible
+        encodings are: (q = quantity, v = value)
+        
+          Byte 1                          Byte 2                       Byte 3
+  case 1: [ 0 q6 q5 q4 q3 q2 q1 q0 ]       [ v7 v6 v5 v4 v3 v2 v1 v0 ]  [ ]
+  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 ]
+*/
+
+
+unsigned int
+encode_rle(unsigned char * fileArr, unsigned int filePos, unsigned int quantity, unsigned char value)
+{
+    unsigned char single_mask = 0x00;
+    unsigned char double_mask = 0x80;
+    unsigned char slots_used = 0;
+    
+    if (quantity < 128) {
+        fileArr[filePos] = single_mask | quantity;
+        slots_used = 1;
+    } else {
+        fileArr[filePos] = double_mask | (quantity >> 8); // high 7 bits (plus mask)
+        fileArr[filePos+1] = (unsigned char) quantity; // low 8 bits
+        slots_used = 2;
+    }
+    
+    fileArr[filePos+slots_used] = value;
+    slots_used++;
+    
+    return slots_used;
+}