mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-27 11:44:02 +00:00
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
This commit is contained in:
123
firmware/include/bmpblk_header.h
Normal file
123
firmware/include/bmpblk_header.h
Normal file
@@ -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_ */
|
||||
@@ -1 +1 @@
|
||||
char* VbootVersion = "VBOOv=9e0713db";
|
||||
char* VbootVersion = "VBOOv=0a42e63b";
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
551
utility/bmpblk_utility.cc
Normal file
551
utility/bmpblk_utility.cc
Normal file
@@ -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
|
||||
112
utility/include/bmpblk_utility.h
Normal file
112
utility/include/bmpblk_utility.h
Normal file
@@ -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_
|
||||
Reference in New Issue
Block a user