summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2011-02-04 15:01:37 -0800
committerBill Richardson <wfrichar@chromium.org>2011-02-04 15:01:37 -0800
commitd55085da49da8b7981494ea53ad23a6038fbb5c9 (patch)
treee483d0964d164c3a87c88eef343fc4e3dae0fc1b
parent6b2b81c13081fc22865e1f5ae2ce5789c91b3ce0 (diff)
downloadvboot-d55085da49da8b7981494ea53ad23a6038fbb5c9.tar.gz
Slight modification to a previously-LGTM'd CL, to work with ebuild changes.
This replaces http://codereview.chromium.org/6307007. The only difference is the Makefile. The vboot_reference ebuild has been changed so that we only attempt to build bmpblk_utility on the host. Change-Id: I4902703baba155e0d2d7646d19b233aa695c282f BUG=chromium-os:11017,chromium-os:10599 TEST=none No test needed. If buildbot is green, it's verified. Review URL: http://codereview.chromium.org/6334111
-rw-r--r--firmware/include/bmpblk_header.h123
-rw-r--r--firmware/version.c2
-rw-r--r--utility/Makefile7
-rw-r--r--utility/bmpblk_utility.cc551
-rw-r--r--utility/include/bmpblk_utility.h112
5 files changed, 794 insertions, 1 deletions
diff --git a/firmware/include/bmpblk_header.h b/firmware/include/bmpblk_header.h
new file mode 100644
index 00000000..3aa981ce
--- /dev/null
+++ b/firmware/include/bmpblk_header.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Data structure definitions for firmware screen block (BMPBLOCK).
+ *
+ * The BmpBlock structure looks like:
+ * +-----------------------------------------+
+ * | BmpBlock Header |
+ * +-----------------------------------------+
+ * | ScreenLayout[0] | \
+ * +-----------------------------------------+ |
+ * | ScreenLayout[1] | |
+ * +-----------------------------------------+ Localization[0]
+ * | ... | |
+ * +-----------------------------------------+ |
+ * | ScreenLayout[number_of_screenlayouts-1] | /
+ * +-----------------------------------------+
+ * | ScreenLayout[0] | \
+ * +-----------------------------------------+ Localization[1]
+ * | ... | /
+ * +-----------------------------------------+ ...
+ * | ScreenLayout[0] | \
+ * +-----------------------------------------+ Localization[
+ * | ... | / number_of_localizations-1]
+ * +-----------------------------------------+
+ * | ImageInfo[0] |
+ * +-----------------------------------------+
+ * | Image Content |
+ * +-----------------------------------------+
+ * | ImageInfo[2] | ImageInfo is 4-byte aligned.
+ * +-----------------------------------------+
+ * | Image Content |
+ * +-----------------------------------------+
+ * | ... |
+ * +-----------------------------------------+
+ * | ImageInfo[number_fo_images-1] |
+ * +-----------------------------------------+
+ * | Image Content |
+ * +-----------------------------------------+
+ *
+ */
+
+#ifndef VBOOT_REFERENCE_BMPBLK_HEADER_H_
+#define VBOOT_REFERENCE_BMPBLK_HEADER_H_
+
+#include "sysincludes.h"
+
+__pragma(pack(push, 1)) /* Support packing for MSVC. */
+
+#define BMPBLOCK_SIGNATURE "$BMP"
+#define BMPBLOCK_SIGNATURE_SIZE (4)
+
+#define BMPBLOCK_MAJOR_VERSION (0x0001)
+#define BMPBLOCK_MINOR_VERSION (0x0000)
+
+#define MAX_IMAGE_IN_LAYOUT (8)
+
+/* BMPBLOCK header, describing how many screen layouts and image infos */
+typedef struct BmpBlockHeader {
+ uint8_t signature[BMPBLOCK_SIGNATURE_SIZE]; /* BMPBLOCK_SIGNATURE $BMP */
+ uint16_t major_version; /* see BMPBLOCK_MAJOR_VER */
+ uint16_t minor_version; /* see BMPBLOCK_MINOR_VER */
+ uint32_t number_of_localizations; /* Number of localizations */
+ uint32_t number_of_screenlayouts; /* Number of screen layouts in each
+ * localization */
+ uint32_t number_of_imageinfos; /* Number of image infos */
+ uint32_t reserved[3];
+} __attribute__((packed)) BmpBlockHeader;
+
+/* Screen layout, describing how to stack multiple images on screen */
+typedef struct ScreenLayout {
+ struct {
+ uint32_t x; /* X-offset of the image to be rendered */
+ uint32_t y; /* Y-offset of the image to be rendered */
+ uint32_t image_info_offset; /* Offset of image info from start of
+ * BMPBLOCK. 0 means end of it. */
+ } images[MAX_IMAGE_IN_LAYOUT]; /* Images contained in the screen. Will be
+ * rendered from 0 to (number_of_images-1). */
+} __attribute__((packed)) ScreenLayout;
+
+/* Constants for screen index */
+typedef enum ScreenIndex {
+ SCREEN_DEVELOPER_MODE = 0,
+ SCREEN_RECOVERY_MODE,
+ SCREEN_RECOVERY_NO_OS,
+ SCREEN_RECOVERY_MISSING_OS,
+ MAX_SCREEN_INDEX,
+} ScreenIndex;
+
+/* Image info, describing the information of the image block */
+typedef struct ImageInfo {
+ uint32_t tag; /* Tag it as a special image, like HWID */
+ uint32_t width; /* Width of the image */
+ uint32_t height; /* Height of the image */
+ uint32_t format; /* File format of the image */
+ uint32_t compression; /* Compression method to the image file */
+ uint32_t original_size; /* Size of the original uncompressed image */
+ uint32_t compressed_size; /* Size of the compressed image */
+ uint32_t reserved;
+ /* NOTE: actual image content follows immediately */
+} __attribute__((packed)) ImageInfo;
+
+/* Constants for ImageInfo.tag */
+typedef enum ImageTag {
+ TAG_NONE = 0,
+ TAG_HWID,
+} ImageTag;
+
+/* Constants for ImageInfo.format */
+typedef enum ImageFormat {
+ FORMAT_INVALID = 0,
+ FORMAT_BMP,
+} ImageFormat;
+
+/* Constants for ImageInfo.compression */
+typedef enum Compression {
+ COMPRESS_NONE = 0,
+ COMPRESS_EFIv1, /* The x86 BIOS only supports this */
+ COMPRESS_TBD, /* Only on ARM? */
+} Compression;
+
+#endif /* VBOOT_REFERENCE_BMPBLK_HEADER_H_ */
diff --git a/firmware/version.c b/firmware/version.c
index e3073952..3776bc8b 100644
--- a/firmware/version.c
+++ b/firmware/version.c
@@ -1 +1 @@
-char* VbootVersion = "VBOOv=9e0713db";
+char* VbootVersion = "VBOOv=0a42e63b";
diff --git a/utility/Makefile b/utility/Makefile
index 75b8f3d2..973d7855 100644
--- a/utility/Makefile
+++ b/utility/Makefile
@@ -36,6 +36,10 @@ TARGET_NAMES = dumpRSAPublicKey \
dev_debug_vboot \
pack_firmware_image
+ifeq ($(MINIMAL),)
+TARGET_NAMES += bmpblk_utility
+endif
+
TARGET_BINS = $(addprefix ${BUILD_ROOT}/,$(TARGET_NAMES))
ALL_DEPS = $(addsuffix .d,${TARGET_BINS})
@@ -50,6 +54,9 @@ ${BUILD_ROOT}/dump_kernel_config: dump_kernel_config.c $(LIBS)
${BUILD_ROOT}/gbb_utility: gbb_utility.cc
$(CXX) -DWITH_UTIL_MAIN $(CFLAGS) $< -o $@
+${BUILD_ROOT}/bmpblk_utility: bmpblk_utility.cc
+ $(CXX) -DWITH_UTIL_MAIN -lyaml $(CFLAGS) $< -o $@
+
${BUILD_ROOT}/load_kernel_test: load_kernel_test.c $(LIBS)
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto
diff --git a/utility/bmpblk_utility.cc b/utility/bmpblk_utility.cc
new file mode 100644
index 00000000..8da3e18f
--- /dev/null
+++ b/utility/bmpblk_utility.cc
@@ -0,0 +1,551 @@
+// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Utility for manipulating firmware screen block (BMPBLOCK) in GBB.
+//
+
+#include "bmpblk_utility.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <yaml.h>
+
+/* The offsets of width and height fields in a BMP file.
+ * See http://en.wikipedia.org/wiki/BMP_file_format */
+#define BMP_WIDTH_OFFSET 18
+#define BMP_HEIGHT_OFFSET 22
+
+static void error(const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ fprintf(stderr, "ERROR: ");
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ exit(1);
+}
+
+///////////////////////////////////////////////////////////////////////
+// BmpBlock Utility implementation
+
+namespace vboot_reference {
+
+BmpBlockUtil::BmpBlockUtil() {
+ initialize();
+}
+
+BmpBlockUtil::~BmpBlockUtil() {
+}
+
+void BmpBlockUtil::initialize() {
+ config_.config_filename.clear();
+ memset(&config_.header, '\0', BMPBLOCK_SIGNATURE_SIZE);
+ config_.images_map.clear();
+ config_.screens_map.clear();
+ config_.localizations.clear();
+ bmpblock_.clear();
+}
+
+void BmpBlockUtil::load_from_config(const char *filename) {
+ load_yaml_config(filename);
+ fill_bmpblock_header();
+ load_all_image_files();
+ fill_all_image_infos();
+}
+
+void BmpBlockUtil::load_yaml_config(const char *filename) {
+ yaml_parser_t parser;
+
+ config_.config_filename = filename;
+ config_.images_map.clear();
+ config_.screens_map.clear();
+ config_.localizations.clear();
+
+ FILE *fp = fopen(filename, "rb");
+ if (!fp) {
+ perror(filename);
+ exit(errno);
+ }
+
+ yaml_parser_initialize(&parser);
+ yaml_parser_set_input_file(&parser, fp);
+ parse_config(&parser);
+ yaml_parser_delete(&parser);
+ fclose(fp);
+}
+
+void BmpBlockUtil::expect_event(yaml_parser_t *parser,
+ const yaml_event_type_e type) {
+ yaml_event_t event;
+ yaml_parser_parse(parser, &event);
+ if (event.type != type) {
+ error("Syntax error.\n");
+ }
+ yaml_event_delete(&event);
+}
+
+void BmpBlockUtil::parse_config(yaml_parser_t *parser) {
+ expect_event(parser, YAML_STREAM_START_EVENT);
+ expect_event(parser, YAML_DOCUMENT_START_EVENT);
+ parse_first_layer(parser);
+ expect_event(parser, YAML_DOCUMENT_END_EVENT);
+ expect_event(parser, YAML_STREAM_END_EVENT);
+}
+
+void BmpBlockUtil::parse_first_layer(yaml_parser_t *parser) {
+ yaml_event_t event;
+ string keyword;
+ expect_event(parser, YAML_MAPPING_START_EVENT);
+ for (;;) {
+ yaml_parser_parse(parser, &event);
+ switch (event.type) {
+ case YAML_SCALAR_EVENT:
+ keyword = (char*)event.data.scalar.value;
+ if (keyword == "bmpblock") {
+ parse_bmpblock(parser);
+ } else if (keyword == "images") {
+ parse_images(parser);
+ } else if (keyword == "screens") {
+ parse_screens(parser);
+ } else if (keyword == "localizations") {
+ parse_localizations(parser);
+ }
+ break;
+ case YAML_MAPPING_END_EVENT:
+ yaml_event_delete(&event);
+ return;
+ default:
+ error("Syntax error in parsing config file.\n");
+ }
+ yaml_event_delete(&event);
+ }
+}
+
+void BmpBlockUtil::parse_bmpblock(yaml_parser_t *parser) {
+ yaml_event_t event;
+ yaml_parser_parse(parser, &event);
+ if (event.type != YAML_SCALAR_EVENT) {
+ error("Syntax error in parsing bmpblock.\n");
+ }
+ config_.header.major_version = atoi((char*)event.data.scalar.value);
+ config_.header.minor_version = atoi(
+ strchr((char*)event.data.scalar.value, '.') + 1);
+ yaml_event_delete(&event);
+}
+
+void BmpBlockUtil::parse_images(yaml_parser_t *parser) {
+ yaml_event_t event;
+ string image_name, image_filename;
+ expect_event(parser, YAML_MAPPING_START_EVENT);
+ for (;;) {
+ yaml_parser_parse(parser, &event);
+ switch (event.type) {
+ case YAML_SCALAR_EVENT:
+ image_name = (char*)event.data.scalar.value;
+ yaml_event_delete(&event);
+ yaml_parser_parse(parser, &event);
+ if (event.type != YAML_SCALAR_EVENT) {
+ error("Syntax error in parsing images.\n");
+ }
+ image_filename = (char*)event.data.scalar.value;
+ config_.images_map[image_name] = ImageConfig();
+ config_.images_map[image_name].filename = image_filename;
+ break;
+ case YAML_MAPPING_END_EVENT:
+ yaml_event_delete(&event);
+ return;
+ default:
+ error("Syntax error in parsing images.\n");
+ }
+ yaml_event_delete(&event);
+ }
+}
+
+void BmpBlockUtil::parse_layout(yaml_parser_t *parser, ScreenConfig &screen) {
+ yaml_event_t event;
+ string screen_name;
+ int depth = 0, index1 = 0, index2 = 0;
+ expect_event(parser, YAML_SEQUENCE_START_EVENT);
+ for (;;) {
+ yaml_parser_parse(parser, &event);
+ switch (event.type) {
+ case YAML_SEQUENCE_START_EVENT:
+ depth++;
+ break;
+ case YAML_SCALAR_EVENT:
+ switch (index2) {
+ case 0:
+ screen.data.images[index1].x = atoi((char*)event.data.scalar.value);
+ break;
+ case 1:
+ screen.data.images[index1].y = atoi((char*)event.data.scalar.value);
+ break;
+ case 2:
+ screen.image_names[index1] = (char*)event.data.scalar.value;
+ break;
+ default:
+ error("Syntax error in parsing layout.\n");
+ }
+ index2++;
+ break;
+ case YAML_SEQUENCE_END_EVENT:
+ if (depth == 1) {
+ index1++;
+ index2 = 0;
+ } else if (depth == 0) {
+ yaml_event_delete(&event);
+ return;
+ }
+ depth--;
+ break;
+ default:
+ error("Syntax error in paring layout.\n");
+ }
+ yaml_event_delete(&event);
+ }
+}
+
+void BmpBlockUtil::parse_screens(yaml_parser_t *parser) {
+ yaml_event_t event;
+ string screen_name;
+ expect_event(parser, YAML_MAPPING_START_EVENT);
+ for (;;) {
+ yaml_parser_parse(parser, &event);
+ switch (event.type) {
+ case YAML_SCALAR_EVENT:
+ screen_name = (char*)event.data.scalar.value;
+ config_.screens_map[screen_name] = ScreenConfig();
+ parse_layout(parser, config_.screens_map[screen_name]);
+ break;
+ case YAML_MAPPING_END_EVENT:
+ yaml_event_delete(&event);
+ return;
+ default:
+ error("Syntax error in parsing screens.\n");
+ }
+ yaml_event_delete(&event);
+ }
+}
+
+void BmpBlockUtil::parse_localizations(yaml_parser_t *parser) {
+ yaml_event_t event;
+ int depth = 0, index = 0;
+ expect_event(parser, YAML_SEQUENCE_START_EVENT);
+ for (;;) {
+ yaml_parser_parse(parser, &event);
+ switch (event.type) {
+ case YAML_SEQUENCE_START_EVENT:
+ config_.localizations.push_back(vector<string>());
+ depth++;
+ break;
+ case YAML_SCALAR_EVENT:
+ config_.localizations[index].push_back((char*)event.data.scalar.value);
+ break;
+ case YAML_SEQUENCE_END_EVENT:
+ if (depth == 1) {
+ index++;
+ } else if (depth == 0) {
+ yaml_event_delete(&event);
+ return;
+ }
+ depth--;
+ break;
+ default:
+ error("Syntax error in parsing localizations.\n");
+ }
+ yaml_event_delete(&event);
+ }
+}
+
+void BmpBlockUtil::load_all_image_files() {
+ for (StrImageConfigMap::iterator it = config_.images_map.begin();
+ it != config_.images_map.end();
+ ++it) {
+ const string &content = read_image_file(it->second.filename.c_str());
+ it->second.raw_content = content;
+ it->second.data.original_size = content.size();
+ /* Use no compression as default */
+ it->second.data.compression = COMPRESS_NONE;
+ it->second.compressed_content = content;
+ it->second.data.compressed_size = content.size();
+ }
+}
+
+const string BmpBlockUtil::read_image_file(const char *filename) {
+ string content;
+ vector<char> buffer;
+
+ FILE *fp = fopen(filename, "rb");
+ if (!fp) {
+ perror(filename);
+ exit(errno);
+ }
+
+ if (fseek(fp, 0, SEEK_END) == 0) {
+ buffer.resize(ftell(fp));
+ rewind(fp);
+ }
+
+ if (!buffer.empty()) {
+ if(fread(&buffer[0], buffer.size(), 1, fp) != 1) {
+ perror(filename);
+ buffer.clear();
+ } else {
+ content.assign(buffer.begin(), buffer.end());
+ }
+ }
+
+ fclose(fp);
+ return content;
+}
+
+ImageFormat BmpBlockUtil::get_image_format(const string content) {
+ if (content[0] == 'B' && content[1] == 'M')
+ return FORMAT_BMP;
+ else
+ return FORMAT_INVALID;
+}
+
+uint32_t BmpBlockUtil::get_bmp_image_width(const string content) {
+ const char *start = content.c_str();
+ uint32_t width = *(uint32_t*)(start + BMP_WIDTH_OFFSET);
+ /* Do a rough verification. */
+ assert(width > 0 && width < 1600);
+ return width;
+}
+
+uint32_t BmpBlockUtil::get_bmp_image_height(const string content) {
+ const char *start = content.c_str();
+ uint32_t height = *(uint32_t*)(start + BMP_HEIGHT_OFFSET);
+ /* Do a rough verification. */
+ assert(height > 0 && height < 1000);
+ return height;
+}
+
+void BmpBlockUtil::fill_all_image_infos() {
+ for (StrImageConfigMap::iterator it = config_.images_map.begin();
+ it != config_.images_map.end();
+ ++it) {
+ it->second.data.format = (uint32_t)get_image_format(it->second.raw_content);
+ switch (it->second.data.format) {
+ case FORMAT_BMP:
+ it->second.data.width = get_bmp_image_width(it->second.raw_content);
+ it->second.data.height = get_bmp_image_height(it->second.raw_content);
+ break;
+ default:
+ error("Unsupported image format.");
+ }
+ }
+}
+
+void BmpBlockUtil::compress_all_images(const Compression compress) {
+ switch (compress) {
+ case COMPRESS_NONE:
+ for (StrImageConfigMap::iterator it = config_.images_map.begin();
+ it != config_.images_map.end();
+ ++it) {
+ it->second.data.compression = compress;
+ it->second.compressed_content = it->second.raw_content;
+ it->second.data.compressed_size = it->second.compressed_content.size();
+ }
+ break;
+ default:
+ error("Unsupported data compression.");
+ }
+}
+
+void BmpBlockUtil::fill_bmpblock_header() {
+ memset(&config_.header, '\0', sizeof(config_.header));
+ memcpy(&config_.header.signature, BMPBLOCK_SIGNATURE,
+ BMPBLOCK_SIGNATURE_SIZE);
+ config_.header.number_of_localizations = config_.localizations.size();
+ config_.header.number_of_screenlayouts = config_.localizations[0].size();
+ for (unsigned int i = 1; i < config_.localizations.size(); ++i) {
+ assert(config_.header.number_of_screenlayouts ==
+ config_.localizations[i].size());
+ }
+ config_.header.number_of_imageinfos = config_.images_map.size();
+}
+
+void BmpBlockUtil::pack_bmpblock() {
+ bmpblock_.clear();
+
+ /* Compute the ImageInfo offsets from start of BMPBLOCK. */
+ uint32_t current_offset = sizeof(BmpBlockHeader) +
+ sizeof(ScreenLayout) * config_.images_map.size();
+ for (StrImageConfigMap::iterator it = config_.images_map.begin();
+ it != config_.images_map.end();
+ ++it) {
+ it->second.offset = current_offset;
+ current_offset += sizeof(ImageInfo) + it->second.data.compressed_size;
+ /* Make it 4-byte aligned. */
+ if ((current_offset & 3) > 0) {
+ current_offset = (current_offset & ~3) + 4;
+ }
+ }
+ bmpblock_.resize(current_offset);
+
+ /* Fill BmpBlockHeader struct. */
+ string::iterator current_filled = bmpblock_.begin();
+ std::copy(reinterpret_cast<char*>(&config_.header),
+ reinterpret_cast<char*>(&config_.header + 1),
+ current_filled);
+ current_filled += sizeof(config_.header);
+
+ /* Fill all ScreenLayout structs. */
+ for (unsigned int i = 0; i < config_.localizations.size(); ++i) {
+ for (unsigned int j = 0; j < config_.localizations[i].size(); ++j) {
+ ScreenConfig &screen = config_.screens_map[config_.localizations[i][j]];
+ for (unsigned int k = 0;
+ k < MAX_IMAGE_IN_LAYOUT && !screen.image_names[k].empty();
+ ++k) {
+ screen.data.images[k].image_info_offset =
+ config_.images_map[screen.image_names[k]].offset;
+ }
+ std::copy(reinterpret_cast<char*>(&screen.data),
+ reinterpret_cast<char*>(&screen.data + 1),
+ current_filled);
+ current_filled += sizeof(screen.data);
+ }
+ }
+
+ /* Fill all ImageInfo structs and image contents. */
+ for (StrImageConfigMap::iterator it = config_.images_map.begin();
+ it != config_.images_map.end();
+ ++it) {
+ current_filled = bmpblock_.begin() + it->second.offset;
+ std::copy(reinterpret_cast<char*>(&it->second.data),
+ reinterpret_cast<char*>(&it->second.data + 1),
+ current_filled);
+ current_filled += sizeof(it->second.data);
+ std::copy(it->second.compressed_content.begin(),
+ it->second.compressed_content.end(),
+ current_filled);
+ }
+}
+
+void BmpBlockUtil::write_to_bmpblock(const char *filename) {
+ assert(!bmpblock_.empty());
+
+ FILE *fp = fopen(filename, "wb");
+ if (!fp) {
+ perror(filename);
+ exit(errno);
+ }
+
+ int r = fwrite(bmpblock_.c_str(), bmpblock_.size(), 1, fp);
+ fclose(fp);
+ if (r != 1) {
+ perror(filename);
+ exit(errno);
+ }
+}
+
+} // namespace vboot_reference
+
+#ifdef WITH_UTIL_MAIN
+
+///////////////////////////////////////////////////////////////////////
+// Command line utilities
+
+using vboot_reference::BmpBlockUtil;
+
+// utility function: provide usage of this utility and exit.
+static void usagehelp_exit(const char *prog_name) {
+ printf(
+ "Utility to manage firmware screen block (BMPBLOCK)\n"
+ "Usage: %s -c|-l|-x [options] BMPBLOCK_FILE\n"
+ "\n"
+ "Main Operation Mode:\n"
+ " -c, --create Create a new BMPBLOCK file. Should specify --config.\n"
+ " -l, --list List the contents of a BMPBLOCK file.\n"
+ " -x, --extract Extract embedded images and config file from a BMPBLOCK\n"
+ " file.\n"
+ "\n"
+ "Other Options:\n"
+ " -C, --config=CONFIG_FILE Config file describing screen layouts and\n"
+ " embedded images. (default: bmpblk.cfg)\n"
+ "\n"
+ "Example:\n"
+ " %s --create --config=screens.cfg bmpblk.bin\n"
+ , prog_name, prog_name);
+ exit(1);
+}
+
+///////////////////////////////////////////////////////////////////////
+// main
+
+int main(int argc, char *argv[]) {
+ const char *prog_name = argv[0];
+ BmpBlockUtil util;
+
+ struct BmpBlockUtilOptions {
+ bool create_mode, list_mode, extract_mode;
+ string config_fn, bmpblock_fn;
+ } options;
+
+ int longindex, opt;
+ static struct option longopts[] = {
+ {"create", 0, NULL, 'c'},
+ {"list", 0, NULL, 'l'},
+ {"extract", 0, NULL, 'x'},
+ {"config", 1, NULL, 'C'},
+ { NULL, 0, NULL, 0 },
+ };
+
+ while ((opt = getopt_long(argc, argv, "clxC:", longopts, &longindex)) >= 0) {
+ switch (opt) {
+ case 'c':
+ options.create_mode = true;
+ break;
+ case 'l':
+ options.list_mode = true;
+ break;
+ case 'x':
+ options.extract_mode = true;
+ break;
+ case 'C':
+ options.config_fn = optarg;
+ break;
+ default:
+ case '?':
+ usagehelp_exit(prog_name);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 1) {
+ options.bmpblock_fn = argv[0];
+ } else {
+ usagehelp_exit(prog_name);
+ }
+
+ if (options.create_mode) {
+ util.load_from_config(options.config_fn.c_str());
+ util.pack_bmpblock();
+ util.write_to_bmpblock(options.bmpblock_fn.c_str());
+ printf("The BMPBLOCK is sucessfully created in: %s.\n",
+ options.bmpblock_fn.c_str());
+ }
+
+ if (options.list_mode) {
+ /* TODO(waihong): Implement the list mode. */
+ error("List mode hasn't been implemented yet.\n");
+ }
+
+ if (options.extract_mode) {
+ /* TODO(waihong): Implement the extract mode. */
+ error("Extract mode hasn't been implemented yet.\n");
+ }
+
+ return 0;
+}
+
+#endif // WITH_UTIL_MAIN
diff --git a/utility/include/bmpblk_utility.h b/utility/include/bmpblk_utility.h
new file mode 100644
index 00000000..b73b6630
--- /dev/null
+++ b/utility/include/bmpblk_utility.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#ifndef VBOOT_REFERENCE_BMPBLK_UTILITY_H_
+#define VBOOT_REFERENCE_BMPBLK_UTILITY_H_
+
+#include "bmpblk_header.h"
+
+#include <yaml.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+using std::map;
+using std::string;
+using std::vector;
+
+namespace vboot_reference {
+
+/* Internal struct for contructing ImageInfo. */
+typedef struct ImageConfig {
+ ImageInfo data;
+ string filename;
+ string raw_content;
+ string compressed_content;
+ uint32_t offset;
+} ImageConfig;
+
+/* Internal struct for contructing ScreenLayout. */
+typedef struct ScreenConfig {
+ ScreenLayout data;
+ string image_names[MAX_IMAGE_IN_LAYOUT];
+} ScreenConfig;
+
+typedef map<string, ImageConfig> StrImageConfigMap;
+typedef map<string, ScreenConfig> StrScreenConfigMap;
+
+/* Internal struct for contructing the whole BmpBlock. */
+typedef struct BmpBlockConfig {
+ string config_filename;
+ BmpBlockHeader header;
+ StrImageConfigMap images_map;
+ StrScreenConfigMap screens_map;
+ vector<vector<string> > localizations;
+} BmpBlockConfig;
+
+class BmpBlockUtil {
+ public:
+ BmpBlockUtil();
+ ~BmpBlockUtil();
+
+ /* Load all the images and related infomations according to a config file. */
+ void load_from_config(const char *filename);
+
+ /* Compress all the images using a given comression method. */
+ void compress_all_images(const Compression compress);
+
+ /* Contruct the bmpblock. */
+ void pack_bmpblock();
+
+ /* Write the bmpblock to a file */
+ void write_to_bmpblock(const char *filename);
+
+ private:
+ /* Clear all internal data. */
+ void initialize();
+
+ /* Elemental function called from load_from_config.
+ * Load the config file (yaml format) and parse it. */
+ void load_yaml_config(const char *filename);
+
+ /* Elemental function called from load_from_config.
+ * Load all image files into the internal variables. */
+ void load_all_image_files();
+
+ /* Elemental function called from load_from_config.
+ * Contruct all ImageInfo structs. */
+ void fill_all_image_infos();
+
+ /* Elemental function called from load_from_config.
+ * Contruct the BmpBlockHeader struct. */
+ void fill_bmpblock_header();
+
+ /* Helper functions for parsing a YAML config file. */
+ void expect_event(yaml_parser_t *parser, const yaml_event_type_e type);
+ void parse_config(yaml_parser_t *parser);
+ void parse_first_layer(yaml_parser_t *parser);
+ void parse_bmpblock(yaml_parser_t *parser);
+ void parse_images(yaml_parser_t *parser);
+ void parse_layout(yaml_parser_t *parser, ScreenConfig &screen);
+ void parse_screens(yaml_parser_t *parser);
+ void parse_localizations(yaml_parser_t *parser);
+
+ /* Useful functions */
+ const string read_image_file(const char *filename);
+ ImageFormat get_image_format(const string content);
+ uint32_t get_bmp_image_width(const string content);
+ uint32_t get_bmp_image_height(const string content);
+
+ /* Internal variable for storing the config of BmpBlock. */
+ BmpBlockConfig config_;
+
+ /* Internal variable for storing the content of BmpBlock. */
+ string bmpblock_;
+};
+
+} // namespace vboot_reference
+
+#endif // VBOOT_REFERENCE_BMPBLK_UTILITY_H_