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 #include <errno.h> | 5 #include <errno.h> |
6 #include <fcntl.h> | 6 #include <fcntl.h> |
| 7 #include <limits.h> |
7 #include <stdio.h> | 8 #include <stdio.h> |
8 #include <string.h> | 9 #include <string.h> |
9 #include <sys/mman.h> | 10 #include <sys/mman.h> |
10 #include <sys/stat.h> | 11 #include <sys/stat.h> |
11 #include <sys/types.h> | 12 #include <sys/types.h> |
12 #include <unistd.h> | 13 #include <unistd.h> |
13 | 14 |
14 #include "bmpblk_util.h" | 15 #include "bmpblk_util.h" |
| 16 #include "eficompress.h" |
15 | 17 |
16 | 18 |
17 // Returns pointer to buffer containing entire file, sets length. | 19 // Returns pointer to buffer containing entire file, sets length. |
18 static void *read_entire_file(const char *filename, size_t *length) { | 20 static void *read_entire_file(const char *filename, size_t *length) { |
19 int fd; | 21 int fd; |
20 struct stat sbuf; | 22 struct stat sbuf; |
21 void *ptr; | 23 void *ptr; |
22 | 24 |
23 *length = 0; // just in case | 25 *length = 0; // just in case |
24 | 26 |
(...skipping 26 matching lines...) Expand all Loading... |
51 | 53 |
52 return ptr; | 54 return ptr; |
53 } | 55 } |
54 | 56 |
55 | 57 |
56 // Reclaims buffer from read_entire_file(). | 58 // Reclaims buffer from read_entire_file(). |
57 static void discard_file(void *ptr, size_t length) { | 59 static void discard_file(void *ptr, size_t length) { |
58 munmap(ptr, length); | 60 munmap(ptr, length); |
59 } | 61 } |
60 | 62 |
| 63 ////////////////////////////////////////////////////////////////////////////// |
61 | 64 |
62 // Show what's inside | 65 static int require_dir(const char *dirname) { |
63 int display_bmpblock(const char *infile) { | 66 struct stat sbuf; |
64 char *ptr; | 67 |
| 68 if (0 == stat(dirname, &sbuf)) { |
| 69 // Something's there. Is it a directory? |
| 70 if (S_ISDIR(sbuf.st_mode)) { |
| 71 return 0; |
| 72 } |
| 73 fprintf(stderr, "%s already exists and is not a directory\n", dirname); |
| 74 return 1; |
| 75 } |
| 76 |
| 77 // dirname doesn't exist. Try to create it. |
| 78 if (ENOENT == errno) { |
| 79 if (0 != mkdir(dirname, 0777)) { |
| 80 fprintf(stderr, "Unable to create directory %s: %s\n", |
| 81 dirname, strerror(errno)); |
| 82 return 1; |
| 83 } |
| 84 return 0; |
| 85 } |
| 86 |
| 87 fprintf(stderr, "Unable to stat %s: %s\n", dirname, strerror(errno)); |
| 88 return 1; |
| 89 } |
| 90 |
| 91 |
| 92 |
| 93 static void *do_efi_decompress(ImageInfo *img) { |
| 94 void *ibuf; |
| 95 void *sbuf; |
| 96 void *obuf; |
| 97 uint32_t isize; |
| 98 uint32_t ssize; |
| 99 uint32_t osize; |
| 100 EFI_STATUS r; |
| 101 |
| 102 ibuf = ((void *)img) + sizeof(ImageInfo); |
| 103 isize = img->compressed_size; |
| 104 |
| 105 r = EfiGetInfo(ibuf, isize, &osize, &ssize); |
| 106 if (EFI_SUCCESS != r) { |
| 107 fprintf(stderr, "EfiGetInfo() failed with code %d\n", |
| 108 r); |
| 109 return 0; |
| 110 } |
| 111 |
| 112 sbuf = malloc(ssize); |
| 113 if (!sbuf) { |
| 114 fprintf(stderr, "Can't allocate %d bytes: %s\n", |
| 115 ssize, |
| 116 strerror(errno)); |
| 117 return 0; |
| 118 } |
| 119 |
| 120 obuf = malloc(osize); |
| 121 if (!obuf) { |
| 122 fprintf(stderr, "Can't allocate %d bytes: %s\n", |
| 123 osize, |
| 124 strerror(errno)); |
| 125 free(sbuf); |
| 126 return 0; |
| 127 } |
| 128 |
| 129 r = EfiDecompress(ibuf, isize, obuf, osize, sbuf, ssize); |
| 130 if (r != EFI_SUCCESS) { |
| 131 fprintf(stderr, "EfiDecompress failed with code %d\n", r); |
| 132 free(obuf); |
| 133 free(sbuf); |
| 134 return 0; |
| 135 } |
| 136 |
| 137 free(sbuf); |
| 138 return obuf; |
| 139 } |
| 140 |
| 141 |
| 142 // Show what's inside. If todir is NULL, just print. Otherwise unpack. |
| 143 int dump_bmpblock(const char *infile, int show_as_yaml, |
| 144 const char *todir, int overwrite) { |
| 145 void *ptr, *data_ptr; |
65 size_t length = 0; | 146 size_t length = 0; |
66 BmpBlockHeader *hdr; | 147 BmpBlockHeader *hdr; |
| 148 ImageInfo *img; |
| 149 ScreenLayout *scr; |
| 150 int loc_num; |
| 151 int screen_num; |
| 152 int i; |
| 153 int offset; |
| 154 int free_data; |
| 155 char image_name[80]; |
| 156 char full_path_name[PATH_MAX]; |
| 157 int yfd, bfd; |
| 158 FILE *yfp = stdout; |
| 159 FILE *bfp = stdout; |
67 | 160 |
68 ptr = (char *)read_entire_file(infile, &length); | 161 ptr = (void *)read_entire_file(infile, &length); |
69 if (!ptr) | 162 if (!ptr) |
70 return 1; | 163 return 1; |
71 | 164 |
72 if (length < sizeof(BmpBlockHeader)) { | 165 if (length < sizeof(BmpBlockHeader)) { |
73 fprintf(stderr, "File %s is too small to be a BMPBLOCK\n", infile); | 166 fprintf(stderr, "File %s is too small to be a BMPBLOCK\n", infile); |
74 discard_file(ptr, length); | 167 discard_file(ptr, length); |
75 return 1; | 168 return 1; |
76 } | 169 } |
77 | 170 |
78 if (0 != memcmp(ptr, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE)) { | 171 if (0 != memcmp(ptr, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE)) { |
79 fprintf(stderr, "File %s is not a BMPBLOCK\n", infile); | 172 fprintf(stderr, "File %s is not a BMPBLOCK\n", infile); |
80 discard_file(ptr, length); | 173 discard_file(ptr, length); |
81 return 1; | 174 return 1; |
82 } | 175 } |
83 | 176 |
| 177 if (todir) { |
| 178 // Unpacking everything. Create the output directory if needed. |
| 179 if (0 != require_dir(todir)) { |
| 180 discard_file(ptr, length); |
| 181 return 1; |
| 182 } |
| 183 |
| 184 // Open yaml output. |
| 185 show_as_yaml = 1; |
| 186 |
| 187 sprintf(full_path_name, "%s/%s", todir, "config.yaml"); |
| 188 yfd = open(full_path_name, |
| 189 O_WRONLY | O_CREAT | O_TRUNC | (overwrite ? 0 : O_EXCL), |
| 190 0666); |
| 191 if (yfd < 0) { |
| 192 fprintf(stderr, "Unable to open %s: %s\n", full_path_name, |
| 193 strerror(errno)); |
| 194 discard_file(ptr, length); |
| 195 return 1; |
| 196 } |
| 197 |
| 198 yfp = fdopen(yfd, "wb"); |
| 199 if (!yfp) { |
| 200 fprintf(stderr, "Unable to fdopen %s: %s\n", full_path_name, |
| 201 strerror(errno)); |
| 202 close(yfd); |
| 203 discard_file(ptr, length); |
| 204 return 1; |
| 205 } |
| 206 } |
| 207 |
84 hdr = (BmpBlockHeader *)ptr; | 208 hdr = (BmpBlockHeader *)ptr; |
85 printf("%s:\n", infile); | 209 |
86 printf(" version %d.%d\n", hdr->major_version, hdr->minor_version); | 210 if (!show_as_yaml) { |
87 printf(" %d screens\n", hdr->number_of_screenlayouts); | 211 printf("%s:\n", infile); |
88 printf(" %d localizations\n", hdr->number_of_localizations); | 212 printf(" version %d.%d\n", hdr->major_version, hdr->minor_version); |
89 printf(" %d discrete images\n", hdr->number_of_imageinfos); | 213 printf(" %d screens\n", hdr->number_of_screenlayouts); |
| 214 printf(" %d localizations\n", hdr->number_of_localizations); |
| 215 printf(" %d discrete images\n", hdr->number_of_imageinfos); |
| 216 discard_file(ptr, length); |
| 217 return 0; |
| 218 } |
| 219 |
| 220 // Write out yaml |
| 221 fprintf(yfp, "bmpblock: %d.%d\n", hdr->major_version, hdr->minor_version); |
| 222 fprintf(yfp, "images:\n"); |
| 223 offset = sizeof(BmpBlockHeader) + |
| 224 (sizeof(ScreenLayout) * |
| 225 hdr->number_of_localizations * |
| 226 hdr->number_of_screenlayouts); |
| 227 for(i=0; i<hdr->number_of_imageinfos; i++) { |
| 228 img = (ImageInfo *)(ptr + offset); |
| 229 sprintf(image_name, "img_%08x.bmp", offset); |
| 230 fprintf(yfp, " img_%08x: %s # %dx%d %d/%d\n", offset, image_name, |
| 231 img->width, img->height, |
| 232 img->compressed_size, img->original_size); |
| 233 if (todir) { |
| 234 sprintf(full_path_name, "%s/%s", todir, image_name); |
| 235 bfd = open(full_path_name, |
| 236 O_WRONLY | O_CREAT | O_TRUNC | (overwrite ? 0 : O_EXCL), |
| 237 0666); |
| 238 if (bfd < 0) { |
| 239 fprintf(stderr, "Unable to open %s: %s\n", full_path_name, |
| 240 strerror(errno)); |
| 241 fclose(yfp); |
| 242 discard_file(ptr, length); |
| 243 return 1; |
| 244 } |
| 245 bfp = fdopen(bfd, "wb"); |
| 246 if (!bfp) { |
| 247 fprintf(stderr, "Unable to fdopen %s: %s\n", full_path_name, |
| 248 strerror(errno)); |
| 249 close(bfd); |
| 250 fclose(yfp); |
| 251 discard_file(ptr, length); |
| 252 return 1; |
| 253 } |
| 254 switch(img->compression) { |
| 255 case COMPRESS_NONE: |
| 256 data_ptr = ptr + offset + sizeof(ImageInfo); |
| 257 free_data = 0; |
| 258 break; |
| 259 case COMPRESS_EFIv1: |
| 260 data_ptr = do_efi_decompress(img); |
| 261 if (!data_ptr) { |
| 262 fclose(bfp); |
| 263 fclose(yfp); |
| 264 discard_file(ptr, length); |
| 265 return 1; |
| 266 } |
| 267 free_data = 1; |
| 268 break; |
| 269 default: |
| 270 fprintf(stderr, "Unsupported compression method encountered.\n"); |
| 271 fclose(bfp); |
| 272 fclose(yfp); |
| 273 discard_file(ptr, length); |
| 274 return 1; |
| 275 } |
| 276 if (1 != fwrite(data_ptr, img->original_size, 1, bfp)) { |
| 277 fprintf(stderr, "Unable to write %s: %s\n", full_path_name, |
| 278 strerror(errno)); |
| 279 fclose(bfp); |
| 280 fclose(yfp); |
| 281 discard_file(ptr, length); |
| 282 return 1; |
| 283 } |
| 284 fclose(bfp); |
| 285 if (free_data) |
| 286 free(data_ptr); |
| 287 } |
| 288 offset += sizeof(ImageInfo); |
| 289 offset += img->compressed_size; |
| 290 // 4-byte aligned |
| 291 if ((offset & 3) > 0) |
| 292 offset = (offset & ~3) + 4; |
| 293 } |
| 294 fprintf(yfp, "screens:\n"); |
| 295 for(loc_num = 0; |
| 296 loc_num < hdr->number_of_localizations; |
| 297 loc_num++) { |
| 298 for(screen_num = 0; |
| 299 screen_num < hdr->number_of_screenlayouts; |
| 300 screen_num++) { |
| 301 fprintf(yfp, " scr_%d_%d:\n", loc_num, screen_num); |
| 302 i = loc_num * hdr->number_of_screenlayouts + screen_num; |
| 303 offset = sizeof(BmpBlockHeader) + i * sizeof(ScreenLayout); |
| 304 scr = (ScreenLayout *)(ptr + offset); |
| 305 for(i=0; i<MAX_IMAGE_IN_LAYOUT; i++) { |
| 306 if (scr->images[i].image_info_offset) { |
| 307 fprintf(yfp, " - [%d, %d, img_%08x]\n", |
| 308 scr->images[i].x, scr->images[i].y, |
| 309 scr->images[i].image_info_offset); |
| 310 } |
| 311 } |
| 312 } |
| 313 } |
| 314 fprintf(yfp, "localizations:\n"); |
| 315 for(loc_num = 0; |
| 316 loc_num < hdr->number_of_localizations; |
| 317 loc_num++) { |
| 318 fprintf(yfp, " - ["); |
| 319 for(screen_num = 0; |
| 320 screen_num < hdr->number_of_screenlayouts; |
| 321 screen_num++) { |
| 322 fprintf(yfp, " scr_%d_%d", loc_num, screen_num); |
| 323 if (screen_num != hdr->number_of_screenlayouts - 1) |
| 324 fprintf(yfp, ","); |
| 325 } |
| 326 fprintf(yfp, " ]\n"); |
| 327 } |
| 328 |
| 329 if (todir) |
| 330 fclose(yfp); |
90 | 331 |
91 discard_file(ptr, length); | 332 discard_file(ptr, length); |
92 | 333 |
93 return 0; | 334 return 0; |
94 } | 335 } |
95 | 336 |
96 int extract_bmpblock(const char *infile, const char *dirname, int force) { | |
97 printf("extract parts from %s into %s %s overwriting\n", | |
98 infile, dirname, force ? "with" : "without"); | |
99 printf("NOT YET IMPLEMENTED\n"); | |
100 return 0; | |
101 } | |
OLD | NEW |