blob: 9f912d0b0a0b6ae1af239a0e6438013551ddbf77 [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>
13#include <stdarg.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <yaml.h>
18
Bill Richardson61362d62011-02-14 10:28:03 -080019extern "C" {
20#include "eficompress.h"
21}
22
23
Bill Richardsonfc05bb82011-02-08 15:03:36 -080024/* BMP header, used to validate image requirements
25 * See http://en.wikipedia.org/wiki/BMP_file_format
26 */
27typedef struct {
28 uint8_t CharB; // must be 'B'
29 uint8_t CharM; // must be 'M'
30 uint32_t Size;
31 uint16_t Reserved[2];
32 uint32_t ImageOffset;
33 uint32_t HeaderSize;
34 uint32_t PixelWidth;
35 uint32_t PixelHeight;
36 uint16_t Planes; // Must be 1 for x86
37 uint16_t BitPerPixel; // 1, 4, 8, or 24 for x86
Tom Wai-Hong Tama985ed42011-02-14 16:08:49 +080038 uint32_t CompressionType; // 0 (none) for x86, 1 (RLE) for arm
Bill Richardsonfc05bb82011-02-08 15:03:36 -080039 uint32_t ImageSize;
40 uint32_t XPixelsPerMeter;
41 uint32_t YPixelsPerMeter;
42 uint32_t NumberOfColors;
43 uint32_t ImportantColors;
44} __attribute__((packed)) BMP_IMAGE_HEADER;
45
Bill Richardsond55085d2011-02-04 15:01:37 -080046
47static void error(const char *format, ...) {
48 va_list ap;
49 va_start(ap, format);
50 fprintf(stderr, "ERROR: ");
51 vfprintf(stderr, format, ap);
52 va_end(ap);
53 exit(1);
54}
55
56///////////////////////////////////////////////////////////////////////
57// BmpBlock Utility implementation
58
59namespace vboot_reference {
60
61BmpBlockUtil::BmpBlockUtil() {
62 initialize();
63}
64
65BmpBlockUtil::~BmpBlockUtil() {
66}
67
68void BmpBlockUtil::initialize() {
69 config_.config_filename.clear();
70 memset(&config_.header, '\0', BMPBLOCK_SIGNATURE_SIZE);
71 config_.images_map.clear();
72 config_.screens_map.clear();
73 config_.localizations.clear();
74 bmpblock_.clear();
Bill Richardson61362d62011-02-14 10:28:03 -080075 set_compression_ = false;
76 compression_ = COMPRESS_NONE;
77}
78
79void BmpBlockUtil::force_compression(uint32_t compression) {
80 compression_ = compression;
81 set_compression_ = true;
Bill Richardsond55085d2011-02-04 15:01:37 -080082}
83
84void BmpBlockUtil::load_from_config(const char *filename) {
85 load_yaml_config(filename);
86 fill_bmpblock_header();
87 load_all_image_files();
88 fill_all_image_infos();
89}
90
91void BmpBlockUtil::load_yaml_config(const char *filename) {
92 yaml_parser_t parser;
93
94 config_.config_filename = filename;
95 config_.images_map.clear();
96 config_.screens_map.clear();
97 config_.localizations.clear();
98
99 FILE *fp = fopen(filename, "rb");
100 if (!fp) {
101 perror(filename);
102 exit(errno);
103 }
104
105 yaml_parser_initialize(&parser);
106 yaml_parser_set_input_file(&parser, fp);
107 parse_config(&parser);
108 yaml_parser_delete(&parser);
109 fclose(fp);
110}
111
112void BmpBlockUtil::expect_event(yaml_parser_t *parser,
113 const yaml_event_type_e type) {
114 yaml_event_t event;
115 yaml_parser_parse(parser, &event);
116 if (event.type != type) {
117 error("Syntax error.\n");
118 }
119 yaml_event_delete(&event);
120}
121
122void BmpBlockUtil::parse_config(yaml_parser_t *parser) {
123 expect_event(parser, YAML_STREAM_START_EVENT);
124 expect_event(parser, YAML_DOCUMENT_START_EVENT);
125 parse_first_layer(parser);
126 expect_event(parser, YAML_DOCUMENT_END_EVENT);
127 expect_event(parser, YAML_STREAM_END_EVENT);
128}
129
130void BmpBlockUtil::parse_first_layer(yaml_parser_t *parser) {
131 yaml_event_t event;
132 string keyword;
133 expect_event(parser, YAML_MAPPING_START_EVENT);
134 for (;;) {
135 yaml_parser_parse(parser, &event);
136 switch (event.type) {
137 case YAML_SCALAR_EVENT:
138 keyword = (char*)event.data.scalar.value;
139 if (keyword == "bmpblock") {
140 parse_bmpblock(parser);
141 } else if (keyword == "images") {
142 parse_images(parser);
143 } else if (keyword == "screens") {
144 parse_screens(parser);
145 } else if (keyword == "localizations") {
146 parse_localizations(parser);
147 }
148 break;
149 case YAML_MAPPING_END_EVENT:
150 yaml_event_delete(&event);
151 return;
152 default:
153 error("Syntax error in parsing config file.\n");
154 }
155 yaml_event_delete(&event);
156 }
157}
158
159void BmpBlockUtil::parse_bmpblock(yaml_parser_t *parser) {
160 yaml_event_t event;
161 yaml_parser_parse(parser, &event);
162 if (event.type != YAML_SCALAR_EVENT) {
163 error("Syntax error in parsing bmpblock.\n");
164 }
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800165 char wantversion[20];
166 sprintf(wantversion, "%d.%d",
167 BMPBLOCK_MAJOR_VERSION,
168 BMPBLOCK_MINOR_VERSION);
169 string gotversion = (char*)event.data.scalar.value;
170 if (gotversion != wantversion) {
171 error("Invalid version specified in config file\n");
172 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800173 yaml_event_delete(&event);
174}
175
176void BmpBlockUtil::parse_images(yaml_parser_t *parser) {
177 yaml_event_t event;
178 string image_name, image_filename;
179 expect_event(parser, YAML_MAPPING_START_EVENT);
180 for (;;) {
181 yaml_parser_parse(parser, &event);
182 switch (event.type) {
183 case YAML_SCALAR_EVENT:
184 image_name = (char*)event.data.scalar.value;
185 yaml_event_delete(&event);
186 yaml_parser_parse(parser, &event);
187 if (event.type != YAML_SCALAR_EVENT) {
188 error("Syntax error in parsing images.\n");
189 }
190 image_filename = (char*)event.data.scalar.value;
191 config_.images_map[image_name] = ImageConfig();
192 config_.images_map[image_name].filename = image_filename;
193 break;
194 case YAML_MAPPING_END_EVENT:
195 yaml_event_delete(&event);
196 return;
197 default:
198 error("Syntax error in parsing images.\n");
199 }
200 yaml_event_delete(&event);
201 }
202}
203
204void BmpBlockUtil::parse_layout(yaml_parser_t *parser, ScreenConfig &screen) {
205 yaml_event_t event;
206 string screen_name;
207 int depth = 0, index1 = 0, index2 = 0;
208 expect_event(parser, YAML_SEQUENCE_START_EVENT);
209 for (;;) {
210 yaml_parser_parse(parser, &event);
211 switch (event.type) {
212 case YAML_SEQUENCE_START_EVENT:
213 depth++;
214 break;
215 case YAML_SCALAR_EVENT:
216 switch (index2) {
217 case 0:
218 screen.data.images[index1].x = atoi((char*)event.data.scalar.value);
219 break;
220 case 1:
221 screen.data.images[index1].y = atoi((char*)event.data.scalar.value);
222 break;
223 case 2:
224 screen.image_names[index1] = (char*)event.data.scalar.value;
225 break;
226 default:
227 error("Syntax error in parsing layout.\n");
228 }
229 index2++;
230 break;
231 case YAML_SEQUENCE_END_EVENT:
232 if (depth == 1) {
233 index1++;
234 index2 = 0;
235 } else if (depth == 0) {
236 yaml_event_delete(&event);
237 return;
238 }
239 depth--;
240 break;
241 default:
242 error("Syntax error in paring layout.\n");
243 }
244 yaml_event_delete(&event);
245 }
246}
247
248void BmpBlockUtil::parse_screens(yaml_parser_t *parser) {
249 yaml_event_t event;
250 string screen_name;
251 expect_event(parser, YAML_MAPPING_START_EVENT);
252 for (;;) {
253 yaml_parser_parse(parser, &event);
254 switch (event.type) {
255 case YAML_SCALAR_EVENT:
256 screen_name = (char*)event.data.scalar.value;
257 config_.screens_map[screen_name] = ScreenConfig();
258 parse_layout(parser, config_.screens_map[screen_name]);
259 break;
260 case YAML_MAPPING_END_EVENT:
261 yaml_event_delete(&event);
262 return;
263 default:
264 error("Syntax error in parsing screens.\n");
265 }
266 yaml_event_delete(&event);
267 }
268}
269
270void BmpBlockUtil::parse_localizations(yaml_parser_t *parser) {
271 yaml_event_t event;
272 int depth = 0, index = 0;
273 expect_event(parser, YAML_SEQUENCE_START_EVENT);
274 for (;;) {
275 yaml_parser_parse(parser, &event);
276 switch (event.type) {
277 case YAML_SEQUENCE_START_EVENT:
278 config_.localizations.push_back(vector<string>());
279 depth++;
280 break;
281 case YAML_SCALAR_EVENT:
282 config_.localizations[index].push_back((char*)event.data.scalar.value);
283 break;
284 case YAML_SEQUENCE_END_EVENT:
285 if (depth == 1) {
286 index++;
287 } else if (depth == 0) {
288 yaml_event_delete(&event);
289 return;
290 }
291 depth--;
292 break;
293 default:
294 error("Syntax error in parsing localizations.\n");
295 }
296 yaml_event_delete(&event);
297 }
298}
299
300void BmpBlockUtil::load_all_image_files() {
301 for (StrImageConfigMap::iterator it = config_.images_map.begin();
302 it != config_.images_map.end();
303 ++it) {
304 const string &content = read_image_file(it->second.filename.c_str());
305 it->second.raw_content = content;
306 it->second.data.original_size = content.size();
Bill Richardson61362d62011-02-14 10:28:03 -0800307 switch(compression_) {
308 case COMPRESS_NONE:
309 it->second.data.compression = compression_;
310 it->second.compressed_content = content;
311 it->second.data.compressed_size = content.size();
312 break;
313 case COMPRESS_EFIv1:
314 {
315 // The content will always compress smaller (so sez the docs).
316 uint32_t tmpsize = content.size();
317 uint8_t *tmpbuf = (uint8_t *)malloc(tmpsize);
318 // The size of the compressed content is also returned.
319 if (EFI_SUCCESS != EfiCompress((uint8_t *)content.c_str(), tmpsize,
320 tmpbuf, &tmpsize)) {
321 error("Unable to compress!\n");
322 }
323 it->second.data.compression = compression_;
324 it->second.compressed_content.assign((const char *)tmpbuf, tmpsize);
325 it->second.data.compressed_size = tmpsize;
326 free(tmpbuf);
327 }
328 break;
329 default:
330 error("Unsupported compression method attempted.\n");
331 }
Bill Richardsond55085d2011-02-04 15:01:37 -0800332 }
333}
334
335const string BmpBlockUtil::read_image_file(const char *filename) {
336 string content;
337 vector<char> buffer;
338
339 FILE *fp = fopen(filename, "rb");
340 if (!fp) {
341 perror(filename);
342 exit(errno);
343 }
344
345 if (fseek(fp, 0, SEEK_END) == 0) {
346 buffer.resize(ftell(fp));
347 rewind(fp);
348 }
349
350 if (!buffer.empty()) {
351 if(fread(&buffer[0], buffer.size(), 1, fp) != 1) {
352 perror(filename);
353 buffer.clear();
354 } else {
355 content.assign(buffer.begin(), buffer.end());
356 }
357 }
358
359 fclose(fp);
360 return content;
361}
362
363ImageFormat BmpBlockUtil::get_image_format(const string content) {
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800364 if (content.size() < sizeof(BMP_IMAGE_HEADER))
Bill Richardsond55085d2011-02-04 15:01:37 -0800365 return FORMAT_INVALID;
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800366 const BMP_IMAGE_HEADER *hdr = (const BMP_IMAGE_HEADER *)content.c_str();
367
368 if (hdr->CharB != 'B' || hdr->CharM != 'M' ||
369 hdr->Planes != 1 ||
Tom Wai-Hong Tama985ed42011-02-14 16:08:49 +0800370 (hdr->CompressionType != 0 && hdr->CompressionType != 1) ||
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800371 (hdr->BitPerPixel != 1 && hdr->BitPerPixel != 4 &&
372 hdr->BitPerPixel != 8 && hdr->BitPerPixel != 24))
373 return FORMAT_INVALID;
374
375 return FORMAT_BMP;
Bill Richardsond55085d2011-02-04 15:01:37 -0800376}
377
378uint32_t BmpBlockUtil::get_bmp_image_width(const string content) {
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800379 const BMP_IMAGE_HEADER *hdr = (const BMP_IMAGE_HEADER *)content.c_str();
380 return hdr->PixelWidth;
Bill Richardsond55085d2011-02-04 15:01:37 -0800381}
382
383uint32_t BmpBlockUtil::get_bmp_image_height(const string content) {
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800384 const BMP_IMAGE_HEADER *hdr = (const BMP_IMAGE_HEADER *)content.c_str();
385 return hdr->PixelHeight;
Bill Richardsond55085d2011-02-04 15:01:37 -0800386}
387
388void BmpBlockUtil::fill_all_image_infos() {
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800389 int errcnt = 0;
Bill Richardsond55085d2011-02-04 15:01:37 -0800390 for (StrImageConfigMap::iterator it = config_.images_map.begin();
391 it != config_.images_map.end();
392 ++it) {
393 it->second.data.format = (uint32_t)get_image_format(it->second.raw_content);
394 switch (it->second.data.format) {
395 case FORMAT_BMP:
396 it->second.data.width = get_bmp_image_width(it->second.raw_content);
397 it->second.data.height = get_bmp_image_height(it->second.raw_content);
398 break;
399 default:
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800400 fprintf(stderr, "Unsupported image format in %s\n",
401 it->second.filename.c_str());
402 errcnt++;
Bill Richardsond55085d2011-02-04 15:01:37 -0800403 }
404 }
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800405 if (errcnt)
406 error("Unable to continue due to errors.\n");
Bill Richardsond55085d2011-02-04 15:01:37 -0800407}
408
409void BmpBlockUtil::compress_all_images(const Compression compress) {
410 switch (compress) {
411 case COMPRESS_NONE:
412 for (StrImageConfigMap::iterator it = config_.images_map.begin();
413 it != config_.images_map.end();
414 ++it) {
415 it->second.data.compression = compress;
416 it->second.compressed_content = it->second.raw_content;
417 it->second.data.compressed_size = it->second.compressed_content.size();
418 }
419 break;
420 default:
Bill Richardson856e0722011-02-07 15:39:45 -0800421 error("Unsupported data compression.\n");
Bill Richardsond55085d2011-02-04 15:01:37 -0800422 }
423}
424
425void BmpBlockUtil::fill_bmpblock_header() {
426 memset(&config_.header, '\0', sizeof(config_.header));
427 memcpy(&config_.header.signature, BMPBLOCK_SIGNATURE,
428 BMPBLOCK_SIGNATURE_SIZE);
Bill Richardsonfc05bb82011-02-08 15:03:36 -0800429 config_.header.major_version = BMPBLOCK_MAJOR_VERSION;
430 config_.header.minor_version = BMPBLOCK_MINOR_VERSION;
Bill Richardsond55085d2011-02-04 15:01:37 -0800431 config_.header.number_of_localizations = config_.localizations.size();
432 config_.header.number_of_screenlayouts = config_.localizations[0].size();
433 for (unsigned int i = 1; i < config_.localizations.size(); ++i) {
434 assert(config_.header.number_of_screenlayouts ==
435 config_.localizations[i].size());
436 }
437 config_.header.number_of_imageinfos = config_.images_map.size();
438}
439
440void BmpBlockUtil::pack_bmpblock() {
441 bmpblock_.clear();
442
443 /* Compute the ImageInfo offsets from start of BMPBLOCK. */
444 uint32_t current_offset = sizeof(BmpBlockHeader) +
Bill Richardson61362d62011-02-14 10:28:03 -0800445 sizeof(ScreenLayout) * config_.screens_map.size();
Bill Richardsond55085d2011-02-04 15:01:37 -0800446 for (StrImageConfigMap::iterator it = config_.images_map.begin();
447 it != config_.images_map.end();
448 ++it) {
449 it->second.offset = current_offset;
450 current_offset += sizeof(ImageInfo) + it->second.data.compressed_size;
451 /* Make it 4-byte aligned. */
452 if ((current_offset & 3) > 0) {
453 current_offset = (current_offset & ~3) + 4;
454 }
455 }
456 bmpblock_.resize(current_offset);
457
458 /* Fill BmpBlockHeader struct. */
459 string::iterator current_filled = bmpblock_.begin();
460 std::copy(reinterpret_cast<char*>(&config_.header),
461 reinterpret_cast<char*>(&config_.header + 1),
462 current_filled);
463 current_filled += sizeof(config_.header);
464
465 /* Fill all ScreenLayout structs. */
466 for (unsigned int i = 0; i < config_.localizations.size(); ++i) {
467 for (unsigned int j = 0; j < config_.localizations[i].size(); ++j) {
468 ScreenConfig &screen = config_.screens_map[config_.localizations[i][j]];
469 for (unsigned int k = 0;
470 k < MAX_IMAGE_IN_LAYOUT && !screen.image_names[k].empty();
471 ++k) {
472 screen.data.images[k].image_info_offset =
473 config_.images_map[screen.image_names[k]].offset;
474 }
475 std::copy(reinterpret_cast<char*>(&screen.data),
476 reinterpret_cast<char*>(&screen.data + 1),
477 current_filled);
478 current_filled += sizeof(screen.data);
479 }
480 }
481
482 /* Fill all ImageInfo structs and image contents. */
483 for (StrImageConfigMap::iterator it = config_.images_map.begin();
484 it != config_.images_map.end();
485 ++it) {
486 current_filled = bmpblock_.begin() + it->second.offset;
487 std::copy(reinterpret_cast<char*>(&it->second.data),
488 reinterpret_cast<char*>(&it->second.data + 1),
489 current_filled);
490 current_filled += sizeof(it->second.data);
491 std::copy(it->second.compressed_content.begin(),
492 it->second.compressed_content.end(),
493 current_filled);
494 }
495}
496
497void BmpBlockUtil::write_to_bmpblock(const char *filename) {
498 assert(!bmpblock_.empty());
499
500 FILE *fp = fopen(filename, "wb");
501 if (!fp) {
502 perror(filename);
503 exit(errno);
504 }
505
506 int r = fwrite(bmpblock_.c_str(), bmpblock_.size(), 1, fp);
507 fclose(fp);
508 if (r != 1) {
509 perror(filename);
510 exit(errno);
511 }
512}
513
514} // namespace vboot_reference
515
516#ifdef WITH_UTIL_MAIN
517
Bill Richardson794d4d42011-02-10 19:13:10 -0800518//////////////////////////////////////////////////////////////////////////////
519// Command line utilities.
520
521extern "C" {
522#include "bmpblk_util.h"
523}
Bill Richardsond55085d2011-02-04 15:01:37 -0800524
525using vboot_reference::BmpBlockUtil;
526
527// utility function: provide usage of this utility and exit.
528static void usagehelp_exit(const char *prog_name) {
529 printf(
Bill Richardsond55085d2011-02-04 15:01:37 -0800530 "\n"
Bill Richardson794d4d42011-02-10 19:13:10 -0800531 "To create a new BMPBLOCK file using config from YAML file:\n"
Bill Richardsond55085d2011-02-04 15:01:37 -0800532 "\n"
Bill Richardson794d4d42011-02-10 19:13:10 -0800533 " %s [-z NUM] -c YAML BMPBLOCK\n"
Bill Richardsond55085d2011-02-04 15:01:37 -0800534 "\n"
Bill Richardson794d4d42011-02-10 19:13:10 -0800535 " -z NUM = compression algorithm to use\n"
536 " 0 = none\n"
537 " 1 = EFIv1\n"
538 " 2 = TBD\n"
539 "\n", prog_name);
540 printf(
541 "To display the contents of a BMPBLOCK:\n"
542 "\n"
Bill Richardson61362d62011-02-14 10:28:03 -0800543 " %s [-y] BMPBLOCK\n"
544 "\n"
545 " -y = display as yaml\n"
Bill Richardson794d4d42011-02-10 19:13:10 -0800546 "\n", prog_name);
547 printf(
548 "To unpack a BMPBLOCK file:\n"
549 "\n"
550 " %s -x [-d DIR] [-f] BMPBLOCK\n"
551 "\n"
552 " -d DIR = directory to use (default '.')\n"
553 " -f = force overwriting existing files\n"
554 "\n", prog_name);
Bill Richardsond55085d2011-02-04 15:01:37 -0800555 exit(1);
556}
557
558///////////////////////////////////////////////////////////////////////
559// main
560
561int main(int argc, char *argv[]) {
Bill Richardsond55085d2011-02-04 15:01:37 -0800562
Bill Richardson794d4d42011-02-10 19:13:10 -0800563 const char *prog_name = strrchr(argv[0], '/');
564 if (prog_name)
565 prog_name++;
566 else
567 prog_name = argv[0];
Bill Richardsond55085d2011-02-04 15:01:37 -0800568
Bill Richardson61362d62011-02-14 10:28:03 -0800569 int overwrite = 0, extract_mode = 0;
Bill Richardson794d4d42011-02-10 19:13:10 -0800570 int compression = 0;
Bill Richardson61362d62011-02-14 10:28:03 -0800571 int set_compression = 0;
Bill Richardson794d4d42011-02-10 19:13:10 -0800572 const char *config_fn = 0, *bmpblock_fn = 0, *extract_dir = ".";
Bill Richardson61362d62011-02-14 10:28:03 -0800573 int show_as_yaml = 0;
Bill Richardsond55085d2011-02-04 15:01:37 -0800574
Bill Richardson794d4d42011-02-10 19:13:10 -0800575 int opt;
576 opterr = 0; // quiet
577 int errorcnt = 0;
578 char *e = 0;
Bill Richardson61362d62011-02-14 10:28:03 -0800579 while ((opt = getopt(argc, argv, ":c:xz:fd:y")) != -1) {
Bill Richardsond55085d2011-02-04 15:01:37 -0800580 switch (opt) {
Bill Richardson794d4d42011-02-10 19:13:10 -0800581 case 'c':
582 config_fn = optarg;
583 break;
584 case 'x':
585 extract_mode = 1;
586 break;
Bill Richardson61362d62011-02-14 10:28:03 -0800587 case 'y':
588 show_as_yaml = 1;
589 break;
Bill Richardson794d4d42011-02-10 19:13:10 -0800590 case 'z':
591 compression = (int)strtoul(optarg, &e, 0);
592 if (!*optarg || (e && *e)) {
593 fprintf(stderr, "%s: invalid argument to -%c: \"%s\"\n",
594 prog_name, opt, optarg);
595 errorcnt++;
596 }
597 if (compression >= MAX_COMPRESS) {
598 fprintf(stderr, "%s: compression type must be less than %d\n",
Bill Richardson61362d62011-02-14 10:28:03 -0800599 prog_name, MAX_COMPRESS);
Bill Richardson794d4d42011-02-10 19:13:10 -0800600 errorcnt++;
601 }
Bill Richardson61362d62011-02-14 10:28:03 -0800602 set_compression = 1;
Bill Richardson794d4d42011-02-10 19:13:10 -0800603 break;
604 case 'f':
Bill Richardson61362d62011-02-14 10:28:03 -0800605 overwrite = 1;
Bill Richardson794d4d42011-02-10 19:13:10 -0800606 break;
607 case 'd':
608 extract_dir= optarg;
609 break;
610 case ':':
611 fprintf(stderr, "%s: missing argument to -%c\n",
612 prog_name, optopt);
613 errorcnt++;
614 break;
615 default:
616 fprintf(stderr, "%s: unrecognized switch: -%c\n",
617 prog_name, optopt);
618 errorcnt++;
619 break;
Bill Richardsond55085d2011-02-04 15:01:37 -0800620 }
621 }
622 argc -= optind;
623 argv += optind;
624
Bill Richardson794d4d42011-02-10 19:13:10 -0800625 if (argc >= 1) {
626 bmpblock_fn = argv[0];
Bill Richardsond55085d2011-02-04 15:01:37 -0800627 } else {
Bill Richardson794d4d42011-02-10 19:13:10 -0800628 fprintf(stderr, "%s: missing BMPBLOCK name\n", prog_name);
629 errorcnt++;
630 }
631
632 if (errorcnt)
Bill Richardsond55085d2011-02-04 15:01:37 -0800633 usagehelp_exit(prog_name);
Bill Richardsond55085d2011-02-04 15:01:37 -0800634
Bill Richardson794d4d42011-02-10 19:13:10 -0800635 BmpBlockUtil util;
636
637 if (config_fn) {
Bill Richardson61362d62011-02-14 10:28:03 -0800638 if (set_compression)
639 util.force_compression(compression);
Bill Richardson794d4d42011-02-10 19:13:10 -0800640 util.load_from_config(config_fn);
Bill Richardsond55085d2011-02-04 15:01:37 -0800641 util.pack_bmpblock();
Bill Richardson794d4d42011-02-10 19:13:10 -0800642 util.write_to_bmpblock(bmpblock_fn);
Bill Richardsond55085d2011-02-04 15:01:37 -0800643 }
644
Bill Richardson794d4d42011-02-10 19:13:10 -0800645 else if (extract_mode) {
Bill Richardson61362d62011-02-14 10:28:03 -0800646 return dump_bmpblock(bmpblock_fn, 1, extract_dir, overwrite);
647 } else {
648 return dump_bmpblock(bmpblock_fn, show_as_yaml, 0, 0);
Bill Richardsond55085d2011-02-04 15:01:37 -0800649 }
650
Bill Richardsond55085d2011-02-04 15:01:37 -0800651 return 0;
652}
653
654#endif // WITH_UTIL_MAIN