| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 // | 4 // |
| 5 // Utility for manipulating firmware screen block (BMPBLOCK) in GBB. | 5 // Utility for manipulating firmware screen block (BMPBLOCK) in GBB. |
| 6 // | 6 // |
| 7 | 7 |
| 8 #include "bmpblk_utility.h" | 8 #include "bmpblk_utility.h" |
| 9 | 9 |
| 10 #include <assert.h> | 10 #include <assert.h> |
| 11 #include <errno.h> | 11 #include <errno.h> |
| 12 #include <getopt.h> | 12 #include <getopt.h> |
| 13 #include <stdarg.h> | 13 #include <stdarg.h> |
| 14 #include <stdio.h> | 14 #include <stdio.h> |
| 15 #include <stdlib.h> | 15 #include <stdlib.h> |
| 16 #include <string.h> | 16 #include <string.h> |
| 17 #include <yaml.h> | 17 #include <yaml.h> |
| 18 | 18 |
| 19 /* The offsets of width and height fields in a BMP file. | 19 /* BMP header, used to validate image requirements |
| 20 * See http://en.wikipedia.org/wiki/BMP_file_format */ | 20 * See http://en.wikipedia.org/wiki/BMP_file_format |
| 21 #define BMP_WIDTH_OFFSET 18 | 21 */ |
| 22 #define BMP_HEIGHT_OFFSET 22 | 22 typedef struct { |
| 23 uint8_t CharB; // must be 'B' |
| 24 uint8_t CharM; // must be 'M' |
| 25 uint32_t Size; |
| 26 uint16_t Reserved[2]; |
| 27 uint32_t ImageOffset; |
| 28 uint32_t HeaderSize; |
| 29 uint32_t PixelWidth; |
| 30 uint32_t PixelHeight; |
| 31 uint16_t Planes; // Must be 1 for x86 |
| 32 uint16_t BitPerPixel; // 1, 4, 8, or 24 for x86 |
| 33 uint32_t CompressionType; // must be 0 for x86 |
| 34 uint32_t ImageSize; |
| 35 uint32_t XPixelsPerMeter; |
| 36 uint32_t YPixelsPerMeter; |
| 37 uint32_t NumberOfColors; |
| 38 uint32_t ImportantColors; |
| 39 } __attribute__((packed)) BMP_IMAGE_HEADER; |
| 40 |
| 23 | 41 |
| 24 static void error(const char *format, ...) { | 42 static void error(const char *format, ...) { |
| 25 va_list ap; | 43 va_list ap; |
| 26 va_start(ap, format); | 44 va_start(ap, format); |
| 27 fprintf(stderr, "ERROR: "); | 45 fprintf(stderr, "ERROR: "); |
| 28 vfprintf(stderr, format, ap); | 46 vfprintf(stderr, format, ap); |
| 29 va_end(ap); | 47 va_end(ap); |
| 30 exit(1); | 48 exit(1); |
| 31 } | 49 } |
| 32 | 50 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 yaml_event_delete(&event); | 143 yaml_event_delete(&event); |
| 126 } | 144 } |
| 127 } | 145 } |
| 128 | 146 |
| 129 void BmpBlockUtil::parse_bmpblock(yaml_parser_t *parser) { | 147 void BmpBlockUtil::parse_bmpblock(yaml_parser_t *parser) { |
| 130 yaml_event_t event; | 148 yaml_event_t event; |
| 131 yaml_parser_parse(parser, &event); | 149 yaml_parser_parse(parser, &event); |
| 132 if (event.type != YAML_SCALAR_EVENT) { | 150 if (event.type != YAML_SCALAR_EVENT) { |
| 133 error("Syntax error in parsing bmpblock.\n"); | 151 error("Syntax error in parsing bmpblock.\n"); |
| 134 } | 152 } |
| 135 config_.header.major_version = atoi((char*)event.data.scalar.value); | 153 char wantversion[20]; |
| 136 config_.header.minor_version = atoi( | 154 sprintf(wantversion, "%d.%d", |
| 137 strchr((char*)event.data.scalar.value, '.') + 1); | 155 BMPBLOCK_MAJOR_VERSION, |
| 156 BMPBLOCK_MINOR_VERSION); |
| 157 string gotversion = (char*)event.data.scalar.value; |
| 158 if (gotversion != wantversion) { |
| 159 error("Invalid version specified in config file\n"); |
| 160 } |
| 138 yaml_event_delete(&event); | 161 yaml_event_delete(&event); |
| 139 } | 162 } |
| 140 | 163 |
| 141 void BmpBlockUtil::parse_images(yaml_parser_t *parser) { | 164 void BmpBlockUtil::parse_images(yaml_parser_t *parser) { |
| 142 yaml_event_t event; | 165 yaml_event_t event; |
| 143 string image_name, image_filename; | 166 string image_name, image_filename; |
| 144 expect_event(parser, YAML_MAPPING_START_EVENT); | 167 expect_event(parser, YAML_MAPPING_START_EVENT); |
| 145 for (;;) { | 168 for (;;) { |
| 146 yaml_parser_parse(parser, &event); | 169 yaml_parser_parse(parser, &event); |
| 147 switch (event.type) { | 170 switch (event.type) { |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 298 } else { | 321 } else { |
| 299 content.assign(buffer.begin(), buffer.end()); | 322 content.assign(buffer.begin(), buffer.end()); |
| 300 } | 323 } |
| 301 } | 324 } |
| 302 | 325 |
| 303 fclose(fp); | 326 fclose(fp); |
| 304 return content; | 327 return content; |
| 305 } | 328 } |
| 306 | 329 |
| 307 ImageFormat BmpBlockUtil::get_image_format(const string content) { | 330 ImageFormat BmpBlockUtil::get_image_format(const string content) { |
| 308 if (content[0] == 'B' && content[1] == 'M') | 331 if (content.size() < sizeof(BMP_IMAGE_HEADER)) |
| 309 return FORMAT_BMP; | |
| 310 else | |
| 311 return FORMAT_INVALID; | 332 return FORMAT_INVALID; |
| 333 const BMP_IMAGE_HEADER *hdr = (const BMP_IMAGE_HEADER *)content.c_str(); |
| 334 |
| 335 if (hdr->CharB != 'B' || hdr->CharM != 'M' || |
| 336 hdr->Planes != 1 || |
| 337 hdr->CompressionType != 0 || |
| 338 (hdr->BitPerPixel != 1 && hdr->BitPerPixel != 4 && |
| 339 hdr->BitPerPixel != 8 && hdr->BitPerPixel != 24)) |
| 340 return FORMAT_INVALID; |
| 341 |
| 342 return FORMAT_BMP; |
| 312 } | 343 } |
| 313 | 344 |
| 314 uint32_t BmpBlockUtil::get_bmp_image_width(const string content) { | 345 uint32_t BmpBlockUtil::get_bmp_image_width(const string content) { |
| 315 const char *start = content.c_str(); | 346 const BMP_IMAGE_HEADER *hdr = (const BMP_IMAGE_HEADER *)content.c_str(); |
| 316 uint32_t width = *(uint32_t*)(start + BMP_WIDTH_OFFSET); | 347 return hdr->PixelWidth; |
| 317 /* Do a rough verification. */ | |
| 318 assert(width > 0 && width < 1600); | |
| 319 return width; | |
| 320 } | 348 } |
| 321 | 349 |
| 322 uint32_t BmpBlockUtil::get_bmp_image_height(const string content) { | 350 uint32_t BmpBlockUtil::get_bmp_image_height(const string content) { |
| 323 const char *start = content.c_str(); | 351 const BMP_IMAGE_HEADER *hdr = (const BMP_IMAGE_HEADER *)content.c_str(); |
| 324 uint32_t height = *(uint32_t*)(start + BMP_HEIGHT_OFFSET); | 352 return hdr->PixelHeight; |
| 325 /* Do a rough verification. */ | |
| 326 assert(height > 0 && height < 1000); | |
| 327 return height; | |
| 328 } | 353 } |
| 329 | 354 |
| 330 void BmpBlockUtil::fill_all_image_infos() { | 355 void BmpBlockUtil::fill_all_image_infos() { |
| 356 int errcnt = 0; |
| 331 for (StrImageConfigMap::iterator it = config_.images_map.begin(); | 357 for (StrImageConfigMap::iterator it = config_.images_map.begin(); |
| 332 it != config_.images_map.end(); | 358 it != config_.images_map.end(); |
| 333 ++it) { | 359 ++it) { |
| 334 it->second.data.format = (uint32_t)get_image_format(it->second.raw_content); | 360 it->second.data.format = (uint32_t)get_image_format(it->second.raw_content); |
| 335 switch (it->second.data.format) { | 361 switch (it->second.data.format) { |
| 336 case FORMAT_BMP: | 362 case FORMAT_BMP: |
| 337 it->second.data.width = get_bmp_image_width(it->second.raw_content); | 363 it->second.data.width = get_bmp_image_width(it->second.raw_content); |
| 338 it->second.data.height = get_bmp_image_height(it->second.raw_content); | 364 it->second.data.height = get_bmp_image_height(it->second.raw_content); |
| 339 break; | 365 break; |
| 340 default: | 366 default: |
| 341 error("Unsupported image format.\n"); | 367 fprintf(stderr, "Unsupported image format in %s\n", |
| 368 it->second.filename.c_str()); |
| 369 errcnt++; |
| 342 } | 370 } |
| 343 } | 371 } |
| 372 if (errcnt) |
| 373 error("Unable to continue due to errors.\n"); |
| 344 } | 374 } |
| 345 | 375 |
| 346 void BmpBlockUtil::compress_all_images(const Compression compress) { | 376 void BmpBlockUtil::compress_all_images(const Compression compress) { |
| 347 switch (compress) { | 377 switch (compress) { |
| 348 case COMPRESS_NONE: | 378 case COMPRESS_NONE: |
| 349 for (StrImageConfigMap::iterator it = config_.images_map.begin(); | 379 for (StrImageConfigMap::iterator it = config_.images_map.begin(); |
| 350 it != config_.images_map.end(); | 380 it != config_.images_map.end(); |
| 351 ++it) { | 381 ++it) { |
| 352 it->second.data.compression = compress; | 382 it->second.data.compression = compress; |
| 353 it->second.compressed_content = it->second.raw_content; | 383 it->second.compressed_content = it->second.raw_content; |
| 354 it->second.data.compressed_size = it->second.compressed_content.size(); | 384 it->second.data.compressed_size = it->second.compressed_content.size(); |
| 355 } | 385 } |
| 356 break; | 386 break; |
| 357 default: | 387 default: |
| 358 error("Unsupported data compression.\n"); | 388 error("Unsupported data compression.\n"); |
| 359 } | 389 } |
| 360 } | 390 } |
| 361 | 391 |
| 362 void BmpBlockUtil::fill_bmpblock_header() { | 392 void BmpBlockUtil::fill_bmpblock_header() { |
| 363 memset(&config_.header, '\0', sizeof(config_.header)); | 393 memset(&config_.header, '\0', sizeof(config_.header)); |
| 364 memcpy(&config_.header.signature, BMPBLOCK_SIGNATURE, | 394 memcpy(&config_.header.signature, BMPBLOCK_SIGNATURE, |
| 365 BMPBLOCK_SIGNATURE_SIZE); | 395 BMPBLOCK_SIGNATURE_SIZE); |
| 396 config_.header.major_version = BMPBLOCK_MAJOR_VERSION; |
| 397 config_.header.minor_version = BMPBLOCK_MINOR_VERSION; |
| 366 config_.header.number_of_localizations = config_.localizations.size(); | 398 config_.header.number_of_localizations = config_.localizations.size(); |
| 367 config_.header.number_of_screenlayouts = config_.localizations[0].size(); | 399 config_.header.number_of_screenlayouts = config_.localizations[0].size(); |
| 368 for (unsigned int i = 1; i < config_.localizations.size(); ++i) { | 400 for (unsigned int i = 1; i < config_.localizations.size(); ++i) { |
| 369 assert(config_.header.number_of_screenlayouts == | 401 assert(config_.header.number_of_screenlayouts == |
| 370 config_.localizations[i].size()); | 402 config_.localizations[i].size()); |
| 371 } | 403 } |
| 372 config_.header.number_of_imageinfos = config_.images_map.size(); | 404 config_.header.number_of_imageinfos = config_.images_map.size(); |
| 373 } | 405 } |
| 374 | 406 |
| 375 void BmpBlockUtil::pack_bmpblock() { | 407 void BmpBlockUtil::pack_bmpblock() { |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 | 574 |
| 543 if (options.extract_mode) { | 575 if (options.extract_mode) { |
| 544 /* TODO(waihong): Implement the extract mode. */ | 576 /* TODO(waihong): Implement the extract mode. */ |
| 545 error("Extract mode hasn't been implemented yet.\n"); | 577 error("Extract mode hasn't been implemented yet.\n"); |
| 546 } | 578 } |
| 547 | 579 |
| 548 return 0; | 580 return 0; |
| 549 } | 581 } |
| 550 | 582 |
| 551 #endif // WITH_UTIL_MAIN | 583 #endif // WITH_UTIL_MAIN |
| OLD | NEW |