blob: 214beda4b0040d2b2a1b6b88c283665e3b47c2d4 [file] [log] [blame]
Bill Richardson794d4d42011-02-10 19:13:10 -08001// Copyright (c) 2010 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>
Bill Richardson61362d62011-02-14 10:28:03 -08007#include <limits.h>
Bill Richardson794d4d42011-02-10 19:13:10 -08008#include <stdio.h>
9#include <string.h>
10#include <sys/mman.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13#include <unistd.h>
14
15#include "bmpblk_util.h"
Bill Richardson61362d62011-02-14 10:28:03 -080016#include "eficompress.h"
Bill Richardson794d4d42011-02-10 19:13:10 -080017
18
19// Returns pointer to buffer containing entire file, sets length.
20static void *read_entire_file(const char *filename, size_t *length) {
21 int fd;
22 struct stat sbuf;
23 void *ptr;
24
25 *length = 0; // just in case
26
27 if (0 != stat(filename, &sbuf)) {
28 fprintf(stderr, "Unable to stat %s: %s\n", filename, strerror(errno));
29 return 0;
30 }
31
32 if (!sbuf.st_size) {
33 fprintf(stderr, "File %s is empty\n", filename);
34 return 0;
35 }
36
37 fd = open(filename, O_RDONLY);
38 if (fd < 0) {
39 fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
40 return 0;
41 }
42
43 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
44 if (MAP_FAILED == ptr) {
45 fprintf(stderr, "Unable to mmap %s: %s\n", filename, strerror(errno));
46 close(fd);
47 return 0;
48 }
49
50 *length = sbuf.st_size;
51
52 close(fd);
53
54 return ptr;
55}
56
57
58// Reclaims buffer from read_entire_file().
59static void discard_file(void *ptr, size_t length) {
60 munmap(ptr, length);
61}
62
Bill Richardson61362d62011-02-14 10:28:03 -080063//////////////////////////////////////////////////////////////////////////////
Bill Richardson794d4d42011-02-10 19:13:10 -080064
Bill Richardson61362d62011-02-14 10:28:03 -080065static int require_dir(const char *dirname) {
66 struct stat sbuf;
67
68 if (0 == stat(dirname, &sbuf)) {
69 // Something's there. Is it a directory?
70 if (S_ISDIR(sbuf.st_mode)) {
71 return 0;
72 }
73 fprintf(stderr, "%s already exists and is not a directory\n", dirname);
74 return 1;
75 }
76
77 // dirname doesn't exist. Try to create it.
78 if (ENOENT == errno) {
79 if (0 != mkdir(dirname, 0777)) {
80 fprintf(stderr, "Unable to create directory %s: %s\n",
81 dirname, strerror(errno));
82 return 1;
83 }
84 return 0;
85 }
86
87 fprintf(stderr, "Unable to stat %s: %s\n", dirname, strerror(errno));
88 return 1;
89}
90
91
92
93static void *do_efi_decompress(ImageInfo *img) {
94 void *ibuf;
95 void *sbuf;
96 void *obuf;
97 uint32_t isize;
98 uint32_t ssize;
99 uint32_t osize;
100 EFI_STATUS r;
101
102 ibuf = ((void *)img) + sizeof(ImageInfo);
103 isize = img->compressed_size;
104
105 r = EfiGetInfo(ibuf, isize, &osize, &ssize);
106 if (EFI_SUCCESS != r) {
107 fprintf(stderr, "EfiGetInfo() failed with code %d\n",
108 r);
109 return 0;
110 }
111
112 sbuf = malloc(ssize);
113 if (!sbuf) {
114 fprintf(stderr, "Can't allocate %d bytes: %s\n",
115 ssize,
116 strerror(errno));
117 return 0;
118 }
119
120 obuf = malloc(osize);
121 if (!obuf) {
122 fprintf(stderr, "Can't allocate %d bytes: %s\n",
123 osize,
124 strerror(errno));
125 free(sbuf);
126 return 0;
127 }
128
129 r = EfiDecompress(ibuf, isize, obuf, osize, sbuf, ssize);
130 if (r != EFI_SUCCESS) {
131 fprintf(stderr, "EfiDecompress failed with code %d\n", r);
132 free(obuf);
133 free(sbuf);
134 return 0;
135 }
136
137 free(sbuf);
138 return obuf;
139}
140
141
142// Show what's inside. If todir is NULL, just print. Otherwise unpack.
143int dump_bmpblock(const char *infile, int show_as_yaml,
144 const char *todir, int overwrite) {
145 void *ptr, *data_ptr;
Bill Richardson794d4d42011-02-10 19:13:10 -0800146 size_t length = 0;
147 BmpBlockHeader *hdr;
Bill Richardson61362d62011-02-14 10:28:03 -0800148 ImageInfo *img;
149 ScreenLayout *scr;
150 int loc_num;
151 int screen_num;
152 int i;
153 int offset;
154 int free_data;
155 char image_name[80];
156 char full_path_name[PATH_MAX];
157 int yfd, bfd;
158 FILE *yfp = stdout;
159 FILE *bfp = stdout;
Bill Richardson794d4d42011-02-10 19:13:10 -0800160
Bill Richardson61362d62011-02-14 10:28:03 -0800161 ptr = (void *)read_entire_file(infile, &length);
Bill Richardson794d4d42011-02-10 19:13:10 -0800162 if (!ptr)
163 return 1;
164
165 if (length < sizeof(BmpBlockHeader)) {
166 fprintf(stderr, "File %s is too small to be a BMPBLOCK\n", infile);
167 discard_file(ptr, length);
168 return 1;
169 }
170
171 if (0 != memcmp(ptr, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE)) {
172 fprintf(stderr, "File %s is not a BMPBLOCK\n", infile);
173 discard_file(ptr, length);
174 return 1;
175 }
176
Bill Richardson61362d62011-02-14 10:28:03 -0800177 if (todir) {
178 // Unpacking everything. Create the output directory if needed.
179 if (0 != require_dir(todir)) {
180 discard_file(ptr, length);
181 return 1;
182 }
183
184 // Open yaml output.
185 show_as_yaml = 1;
186
187 sprintf(full_path_name, "%s/%s", todir, "config.yaml");
188 yfd = open(full_path_name,
189 O_WRONLY | O_CREAT | O_TRUNC | (overwrite ? 0 : O_EXCL),
190 0666);
191 if (yfd < 0) {
192 fprintf(stderr, "Unable to open %s: %s\n", full_path_name,
193 strerror(errno));
194 discard_file(ptr, length);
195 return 1;
196 }
197
198 yfp = fdopen(yfd, "wb");
199 if (!yfp) {
200 fprintf(stderr, "Unable to fdopen %s: %s\n", full_path_name,
201 strerror(errno));
202 close(yfd);
203 discard_file(ptr, length);
204 return 1;
205 }
206 }
207
Bill Richardson794d4d42011-02-10 19:13:10 -0800208 hdr = (BmpBlockHeader *)ptr;
Bill Richardson61362d62011-02-14 10:28:03 -0800209
210 if (!show_as_yaml) {
211 printf("%s:\n", infile);
212 printf(" version %d.%d\n", hdr->major_version, hdr->minor_version);
213 printf(" %d screens\n", hdr->number_of_screenlayouts);
214 printf(" %d localizations\n", hdr->number_of_localizations);
215 printf(" %d discrete images\n", hdr->number_of_imageinfos);
216 discard_file(ptr, length);
217 return 0;
218 }
219
220 // Write out yaml
221 fprintf(yfp, "bmpblock: %d.%d\n", hdr->major_version, hdr->minor_version);
222 fprintf(yfp, "images:\n");
223 offset = sizeof(BmpBlockHeader) +
224 (sizeof(ScreenLayout) *
225 hdr->number_of_localizations *
226 hdr->number_of_screenlayouts);
227 for(i=0; i<hdr->number_of_imageinfos; i++) {
228 img = (ImageInfo *)(ptr + offset);
229 sprintf(image_name, "img_%08x.bmp", offset);
230 fprintf(yfp, " img_%08x: %s # %dx%d %d/%d\n", offset, image_name,
231 img->width, img->height,
232 img->compressed_size, img->original_size);
233 if (todir) {
234 sprintf(full_path_name, "%s/%s", todir, image_name);
235 bfd = open(full_path_name,
236 O_WRONLY | O_CREAT | O_TRUNC | (overwrite ? 0 : O_EXCL),
237 0666);
238 if (bfd < 0) {
239 fprintf(stderr, "Unable to open %s: %s\n", full_path_name,
240 strerror(errno));
241 fclose(yfp);
242 discard_file(ptr, length);
243 return 1;
244 }
245 bfp = fdopen(bfd, "wb");
246 if (!bfp) {
247 fprintf(stderr, "Unable to fdopen %s: %s\n", full_path_name,
248 strerror(errno));
249 close(bfd);
250 fclose(yfp);
251 discard_file(ptr, length);
252 return 1;
253 }
254 switch(img->compression) {
255 case COMPRESS_NONE:
256 data_ptr = ptr + offset + sizeof(ImageInfo);
257 free_data = 0;
258 break;
259 case COMPRESS_EFIv1:
260 data_ptr = do_efi_decompress(img);
261 if (!data_ptr) {
262 fclose(bfp);
263 fclose(yfp);
264 discard_file(ptr, length);
265 return 1;
266 }
267 free_data = 1;
268 break;
269 default:
270 fprintf(stderr, "Unsupported compression method encountered.\n");
271 fclose(bfp);
272 fclose(yfp);
273 discard_file(ptr, length);
274 return 1;
275 }
276 if (1 != fwrite(data_ptr, img->original_size, 1, bfp)) {
277 fprintf(stderr, "Unable to write %s: %s\n", full_path_name,
278 strerror(errno));
279 fclose(bfp);
280 fclose(yfp);
281 discard_file(ptr, length);
282 return 1;
283 }
284 fclose(bfp);
285 if (free_data)
286 free(data_ptr);
287 }
288 offset += sizeof(ImageInfo);
289 offset += img->compressed_size;
290 // 4-byte aligned
291 if ((offset & 3) > 0)
292 offset = (offset & ~3) + 4;
293 }
294 fprintf(yfp, "screens:\n");
295 for(loc_num = 0;
296 loc_num < hdr->number_of_localizations;
297 loc_num++) {
298 for(screen_num = 0;
299 screen_num < hdr->number_of_screenlayouts;
300 screen_num++) {
301 fprintf(yfp, " scr_%d_%d:\n", loc_num, screen_num);
302 i = loc_num * hdr->number_of_screenlayouts + screen_num;
303 offset = sizeof(BmpBlockHeader) + i * sizeof(ScreenLayout);
304 scr = (ScreenLayout *)(ptr + offset);
305 for(i=0; i<MAX_IMAGE_IN_LAYOUT; i++) {
306 if (scr->images[i].image_info_offset) {
307 fprintf(yfp, " - [%d, %d, img_%08x]\n",
308 scr->images[i].x, scr->images[i].y,
309 scr->images[i].image_info_offset);
310 }
311 }
312 }
313 }
314 fprintf(yfp, "localizations:\n");
315 for(loc_num = 0;
316 loc_num < hdr->number_of_localizations;
317 loc_num++) {
318 fprintf(yfp, " - [");
319 for(screen_num = 0;
320 screen_num < hdr->number_of_screenlayouts;
321 screen_num++) {
322 fprintf(yfp, " scr_%d_%d", loc_num, screen_num);
323 if (screen_num != hdr->number_of_screenlayouts - 1)
324 fprintf(yfp, ",");
325 }
326 fprintf(yfp, " ]\n");
327 }
328
329 if (todir)
330 fclose(yfp);
Bill Richardson794d4d42011-02-10 19:13:10 -0800331
332 discard_file(ptr, length);
333
334 return 0;
335}
336