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