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 \
|
dev_debug_vboot \
|
||||||
pack_firmware_image
|
pack_firmware_image
|
||||||
|
|
||||||
|
ifeq ($(MINIMAL),)
|
||||||
|
TARGET_NAMES += bmpblk_utility
|
||||||
|
endif
|
||||||
|
|
||||||
TARGET_BINS = $(addprefix ${BUILD_ROOT}/,$(TARGET_NAMES))
|
TARGET_BINS = $(addprefix ${BUILD_ROOT}/,$(TARGET_NAMES))
|
||||||
ALL_DEPS = $(addsuffix .d,${TARGET_BINS})
|
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
|
${BUILD_ROOT}/gbb_utility: gbb_utility.cc
|
||||||
$(CXX) -DWITH_UTIL_MAIN $(CFLAGS) $< -o $@
|
$(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)
|
${BUILD_ROOT}/load_kernel_test: load_kernel_test.c $(LIBS)
|
||||||
$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) -lcrypto
|
$(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