blob: 49573af9777a2268c4c4af6aef83d27dde7d2c63 [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>
Tom Wai-Hong Tamee2bc912011-02-17 12:58:58 +08008#include <lzma.h>
Bill Richardson794d4d42011-02-10 19:13:10 -08009#include <stdio.h>
10#include <string.h>
11#include <sys/mman.h>
12#include <sys/stat.h>
13#include <sys/types.h>
14#include <unistd.h>
15
16#include "bmpblk_util.h"
Bill Richardson61362d62011-02-14 10:28:03 -080017#include "eficompress.h"
Bill Richardson794d4d42011-02-10 19:13:10 -080018
19
20// Returns pointer to buffer containing entire file, sets length.
21static void *read_entire_file(const char *filename, size_t *length) {
22 int fd;
23 struct stat sbuf;
24 void *ptr;
25
26 *length = 0; // just in case
27
28 if (0 != stat(filename, &sbuf)) {
29 fprintf(stderr, "Unable to stat %s: %s\n", filename, strerror(errno));
30 return 0;
31 }
32
33 if (!sbuf.st_size) {
34 fprintf(stderr, "File %s is empty\n", filename);
35 return 0;
36 }
37
38 fd = open(filename, O_RDONLY);
39 if (fd < 0) {
40 fprintf(stderr, "Unable to open %s: %s\n", filename, strerror(errno));
41 return 0;
42 }
43
44 ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
45 if (MAP_FAILED == ptr) {
46 fprintf(stderr, "Unable to mmap %s: %s\n", filename, strerror(errno));
47 close(fd);
48 return 0;
49 }
50
51 *length = sbuf.st_size;
52
53 close(fd);
54
55 return ptr;
56}
57
58
59// Reclaims buffer from read_entire_file().
60static void discard_file(void *ptr, size_t length) {
61 munmap(ptr, length);
62}
63
Bill Richardson61362d62011-02-14 10:28:03 -080064//////////////////////////////////////////////////////////////////////////////
Bill Richardson794d4d42011-02-10 19:13:10 -080065
Bill Richardson61362d62011-02-14 10:28:03 -080066static int require_dir(const char *dirname) {
67 struct stat sbuf;
68
69 if (0 == stat(dirname, &sbuf)) {
70 // Something's there. Is it a directory?
71 if (S_ISDIR(sbuf.st_mode)) {
72 return 0;
73 }
74 fprintf(stderr, "%s already exists and is not a directory\n", dirname);
75 return 1;
76 }
77
78 // dirname doesn't exist. Try to create it.
79 if (ENOENT == errno) {
80 if (0 != mkdir(dirname, 0777)) {
81 fprintf(stderr, "Unable to create directory %s: %s\n",
82 dirname, strerror(errno));
83 return 1;
84 }
85 return 0;
86 }
87
88 fprintf(stderr, "Unable to stat %s: %s\n", dirname, strerror(errno));
89 return 1;
90}
91
92
93
94static void *do_efi_decompress(ImageInfo *img) {
95 void *ibuf;
96 void *sbuf;
97 void *obuf;
98 uint32_t isize;
99 uint32_t ssize;
100 uint32_t osize;
101 EFI_STATUS r;
102
Tom Wai-Hong Tamee2bc912011-02-17 12:58:58 +0800103 ibuf = (void*)(img + 1);
Bill Richardson61362d62011-02-14 10:28:03 -0800104 isize = img->compressed_size;
105
106 r = EfiGetInfo(ibuf, isize, &osize, &ssize);
107 if (EFI_SUCCESS != r) {
108 fprintf(stderr, "EfiGetInfo() failed with code %d\n",
109 r);
110 return 0;
111 }
112
113 sbuf = malloc(ssize);
114 if (!sbuf) {
115 fprintf(stderr, "Can't allocate %d bytes: %s\n",
116 ssize,
117 strerror(errno));
118 return 0;
119 }
120
121 obuf = malloc(osize);
122 if (!obuf) {
123 fprintf(stderr, "Can't allocate %d bytes: %s\n",
124 osize,
125 strerror(errno));
126 free(sbuf);
127 return 0;
128 }
129
130 r = EfiDecompress(ibuf, isize, obuf, osize, sbuf, ssize);
131 if (r != EFI_SUCCESS) {
132 fprintf(stderr, "EfiDecompress failed with code %d\n", r);
133 free(obuf);
134 free(sbuf);
135 return 0;
136 }
137
138 free(sbuf);
139 return obuf;
140}
141
142
Tom Wai-Hong Tamee2bc912011-02-17 12:58:58 +0800143
144static void *do_lzma_decompress(ImageInfo *img) {
145 void *ibuf;
146 void *obuf;
147 uint32_t isize;
148 uint32_t osize;
149 lzma_stream stream = LZMA_STREAM_INIT;
150 lzma_ret result;
151
152 ibuf = (void*)(img + 1);
153 isize = img->compressed_size;
154 osize = img->original_size;
155 obuf = malloc(osize);
156 if (!obuf) {
157 fprintf(stderr, "Can't allocate %d bytes: %s\n",
158 osize,
159 strerror(errno));
160 return 0;
161 }
162
163 result = lzma_auto_decoder(&stream, -1, 0);
164 if (result != LZMA_OK) {
165 fprintf(stderr, "Unable to initialize auto decoder (error: %d)!\n",
166 result);
167 free(obuf);
168 return 0;
169 }
170
171 stream.next_in = ibuf;
172 stream.avail_in = isize;
173 stream.next_out = obuf;
174 stream.avail_out = osize;
175 result = lzma_code(&stream, LZMA_FINISH);
176 if (result != LZMA_STREAM_END) {
177 fprintf(stderr, "Unalbe to decode data (error: %d)!\n", result);
178 free(obuf);
179 return 0;
180 }
181 lzma_end(&stream);
182 return obuf;
183}
184
185
186
Bill Richardson61362d62011-02-14 10:28:03 -0800187// Show what's inside. If todir is NULL, just print. Otherwise unpack.
188int dump_bmpblock(const char *infile, int show_as_yaml,
189 const char *todir, int overwrite) {
190 void *ptr, *data_ptr;
Bill Richardson794d4d42011-02-10 19:13:10 -0800191 size_t length = 0;
192 BmpBlockHeader *hdr;
Bill Richardson61362d62011-02-14 10:28:03 -0800193 ImageInfo *img;
194 ScreenLayout *scr;
195 int loc_num;
196 int screen_num;
197 int i;
198 int offset;
199 int free_data;
200 char image_name[80];
201 char full_path_name[PATH_MAX];
202 int yfd, bfd;
203 FILE *yfp = stdout;
204 FILE *bfp = stdout;
Bill Richardson794d4d42011-02-10 19:13:10 -0800205
Bill Richardson61362d62011-02-14 10:28:03 -0800206 ptr = (void *)read_entire_file(infile, &length);
Bill Richardson794d4d42011-02-10 19:13:10 -0800207 if (!ptr)
208 return 1;
209
210 if (length < sizeof(BmpBlockHeader)) {
211 fprintf(stderr, "File %s is too small to be a BMPBLOCK\n", infile);
212 discard_file(ptr, length);
213 return 1;
214 }
215
216 if (0 != memcmp(ptr, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE)) {
217 fprintf(stderr, "File %s is not a BMPBLOCK\n", infile);
218 discard_file(ptr, length);
219 return 1;
220 }
221
Bill Richardson61362d62011-02-14 10:28:03 -0800222 if (todir) {
223 // Unpacking everything. Create the output directory if needed.
224 if (0 != require_dir(todir)) {
225 discard_file(ptr, length);
226 return 1;
227 }
228
229 // Open yaml output.
230 show_as_yaml = 1;
231
232 sprintf(full_path_name, "%s/%s", todir, "config.yaml");
233 yfd = open(full_path_name,
234 O_WRONLY | O_CREAT | O_TRUNC | (overwrite ? 0 : O_EXCL),
235 0666);
236 if (yfd < 0) {
237 fprintf(stderr, "Unable to open %s: %s\n", full_path_name,
238 strerror(errno));
239 discard_file(ptr, length);
240 return 1;
241 }
242
243 yfp = fdopen(yfd, "wb");
244 if (!yfp) {
245 fprintf(stderr, "Unable to fdopen %s: %s\n", full_path_name,
246 strerror(errno));
247 close(yfd);
248 discard_file(ptr, length);
249 return 1;
250 }
251 }
252
Bill Richardson794d4d42011-02-10 19:13:10 -0800253 hdr = (BmpBlockHeader *)ptr;
Bill Richardson61362d62011-02-14 10:28:03 -0800254
255 if (!show_as_yaml) {
256 printf("%s:\n", infile);
257 printf(" version %d.%d\n", hdr->major_version, hdr->minor_version);
258 printf(" %d screens\n", hdr->number_of_screenlayouts);
259 printf(" %d localizations\n", hdr->number_of_localizations);
260 printf(" %d discrete images\n", hdr->number_of_imageinfos);
261 discard_file(ptr, length);
262 return 0;
263 }
264
265 // Write out yaml
266 fprintf(yfp, "bmpblock: %d.%d\n", hdr->major_version, hdr->minor_version);
Bill Richardson61362d62011-02-14 10:28:03 -0800267 offset = sizeof(BmpBlockHeader) +
268 (sizeof(ScreenLayout) *
269 hdr->number_of_localizations *
270 hdr->number_of_screenlayouts);
Bill Richardsona7209ee2011-02-17 14:30:14 -0800271 // FIXME(chromium-os:12134): The bmbblock structure allows each image to be
272 // compressed differently, but we haven't provided a way for the yaml file to
273 // specify that. Additionally, we allow the yaml file to specify a default
274 // compression scheme for all images, but only if that line appears in the
275 // yaml file before any images. Accordingly, we'll just check the first image
276 // to see if it has any compression, and if it does, we'll write that out as
277 // the default. When this bug is fixed, we should just write each image's
278 // compression setting separately.
279 img = (ImageInfo *)(ptr + offset);
280 if (img->compression)
281 fprintf(yfp, "compression: %d\n", img->compression);
282 fprintf(yfp, "images:\n");
Bill Richardson61362d62011-02-14 10:28:03 -0800283 for(i=0; i<hdr->number_of_imageinfos; i++) {
284 img = (ImageInfo *)(ptr + offset);
Bill Richardson54e95822011-05-05 15:12:10 -0700285 if (img->compressed_size) {
286 sprintf(image_name, "img_%08x.bmp", offset);
287 if (img->tag == TAG_HWID) {
Bill Richardson0a9977e2011-08-22 16:03:59 -0700288 fprintf(yfp, " %s: %s # %dx%d %d/%d tag=%d fmt=%d\n",
Bill Richardson54e95822011-05-05 15:12:10 -0700289 RENDER_HWID, image_name,
290 img->width, img->height,
Bill Richardson0a9977e2011-08-22 16:03:59 -0700291 img->compressed_size, img->original_size,
292 img->tag, img->format);
Bill Richardson54e95822011-05-05 15:12:10 -0700293 } else if (img->tag == TAG_HWID_RTOL) {
Bill Richardson0a9977e2011-08-22 16:03:59 -0700294 fprintf(yfp, " %s: %s # %dx%d %d/%d tag=%d fmt=%d\n",
Bill Richardson54e95822011-05-05 15:12:10 -0700295 RENDER_HWID_RTOL, image_name,
296 img->width, img->height,
Bill Richardson0a9977e2011-08-22 16:03:59 -0700297 img->compressed_size, img->original_size,
298 img->tag, img->format);
Bill Richardson54e95822011-05-05 15:12:10 -0700299 } else {
Bill Richardson0a9977e2011-08-22 16:03:59 -0700300 fprintf(yfp, " img_%08x: %s # %dx%d %d/%d tag=%d fmt=%d\n",
Bill Richardson54e95822011-05-05 15:12:10 -0700301 offset, image_name,
302 img->width, img->height,
Bill Richardson0a9977e2011-08-22 16:03:59 -0700303 img->compressed_size, img->original_size,
304 img->tag, img->format);
Bill Richardson61362d62011-02-14 10:28:03 -0800305 }
Bill Richardson54e95822011-05-05 15:12:10 -0700306 if (todir) {
307 sprintf(full_path_name, "%s/%s", todir, image_name);
308 bfd = open(full_path_name,
309 O_WRONLY | O_CREAT | O_TRUNC | (overwrite ? 0 : O_EXCL),
310 0666);
311 if (bfd < 0) {
312 fprintf(stderr, "Unable to open %s: %s\n", full_path_name,
313 strerror(errno));
314 fclose(yfp);
315 discard_file(ptr, length);
316 return 1;
317 }
318 bfp = fdopen(bfd, "wb");
319 if (!bfp) {
320 fprintf(stderr, "Unable to fdopen %s: %s\n", full_path_name,
321 strerror(errno));
322 close(bfd);
323 fclose(yfp);
324 discard_file(ptr, length);
325 return 1;
326 }
327 switch(img->compression) {
328 case COMPRESS_NONE:
329 data_ptr = ptr + offset + sizeof(ImageInfo);
330 free_data = 0;
331 break;
332 case COMPRESS_EFIv1:
333 data_ptr = do_efi_decompress(img);
334 if (!data_ptr) {
335 fclose(bfp);
336 fclose(yfp);
337 discard_file(ptr, length);
338 return 1;
339 }
340 free_data = 1;
341 break;
342 case COMPRESS_LZMA1:
343 data_ptr = do_lzma_decompress(img);
344 if (!data_ptr) {
345 fclose(bfp);
346 fclose(yfp);
347 discard_file(ptr, length);
348 return 1;
349 }
350 free_data = 1;
351 break;
352 default:
353 fprintf(stderr, "Unsupported compression method encountered.\n");
Bill Richardson61362d62011-02-14 10:28:03 -0800354 fclose(bfp);
355 fclose(yfp);
356 discard_file(ptr, length);
357 return 1;
358 }
Bill Richardson54e95822011-05-05 15:12:10 -0700359 if (1 != fwrite(data_ptr, img->original_size, 1, bfp)) {
360 fprintf(stderr, "Unable to write %s: %s\n", full_path_name,
361 strerror(errno));
Tom Wai-Hong Tamee2bc912011-02-17 12:58:58 +0800362 fclose(bfp);
363 fclose(yfp);
364 discard_file(ptr, length);
365 return 1;
366 }
Bill Richardson61362d62011-02-14 10:28:03 -0800367 fclose(bfp);
Bill Richardson54e95822011-05-05 15:12:10 -0700368 if (free_data)
369 free(data_ptr);
Bill Richardson61362d62011-02-14 10:28:03 -0800370 }
Bill Richardson61362d62011-02-14 10:28:03 -0800371 }
372 offset += sizeof(ImageInfo);
373 offset += img->compressed_size;
374 // 4-byte aligned
375 if ((offset & 3) > 0)
376 offset = (offset & ~3) + 4;
377 }
378 fprintf(yfp, "screens:\n");
379 for(loc_num = 0;
380 loc_num < hdr->number_of_localizations;
381 loc_num++) {
382 for(screen_num = 0;
383 screen_num < hdr->number_of_screenlayouts;
384 screen_num++) {
385 fprintf(yfp, " scr_%d_%d:\n", loc_num, screen_num);
386 i = loc_num * hdr->number_of_screenlayouts + screen_num;
387 offset = sizeof(BmpBlockHeader) + i * sizeof(ScreenLayout);
388 scr = (ScreenLayout *)(ptr + offset);
389 for(i=0; i<MAX_IMAGE_IN_LAYOUT; i++) {
390 if (scr->images[i].image_info_offset) {
Bill Richardson54e95822011-05-05 15:12:10 -0700391 ImageInfo *iptr =
392 (ImageInfo *)(ptr + scr->images[i].image_info_offset);
393 if (iptr->tag == TAG_HWID) {
Bill Richardson0a9977e2011-08-22 16:03:59 -0700394 fprintf(yfp, " - [%d, %d, %s] # tag=%d fmt=%d c=%d %d/%d\n",
Bill Richardson54e95822011-05-05 15:12:10 -0700395 scr->images[i].x, scr->images[i].y,
Bill Richardson0a9977e2011-08-22 16:03:59 -0700396 RENDER_HWID, iptr->tag, iptr->format, iptr->compression,
397 iptr->compressed_size, iptr->original_size);
Bill Richardson54e95822011-05-05 15:12:10 -0700398 } else if (iptr->tag == TAG_HWID_RTOL) {
Bill Richardson0a9977e2011-08-22 16:03:59 -0700399 fprintf(yfp, " - [%d, %d, %s] # tag=%d fmt=%d c=%d %d/%d\n",
Bill Richardson54e95822011-05-05 15:12:10 -0700400 scr->images[i].x, scr->images[i].y,
Bill Richardson0a9977e2011-08-22 16:03:59 -0700401 RENDER_HWID_RTOL, iptr->tag,
402 iptr->format, iptr->compression,
403 iptr->compressed_size, iptr->original_size);
Bill Richardson54e95822011-05-05 15:12:10 -0700404 } else {
Bill Richardson0a9977e2011-08-22 16:03:59 -0700405 fprintf(yfp, " - [%d, %d, img_%08x]"
406 " # tag=%d fmt=%d c=%d %d/%d\n",
Bill Richardson54e95822011-05-05 15:12:10 -0700407 scr->images[i].x, scr->images[i].y,
Bill Richardson0a9977e2011-08-22 16:03:59 -0700408 scr->images[i].image_info_offset,
409 iptr->tag, iptr->format, iptr->compression,
410 iptr->compressed_size, iptr->original_size);
Bill Richardson54e95822011-05-05 15:12:10 -0700411 }
Bill Richardson61362d62011-02-14 10:28:03 -0800412 }
413 }
414 }
415 }
416 fprintf(yfp, "localizations:\n");
417 for(loc_num = 0;
418 loc_num < hdr->number_of_localizations;
419 loc_num++) {
420 fprintf(yfp, " - [");
421 for(screen_num = 0;
422 screen_num < hdr->number_of_screenlayouts;
423 screen_num++) {
424 fprintf(yfp, " scr_%d_%d", loc_num, screen_num);
425 if (screen_num != hdr->number_of_screenlayouts - 1)
426 fprintf(yfp, ",");
427 }
428 fprintf(yfp, " ]\n");
429 }
430
Bill Richardson8ba3d792011-05-18 18:25:31 -0700431 if (hdr->locale_string_offset) {
432 char *loc_ptr = (char *)ptr + hdr->locale_string_offset;
433 char c;
434 fprintf(yfp, "locale_index:\n");
435 while ((c = *loc_ptr) != '\0') {
436 fprintf(yfp, " - ");
437 do {
438 fputc(c, yfp);
439 loc_ptr++;
440 } while((c = *loc_ptr) != '\0');
441 loc_ptr++;
442 fputc('\n', yfp);
443 }
444 }
445
Bill Richardson61362d62011-02-14 10:28:03 -0800446 if (todir)
447 fclose(yfp);
Bill Richardson794d4d42011-02-10 19:13:10 -0800448
449 discard_file(ptr, length);
450
451 return 0;
452}
453