blob: 3cc31ad2a048a6ed1326993fa61930609a02ce3d [file] [log] [blame]
Bill Richardsond55085d2011-02-04 15:01:37 -08001// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4//
5// Utility for manipulating firmware screen block (BMPBLOCK) in GBB.
6//
7
8#include "bmpblk_utility.h"
9
10#include <assert.h>
11#include <errno.h>
12#include <getopt.h>
Tom Wai-Hong Tamee2bc912011-02-17 12:58:58 +080013#include <lzma.h>
Bill Richardsond55085d2011-02-04 15:01:37 -080014#include <stdarg.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <yaml.h>
19
Bill Richardson61362d62011-02-14 10:28:03 -080020extern "C" {
21#include "eficompress.h"
22}
23
24
Bill Richardsonfc05bb82011-02-08 15:03:36 -080025/* BMP header, used to validate image requirements
26 * See http://en.wikipedia.org/wiki/BMP_file_format
27 */
28typedef struct {
29 uint8_t CharB; // must be 'B'
30 uint8_t CharM; // must be 'M'
31 uint32_t Size;
32 uint16_t Reserved[2];
33 uint32_t ImageOffset;
34 uint32_t HeaderSize;
35 uint32_t PixelWidth;
36 uint32_t PixelHeight;
37 uint16_t Planes; // Must be 1 for x86
38 uint16_t BitPerPixel; // 1, 4, 8, or 24 for x86
Tom Wai-Hong Tama985ed42011-02-14 16:08:49 +080039 uint32_t CompressionType; // 0 (none) for x86, 1 (RLE) for arm
Bill Richardsonfc05bb82011-02-08 15:03:36 -080040 uint32_t ImageSize;
41 uint32_t XPixelsPerMeter;
42 uint32_t YPixelsPerMeter;
43 uint32_t NumberOfColors;
44 uint32_t ImportantColors;
45} __attribute__((packed)) BMP_IMAGE_HEADER;
46
Bill Richardsond55085d2011-02-04 15:01:37 -080047
48static void error(const char *format, ...) {
49 va_list ap;
50 va_start(ap, format);
51 fprintf(stderr, "ERROR: ");
52 vfprintf(stderr, format, ap);
53 va_end(ap);
54 exit(1);
55}
56
57///////////////////////////////////////////////////////////////////////
58// BmpBlock Utility implementation
59
60namespace vboot_reference {
61
Bill Richardson54e95822011-05-05 15:12:10 -070062 BmpBlockUtil::BmpBlockUtil(bool debug) {
63 major_version_ = BMPBLOCK_MAJOR_VERSION;
64 minor_version_ = BMPBLOCK_MINOR_VERSION;
65 config_.config_filename.clear();
66 memset(&config_.header, '\0', BMPBLOCK_SIGNATURE_SIZE);
67 config_.images_map.clear();
68 config_.screens_map.clear();
69 config_.localizations.clear();
70 bmpblock_.clear();
71 set_compression_ = false;
72 compression_ = COMPRESS_NONE;
73 debug_ = debug;
Bill Richardsond55085d2011-02-04 15:01:37 -080074 }
75
Bill Richardson54e95822011-05-05 15:12:10 -070076 BmpBlockUtil::~BmpBlockUtil() {
Bill Richardsond55085d2011-02-04 15:01:37 -080077 }
Bill Richardsond55085d2011-02-04 15:01:37 -080078
Bill Richardson54e95822011-05-05 15:12:10 -070079 void BmpBlockUtil::force_compression(uint32_t compression) {
80 compression_ = compression;
81 set_compression_ = true;
82 }
Bill Richardsond55085d2011-02-04 15:01:37 -080083
Bill Richardson54e95822011-05-05 15:12:10 -070084 void BmpBlockUtil::load_from_config(const char *filename) {
85 load_yaml_config(filename);
86 fill_bmpblock_header();
87 load_all_image_files();
88 }
89
90 void BmpBlockUtil::load_yaml_config(const char *filename) {
91 yaml_parser_t parser;
92
93 config_.config_filename = filename;
94 config_.images_map.clear();
95 config_.screens_map.clear();
96 config_.localizations.clear();
97
98 FILE *fp = fopen(filename, "rb");
99 if (!fp) {
100 perror(filename);
101 exit(errno);
102 }
103
104 yaml_parser_initialize(&parser);
105 yaml_parser_set_input_file(&parser, fp);
106 parse_config(&parser);
107 yaml_parser_delete(&parser);
108 fclose(fp);
109
110
111 // HEY: Check the yaml file for self-consistency now. Warn on any problems.
112 // All images should be used somewhere in the screens.
113 // All images referenced in the screens should be defined.
114 // All screens should be used somewhere in the localizations.
115 // All screens referenced in the localizations should be defined.
116
117 if (debug_) {
118 printf("%ld image_names\n", config_.image_names.size());
119 for (unsigned int i = 0; i < config_.image_names.size(); ++i) {
120 printf(" %d: \"%s\"\n", i, config_.image_names[i].c_str());
121 }
122 printf("%ld images_map\n", config_.images_map.size());
123 for (StrImageConfigMap::iterator it = config_.images_map.begin();
124 it != config_.images_map.end();
125 ++it) {
126 printf(" \"%s\": filename=\"%s\" offset=0x%x tag=%d\n",
127 it->first.c_str(),
128 it->second.filename.c_str(),
129 it->second.offset,
130 it->second.data.tag);
131 }
132 printf("%ld screens_map\n", config_.screens_map.size());
133 for (StrScreenConfigMap::iterator it = config_.screens_map.begin();
134 it != config_.screens_map.end();
135 ++it) {
136 printf(" \"%s\":\n", it->first.c_str());
137 for (int k=0; k<MAX_IMAGE_IN_LAYOUT; k++) {
138 printf(" %d: \"%s\" (%d,%d) ofs=0x%x\n",
139 k,
140 it->second.image_names[k].c_str(),
141 it->second.data.images[k].x,
142 it->second.data.images[k].y,
143 it->second.data.images[k].image_info_offset);
144 }
145 }
146 }
147 }
148
149 void BmpBlockUtil::expect_event(yaml_parser_t *parser,
150 const yaml_event_type_e type) {
151 yaml_event_t event;
Bill Richardsond55085d2011-02-04 15:01:37 -0800152 yaml_parser_parse(parser, &event);
Bill Richardson54e95822011-05-05 15:12:10 -0700153 if (event.type != type) {
154 error("Syntax error.\n");
155 }
156 yaml_event_delete(&event);
157 }
158
159 void BmpBlockUtil::parse_config(yaml_parser_t *parser) {
160 expect_event(parser, YAML_STREAM_START_EVENT);
161 expect_event(parser, YAML_DOCUMENT_START_EVENT);
162 parse_first_layer(parser);
163 expect_event(parser, YAML_DOCUMENT_END_EVENT);
164 expect_event(parser, YAML_STREAM_END_EVENT);
165 }
166
167 void BmpBlockUtil::parse_first_layer(yaml_parser_t *parser) {
168 yaml_event_t event;
169 string keyword;
170 expect_event(parser, YAML_MAPPING_START_EVENT);
171 for (;;) {
172 yaml_parser_parse(parser, &event);
173 switch (event.type) {
Bill Richardsond55085d2011-02-04 15:01:37 -0800174 case YAML_SCALAR_EVENT:
175 keyword = (char*)event.data.scalar.value;
176 if (keyword == "bmpblock") {
177 parse_bmpblock(parser);
Bill Richardsona7209ee2011-02-17 14:30:14 -0800178 } else if (keyword == "compression") {
179 parse_compression(parser);
Bill Richardsond55085d2011-02-04 15:01:37 -0800180 } else if (keyword == "images") {
181 parse_images(parser);
182 } else if (keyword == "screens") {
183 parse_screens(parser);
184 } else if (keyword == "localizations") {
185 parse_localizations(parser);
186 }
187 break;
188 case YAML_MAPPING_END_EVENT:
189 yaml_event_delete(&event);
190 return;
191 default:
192 error("Syntax error in parsing config file.\n");
Bill Richardson54e95822011-05-05 15:12:10 -0700193 }
194 yaml_event_delete(&event);
195 }
196 }
197
198 void BmpBlockUtil::parse_bmpblock(yaml_parser_t *parser) {
199 yaml_event_t event;
200 yaml_parser_parse(parser, &event);
201 if (event.type != YAML_SCALAR_EVENT) {
202 error("Syntax error in parsing bmpblock.\n");
203 }
204 string gotversion = (char*)event.data.scalar.value;
205 if (gotversion == "1.1") {
206 render_hwid_ = true;
207 } else if (gotversion == "1.0") {
208 minor_version_ = 0;
209 render_hwid_ = false;
210 } else {
211 error("Unsupported version specified in config file (%s)\n",
212 gotversion.c_str());
Bill Richardsond55085d2011-02-04 15:01:37 -0800213 }
214 yaml_event_delete(&event);
215 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800216
Bill Richardson54e95822011-05-05 15:12:10 -0700217 void BmpBlockUtil::parse_compression(yaml_parser_t *parser) {
218 yaml_event_t event;
Bill Richardsond55085d2011-02-04 15:01:37 -0800219 yaml_parser_parse(parser, &event);
Bill Richardson54e95822011-05-05 15:12:10 -0700220 if (event.type != YAML_SCALAR_EVENT) {
221 error("Syntax error in parsing bmpblock.\n");
222 }
223 char *comp_str = (char *)event.data.scalar.value;
224 char *e = 0;
225 uint32_t comp = (uint32_t)strtoul(comp_str, &e, 0);
226 if (!*comp_str || (e && *e) || comp >= MAX_COMPRESS) {
227 error("Invalid compression specified in config file (%d)\n", comp);
228 }
229 if (!set_compression_) {
230 compression_ = comp;
231 }
232 yaml_event_delete(&event);
233 }
234
235 void BmpBlockUtil::parse_images(yaml_parser_t *parser) {
236 yaml_event_t event;
237 string image_name, image_filename;
238 expect_event(parser, YAML_MAPPING_START_EVENT);
239 for (;;) {
240 yaml_parser_parse(parser, &event);
241 switch (event.type) {
Bill Richardsond55085d2011-02-04 15:01:37 -0800242 case YAML_SCALAR_EVENT:
243 image_name = (char*)event.data.scalar.value;
244 yaml_event_delete(&event);
245 yaml_parser_parse(parser, &event);
246 if (event.type != YAML_SCALAR_EVENT) {
247 error("Syntax error in parsing images.\n");
248 }
249 image_filename = (char*)event.data.scalar.value;
Bill Richardsonf82f9412011-02-17 08:56:33 -0800250 config_.image_names.push_back(image_name);
Bill Richardsond55085d2011-02-04 15:01:37 -0800251 config_.images_map[image_name] = ImageConfig();
252 config_.images_map[image_name].filename = image_filename;
253 break;
254 case YAML_MAPPING_END_EVENT:
255 yaml_event_delete(&event);
256 return;
257 default:
258 error("Syntax error in parsing images.\n");
Bill Richardson54e95822011-05-05 15:12:10 -0700259 }
260 yaml_event_delete(&event);
Bill Richardsond55085d2011-02-04 15:01:37 -0800261 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800262 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800263
Bill Richardson54e95822011-05-05 15:12:10 -0700264 void BmpBlockUtil::parse_layout(yaml_parser_t *parser, ScreenConfig &screen) {
265 yaml_event_t event;
266 int depth = 0, index1 = 0, index2 = 0;
267 expect_event(parser, YAML_SEQUENCE_START_EVENT);
268 for (;;) {
269 yaml_parser_parse(parser, &event);
270 switch (event.type) {
Bill Richardsond55085d2011-02-04 15:01:37 -0800271 case YAML_SEQUENCE_START_EVENT:
272 depth++;
273 break;
274 case YAML_SCALAR_EVENT:
275 switch (index2) {
Bill Richardson54e95822011-05-05 15:12:10 -0700276 case 0:
277 screen.data.images[index1].x = atoi((char*)event.data.scalar.value);
278 break;
279 case 1:
280 screen.data.images[index1].y = atoi((char*)event.data.scalar.value);
281 break;
282 case 2:
283 screen.image_names[index1] = (char*)event.data.scalar.value;
284 // Detect the special case where we're rendering the HWID string
285 // instead of displaying a bitmap. The image name shouldn't
286 // exist in the list of images, but we will still need an
287 // ImageInfo struct to remember where to draw the text.
288 // Note that if the image name DOES exist, we still will won't
289 // display it (yet). Future versions may use that image to hold the
290 // font glpyhs, which is why we pass it around now.
291 if (render_hwid_) {
292 if (screen.image_names[index1] == RENDER_HWID) {
293 config_.images_map[RENDER_HWID].data.tag = TAG_HWID;
294 } else if (screen.image_names[index1] == RENDER_HWID_RTOL) {
295 config_.images_map[RENDER_HWID_RTOL].data.tag = TAG_HWID_RTOL;
296 }
297 }
298 break;
299 default:
300 error("Syntax error in parsing layout\n");
Bill Richardsond55085d2011-02-04 15:01:37 -0800301 }
302 index2++;
303 break;
304 case YAML_SEQUENCE_END_EVENT:
305 if (depth == 1) {
306 index1++;
307 index2 = 0;
308 } else if (depth == 0) {
309 yaml_event_delete(&event);
310 return;
311 }
312 depth--;
313 break;
314 default:
315 error("Syntax error in paring layout.\n");
Bill Richardson54e95822011-05-05 15:12:10 -0700316 }
317 yaml_event_delete(&event);
Bill Richardsond55085d2011-02-04 15:01:37 -0800318 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800319 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800320
Bill Richardson54e95822011-05-05 15:12:10 -0700321 void BmpBlockUtil::parse_screens(yaml_parser_t *parser) {
322 yaml_event_t event;
323 string screen_name;
324 expect_event(parser, YAML_MAPPING_START_EVENT);
325 for (;;) {
326 yaml_parser_parse(parser, &event);
327 switch (event.type) {
Bill Richardsond55085d2011-02-04 15:01:37 -0800328 case YAML_SCALAR_EVENT:
329 screen_name = (char*)event.data.scalar.value;
330 config_.screens_map[screen_name] = ScreenConfig();
331 parse_layout(parser, config_.screens_map[screen_name]);
332 break;
333 case YAML_MAPPING_END_EVENT:
334 yaml_event_delete(&event);
335 return;
336 default:
337 error("Syntax error in parsing screens.\n");
Bill Richardson54e95822011-05-05 15:12:10 -0700338 }
339 yaml_event_delete(&event);
Bill Richardsond55085d2011-02-04 15:01:37 -0800340 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800341 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800342
Bill Richardson54e95822011-05-05 15:12:10 -0700343 void BmpBlockUtil::parse_localizations(yaml_parser_t *parser) {
344 yaml_event_t event;
345 int depth = 0, index = 0;
346 expect_event(parser, YAML_SEQUENCE_START_EVENT);
347 for (;;) {
348 yaml_parser_parse(parser, &event);
349 switch (event.type) {
Bill Richardsond55085d2011-02-04 15:01:37 -0800350 case YAML_SEQUENCE_START_EVENT:
351 config_.localizations.push_back(vector<string>());
352 depth++;
353 break;
354 case YAML_SCALAR_EVENT:
355 config_.localizations[index].push_back((char*)event.data.scalar.value);
356 break;
357 case YAML_SEQUENCE_END_EVENT:
358 if (depth == 1) {
359 index++;
360 } else if (depth == 0) {
361 yaml_event_delete(&event);
362 return;
363 }
364 depth--;
365 break;
366 default:
367 error("Syntax error in parsing localizations.\n");
Bill Richardson54e95822011-05-05 15:12:10 -0700368 }
369 yaml_event_delete(&event);
Bill Richardsond55085d2011-02-04 15:01:37 -0800370 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800371 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800372
Bill Richardson54e95822011-05-05 15:12:10 -0700373 void BmpBlockUtil::load_all_image_files() {
374 for (unsigned int i = 0; i < config_.image_names.size(); i++) {
375 StrImageConfigMap::iterator it =
376 config_.images_map.find(config_.image_names[i]);
377 if (debug_) {
378 printf("loading image \"%s\" from \"%s\"\n",
379 config_.image_names[i].c_str(),
380 it->second.filename.c_str());
381 }
382 const string &content = read_image_file(it->second.filename.c_str());
383 it->second.raw_content = content;
384 it->second.data.original_size = content.size();
385 it->second.data.format = get_image_format(content);
386 switch (it->second.data.format) {
387 case FORMAT_BMP:
388 it->second.data.width = get_bmp_image_width(it->second.raw_content);
389 it->second.data.height = get_bmp_image_height(it->second.raw_content);
390 break;
391 default:
392 error("Unsupported image format in %s\n", it->second.filename.c_str());
393 }
394 switch(compression_) {
395 case COMPRESS_NONE:
396 it->second.data.compression = compression_;
397 it->second.compressed_content = content;
398 it->second.data.compressed_size = content.size();
399 break;
400 case COMPRESS_EFIv1:
Bill Richardson61362d62011-02-14 10:28:03 -0800401 {
402 // The content will always compress smaller (so sez the docs).
403 uint32_t tmpsize = content.size();
404 uint8_t *tmpbuf = (uint8_t *)malloc(tmpsize);
405 // The size of the compressed content is also returned.
406 if (EFI_SUCCESS != EfiCompress((uint8_t *)content.c_str(), tmpsize,
407 tmpbuf, &tmpsize)) {
408 error("Unable to compress!\n");
409 }
410 it->second.data.compression = compression_;
411 it->second.compressed_content.assign((const char *)tmpbuf, tmpsize);
412 it->second.data.compressed_size = tmpsize;
413 free(tmpbuf);
414 }
415 break;
Bill Richardson54e95822011-05-05 15:12:10 -0700416 case COMPRESS_LZMA1:
Tom Wai-Hong Tamee2bc912011-02-17 12:58:58 +0800417 {
418 // Calculate the worst case of buffer size.
419 uint32_t tmpsize = lzma_stream_buffer_bound(content.size());
420 uint8_t *tmpbuf = (uint8_t *)malloc(tmpsize);
421 lzma_stream stream = LZMA_STREAM_INIT;
422 lzma_options_lzma options;
423 lzma_ret result;
424
425 lzma_lzma_preset(&options, 9);
426 result = lzma_alone_encoder(&stream, &options);
427 if (result != LZMA_OK) {
428 error("Unable to initialize easy encoder (error: %d)!\n", result);
429 }
430
431 stream.next_in = (uint8_t *)content.data();
432 stream.avail_in = content.size();
433 stream.next_out = tmpbuf;
434 stream.avail_out = tmpsize;
435 result = lzma_code(&stream, LZMA_FINISH);
436 if (result != LZMA_STREAM_END) {
437 error("Unable to encode data (error: %d)!\n", result);
438 }
439
440 it->second.data.compression = compression_;
441 it->second.compressed_content.assign((const char *)tmpbuf,
442 tmpsize - stream.avail_out);
443 it->second.data.compressed_size = tmpsize - stream.avail_out;
444 lzma_end(&stream);
445 free(tmpbuf);
446 }
447 break;
Bill Richardsond55085d2011-02-04 15:01:37 -0800448 default:
Bill Richardson54e95822011-05-05 15:12:10 -0700449 error("Unsupported compression method attempted.\n");
Bill Richardsond55085d2011-02-04 15:01:37 -0800450 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800451 }
452 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800453
Bill Richardson54e95822011-05-05 15:12:10 -0700454 const string BmpBlockUtil::read_image_file(const char *filename) {
455 string content;
456 vector<char> buffer;
Bill Richardsond55085d2011-02-04 15:01:37 -0800457
Bill Richardson54e95822011-05-05 15:12:10 -0700458 FILE *fp = fopen(filename, "rb");
459 if (!fp) {
460 perror(filename);
461 exit(errno);
462 }
463
464 if (fseek(fp, 0, SEEK_END) == 0) {
465 buffer.resize(ftell(fp));
466 rewind(fp);
467 }
468
469 if (!buffer.empty()) {
470 if(fread(&buffer[0], buffer.size(), 1, fp) != 1) {
471 perror(filename);
472 buffer.clear();
473 } else {
474 content.assign(buffer.begin(), buffer.end());
475 }
476 }
477
478 fclose(fp);
479 return content;
480 }
481
482 ImageFormat BmpBlockUtil::get_image_format(const string content) {
483 if (content.size() < sizeof(BMP_IMAGE_HEADER))
484 return FORMAT_INVALID;
485 const BMP_IMAGE_HEADER *hdr = (const BMP_IMAGE_HEADER *)content.c_str();
486
487 if (hdr->CharB != 'B' || hdr->CharM != 'M' ||
488 hdr->Planes != 1 ||
489 (hdr->CompressionType != 0 && hdr->CompressionType != 1) ||
490 (hdr->BitPerPixel != 1 && hdr->BitPerPixel != 4 &&
491 hdr->BitPerPixel != 8 && hdr->BitPerPixel != 24))
492 return FORMAT_INVALID;
493
494 return FORMAT_BMP;
495 }
496
497 uint32_t BmpBlockUtil::get_bmp_image_width(const string content) {
498 const BMP_IMAGE_HEADER *hdr = (const BMP_IMAGE_HEADER *)content.c_str();
499 return hdr->PixelWidth;
500 }
501
502 uint32_t BmpBlockUtil::get_bmp_image_height(const string content) {
503 const BMP_IMAGE_HEADER *hdr = (const BMP_IMAGE_HEADER *)content.c_str();
504 return hdr->PixelHeight;
505 }
506
507 void BmpBlockUtil::fill_bmpblock_header() {
508 memset(&config_.header, '\0', sizeof(config_.header));
509 memcpy(&config_.header.signature, BMPBLOCK_SIGNATURE,
510 BMPBLOCK_SIGNATURE_SIZE);
511 config_.header.major_version = major_version_;
512 config_.header.minor_version = minor_version_;
513 config_.header.number_of_localizations = config_.localizations.size();
514 config_.header.number_of_screenlayouts = config_.localizations[0].size();
515 // HEY: this is part of the yaml consistency check
516 for (unsigned int i = 1; i < config_.localizations.size(); ++i) {
517 assert(config_.header.number_of_screenlayouts ==
518 config_.localizations[i].size());
519 }
520 config_.header.number_of_imageinfos = config_.images_map.size();
521 }
522
523 void BmpBlockUtil::pack_bmpblock() {
524 bmpblock_.clear();
525
526 /* Compute the ImageInfo offsets from start of BMPBLOCK. */
527 uint32_t current_offset = sizeof(BmpBlockHeader) +
528 sizeof(ScreenLayout) * (config_.header.number_of_localizations *
529 config_.header.number_of_screenlayouts);
530 for (StrImageConfigMap::iterator it = config_.images_map.begin();
531 it != config_.images_map.end();
532 ++it) {
533 it->second.offset = current_offset;
534 if (debug_)
535 printf(" \"%s\": filename=\"%s\" offset=0x%x tag=%d\n",
536 it->first.c_str(),
537 it->second.filename.c_str(),
538 it->second.offset,
539 it->second.data.tag);
540 current_offset += sizeof(ImageInfo) +
541 it->second.data.compressed_size;
542 /* Make it 4-byte aligned. */
543 if ((current_offset & 3) > 0) {
544 current_offset = (current_offset & ~3) + 4;
545 }
546 }
547 bmpblock_.resize(current_offset);
548
549 /* Fill BmpBlockHeader struct. */
550 string::iterator current_filled = bmpblock_.begin();
551 std::copy(reinterpret_cast<char*>(&config_.header),
552 reinterpret_cast<char*>(&config_.header + 1),
553 current_filled);
554 current_filled += sizeof(config_.header);
555 current_offset = sizeof(config_.header);
556
557 /* Fill all ScreenLayout structs. */
558 for (unsigned int i = 0; i < config_.localizations.size(); ++i) {
559 for (unsigned int j = 0; j < config_.localizations[i].size(); ++j) {
560 ScreenConfig &screen = config_.screens_map[config_.localizations[i][j]];
561 for (unsigned int k = 0;
562 k < MAX_IMAGE_IN_LAYOUT && !screen.image_names[k].empty();
563 ++k) {
564 if (config_.images_map.find(screen.image_names[k]) ==
565 config_.images_map.end()) {
566 error("Invalid image name \"%s\"\n", screen.image_names[k].c_str());
567 }
568 if (debug_)
569 printf("i=%d j=%d k=%d=\"%s\" (%d,%d) ofs=%x\n", i,j,k,
570 screen.image_names[k].c_str(),
571 screen.data.images[k].x, screen.data.images[k].y,
572 config_.images_map[screen.image_names[k]].offset
573 );
574 screen.data.images[k].image_info_offset =
Bill Richardsond55085d2011-02-04 15:01:37 -0800575 config_.images_map[screen.image_names[k]].offset;
Bill Richardson54e95822011-05-05 15:12:10 -0700576 }
577 std::copy(reinterpret_cast<char*>(&screen.data),
578 reinterpret_cast<char*>(&screen.data + 1),
579 current_filled);
580 current_filled += sizeof(screen.data);
581 if (debug_)
582 printf("S: current offset is 0x%08x\n", current_offset);
583 current_offset += sizeof(screen.data);
Bill Richardsond55085d2011-02-04 15:01:37 -0800584 }
Bill Richardson54e95822011-05-05 15:12:10 -0700585 }
586
587 /* Fill all ImageInfo structs and image contents. */
588 for (StrImageConfigMap::iterator it = config_.images_map.begin();
589 it != config_.images_map.end();
590 ++it) {
591 current_filled = bmpblock_.begin() + it->second.offset;
592 current_offset = it->second.offset;
593 if (debug_)
594 printf("I0: current offset is 0x%08x\n", current_offset);
595 std::copy(reinterpret_cast<char*>(&it->second.data),
596 reinterpret_cast<char*>(&it->second.data + 1),
Bill Richardsond55085d2011-02-04 15:01:37 -0800597 current_filled);
Bill Richardson54e95822011-05-05 15:12:10 -0700598 current_filled += sizeof(it->second.data);
599 current_offset += sizeof(it->second.data);
600 if (debug_)
601 printf("I1: current offset is 0x%08x (len %ld)\n",
602 current_offset, it->second.compressed_content.length());
603 std::copy(it->second.compressed_content.begin(),
604 it->second.compressed_content.end(),
605 current_filled);
Bill Richardsond55085d2011-02-04 15:01:37 -0800606 }
607 }
608
Bill Richardson54e95822011-05-05 15:12:10 -0700609 void BmpBlockUtil::write_to_bmpblock(const char *filename) {
610 assert(!bmpblock_.empty());
Bill Richardsond55085d2011-02-04 15:01:37 -0800611
Bill Richardson54e95822011-05-05 15:12:10 -0700612 FILE *fp = fopen(filename, "wb");
613 if (!fp) {
614 perror(filename);
615 exit(errno);
616 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800617
Bill Richardson54e95822011-05-05 15:12:10 -0700618 int r = fwrite(bmpblock_.c_str(), bmpblock_.size(), 1, fp);
619 fclose(fp);
620 if (r != 1) {
621 perror(filename);
622 exit(errno);
623 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800624 }
625
Bill Richardsond55085d2011-02-04 15:01:37 -0800626} // namespace vboot_reference
627
628#ifdef WITH_UTIL_MAIN
629
Bill Richardson54e95822011-05-05 15:12:10 -0700630 //////////////////////////////////////////////////////////////////////////////
631 // Command line utilities.
Bill Richardson794d4d42011-02-10 19:13:10 -0800632
Bill Richardson54e95822011-05-05 15:12:10 -0700633 extern "C" {
Bill Richardson794d4d42011-02-10 19:13:10 -0800634#include "bmpblk_util.h"
Bill Richardson54e95822011-05-05 15:12:10 -0700635 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800636
Bill Richardson54e95822011-05-05 15:12:10 -0700637 using vboot_reference::BmpBlockUtil;
Bill Richardsond55085d2011-02-04 15:01:37 -0800638
Bill Richardson54e95822011-05-05 15:12:10 -0700639 // utility function: provide usage of this utility and exit.
640 static void usagehelp_exit(const char *prog_name) {
641 printf(
642 "\n"
643 "To create a new BMPBLOCK file using config from YAML file:\n"
644 "\n"
645 " %s [-z NUM] -c YAML BMPBLOCK\n"
646 "\n"
647 " -z NUM = compression algorithm to use\n"
648 " 0 = none\n"
649 " 1 = EFIv1\n"
650 " 2 = LZMA1\n"
651 "\n", prog_name);
652 printf(
653 "To display the contents of a BMPBLOCK:\n"
654 "\n"
655 " %s [-y] BMPBLOCK\n"
656 "\n"
657 " -y = display as yaml\n"
658 "\n", prog_name);
659 printf(
660 "To unpack a BMPBLOCK file:\n"
661 "\n"
662 " %s -x [-d DIR] [-f] BMPBLOCK\n"
663 "\n"
664 " -d DIR = directory to use (default '.')\n"
665 " -f = force overwriting existing files\n"
666 "\n", prog_name);
667 exit(1);
668 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800669
Bill Richardson54e95822011-05-05 15:12:10 -0700670 ///////////////////////////////////////////////////////////////////////
671 // main
Bill Richardsond55085d2011-02-04 15:01:37 -0800672
Bill Richardson54e95822011-05-05 15:12:10 -0700673 int main(int argc, char *argv[]) {
Bill Richardsond55085d2011-02-04 15:01:37 -0800674
Bill Richardson54e95822011-05-05 15:12:10 -0700675 const char *prog_name = strrchr(argv[0], '/');
676 if (prog_name)
677 prog_name++;
678 else
679 prog_name = argv[0];
Bill Richardsond55085d2011-02-04 15:01:37 -0800680
Bill Richardson54e95822011-05-05 15:12:10 -0700681 int overwrite = 0, extract_mode = 0;
682 int compression = 0;
683 int set_compression = 0;
684 const char *config_fn = 0, *bmpblock_fn = 0, *extract_dir = ".";
685 int show_as_yaml = 0;
686 bool debug = false;
Bill Richardsond55085d2011-02-04 15:01:37 -0800687
Bill Richardson54e95822011-05-05 15:12:10 -0700688 int opt;
689 opterr = 0; // quiet
690 int errorcnt = 0;
691 char *e = 0;
692 while ((opt = getopt(argc, argv, ":c:xz:fd:yD")) != -1) {
693 switch (opt) {
694 case 'c':
695 config_fn = optarg;
696 break;
697 case 'x':
698 extract_mode = 1;
699 break;
700 case 'y':
701 show_as_yaml = 1;
702 break;
703 case 'z':
704 compression = (int)strtoul(optarg, &e, 0);
705 if (!*optarg || (e && *e)) {
706 fprintf(stderr, "%s: invalid argument to -%c: \"%s\"\n",
707 prog_name, opt, optarg);
708 errorcnt++;
709 }
710 if (compression >= MAX_COMPRESS) {
711 fprintf(stderr, "%s: compression type must be less than %d\n",
712 prog_name, MAX_COMPRESS);
713 errorcnt++;
714 }
715 set_compression = 1;
716 break;
717 case 'f':
718 overwrite = 1;
719 break;
720 case 'd':
721 extract_dir= optarg;
722 break;
723 case 'D':
724 debug = true;
725 break;
726 case ':':
727 fprintf(stderr, "%s: missing argument to -%c\n",
728 prog_name, optopt);
Bill Richardson794d4d42011-02-10 19:13:10 -0800729 errorcnt++;
Bill Richardson54e95822011-05-05 15:12:10 -0700730 break;
731 default:
732 fprintf(stderr, "%s: unrecognized switch: -%c\n",
733 prog_name, optopt);
Bill Richardson794d4d42011-02-10 19:13:10 -0800734 errorcnt++;
Bill Richardson54e95822011-05-05 15:12:10 -0700735 break;
Bill Richardson794d4d42011-02-10 19:13:10 -0800736 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800737 }
Bill Richardson54e95822011-05-05 15:12:10 -0700738 argc -= optind;
739 argv += optind;
740
741 if (argc >= 1) {
742 bmpblock_fn = argv[0];
743 } else {
744 fprintf(stderr, "%s: missing BMPBLOCK name\n", prog_name);
745 errorcnt++;
746 }
747
748 if (errorcnt)
749 usagehelp_exit(prog_name);
750
751 BmpBlockUtil util(debug);
752
753 if (config_fn) {
754 if (set_compression)
755 util.force_compression(compression);
756 util.load_from_config(config_fn);
757 util.pack_bmpblock();
758 util.write_to_bmpblock(bmpblock_fn);
759 }
760
761 else if (extract_mode) {
762 return dump_bmpblock(bmpblock_fn, 1, extract_dir, overwrite);
763 } else {
764 return dump_bmpblock(bmpblock_fn, show_as_yaml, 0, 0);
765 }
766
767 return 0;
Bill Richardsond55085d2011-02-04 15:01:37 -0800768 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800769
770#endif // WITH_UTIL_MAIN