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