1 // Copyright (c) 2011 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <errno.h> 6 #include <fcntl.h> 7 #include <getopt.h> 8 #include <limits.h> 9 #include <stdarg.h> 10 #include <stdint.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <sys/mman.h> 15 #include <sys/stat.h> 16 #include <sys/types.h> 17 #include <unistd.h> 18 19 #include "bmpblk_font.h" 20 #include "image_types.h" 21 #include "vboot_api.h" 22 23 static char *progname; 24 25 static void error(const char *fmt, ...) 26 { 27 va_list args; 28 va_start( args, fmt ); 29 fprintf(stderr, "%s: ", progname); 30 vfprintf( stderr, fmt, args ); 31 va_end( args ); 32 } 33 #define fatal(args...) do { error(args); exit(1); } while(0) 34 35 36 /* Command line options */ 37 enum { 38 OPT_OUTFILE = 1000, 39 }; 40 41 #define DEFAULT_OUTFILE "font.bin" 42 43 44 static struct option long_opts[] = { 45 {"outfile", 1, 0, OPT_OUTFILE }, 46 {NULL, 0, 0, 0} 47 }; 48 49 50 /* Print help and return error */ 51 static void HelpAndDie(void) { 52 fprintf(stderr, 53 "\n" 54 "%s - Create a vboot fontfile from a set of BMP files.\n" 55 "\n" 56 "Usage: %s [OPTIONS] BMPFILE [BMPFILE...]\n" 57 "\n" 58 "Each BMP file must match *_HEX.bmp, where HEX is the hexadecimal\n" 59 "representation of the character that the file displays. The images\n" 60 "will be encoded in the given order. Typically the first image is\n" 61 "reused to represent any missing characters.\n" 62 "\n" 63 "OPTIONS are:\n" 64 " --outfile <filename> Output file (default is %s)\n" 65 "\n", progname, progname, DEFAULT_OUTFILE); 66 exit(1); 67 } 68 69 ////////////////////////////////////////////////////////////////////////////// 70 71 // Returns pointer to buffer containing entire file, sets length. 72 static void *read_entire_file(const char *filename, size_t *length) { 73 int fd; 74 struct stat sbuf; 75 void *ptr; 76 77 *length = 0; // just in case 78 79 if (0 != stat(filename, &sbuf)) { 80 error("Unable to stat %s: %s\n", filename, strerror(errno)); 81 return 0; 82 } 83 84 if (!sbuf.st_size) { 85 error("File %s is empty\n", filename); 86 return 0; 87 } 88 89 fd = open(filename, O_RDONLY); 90 if (fd < 0) { 91 error("Unable to open %s: %s\n", filename, strerror(errno)); 92 return 0; 93 } 94 95 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 96 if (MAP_FAILED == ptr) { 97 error("Unable to mmap %s: %s\n", filename, strerror(errno)); 98 close(fd); 99 return 0; 100 } 101 102 *length = sbuf.st_size; 103 104 close(fd); 105 106 return ptr; 107 } 108 109 110 // Reclaims buffer from read_entire_file(). 111 static void discard_file(void *ptr, size_t length) { 112 munmap(ptr, length); 113 } 114 115 ////////////////////////////////////////////////////////////////////////////// 116 117 118 119 int main(int argc, char* argv[]) { 120 char* outfile = DEFAULT_OUTFILE; 121 int numimages = 0; 122 int parse_error = 0; 123 int i; 124 FILE *ofp; 125 FontArrayHeader header; 126 FontArrayEntryHeader entry; 127 128 progname = strrchr(argv[0], '/'); 129 if (progname) 130 progname++; 131 else 132 progname = argv[0]; 133 134 while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { 135 switch (i) { 136 case OPT_OUTFILE: 137 outfile = optarg; 138 break; 139 140 default: 141 /* Unhandled option */ 142 printf("Unknown option\n"); 143 parse_error = 1; 144 break; 145 } 146 } 147 148 numimages = argc - optind; 149 150 if (parse_error || numimages < 1) 151 HelpAndDie(); 152 153 printf("outfile is %s\n", outfile); 154 printf("numimages is %d\n", numimages); 155 156 ofp = fopen(outfile, "wb"); 157 if (!ofp) 158 fatal("Unable to open %s: %s\n", outfile, strerror(errno)); 159 160 memcpy(&header.signature, FONT_SIGNATURE, FONT_SIGNATURE_SIZE); 161 header.num_entries = numimages; 162 if (1 != fwrite(&header, sizeof(header), 1, ofp)) { 163 error("Can't write header to %s: %s\n", outfile, strerror(errno)); 164 goto bad1; 165 } 166 167 for(i=0; i<numimages; i++) { 168 char *imgfile = argv[optind+i]; 169 char *s; 170 uint32_t ascii; 171 void *imgdata = 0; 172 size_t imgsize, filesize, diff; 173 174 s = strrchr(imgfile, '_'); 175 if (!s || 1 != sscanf(s, "_%x.bmp", &ascii)) { // This is not foolproof. 176 error("Unable to parse the character from filename %s\n", imgfile); 177 goto bad1; 178 } 179 180 imgdata = read_entire_file(imgfile, &imgsize); 181 if (!imgdata) 182 goto bad1; 183 184 if (FORMAT_BMP != identify_image_type(imgdata, imgsize, &entry.info)) { 185 error("%s does not contain a valid BMP image\n", imgfile); 186 goto bad1; 187 } 188 189 // Pad the image to align it on a 4-byte boundary. 190 filesize = imgsize; 191 if (imgsize % 4) 192 filesize = ((imgsize + 4) / 4) * 4; 193 diff = filesize - imgsize; 194 195 entry.ascii = ascii; 196 entry.info.tag = TAG_NONE; 197 entry.info.compression = COMPRESS_NONE; // we'll compress it all later 198 entry.info.original_size = filesize; 199 entry.info.compressed_size = filesize; 200 201 printf("%s => 0x%x %dx%d\n", imgfile, entry.ascii, 202 entry.info.width, entry.info.height); 203 204 if (1 != fwrite(&entry, sizeof(entry), 1, ofp)) { 205 error("Can't write entry to %s: %s\n", outfile, strerror(errno)); 206 goto bad1; 207 } 208 if (1 != fwrite(imgdata, imgsize, 1, ofp)) { 209 error("Can't write image to %s: %s\n", outfile, strerror(errno)); 210 goto bad1; 211 } 212 if (diff && 1 != fwrite("\0\0\0\0\0\0\0\0", diff, 1, ofp)) { 213 error("Can't write padding to %s: %s\n", outfile, strerror(errno)); 214 goto bad1; 215 } 216 217 218 discard_file(imgdata, imgsize); 219 } 220 221 fclose(ofp); 222 return 0; 223 224 bad1: 225 fclose(ofp); 226 error("Aborting\n"); 227 (void) unlink(outfile); 228 exit(1); 229 } 230