| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // Utility for manipulating firmware screen block (BMPBLOCK) in GBB. | 5 // Utility for manipulating firmware screen block (BMPBLOCK) in GBB. |
| 6 // | 6 // |
| 7 | 7 |
| 8 #include "bmpblk_utility.h" | 8 #include "bmpblk_utility.h" |
| 9 | 9 |
| 10 #include <assert.h> | 10 #include <assert.h> |
| 11 #include <errno.h> | 11 #include <errno.h> |
| 12 #include <getopt.h> | 12 #include <getopt.h> |
| 13 #include <stdarg.h> | 13 #include <stdarg.h> |
| 14 #include <stdio.h> | 14 #include <stdio.h> |
| 15 #include <stdlib.h> | 15 #include <stdlib.h> |
| 16 #include <string.h> | 16 #include <string.h> |
| 17 #include <yaml.h> | 17 #include <yaml.h> |
| 18 | 18 |
| 19 extern "C" { |
| 20 #include "eficompress.h" |
| 21 } |
| 22 |
| 23 |
| 19 /* BMP header, used to validate image requirements | 24 /* BMP header, used to validate image requirements |
| 20 * See http://en.wikipedia.org/wiki/BMP_file_format | 25 * See http://en.wikipedia.org/wiki/BMP_file_format |
| 21 */ | 26 */ |
| 22 typedef struct { | 27 typedef struct { |
| 23 uint8_t CharB; // must be 'B' | 28 uint8_t CharB; // must be 'B' |
| 24 uint8_t CharM; // must be 'M' | 29 uint8_t CharM; // must be 'M' |
| 25 uint32_t Size; | 30 uint32_t Size; |
| 26 uint16_t Reserved[2]; | 31 uint16_t Reserved[2]; |
| 27 uint32_t ImageOffset; | 32 uint32_t ImageOffset; |
| 28 uint32_t HeaderSize; | 33 uint32_t HeaderSize; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 BmpBlockUtil::~BmpBlockUtil() { | 65 BmpBlockUtil::~BmpBlockUtil() { |
| 61 } | 66 } |
| 62 | 67 |
| 63 void BmpBlockUtil::initialize() { | 68 void BmpBlockUtil::initialize() { |
| 64 config_.config_filename.clear(); | 69 config_.config_filename.clear(); |
| 65 memset(&config_.header, '\0', BMPBLOCK_SIGNATURE_SIZE); | 70 memset(&config_.header, '\0', BMPBLOCK_SIGNATURE_SIZE); |
| 66 config_.images_map.clear(); | 71 config_.images_map.clear(); |
| 67 config_.screens_map.clear(); | 72 config_.screens_map.clear(); |
| 68 config_.localizations.clear(); | 73 config_.localizations.clear(); |
| 69 bmpblock_.clear(); | 74 bmpblock_.clear(); |
| 75 set_compression_ = false; |
| 76 compression_ = COMPRESS_NONE; |
| 77 } |
| 78 |
| 79 void BmpBlockUtil::force_compression(uint32_t compression) { |
| 80 compression_ = compression; |
| 81 set_compression_ = true; |
| 70 } | 82 } |
| 71 | 83 |
| 72 void BmpBlockUtil::load_from_config(const char *filename) { | 84 void BmpBlockUtil::load_from_config(const char *filename) { |
| 73 load_yaml_config(filename); | 85 load_yaml_config(filename); |
| 74 fill_bmpblock_header(); | 86 fill_bmpblock_header(); |
| 75 load_all_image_files(); | 87 load_all_image_files(); |
| 76 fill_all_image_infos(); | 88 fill_all_image_infos(); |
| 77 } | 89 } |
| 78 | 90 |
| 79 void BmpBlockUtil::load_yaml_config(const char *filename) { | 91 void BmpBlockUtil::load_yaml_config(const char *filename) { |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 285 } | 297 } |
| 286 } | 298 } |
| 287 | 299 |
| 288 void BmpBlockUtil::load_all_image_files() { | 300 void BmpBlockUtil::load_all_image_files() { |
| 289 for (StrImageConfigMap::iterator it = config_.images_map.begin(); | 301 for (StrImageConfigMap::iterator it = config_.images_map.begin(); |
| 290 it != config_.images_map.end(); | 302 it != config_.images_map.end(); |
| 291 ++it) { | 303 ++it) { |
| 292 const string &content = read_image_file(it->second.filename.c_str()); | 304 const string &content = read_image_file(it->second.filename.c_str()); |
| 293 it->second.raw_content = content; | 305 it->second.raw_content = content; |
| 294 it->second.data.original_size = content.size(); | 306 it->second.data.original_size = content.size(); |
| 295 /* Use no compression as default */ | 307 switch(compression_) { |
| 296 it->second.data.compression = COMPRESS_NONE; | 308 case COMPRESS_NONE: |
| 297 it->second.compressed_content = content; | 309 it->second.data.compression = compression_; |
| 298 it->second.data.compressed_size = content.size(); | 310 it->second.compressed_content = content; |
| 311 it->second.data.compressed_size = content.size(); |
| 312 break; |
| 313 case COMPRESS_EFIv1: |
| 314 { |
| 315 // The content will always compress smaller (so sez the docs). |
| 316 uint32_t tmpsize = content.size(); |
| 317 uint8_t *tmpbuf = (uint8_t *)malloc(tmpsize); |
| 318 // The size of the compressed content is also returned. |
| 319 if (EFI_SUCCESS != EfiCompress((uint8_t *)content.c_str(), tmpsize, |
| 320 tmpbuf, &tmpsize)) { |
| 321 error("Unable to compress!\n"); |
| 322 } |
| 323 it->second.data.compression = compression_; |
| 324 it->second.compressed_content.assign((const char *)tmpbuf, tmpsize); |
| 325 it->second.data.compressed_size = tmpsize; |
| 326 free(tmpbuf); |
| 327 } |
| 328 break; |
| 329 default: |
| 330 error("Unsupported compression method attempted.\n"); |
| 331 } |
| 299 } | 332 } |
| 300 } | 333 } |
| 301 | 334 |
| 302 const string BmpBlockUtil::read_image_file(const char *filename) { | 335 const string BmpBlockUtil::read_image_file(const char *filename) { |
| 303 string content; | 336 string content; |
| 304 vector<char> buffer; | 337 vector<char> buffer; |
| 305 | 338 |
| 306 FILE *fp = fopen(filename, "rb"); | 339 FILE *fp = fopen(filename, "rb"); |
| 307 if (!fp) { | 340 if (!fp) { |
| 308 perror(filename); | 341 perror(filename); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 402 config_.localizations[i].size()); | 435 config_.localizations[i].size()); |
| 403 } | 436 } |
| 404 config_.header.number_of_imageinfos = config_.images_map.size(); | 437 config_.header.number_of_imageinfos = config_.images_map.size(); |
| 405 } | 438 } |
| 406 | 439 |
| 407 void BmpBlockUtil::pack_bmpblock() { | 440 void BmpBlockUtil::pack_bmpblock() { |
| 408 bmpblock_.clear(); | 441 bmpblock_.clear(); |
| 409 | 442 |
| 410 /* Compute the ImageInfo offsets from start of BMPBLOCK. */ | 443 /* Compute the ImageInfo offsets from start of BMPBLOCK. */ |
| 411 uint32_t current_offset = sizeof(BmpBlockHeader) + | 444 uint32_t current_offset = sizeof(BmpBlockHeader) + |
| 412 sizeof(ScreenLayout) * config_.images_map.size(); | 445 sizeof(ScreenLayout) * config_.screens_map.size(); |
| 413 for (StrImageConfigMap::iterator it = config_.images_map.begin(); | 446 for (StrImageConfigMap::iterator it = config_.images_map.begin(); |
| 414 it != config_.images_map.end(); | 447 it != config_.images_map.end(); |
| 415 ++it) { | 448 ++it) { |
| 416 it->second.offset = current_offset; | 449 it->second.offset = current_offset; |
| 417 current_offset += sizeof(ImageInfo) + it->second.data.compressed_size; | 450 current_offset += sizeof(ImageInfo) + it->second.data.compressed_size; |
| 418 /* Make it 4-byte aligned. */ | 451 /* Make it 4-byte aligned. */ |
| 419 if ((current_offset & 3) > 0) { | 452 if ((current_offset & 3) > 0) { |
| 420 current_offset = (current_offset & ~3) + 4; | 453 current_offset = (current_offset & ~3) + 4; |
| 421 } | 454 } |
| 422 } | 455 } |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 500 " %s [-z NUM] -c YAML BMPBLOCK\n" | 533 " %s [-z NUM] -c YAML BMPBLOCK\n" |
| 501 "\n" | 534 "\n" |
| 502 " -z NUM = compression algorithm to use\n" | 535 " -z NUM = compression algorithm to use\n" |
| 503 " 0 = none\n" | 536 " 0 = none\n" |
| 504 " 1 = EFIv1\n" | 537 " 1 = EFIv1\n" |
| 505 " 2 = TBD\n" | 538 " 2 = TBD\n" |
| 506 "\n", prog_name); | 539 "\n", prog_name); |
| 507 printf( | 540 printf( |
| 508 "To display the contents of a BMPBLOCK:\n" | 541 "To display the contents of a BMPBLOCK:\n" |
| 509 "\n" | 542 "\n" |
| 510 " %s BMPBLOCK\n" | 543 " %s [-y] BMPBLOCK\n" |
| 544 "\n" |
| 545 " -y = display as yaml\n" |
| 511 "\n", prog_name); | 546 "\n", prog_name); |
| 512 printf( | 547 printf( |
| 513 "To unpack a BMPBLOCK file:\n" | 548 "To unpack a BMPBLOCK file:\n" |
| 514 "\n" | 549 "\n" |
| 515 " %s -x [-d DIR] [-f] BMPBLOCK\n" | 550 " %s -x [-d DIR] [-f] BMPBLOCK\n" |
| 516 "\n" | 551 "\n" |
| 517 " -d DIR = directory to use (default '.')\n" | 552 " -d DIR = directory to use (default '.')\n" |
| 518 " -f = force overwriting existing files\n" | 553 " -f = force overwriting existing files\n" |
| 519 "\n", prog_name); | 554 "\n", prog_name); |
| 520 exit(1); | 555 exit(1); |
| 521 } | 556 } |
| 522 | 557 |
| 523 /////////////////////////////////////////////////////////////////////// | 558 /////////////////////////////////////////////////////////////////////// |
| 524 // main | 559 // main |
| 525 | 560 |
| 526 int main(int argc, char *argv[]) { | 561 int main(int argc, char *argv[]) { |
| 527 | 562 |
| 528 const char *prog_name = strrchr(argv[0], '/'); | 563 const char *prog_name = strrchr(argv[0], '/'); |
| 529 if (prog_name) | 564 if (prog_name) |
| 530 prog_name++; | 565 prog_name++; |
| 531 else | 566 else |
| 532 prog_name = argv[0]; | 567 prog_name = argv[0]; |
| 533 | 568 |
| 534 int force = 0, extract_mode = 0; | 569 int overwrite = 0, extract_mode = 0; |
| 535 int compression = 0; | 570 int compression = 0; |
| 571 int set_compression = 0; |
| 536 const char *config_fn = 0, *bmpblock_fn = 0, *extract_dir = "."; | 572 const char *config_fn = 0, *bmpblock_fn = 0, *extract_dir = "."; |
| 573 int show_as_yaml = 0; |
| 537 | 574 |
| 538 int opt; | 575 int opt; |
| 539 opterr = 0; // quiet | 576 opterr = 0; // quiet |
| 540 int errorcnt = 0; | 577 int errorcnt = 0; |
| 541 char *e = 0; | 578 char *e = 0; |
| 542 while ((opt = getopt(argc, argv, ":c:xz:fd:")) != -1) { | 579 while ((opt = getopt(argc, argv, ":c:xz:fd:y")) != -1) { |
| 543 switch (opt) { | 580 switch (opt) { |
| 544 case 'c': | 581 case 'c': |
| 545 config_fn = optarg; | 582 config_fn = optarg; |
| 546 break; | 583 break; |
| 547 case 'x': | 584 case 'x': |
| 548 extract_mode = 1; | 585 extract_mode = 1; |
| 549 break; | 586 break; |
| 587 case 'y': |
| 588 show_as_yaml = 1; |
| 589 break; |
| 550 case 'z': | 590 case 'z': |
| 551 compression = (int)strtoul(optarg, &e, 0); | 591 compression = (int)strtoul(optarg, &e, 0); |
| 552 if (!*optarg || (e && *e)) { | 592 if (!*optarg || (e && *e)) { |
| 553 fprintf(stderr, "%s: invalid argument to -%c: \"%s\"\n", | 593 fprintf(stderr, "%s: invalid argument to -%c: \"%s\"\n", |
| 554 prog_name, opt, optarg); | 594 prog_name, opt, optarg); |
| 555 errorcnt++; | 595 errorcnt++; |
| 556 } | 596 } |
| 557 if (compression >= MAX_COMPRESS) { | 597 if (compression >= MAX_COMPRESS) { |
| 558 fprintf(stderr, "%s: compression type must be less than %d\n", | 598 fprintf(stderr, "%s: compression type must be less than %d\n", |
| 559 prog_name, compression); | 599 prog_name, MAX_COMPRESS); |
| 560 errorcnt++; | 600 errorcnt++; |
| 561 } | 601 } |
| 602 set_compression = 1; |
| 562 break; | 603 break; |
| 563 case 'f': | 604 case 'f': |
| 564 force = 1; | 605 overwrite = 1; |
| 565 break; | 606 break; |
| 566 case 'd': | 607 case 'd': |
| 567 extract_dir= optarg; | 608 extract_dir= optarg; |
| 568 break; | 609 break; |
| 569 case ':': | 610 case ':': |
| 570 fprintf(stderr, "%s: missing argument to -%c\n", | 611 fprintf(stderr, "%s: missing argument to -%c\n", |
| 571 prog_name, optopt); | 612 prog_name, optopt); |
| 572 errorcnt++; | 613 errorcnt++; |
| 573 break; | 614 break; |
| 574 default: | 615 default: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 587 fprintf(stderr, "%s: missing BMPBLOCK name\n", prog_name); | 628 fprintf(stderr, "%s: missing BMPBLOCK name\n", prog_name); |
| 588 errorcnt++; | 629 errorcnt++; |
| 589 } | 630 } |
| 590 | 631 |
| 591 if (errorcnt) | 632 if (errorcnt) |
| 592 usagehelp_exit(prog_name); | 633 usagehelp_exit(prog_name); |
| 593 | 634 |
| 594 BmpBlockUtil util; | 635 BmpBlockUtil util; |
| 595 | 636 |
| 596 if (config_fn) { | 637 if (config_fn) { |
| 597 printf("compression is %d\n", compression); | 638 if (set_compression) |
| 639 util.force_compression(compression); |
| 598 util.load_from_config(config_fn); | 640 util.load_from_config(config_fn); |
| 599 util.pack_bmpblock(); | 641 util.pack_bmpblock(); |
| 600 util.write_to_bmpblock(bmpblock_fn); | 642 util.write_to_bmpblock(bmpblock_fn); |
| 601 printf("The BMPBLOCK is sucessfully created in: %s.\n", | |
| 602 bmpblock_fn); | |
| 603 } | 643 } |
| 604 | 644 |
| 605 else if (extract_mode) { | 645 else if (extract_mode) { |
| 606 return extract_bmpblock(bmpblock_fn, extract_dir, force); | 646 return dump_bmpblock(bmpblock_fn, 1, extract_dir, overwrite); |
| 607 printf("extract parts from %s into %s %s overwriting\n", | 647 } else { |
| 608 bmpblock_fn, extract_dir, force ? "with" : "without"); | 648 return dump_bmpblock(bmpblock_fn, show_as_yaml, 0, 0); |
| 609 /* TODO(waihong): Implement the list mode. */ | |
| 610 error("Extract mode hasn't been implemented yet.\n"); | |
| 611 } | |
| 612 | |
| 613 else { | |
| 614 return display_bmpblock(bmpblock_fn); | |
| 615 printf("display content of %s\n", bmpblock_fn); | |
| 616 /* TODO(waihong): Implement the list mode. */ | |
| 617 error("List mode hasn't been implemented yet.\n"); | |
| 618 } | 649 } |
| 619 | 650 |
| 620 return 0; | 651 return 0; |
| 621 } | 652 } |
| 622 | 653 |
| 623 #endif // WITH_UTIL_MAIN | 654 #endif // WITH_UTIL_MAIN |
| OLD | NEW |