1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2008-2015 Fuzhou Rockchip Electronics Co., Ltd 4 */ 5 6 #include <errno.h> 7 #include <memory.h> 8 #include <stdint.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <stdbool.h> 12 #include <sys/stat.h> 13 #include <time.h> 14 #include <u-boot/sha1.h> 15 #include <u-boot/sha256.h> 16 17 /* #define DEBUG */ 18 19 static bool g_debug = 20 #ifdef DEBUG 21 true; 22 #else 23 false; 24 #endif /* DEBUG */ 25 26 #define LOGE(fmt, args...) \ 27 fprintf(stderr, "E/%s(%d): " fmt "\n", __func__, __LINE__, ##args) 28 #define LOGD(fmt, args...) \ 29 do { \ 30 if (g_debug) \ 31 fprintf(stderr, "D/%s(%d): " fmt "\n", __func__, __LINE__, ##args); \ 32 } while (0) 33 34 /* sync with ./board/rockchip/rk30xx/rkloader.c #define FDT_PATH */ 35 #define FDT_PATH "rk-kernel.dtb" 36 #define DTD_SUBFIX ".dtb" 37 38 #define DEFAULT_IMAGE_PATH "resource.img" 39 #define DEFAULT_UNPACK_DIR "out" 40 #define BLOCK_SIZE 512 41 42 #define RESOURCE_PTN_HDR_SIZE 1 43 #define INDEX_TBL_ENTR_SIZE 1 44 45 #define RESOURCE_PTN_VERSION 0 46 #define INDEX_TBL_VERSION 0 47 48 #define RESOURCE_PTN_HDR_MAGIC "RSCE" 49 typedef struct { 50 char magic[4]; /* tag, "RSCE" */ 51 uint16_t resource_ptn_version; 52 uint16_t index_tbl_version; 53 uint8_t header_size; /* blocks, size of ptn header. */ 54 uint8_t tbl_offset; /* blocks, offset of index table. */ 55 uint8_t tbl_entry_size; /* blocks, size of index table's entry. */ 56 uint32_t tbl_entry_num; /* numbers of index table's entry. */ 57 } resource_ptn_header; 58 59 #define INDEX_TBL_ENTR_TAG "ENTR" 60 #define MAX_INDEX_ENTRY_PATH_LEN 220 61 #define MAX_HASH_LEN 32 62 63 typedef struct { 64 char tag[4]; /* tag, "ENTR" */ 65 char path[MAX_INDEX_ENTRY_PATH_LEN]; 66 char hash[MAX_HASH_LEN]; /* hash data */ 67 uint32_t hash_size; /* 20 or 32 */ 68 uint32_t content_offset; /* blocks, offset of resource content. */ 69 uint32_t content_size; /* bytes, size of resource content. */ 70 } index_tbl_entry; 71 72 #define OPT_VERBOSE "--verbose" 73 #define OPT_HELP "--help" 74 #define OPT_VERSION "--version" 75 #define OPT_PRINT "--print" 76 #define OPT_PACK "--pack" 77 #define OPT_UNPACK "--unpack" 78 #define OPT_TEST_LOAD "--test_load" 79 #define OPT_TEST_CHARGE "--test_charge" 80 #define OPT_IMAGE "--image=" 81 #define OPT_ROOT "--root=" 82 83 #define VERSION "2014-5-31 14:43:42" 84 85 typedef struct { 86 char path[MAX_INDEX_ENTRY_PATH_LEN]; 87 uint32_t content_offset; /* blocks, offset of resource content. */ 88 uint32_t content_size; /* bytes, size of resource content. */ 89 void *load_addr; 90 } resource_content; 91 92 typedef struct { 93 int max_level; 94 int num; 95 int delay; 96 char prefix[MAX_INDEX_ENTRY_PATH_LEN]; 97 } anim_level_conf; 98 99 #define DEF_CHARGE_DESC_PATH "charge_anim_desc.txt" 100 101 #define OPT_CHARGE_ANIM_DELAY "delay=" 102 #define OPT_CHARGE_ANIM_LOOP_CUR "only_current_level=" 103 #define OPT_CHARGE_ANIM_LEVELS "levels=" 104 #define OPT_CHARGE_ANIM_LEVEL_CONF "max_level=" 105 #define OPT_CHARGE_ANIM_LEVEL_NUM "num=" 106 #define OPT_CHARGE_ANIM_LEVEL_PFX "prefix=" 107 108 static char image_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0"; 109 110 static int fix_blocks(size_t size) 111 { 112 return (size + BLOCK_SIZE - 1) / BLOCK_SIZE; 113 } 114 115 static const char *fix_path(const char *path) 116 { 117 if (!memcmp(path, "./", 2)) { 118 return path + 2; 119 } 120 return path; 121 } 122 123 static uint16_t switch_short(uint16_t x) 124 { 125 uint16_t val; 126 uint8_t *p = (uint8_t *)(&x); 127 128 val = (*p++ & 0xff) << 0; 129 val |= (*p & 0xff) << 8; 130 131 return val; 132 } 133 134 static uint32_t switch_int(uint32_t x) 135 { 136 uint32_t val; 137 uint8_t *p = (uint8_t *)(&x); 138 139 val = (*p++ & 0xff) << 0; 140 val |= (*p++ & 0xff) << 8; 141 val |= (*p++ & 0xff) << 16; 142 val |= (*p & 0xff) << 24; 143 144 return val; 145 } 146 147 static void fix_header(resource_ptn_header *header) 148 { 149 /* switch for be. */ 150 header->resource_ptn_version = switch_short(header->resource_ptn_version); 151 header->index_tbl_version = switch_short(header->index_tbl_version); 152 header->tbl_entry_num = switch_int(header->tbl_entry_num); 153 } 154 155 static void fix_entry(index_tbl_entry *entry) 156 { 157 /* switch for be. */ 158 entry->content_offset = switch_int(entry->content_offset); 159 entry->content_size = switch_int(entry->content_size); 160 } 161 162 static int inline get_ptn_offset(void) 163 { 164 return 0; 165 } 166 167 static bool StorageWriteLba(int offset_block, void *data, int blocks) 168 { 169 bool ret = false; 170 FILE *file = fopen(image_path, "rb+"); 171 if (!file) 172 goto end; 173 int offset = offset_block * BLOCK_SIZE; 174 fseek(file, offset, SEEK_SET); 175 if (offset != ftell(file)) { 176 LOGE("Failed to seek %s to %d!", image_path, offset); 177 goto end; 178 } 179 if (!fwrite(data, blocks * BLOCK_SIZE, 1, file)) { 180 LOGE("Failed to write %s!", image_path); 181 goto end; 182 } 183 ret = true; 184 end: 185 if (file) 186 fclose(file); 187 return ret; 188 } 189 190 static bool StorageReadLba(int offset_block, void *data, int blocks) 191 { 192 bool ret = false; 193 FILE *file = fopen(image_path, "rb"); 194 if (!file) 195 goto end; 196 int offset = offset_block * BLOCK_SIZE; 197 fseek(file, offset, SEEK_SET); 198 if (offset != ftell(file)) { 199 goto end; 200 } 201 if (!fread(data, blocks * BLOCK_SIZE, 1, file)) { 202 goto end; 203 } 204 ret = true; 205 end: 206 if (file) 207 fclose(file); 208 return ret; 209 } 210 211 static bool write_data(int offset_block, void *data, size_t len) 212 { 213 bool ret = false; 214 if (!data) 215 goto end; 216 int blocks = len / BLOCK_SIZE; 217 if (blocks && !StorageWriteLba(offset_block, data, blocks)) { 218 goto end; 219 } 220 int left = len % BLOCK_SIZE; 221 if (left) { 222 char buf[BLOCK_SIZE] = "\0"; 223 memcpy(buf, data + blocks * BLOCK_SIZE, left); 224 if (!StorageWriteLba(offset_block + blocks, buf, 1)) 225 goto end; 226 } 227 ret = true; 228 end: 229 return ret; 230 } 231 232 /**********************load test************************/ 233 static int load_file(const char *file_path, int offset_block, int blocks); 234 235 static int test_load(int argc, char **argv) 236 { 237 if (argc < 1) { 238 LOGE("Nothing to load!"); 239 return -1; 240 } 241 const char *file_path; 242 int offset_block = 0; 243 int blocks = 0; 244 if (argc > 0) { 245 file_path = (const char *)fix_path(argv[0]); 246 argc--, argv++; 247 } 248 if (argc > 0) { 249 offset_block = atoi(argv[0]); 250 argc--, argv++; 251 } 252 if (argc > 0) { 253 blocks = atoi(argv[0]); 254 } 255 return load_file(file_path, offset_block, blocks); 256 } 257 258 static void free_content(resource_content *content) 259 { 260 if (content->load_addr) { 261 free(content->load_addr); 262 content->load_addr = 0; 263 } 264 } 265 266 static void tests_dump_file(const char *path, void *data, int len) 267 { 268 FILE *file = fopen(path, "wb"); 269 if (!file) 270 return; 271 fwrite(data, len, 1, file); 272 fclose(file); 273 } 274 275 static bool load_content(resource_content *content) 276 { 277 if (content->load_addr) 278 return true; 279 int blocks = fix_blocks(content->content_size); 280 content->load_addr = malloc(blocks * BLOCK_SIZE); 281 if (!content->load_addr) 282 return false; 283 if (!StorageReadLba(get_ptn_offset() + content->content_offset, 284 content->load_addr, blocks)) { 285 free_content(content); 286 return false; 287 } 288 289 tests_dump_file(content->path, content->load_addr, content->content_size); 290 return true; 291 } 292 293 static bool load_content_data(resource_content *content, int offset_block, 294 void *data, int blocks) 295 { 296 if (!StorageReadLba(get_ptn_offset() + content->content_offset + offset_block, 297 data, blocks)) { 298 return false; 299 } 300 tests_dump_file(content->path, data, blocks * BLOCK_SIZE); 301 return true; 302 } 303 304 static bool get_entry(const char *file_path, index_tbl_entry *entry) 305 { 306 bool ret = false; 307 char buf[BLOCK_SIZE]; 308 resource_ptn_header header; 309 if (!StorageReadLba(get_ptn_offset(), buf, 1)) { 310 LOGE("Failed to read header!"); 311 goto end; 312 } 313 memcpy(&header, buf, sizeof(header)); 314 315 if (memcmp(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic))) { 316 LOGE("Not a resource image(%s)!", image_path); 317 goto end; 318 } 319 /* test on pc, switch for be. */ 320 fix_header(&header); 321 322 /* TODO: support header_size & tbl_entry_size */ 323 if (header.resource_ptn_version != RESOURCE_PTN_VERSION || 324 header.header_size != RESOURCE_PTN_HDR_SIZE || 325 header.index_tbl_version != INDEX_TBL_VERSION || 326 header.tbl_entry_size != INDEX_TBL_ENTR_SIZE) { 327 LOGE("Not supported in this version!"); 328 goto end; 329 } 330 331 int i; 332 for (i = 0; i < header.tbl_entry_num; i++) { 333 /* TODO: support tbl_entry_size */ 334 if (!StorageReadLba( 335 get_ptn_offset() + header.header_size + i * header.tbl_entry_size, 336 buf, 1)) { 337 LOGE("Failed to read index entry:%d!", i); 338 goto end; 339 } 340 memcpy(entry, buf, sizeof(*entry)); 341 342 if (memcmp(entry->tag, INDEX_TBL_ENTR_TAG, sizeof(entry->tag))) { 343 LOGE("Something wrong with index entry:%d!", i); 344 goto end; 345 } 346 347 if (!strncmp(entry->path, file_path, sizeof(entry->path))) 348 break; 349 } 350 if (i == header.tbl_entry_num) { 351 LOGE("Cannot find %s!", file_path); 352 goto end; 353 } 354 /* test on pc, switch for be. */ 355 fix_entry(entry); 356 357 printf("Found entry:\n\tpath:%s\n\toffset:%d\tsize:%d\n", entry->path, 358 entry->content_offset, entry->content_size); 359 360 ret = true; 361 end: 362 return ret; 363 } 364 365 static bool get_content(resource_content *content) 366 { 367 bool ret = false; 368 index_tbl_entry entry; 369 if (!get_entry(content->path, &entry)) 370 goto end; 371 content->content_offset = entry.content_offset; 372 content->content_size = entry.content_size; 373 ret = true; 374 end: 375 return ret; 376 } 377 378 static int load_file(const char *file_path, int offset_block, int blocks) 379 { 380 printf("Try to load:%s", file_path); 381 if (blocks) { 382 printf(", offset block:%d, blocks:%d\n", offset_block, blocks); 383 } else { 384 printf("\n"); 385 } 386 bool ret = false; 387 resource_content content; 388 snprintf(content.path, sizeof(content.path), "%s", file_path); 389 content.load_addr = 0; 390 if (!get_content(&content)) { 391 goto end; 392 } 393 if (!blocks) { 394 if (!load_content(&content)) { 395 goto end; 396 } 397 } else { 398 void *data = malloc(blocks * BLOCK_SIZE); 399 if (!data) 400 goto end; 401 if (!load_content_data(&content, offset_block, data, blocks)) { 402 goto end; 403 } 404 } 405 ret = true; 406 end: 407 free_content(&content); 408 return ret; 409 } 410 411 /**********************load test end************************/ 412 /**********************anim test************************/ 413 414 static bool parse_level_conf(const char *arg, anim_level_conf *level_conf) 415 { 416 memset(level_conf, 0, sizeof(anim_level_conf)); 417 char *buf = NULL; 418 buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_CONF); 419 if (buf) { 420 level_conf->max_level = atoi(buf + strlen(OPT_CHARGE_ANIM_LEVEL_CONF)); 421 } else { 422 LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_CONF); 423 return false; 424 } 425 buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_NUM); 426 if (buf) { 427 level_conf->num = atoi(buf + strlen(OPT_CHARGE_ANIM_LEVEL_NUM)); 428 if (level_conf->num <= 0) { 429 return false; 430 } 431 } else { 432 LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_NUM); 433 return false; 434 } 435 buf = strstr(arg, OPT_CHARGE_ANIM_DELAY); 436 if (buf) { 437 level_conf->delay = atoi(buf + strlen(OPT_CHARGE_ANIM_DELAY)); 438 } 439 buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_PFX); 440 if (buf) { 441 snprintf(level_conf->prefix, sizeof(level_conf->prefix), "%s", 442 buf + strlen(OPT_CHARGE_ANIM_LEVEL_PFX)); 443 } else { 444 LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_PFX); 445 return false; 446 } 447 448 LOGD("Found conf:\nmax_level:%d, num:%d, delay:%d, prefix:%s", 449 level_conf->max_level, level_conf->num, level_conf->delay, 450 level_conf->prefix); 451 return true; 452 } 453 454 static int test_charge(int argc, char **argv) 455 { 456 const char *desc; 457 if (argc > 0) { 458 desc = argv[0]; 459 } else { 460 desc = DEF_CHARGE_DESC_PATH; 461 } 462 463 resource_content content; 464 snprintf(content.path, sizeof(content.path), "%s", desc); 465 content.load_addr = 0; 466 if (!get_content(&content)) { 467 goto end; 468 } 469 if (!load_content(&content)) { 470 goto end; 471 } 472 473 char *buf = (char *)content.load_addr; 474 char *end = buf + content.content_size - 1; 475 *end = '\0'; 476 LOGD("desc:\n%s", buf); 477 478 int pos = 0; 479 while (1) { 480 char *line = (char *)memchr(buf + pos, '\n', strlen(buf + pos)); 481 if (!line) 482 break; 483 *line = '\0'; 484 LOGD("splite:%s", buf + pos); 485 pos += (strlen(buf + pos) + 1); 486 } 487 488 int delay = 900; 489 int only_current_level = false; 490 anim_level_conf *level_confs = NULL; 491 int level_conf_pos = 0; 492 int level_conf_num = 0; 493 494 while (true) { 495 if (buf >= end) 496 break; 497 const char *arg = buf; 498 buf += (strlen(buf) + 1); 499 500 LOGD("parse arg:%s", arg); 501 if (!memcmp(arg, OPT_CHARGE_ANIM_LEVEL_CONF, 502 strlen(OPT_CHARGE_ANIM_LEVEL_CONF))) { 503 if (!level_confs) { 504 LOGE("Found level conf before levels!"); 505 goto end; 506 } 507 if (level_conf_pos >= level_conf_num) { 508 LOGE("Too many level confs!(%d >= %d)", level_conf_pos, level_conf_num); 509 goto end; 510 } 511 if (!parse_level_conf(arg, level_confs + level_conf_pos)) { 512 LOGE("Failed to parse level conf:%s", arg); 513 goto end; 514 } 515 level_conf_pos++; 516 } else if (!memcmp(arg, OPT_CHARGE_ANIM_DELAY, 517 strlen(OPT_CHARGE_ANIM_DELAY))) { 518 delay = atoi(arg + strlen(OPT_CHARGE_ANIM_DELAY)); 519 LOGD("Found delay:%d", delay); 520 } else if (!memcmp(arg, OPT_CHARGE_ANIM_LOOP_CUR, 521 strlen(OPT_CHARGE_ANIM_LOOP_CUR))) { 522 only_current_level = 523 !memcmp(arg + strlen(OPT_CHARGE_ANIM_LOOP_CUR), "true", 4); 524 LOGD("Found only_current_level:%d", only_current_level); 525 } else if (!memcmp(arg, OPT_CHARGE_ANIM_LEVELS, 526 strlen(OPT_CHARGE_ANIM_LEVELS))) { 527 if (level_conf_num) { 528 goto end; 529 } 530 level_conf_num = atoi(arg + strlen(OPT_CHARGE_ANIM_LEVELS)); 531 if (!level_conf_num) { 532 goto end; 533 } 534 level_confs = 535 (anim_level_conf *)malloc(level_conf_num * sizeof(anim_level_conf)); 536 LOGD("Found levels:%d", level_conf_num); 537 } else { 538 LOGE("Unknown arg:%s", arg); 539 goto end; 540 } 541 } 542 543 if (level_conf_pos != level_conf_num || !level_conf_num) { 544 LOGE("Something wrong with level confs!"); 545 goto end; 546 } 547 548 int i = 0, j = 0; 549 for (i = 0; i < level_conf_num; i++) { 550 if (!level_confs[i].delay) { 551 level_confs[i].delay = delay; 552 } 553 if (!level_confs[i].delay) { 554 LOGE("Missing delay in level conf:%d", i); 555 goto end; 556 } 557 for (j = 0; j < i; j++) { 558 if (level_confs[j].max_level == level_confs[i].max_level) { 559 LOGE("Dup level conf:%d", i); 560 goto end; 561 } 562 if (level_confs[j].max_level > level_confs[i].max_level) { 563 anim_level_conf conf = level_confs[i]; 564 memmove(level_confs + j + 1, level_confs + j, 565 (i - j) * sizeof(anim_level_conf)); 566 level_confs[j] = conf; 567 } 568 } 569 } 570 571 printf("Parse anim desc(%s):\n", desc); 572 printf("only_current_level=%d\n", only_current_level); 573 printf("level conf:\n"); 574 for (i = 0; i < level_conf_num; i++) { 575 printf("\tmax=%d, delay=%d, num=%d, prefix=%s\n", level_confs[i].max_level, 576 level_confs[i].delay, level_confs[i].num, level_confs[i].prefix); 577 } 578 579 end: 580 free_content(&content); 581 return 0; 582 } 583 584 /**********************anim test end************************/ 585 /**********************append file************************/ 586 587 static const char *PROG = NULL; 588 static resource_ptn_header header; 589 static bool just_print = false; 590 static char root_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0"; 591 592 static void version(void) 593 { 594 printf("%s (cjf@rock-chips.com)\t" VERSION "\n", PROG); 595 } 596 597 static void usage(void) 598 { 599 printf("Usage: %s [options] [FILES]\n", PROG); 600 printf("Tools for Rockchip's resource image.\n"); 601 version(); 602 printf("Options:\n"); 603 printf("\t" OPT_PACK "\t\t\tPack image from given files.\n"); 604 printf("\t" OPT_UNPACK "\t\tUnpack given image to current dir.\n"); 605 printf("\t" OPT_IMAGE "path" 606 "\t\tSpecify input/output image path.\n"); 607 printf("\t" OPT_PRINT "\t\t\tJust print informations.\n"); 608 printf("\t" OPT_VERBOSE "\t\tDisplay more runtime informations.\n"); 609 printf("\t" OPT_HELP "\t\t\tDisplay this information.\n"); 610 printf("\t" OPT_VERSION "\t\tDisplay version information.\n"); 611 printf("\t" OPT_ROOT "path" 612 "\t\tSpecify resources' root dir.\n"); 613 } 614 615 static int pack_image(int file_num, const char **files); 616 static int unpack_image(const char *unpack_dir); 617 618 enum ACTION { 619 ACTION_PACK, 620 ACTION_UNPACK, 621 ACTION_TEST_LOAD, 622 ACTION_TEST_CHARGE, 623 }; 624 625 int main(int argc, char **argv) 626 { 627 PROG = fix_path(argv[0]); 628 629 enum ACTION action = ACTION_PACK; 630 631 argc--, argv++; 632 while (argc > 0 && argv[0][0] == '-') { 633 /* it's a opt arg. */ 634 const char *arg = argv[0]; 635 argc--, argv++; 636 if (!strcmp(OPT_VERBOSE, arg)) { 637 g_debug = true; 638 } else if (!strcmp(OPT_HELP, arg)) { 639 usage(); 640 return 0; 641 } else if (!strcmp(OPT_VERSION, arg)) { 642 version(); 643 return 0; 644 } else if (!strcmp(OPT_PRINT, arg)) { 645 just_print = true; 646 } else if (!strcmp(OPT_PACK, arg)) { 647 action = ACTION_PACK; 648 } else if (!strcmp(OPT_UNPACK, arg)) { 649 action = ACTION_UNPACK; 650 } else if (!strcmp(OPT_TEST_LOAD, arg)) { 651 action = ACTION_TEST_LOAD; 652 } else if (!strcmp(OPT_TEST_CHARGE, arg)) { 653 action = ACTION_TEST_CHARGE; 654 } else if (!memcmp(OPT_IMAGE, arg, strlen(OPT_IMAGE))) { 655 snprintf(image_path, sizeof(image_path), "%s", arg + strlen(OPT_IMAGE)); 656 } else if (!memcmp(OPT_ROOT, arg, strlen(OPT_ROOT))) { 657 snprintf(root_path, sizeof(root_path), "%s", arg + strlen(OPT_ROOT)); 658 } else { 659 LOGE("Unknown opt:%s", arg); 660 usage(); 661 return -1; 662 } 663 } 664 665 if (!image_path[0]) { 666 snprintf(image_path, sizeof(image_path), "%s", DEFAULT_IMAGE_PATH); 667 } 668 669 switch (action) { 670 case ACTION_PACK: { 671 int file_num = argc; 672 const char **files = (const char **)argv; 673 if (!file_num) { 674 LOGE("No file to pack!"); 675 return 0; 676 } 677 LOGD("try to pack %d files.", file_num); 678 return pack_image(file_num, files); 679 } 680 case ACTION_UNPACK: { 681 return unpack_image(argc > 0 ? argv[0] : DEFAULT_UNPACK_DIR); 682 } 683 case ACTION_TEST_LOAD: { 684 return test_load(argc, argv); 685 } 686 case ACTION_TEST_CHARGE: { 687 return test_charge(argc, argv); 688 } 689 } 690 /* not reach here. */ 691 return -1; 692 } 693 694 /************unpack code****************/ 695 static bool mkdirs(char *path) 696 { 697 char *tmp = path; 698 char *pos = NULL; 699 char buf[MAX_INDEX_ENTRY_PATH_LEN]; 700 bool ret = true; 701 while ((pos = memchr(tmp, '/', strlen(tmp)))) { 702 strcpy(buf, path); 703 buf[pos - path] = '\0'; 704 tmp = pos + 1; 705 LOGD("mkdir:%s", buf); 706 if (!mkdir(buf, 0755)) { 707 ret = false; 708 } 709 } 710 if (!ret) 711 LOGD("Failed to mkdir(%s)!", path); 712 return ret; 713 } 714 715 static bool dump_file(FILE *file, const char *unpack_dir, 716 index_tbl_entry entry) 717 { 718 LOGD("try to dump entry:%s", entry.path); 719 bool ret = false; 720 FILE *out_file = NULL; 721 long int pos = 0; 722 char path[MAX_INDEX_ENTRY_PATH_LEN * 2 + 1]; 723 if (just_print) { 724 ret = true; 725 goto done; 726 } 727 728 pos = ftell(file); 729 snprintf(path, sizeof(path), "%s/%s", unpack_dir, entry.path); 730 mkdirs(path); 731 out_file = fopen(path, "wb"); 732 if (!out_file) { 733 LOGE("Failed to create:%s", path); 734 goto end; 735 } 736 long int offset = entry.content_offset * BLOCK_SIZE; 737 fseek(file, offset, SEEK_SET); 738 if (offset != ftell(file)) { 739 LOGE("Failed to read content:%s", entry.path); 740 goto end; 741 } 742 char buf[BLOCK_SIZE]; 743 int n; 744 int len = entry.content_size; 745 while (len > 0) { 746 n = len > BLOCK_SIZE ? BLOCK_SIZE : len; 747 if (!fread(buf, n, 1, file)) { 748 LOGE("Failed to read content:%s", entry.path); 749 goto end; 750 } 751 if (!fwrite(buf, n, 1, out_file)) { 752 LOGE("Failed to write:%s", entry.path); 753 goto end; 754 } 755 len -= n; 756 } 757 done: 758 ret = true; 759 end: 760 if (out_file) 761 fclose(out_file); 762 if (pos) 763 fseek(file, pos, SEEK_SET); 764 return ret; 765 } 766 767 static int unpack_image(const char *dir) 768 { 769 FILE *image_file = NULL; 770 bool ret = false; 771 char unpack_dir[MAX_INDEX_ENTRY_PATH_LEN]; 772 if (just_print) 773 dir = "."; 774 snprintf(unpack_dir, sizeof(unpack_dir), "%s", dir); 775 if (!strlen(unpack_dir)) { 776 goto end; 777 } else if (unpack_dir[strlen(unpack_dir) - 1] == '/') { 778 unpack_dir[strlen(unpack_dir) - 1] = '\0'; 779 } 780 781 mkdir(unpack_dir, 0755); 782 image_file = fopen(image_path, "rb"); 783 char buf[BLOCK_SIZE]; 784 if (!image_file) { 785 LOGE("Failed to open:%s", image_path); 786 goto end; 787 } 788 if (!fread(buf, BLOCK_SIZE, 1, image_file)) { 789 LOGE("Failed to read header!"); 790 goto end; 791 } 792 memcpy(&header, buf, sizeof(header)); 793 794 if (memcmp(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic))) { 795 LOGE("Not a resource image(%s)!", image_path); 796 goto end; 797 } 798 /* switch for be. */ 799 fix_header(&header); 800 801 printf("Dump header:\n"); 802 printf("partition version:%d.%d\n", header.resource_ptn_version, 803 header.index_tbl_version); 804 printf("header size:%d\n", header.header_size); 805 printf("index tbl:\n\toffset:%d\tentry size:%d\tentry num:%d\n", 806 header.tbl_offset, header.tbl_entry_size, header.tbl_entry_num); 807 808 /* TODO: support header_size & tbl_entry_size */ 809 if (header.resource_ptn_version != RESOURCE_PTN_VERSION || 810 header.header_size != RESOURCE_PTN_HDR_SIZE || 811 header.index_tbl_version != INDEX_TBL_VERSION || 812 header.tbl_entry_size != INDEX_TBL_ENTR_SIZE) { 813 LOGE("Not supported in this version!"); 814 goto end; 815 } 816 817 printf("Dump Index table:\n"); 818 index_tbl_entry entry; 819 int i; 820 for (i = 0; i < header.tbl_entry_num; i++) { 821 /* TODO: support tbl_entry_size */ 822 if (!fread(buf, BLOCK_SIZE, 1, image_file)) { 823 LOGE("Failed to read index entry:%d!", i); 824 goto end; 825 } 826 memcpy(&entry, buf, sizeof(entry)); 827 828 if (memcmp(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag))) { 829 LOGE("Something wrong with index entry:%d!", i); 830 goto end; 831 } 832 /* switch for be. */ 833 fix_entry(&entry); 834 835 printf("entry(%d):\n\tpath:%s\n\toffset:%d\tsize:%d\n", i, entry.path, 836 entry.content_offset, entry.content_size); 837 if (!dump_file(image_file, unpack_dir, entry)) { 838 goto end; 839 } 840 } 841 printf("Unack %s to %s successed!\n", image_path, unpack_dir); 842 ret = true; 843 end: 844 if (image_file) 845 fclose(image_file); 846 return ret ? 0 : -1; 847 } 848 849 /************unpack code end****************/ 850 /************pack code****************/ 851 852 static inline size_t get_file_size(const char *path) 853 { 854 LOGD("try to get size(%s)...", path); 855 struct stat st; 856 if (stat(path, &st) < 0) { 857 LOGE("Failed to get size:%s", path); 858 return -1; 859 } 860 LOGD("path:%s, size:%ld", path, st.st_size); 861 return st.st_size; 862 } 863 864 static int write_file(int offset_block, const char *src_path, 865 char hash[], int hash_size) 866 { 867 LOGD("try to write file(%s) to offset:%d...", src_path, offset_block); 868 char *buf = NULL; 869 int ret = -1; 870 size_t file_size; 871 FILE *src_file = fopen(src_path, "rb"); 872 if (!src_file) { 873 LOGE("Failed to open:%s", src_path); 874 goto end; 875 } 876 877 file_size = get_file_size(src_path); 878 if (file_size < 0) { 879 goto end; 880 } 881 882 buf = calloc(file_size, 1); 883 if (!buf) 884 goto end; 885 886 if (!fread(buf, file_size, 1, src_file)) 887 goto end; 888 889 if (!write_data(offset_block, buf, file_size)) 890 goto end; 891 892 if (hash_size == 20) 893 sha1_csum((const unsigned char *)buf, file_size, 894 (unsigned char *)hash); 895 else if (hash_size == 32) 896 sha256_csum((const unsigned char *)buf, file_size, 897 (unsigned char *)hash); 898 else 899 goto end; 900 901 ret = file_size; 902 end: 903 if (src_file) 904 fclose(src_file); 905 if (buf) 906 free(buf); 907 908 return ret; 909 } 910 911 static bool write_header(const int file_num) 912 { 913 LOGD("try to write header..."); 914 memcpy(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic)); 915 header.resource_ptn_version = RESOURCE_PTN_VERSION; 916 header.index_tbl_version = INDEX_TBL_VERSION; 917 header.header_size = RESOURCE_PTN_HDR_SIZE; 918 header.tbl_offset = header.header_size; 919 header.tbl_entry_size = INDEX_TBL_ENTR_SIZE; 920 header.tbl_entry_num = file_num; 921 922 /* switch for le. */ 923 resource_ptn_header hdr = header; 924 fix_header(&hdr); 925 return write_data(0, &hdr, sizeof(hdr)); 926 } 927 928 static bool write_index_tbl(const int file_num, const char **files) 929 { 930 LOGD("try to write index table..."); 931 bool ret = false; 932 bool foundFdt = false; 933 int offset = 934 header.header_size + header.tbl_entry_size * header.tbl_entry_num; 935 index_tbl_entry entry; 936 char hash[20]; /* sha1 */ 937 int i; 938 939 memcpy(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag)); 940 for (i = 0; i < file_num; i++) { 941 size_t file_size = get_file_size(files[i]); 942 if (file_size < 0) 943 goto end; 944 entry.content_size = file_size; 945 entry.content_offset = offset; 946 947 if (write_file(offset, files[i], hash, sizeof(hash)) < 0) 948 goto end; 949 950 memcpy(entry.hash, hash, sizeof(hash)); 951 entry.hash_size = sizeof(hash); 952 953 LOGD("try to write index entry(%s)...", files[i]); 954 955 /* switch for le. */ 956 fix_entry(&entry); 957 memset(entry.path, 0, sizeof(entry.path)); 958 const char *path = files[i]; 959 if (root_path[0]) { 960 if (!strncmp(path, root_path, strlen(root_path))) { 961 path += strlen(root_path); 962 if (path[0] == '/') 963 path++; 964 } 965 } 966 path = fix_path(path); 967 if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX), DTD_SUBFIX)) { 968 if (!foundFdt) { 969 /* use default path. */ 970 LOGD("mod fdt path:%s -> %s...", files[i], FDT_PATH); 971 path = FDT_PATH; 972 foundFdt = true; 973 } 974 } 975 snprintf(entry.path, sizeof(entry.path), "%s", path); 976 offset += fix_blocks(file_size); 977 if (!write_data(header.header_size + i * header.tbl_entry_size, &entry, 978 sizeof(entry))) 979 goto end; 980 } 981 ret = true; 982 end: 983 return ret; 984 } 985 986 static int pack_image(int file_num, const char **files) 987 { 988 bool ret = false; 989 FILE *image_file = fopen(image_path, "wb"); 990 if (!image_file) { 991 LOGE("Failed to create:%s", image_path); 992 goto end; 993 } 994 fclose(image_file); 995 996 /* prepare files */ 997 int i = 0; 998 int pos = 0; 999 const char *tmp; 1000 for (i = 0; i < file_num; i++) { 1001 if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX), DTD_SUBFIX)) { 1002 /* dtb files for kernel. */ 1003 tmp = files[pos]; 1004 files[pos] = files[i]; 1005 files[i] = tmp; 1006 pos++; 1007 } else if (!strcmp(fix_path(image_path), fix_path(files[i]))) { 1008 /* not to pack image itself! */ 1009 tmp = files[file_num - 1]; 1010 files[file_num - 1] = files[i]; 1011 files[i] = tmp; 1012 file_num--; 1013 } 1014 } 1015 1016 if (!write_header(file_num)) { 1017 LOGE("Failed to write header!"); 1018 goto end; 1019 } 1020 if (!write_index_tbl(file_num, files)) { 1021 LOGE("Failed to write index table!"); 1022 goto end; 1023 } 1024 printf("Pack to %s successed!\n", image_path); 1025 ret = true; 1026 end: 1027 return ret ? 0 : -1; 1028 } 1029 1030 /************pack code end****************/ 1031