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 |