Index: utility/bmpblk_util.c |
diff --git a/utility/bmpblk_util.c b/utility/bmpblk_util.c |
index d7b9cbf80abbf62706193868bb03466557108e11..214beda4b0040d2b2a1b6b88c283665e3b47c2d4 100644 |
--- a/utility/bmpblk_util.c |
+++ b/utility/bmpblk_util.c |
@@ -4,6 +4,7 @@ |
#include <errno.h> |
#include <fcntl.h> |
+#include <limits.h> |
#include <stdio.h> |
#include <string.h> |
#include <sys/mman.h> |
@@ -12,6 +13,7 @@ |
#include <unistd.h> |
#include "bmpblk_util.h" |
+#include "eficompress.h" |
// Returns pointer to buffer containing entire file, sets length. |
@@ -58,14 +60,105 @@ static void discard_file(void *ptr, size_t length) { |
munmap(ptr, length); |
} |
+////////////////////////////////////////////////////////////////////////////// |
-// Show what's inside |
-int display_bmpblock(const char *infile) { |
- char *ptr; |
+static int require_dir(const char *dirname) { |
+ struct stat sbuf; |
+ |
+ if (0 == stat(dirname, &sbuf)) { |
+ // Something's there. Is it a directory? |
+ if (S_ISDIR(sbuf.st_mode)) { |
+ return 0; |
+ } |
+ fprintf(stderr, "%s already exists and is not a directory\n", dirname); |
+ return 1; |
+ } |
+ |
+ // dirname doesn't exist. Try to create it. |
+ if (ENOENT == errno) { |
+ if (0 != mkdir(dirname, 0777)) { |
+ fprintf(stderr, "Unable to create directory %s: %s\n", |
+ dirname, strerror(errno)); |
+ return 1; |
+ } |
+ return 0; |
+ } |
+ |
+ fprintf(stderr, "Unable to stat %s: %s\n", dirname, strerror(errno)); |
+ return 1; |
+} |
+ |
+ |
+ |
+static void *do_efi_decompress(ImageInfo *img) { |
+ void *ibuf; |
+ void *sbuf; |
+ void *obuf; |
+ uint32_t isize; |
+ uint32_t ssize; |
+ uint32_t osize; |
+ EFI_STATUS r; |
+ |
+ ibuf = ((void *)img) + sizeof(ImageInfo); |
+ isize = img->compressed_size; |
+ |
+ r = EfiGetInfo(ibuf, isize, &osize, &ssize); |
+ if (EFI_SUCCESS != r) { |
+ fprintf(stderr, "EfiGetInfo() failed with code %d\n", |
+ r); |
+ return 0; |
+ } |
+ |
+ sbuf = malloc(ssize); |
+ if (!sbuf) { |
+ fprintf(stderr, "Can't allocate %d bytes: %s\n", |
+ ssize, |
+ strerror(errno)); |
+ return 0; |
+ } |
+ |
+ obuf = malloc(osize); |
+ if (!obuf) { |
+ fprintf(stderr, "Can't allocate %d bytes: %s\n", |
+ osize, |
+ strerror(errno)); |
+ free(sbuf); |
+ return 0; |
+ } |
+ |
+ r = EfiDecompress(ibuf, isize, obuf, osize, sbuf, ssize); |
+ if (r != EFI_SUCCESS) { |
+ fprintf(stderr, "EfiDecompress failed with code %d\n", r); |
+ free(obuf); |
+ free(sbuf); |
+ return 0; |
+ } |
+ |
+ free(sbuf); |
+ return obuf; |
+} |
+ |
+ |
+// Show what's inside. If todir is NULL, just print. Otherwise unpack. |
+int dump_bmpblock(const char *infile, int show_as_yaml, |
+ const char *todir, int overwrite) { |
+ void *ptr, *data_ptr; |
size_t length = 0; |
BmpBlockHeader *hdr; |
+ ImageInfo *img; |
+ ScreenLayout *scr; |
+ int loc_num; |
+ int screen_num; |
+ int i; |
+ int offset; |
+ int free_data; |
+ char image_name[80]; |
+ char full_path_name[PATH_MAX]; |
+ int yfd, bfd; |
+ FILE *yfp = stdout; |
+ FILE *bfp = stdout; |
- ptr = (char *)read_entire_file(infile, &length); |
+ ptr = (void *)read_entire_file(infile, &length); |
if (!ptr) |
return 1; |
@@ -81,21 +174,163 @@ int display_bmpblock(const char *infile) { |
return 1; |
} |
+ if (todir) { |
+ // Unpacking everything. Create the output directory if needed. |
+ if (0 != require_dir(todir)) { |
+ discard_file(ptr, length); |
+ return 1; |
+ } |
+ |
+ // Open yaml output. |
+ show_as_yaml = 1; |
+ |
+ sprintf(full_path_name, "%s/%s", todir, "config.yaml"); |
+ yfd = open(full_path_name, |
+ O_WRONLY | O_CREAT | O_TRUNC | (overwrite ? 0 : O_EXCL), |
+ 0666); |
+ if (yfd < 0) { |
+ fprintf(stderr, "Unable to open %s: %s\n", full_path_name, |
+ strerror(errno)); |
+ discard_file(ptr, length); |
+ return 1; |
+ } |
+ |
+ yfp = fdopen(yfd, "wb"); |
+ if (!yfp) { |
+ fprintf(stderr, "Unable to fdopen %s: %s\n", full_path_name, |
+ strerror(errno)); |
+ close(yfd); |
+ discard_file(ptr, length); |
+ return 1; |
+ } |
+ } |
+ |
hdr = (BmpBlockHeader *)ptr; |
- printf("%s:\n", infile); |
- printf(" version %d.%d\n", hdr->major_version, hdr->minor_version); |
- printf(" %d screens\n", hdr->number_of_screenlayouts); |
- printf(" %d localizations\n", hdr->number_of_localizations); |
- printf(" %d discrete images\n", hdr->number_of_imageinfos); |
+ |
+ if (!show_as_yaml) { |
+ printf("%s:\n", infile); |
+ printf(" version %d.%d\n", hdr->major_version, hdr->minor_version); |
+ printf(" %d screens\n", hdr->number_of_screenlayouts); |
+ printf(" %d localizations\n", hdr->number_of_localizations); |
+ printf(" %d discrete images\n", hdr->number_of_imageinfos); |
+ discard_file(ptr, length); |
+ return 0; |
+ } |
+ |
+ // Write out yaml |
+ fprintf(yfp, "bmpblock: %d.%d\n", hdr->major_version, hdr->minor_version); |
+ fprintf(yfp, "images:\n"); |
+ offset = sizeof(BmpBlockHeader) + |
+ (sizeof(ScreenLayout) * |
+ hdr->number_of_localizations * |
+ hdr->number_of_screenlayouts); |
+ for(i=0; i<hdr->number_of_imageinfos; i++) { |
+ img = (ImageInfo *)(ptr + offset); |
+ sprintf(image_name, "img_%08x.bmp", offset); |
+ fprintf(yfp, " img_%08x: %s # %dx%d %d/%d\n", offset, image_name, |
+ img->width, img->height, |
+ img->compressed_size, img->original_size); |
+ if (todir) { |
+ sprintf(full_path_name, "%s/%s", todir, image_name); |
+ bfd = open(full_path_name, |
+ O_WRONLY | O_CREAT | O_TRUNC | (overwrite ? 0 : O_EXCL), |
+ 0666); |
+ if (bfd < 0) { |
+ fprintf(stderr, "Unable to open %s: %s\n", full_path_name, |
+ strerror(errno)); |
+ fclose(yfp); |
+ discard_file(ptr, length); |
+ return 1; |
+ } |
+ bfp = fdopen(bfd, "wb"); |
+ if (!bfp) { |
+ fprintf(stderr, "Unable to fdopen %s: %s\n", full_path_name, |
+ strerror(errno)); |
+ close(bfd); |
+ fclose(yfp); |
+ discard_file(ptr, length); |
+ return 1; |
+ } |
+ switch(img->compression) { |
+ case COMPRESS_NONE: |
+ data_ptr = ptr + offset + sizeof(ImageInfo); |
+ free_data = 0; |
+ break; |
+ case COMPRESS_EFIv1: |
+ data_ptr = do_efi_decompress(img); |
+ if (!data_ptr) { |
+ fclose(bfp); |
+ fclose(yfp); |
+ discard_file(ptr, length); |
+ return 1; |
+ } |
+ free_data = 1; |
+ break; |
+ default: |
+ fprintf(stderr, "Unsupported compression method encountered.\n"); |
+ fclose(bfp); |
+ fclose(yfp); |
+ discard_file(ptr, length); |
+ return 1; |
+ } |
+ if (1 != fwrite(data_ptr, img->original_size, 1, bfp)) { |
+ fprintf(stderr, "Unable to write %s: %s\n", full_path_name, |
+ strerror(errno)); |
+ fclose(bfp); |
+ fclose(yfp); |
+ discard_file(ptr, length); |
+ return 1; |
+ } |
+ fclose(bfp); |
+ if (free_data) |
+ free(data_ptr); |
+ } |
+ offset += sizeof(ImageInfo); |
+ offset += img->compressed_size; |
+ // 4-byte aligned |
+ if ((offset & 3) > 0) |
+ offset = (offset & ~3) + 4; |
+ } |
+ fprintf(yfp, "screens:\n"); |
+ for(loc_num = 0; |
+ loc_num < hdr->number_of_localizations; |
+ loc_num++) { |
+ for(screen_num = 0; |
+ screen_num < hdr->number_of_screenlayouts; |
+ screen_num++) { |
+ fprintf(yfp, " scr_%d_%d:\n", loc_num, screen_num); |
+ i = loc_num * hdr->number_of_screenlayouts + screen_num; |
+ offset = sizeof(BmpBlockHeader) + i * sizeof(ScreenLayout); |
+ scr = (ScreenLayout *)(ptr + offset); |
+ for(i=0; i<MAX_IMAGE_IN_LAYOUT; i++) { |
+ if (scr->images[i].image_info_offset) { |
+ fprintf(yfp, " - [%d, %d, img_%08x]\n", |
+ scr->images[i].x, scr->images[i].y, |
+ scr->images[i].image_info_offset); |
+ } |
+ } |
+ } |
+ } |
+ fprintf(yfp, "localizations:\n"); |
+ for(loc_num = 0; |
+ loc_num < hdr->number_of_localizations; |
+ loc_num++) { |
+ fprintf(yfp, " - ["); |
+ for(screen_num = 0; |
+ screen_num < hdr->number_of_screenlayouts; |
+ screen_num++) { |
+ fprintf(yfp, " scr_%d_%d", loc_num, screen_num); |
+ if (screen_num != hdr->number_of_screenlayouts - 1) |
+ fprintf(yfp, ","); |
+ } |
+ fprintf(yfp, " ]\n"); |
+ } |
+ |
+ if (todir) |
+ fclose(yfp); |
discard_file(ptr, length); |
return 0; |
} |
-int extract_bmpblock(const char *infile, const char *dirname, int force) { |
- printf("extract parts from %s into %s %s overwriting\n", |
- infile, dirname, force ? "with" : "without"); |
- printf("NOT YET IMPLEMENTED\n"); |
- return 0; |
-} |