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
error(const char * fmt,...)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 */
HelpAndDie(void)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.
read_entire_file(const char * filename,size_t * 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().
discard_file(void * ptr,size_t length)111 static void discard_file(void *ptr, size_t length) {
112 munmap(ptr, length);
113 }
114
115 //////////////////////////////////////////////////////////////////////////////
116
117
118
main(int argc,char * argv[])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