123ba6841SJoseph Chen // SPDX-License-Identifier: GPL-2.0+ 223ba6841SJoseph Chen /* 323ba6841SJoseph Chen * (C) Copyright 2008-2015 Fuzhou Rockchip Electronics Co., Ltd 423ba6841SJoseph Chen */ 523ba6841SJoseph Chen 623ba6841SJoseph Chen #include <errno.h> 723ba6841SJoseph Chen #include <memory.h> 823ba6841SJoseph Chen #include <stdint.h> 923ba6841SJoseph Chen #include <stdio.h> 1023ba6841SJoseph Chen #include <stdlib.h> 1123ba6841SJoseph Chen #include <stdbool.h> 1223ba6841SJoseph Chen #include <sys/stat.h> 1323ba6841SJoseph Chen #include <time.h> 14*5e817a0eSJoseph Chen #include <u-boot/sha1.h> 15*5e817a0eSJoseph Chen #include <u-boot/sha256.h> 1623ba6841SJoseph Chen 1723ba6841SJoseph Chen /* #define DEBUG */ 1823ba6841SJoseph Chen 1923ba6841SJoseph Chen static bool g_debug = 2023ba6841SJoseph Chen #ifdef DEBUG 2123ba6841SJoseph Chen true; 2223ba6841SJoseph Chen #else 2323ba6841SJoseph Chen false; 2423ba6841SJoseph Chen #endif /* DEBUG */ 2523ba6841SJoseph Chen 2623ba6841SJoseph Chen #define LOGE(fmt, args...) \ 2723ba6841SJoseph Chen fprintf(stderr, "E/%s(%d): " fmt "\n", __func__, __LINE__, ##args) 2823ba6841SJoseph Chen #define LOGD(fmt, args...) \ 2923ba6841SJoseph Chen do { \ 3023ba6841SJoseph Chen if (g_debug) \ 3123ba6841SJoseph Chen fprintf(stderr, "D/%s(%d): " fmt "\n", __func__, __LINE__, ##args); \ 3223ba6841SJoseph Chen } while (0) 3323ba6841SJoseph Chen 3423ba6841SJoseph Chen /* sync with ./board/rockchip/rk30xx/rkloader.c #define FDT_PATH */ 3523ba6841SJoseph Chen #define FDT_PATH "rk-kernel.dtb" 3623ba6841SJoseph Chen #define DTD_SUBFIX ".dtb" 3723ba6841SJoseph Chen 3823ba6841SJoseph Chen #define DEFAULT_IMAGE_PATH "resource.img" 3923ba6841SJoseph Chen #define DEFAULT_UNPACK_DIR "out" 4023ba6841SJoseph Chen #define BLOCK_SIZE 512 4123ba6841SJoseph Chen 4223ba6841SJoseph Chen #define RESOURCE_PTN_HDR_SIZE 1 4323ba6841SJoseph Chen #define INDEX_TBL_ENTR_SIZE 1 4423ba6841SJoseph Chen 4523ba6841SJoseph Chen #define RESOURCE_PTN_VERSION 0 4623ba6841SJoseph Chen #define INDEX_TBL_VERSION 0 4723ba6841SJoseph Chen 4823ba6841SJoseph Chen #define RESOURCE_PTN_HDR_MAGIC "RSCE" 4923ba6841SJoseph Chen typedef struct { 5023ba6841SJoseph Chen char magic[4]; /* tag, "RSCE" */ 5123ba6841SJoseph Chen uint16_t resource_ptn_version; 5223ba6841SJoseph Chen uint16_t index_tbl_version; 5323ba6841SJoseph Chen uint8_t header_size; /* blocks, size of ptn header. */ 5423ba6841SJoseph Chen uint8_t tbl_offset; /* blocks, offset of index table. */ 5523ba6841SJoseph Chen uint8_t tbl_entry_size; /* blocks, size of index table's entry. */ 5623ba6841SJoseph Chen uint32_t tbl_entry_num; /* numbers of index table's entry. */ 5723ba6841SJoseph Chen } resource_ptn_header; 5823ba6841SJoseph Chen 5923ba6841SJoseph Chen #define INDEX_TBL_ENTR_TAG "ENTR" 60*5e817a0eSJoseph Chen #define MAX_INDEX_ENTRY_PATH_LEN 220 61*5e817a0eSJoseph Chen #define MAX_HASH_LEN 32 62*5e817a0eSJoseph Chen 6323ba6841SJoseph Chen typedef struct { 6423ba6841SJoseph Chen char tag[4]; /* tag, "ENTR" */ 6523ba6841SJoseph Chen char path[MAX_INDEX_ENTRY_PATH_LEN]; 66*5e817a0eSJoseph Chen char hash[MAX_HASH_LEN]; /* hash data */ 67*5e817a0eSJoseph Chen uint32_t hash_size; /* 20 or 32 */ 6823ba6841SJoseph Chen uint32_t content_offset; /* blocks, offset of resource content. */ 6923ba6841SJoseph Chen uint32_t content_size; /* bytes, size of resource content. */ 7023ba6841SJoseph Chen } index_tbl_entry; 7123ba6841SJoseph Chen 7223ba6841SJoseph Chen #define OPT_VERBOSE "--verbose" 7323ba6841SJoseph Chen #define OPT_HELP "--help" 7423ba6841SJoseph Chen #define OPT_VERSION "--version" 7523ba6841SJoseph Chen #define OPT_PRINT "--print" 7623ba6841SJoseph Chen #define OPT_PACK "--pack" 7723ba6841SJoseph Chen #define OPT_UNPACK "--unpack" 7823ba6841SJoseph Chen #define OPT_TEST_LOAD "--test_load" 7923ba6841SJoseph Chen #define OPT_TEST_CHARGE "--test_charge" 8023ba6841SJoseph Chen #define OPT_IMAGE "--image=" 8123ba6841SJoseph Chen #define OPT_ROOT "--root=" 8223ba6841SJoseph Chen 8323ba6841SJoseph Chen #define VERSION "2014-5-31 14:43:42" 8423ba6841SJoseph Chen 8523ba6841SJoseph Chen typedef struct { 8623ba6841SJoseph Chen char path[MAX_INDEX_ENTRY_PATH_LEN]; 8723ba6841SJoseph Chen uint32_t content_offset; /* blocks, offset of resource content. */ 8823ba6841SJoseph Chen uint32_t content_size; /* bytes, size of resource content. */ 8923ba6841SJoseph Chen void *load_addr; 9023ba6841SJoseph Chen } resource_content; 9123ba6841SJoseph Chen 9223ba6841SJoseph Chen typedef struct { 9323ba6841SJoseph Chen int max_level; 9423ba6841SJoseph Chen int num; 9523ba6841SJoseph Chen int delay; 9623ba6841SJoseph Chen char prefix[MAX_INDEX_ENTRY_PATH_LEN]; 9723ba6841SJoseph Chen } anim_level_conf; 9823ba6841SJoseph Chen 9923ba6841SJoseph Chen #define DEF_CHARGE_DESC_PATH "charge_anim_desc.txt" 10023ba6841SJoseph Chen 10123ba6841SJoseph Chen #define OPT_CHARGE_ANIM_DELAY "delay=" 10223ba6841SJoseph Chen #define OPT_CHARGE_ANIM_LOOP_CUR "only_current_level=" 10323ba6841SJoseph Chen #define OPT_CHARGE_ANIM_LEVELS "levels=" 10423ba6841SJoseph Chen #define OPT_CHARGE_ANIM_LEVEL_CONF "max_level=" 10523ba6841SJoseph Chen #define OPT_CHARGE_ANIM_LEVEL_NUM "num=" 10623ba6841SJoseph Chen #define OPT_CHARGE_ANIM_LEVEL_PFX "prefix=" 10723ba6841SJoseph Chen 10823ba6841SJoseph Chen static char image_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0"; 10923ba6841SJoseph Chen 11023ba6841SJoseph Chen static int fix_blocks(size_t size) 11123ba6841SJoseph Chen { 11223ba6841SJoseph Chen return (size + BLOCK_SIZE - 1) / BLOCK_SIZE; 11323ba6841SJoseph Chen } 11423ba6841SJoseph Chen 11523ba6841SJoseph Chen static const char *fix_path(const char *path) 11623ba6841SJoseph Chen { 11723ba6841SJoseph Chen if (!memcmp(path, "./", 2)) { 11823ba6841SJoseph Chen return path + 2; 11923ba6841SJoseph Chen } 12023ba6841SJoseph Chen return path; 12123ba6841SJoseph Chen } 12223ba6841SJoseph Chen 12323ba6841SJoseph Chen static uint16_t switch_short(uint16_t x) 12423ba6841SJoseph Chen { 12523ba6841SJoseph Chen uint16_t val; 12623ba6841SJoseph Chen uint8_t *p = (uint8_t *)(&x); 12723ba6841SJoseph Chen 12823ba6841SJoseph Chen val = (*p++ & 0xff) << 0; 12923ba6841SJoseph Chen val |= (*p & 0xff) << 8; 13023ba6841SJoseph Chen 13123ba6841SJoseph Chen return val; 13223ba6841SJoseph Chen } 13323ba6841SJoseph Chen 13423ba6841SJoseph Chen static uint32_t switch_int(uint32_t x) 13523ba6841SJoseph Chen { 13623ba6841SJoseph Chen uint32_t val; 13723ba6841SJoseph Chen uint8_t *p = (uint8_t *)(&x); 13823ba6841SJoseph Chen 13923ba6841SJoseph Chen val = (*p++ & 0xff) << 0; 14023ba6841SJoseph Chen val |= (*p++ & 0xff) << 8; 14123ba6841SJoseph Chen val |= (*p++ & 0xff) << 16; 14223ba6841SJoseph Chen val |= (*p & 0xff) << 24; 14323ba6841SJoseph Chen 14423ba6841SJoseph Chen return val; 14523ba6841SJoseph Chen } 14623ba6841SJoseph Chen 14723ba6841SJoseph Chen static void fix_header(resource_ptn_header *header) 14823ba6841SJoseph Chen { 14923ba6841SJoseph Chen /* switch for be. */ 15023ba6841SJoseph Chen header->resource_ptn_version = switch_short(header->resource_ptn_version); 15123ba6841SJoseph Chen header->index_tbl_version = switch_short(header->index_tbl_version); 15223ba6841SJoseph Chen header->tbl_entry_num = switch_int(header->tbl_entry_num); 15323ba6841SJoseph Chen } 15423ba6841SJoseph Chen 15523ba6841SJoseph Chen static void fix_entry(index_tbl_entry *entry) 15623ba6841SJoseph Chen { 15723ba6841SJoseph Chen /* switch for be. */ 15823ba6841SJoseph Chen entry->content_offset = switch_int(entry->content_offset); 15923ba6841SJoseph Chen entry->content_size = switch_int(entry->content_size); 16023ba6841SJoseph Chen } 16123ba6841SJoseph Chen 16223ba6841SJoseph Chen static int inline get_ptn_offset(void) 16323ba6841SJoseph Chen { 16423ba6841SJoseph Chen return 0; 16523ba6841SJoseph Chen } 16623ba6841SJoseph Chen 16723ba6841SJoseph Chen static bool StorageWriteLba(int offset_block, void *data, int blocks) 16823ba6841SJoseph Chen { 16923ba6841SJoseph Chen bool ret = false; 17023ba6841SJoseph Chen FILE *file = fopen(image_path, "rb+"); 17123ba6841SJoseph Chen if (!file) 17223ba6841SJoseph Chen goto end; 17323ba6841SJoseph Chen int offset = offset_block * BLOCK_SIZE; 17423ba6841SJoseph Chen fseek(file, offset, SEEK_SET); 17523ba6841SJoseph Chen if (offset != ftell(file)) { 17623ba6841SJoseph Chen LOGE("Failed to seek %s to %d!", image_path, offset); 17723ba6841SJoseph Chen goto end; 17823ba6841SJoseph Chen } 17923ba6841SJoseph Chen if (!fwrite(data, blocks * BLOCK_SIZE, 1, file)) { 18023ba6841SJoseph Chen LOGE("Failed to write %s!", image_path); 18123ba6841SJoseph Chen goto end; 18223ba6841SJoseph Chen } 18323ba6841SJoseph Chen ret = true; 18423ba6841SJoseph Chen end: 18523ba6841SJoseph Chen if (file) 18623ba6841SJoseph Chen fclose(file); 18723ba6841SJoseph Chen return ret; 18823ba6841SJoseph Chen } 18923ba6841SJoseph Chen 19023ba6841SJoseph Chen static bool StorageReadLba(int offset_block, void *data, int blocks) 19123ba6841SJoseph Chen { 19223ba6841SJoseph Chen bool ret = false; 19323ba6841SJoseph Chen FILE *file = fopen(image_path, "rb"); 19423ba6841SJoseph Chen if (!file) 19523ba6841SJoseph Chen goto end; 19623ba6841SJoseph Chen int offset = offset_block * BLOCK_SIZE; 19723ba6841SJoseph Chen fseek(file, offset, SEEK_SET); 19823ba6841SJoseph Chen if (offset != ftell(file)) { 19923ba6841SJoseph Chen goto end; 20023ba6841SJoseph Chen } 20123ba6841SJoseph Chen if (!fread(data, blocks * BLOCK_SIZE, 1, file)) { 20223ba6841SJoseph Chen goto end; 20323ba6841SJoseph Chen } 20423ba6841SJoseph Chen ret = true; 20523ba6841SJoseph Chen end: 20623ba6841SJoseph Chen if (file) 20723ba6841SJoseph Chen fclose(file); 20823ba6841SJoseph Chen return ret; 20923ba6841SJoseph Chen } 21023ba6841SJoseph Chen 21123ba6841SJoseph Chen static bool write_data(int offset_block, void *data, size_t len) 21223ba6841SJoseph Chen { 21323ba6841SJoseph Chen bool ret = false; 21423ba6841SJoseph Chen if (!data) 21523ba6841SJoseph Chen goto end; 21623ba6841SJoseph Chen int blocks = len / BLOCK_SIZE; 21723ba6841SJoseph Chen if (blocks && !StorageWriteLba(offset_block, data, blocks)) { 21823ba6841SJoseph Chen goto end; 21923ba6841SJoseph Chen } 22023ba6841SJoseph Chen int left = len % BLOCK_SIZE; 22123ba6841SJoseph Chen if (left) { 22223ba6841SJoseph Chen char buf[BLOCK_SIZE] = "\0"; 22323ba6841SJoseph Chen memcpy(buf, data + blocks * BLOCK_SIZE, left); 22423ba6841SJoseph Chen if (!StorageWriteLba(offset_block + blocks, buf, 1)) 22523ba6841SJoseph Chen goto end; 22623ba6841SJoseph Chen } 22723ba6841SJoseph Chen ret = true; 22823ba6841SJoseph Chen end: 22923ba6841SJoseph Chen return ret; 23023ba6841SJoseph Chen } 23123ba6841SJoseph Chen 23223ba6841SJoseph Chen /**********************load test************************/ 23323ba6841SJoseph Chen static int load_file(const char *file_path, int offset_block, int blocks); 23423ba6841SJoseph Chen 23523ba6841SJoseph Chen static int test_load(int argc, char **argv) 23623ba6841SJoseph Chen { 23723ba6841SJoseph Chen if (argc < 1) { 23823ba6841SJoseph Chen LOGE("Nothing to load!"); 23923ba6841SJoseph Chen return -1; 24023ba6841SJoseph Chen } 24123ba6841SJoseph Chen const char *file_path; 24223ba6841SJoseph Chen int offset_block = 0; 24323ba6841SJoseph Chen int blocks = 0; 24423ba6841SJoseph Chen if (argc > 0) { 24523ba6841SJoseph Chen file_path = (const char *)fix_path(argv[0]); 24623ba6841SJoseph Chen argc--, argv++; 24723ba6841SJoseph Chen } 24823ba6841SJoseph Chen if (argc > 0) { 24923ba6841SJoseph Chen offset_block = atoi(argv[0]); 25023ba6841SJoseph Chen argc--, argv++; 25123ba6841SJoseph Chen } 25223ba6841SJoseph Chen if (argc > 0) { 25323ba6841SJoseph Chen blocks = atoi(argv[0]); 25423ba6841SJoseph Chen } 25523ba6841SJoseph Chen return load_file(file_path, offset_block, blocks); 25623ba6841SJoseph Chen } 25723ba6841SJoseph Chen 25823ba6841SJoseph Chen static void free_content(resource_content *content) 25923ba6841SJoseph Chen { 26023ba6841SJoseph Chen if (content->load_addr) { 26123ba6841SJoseph Chen free(content->load_addr); 26223ba6841SJoseph Chen content->load_addr = 0; 26323ba6841SJoseph Chen } 26423ba6841SJoseph Chen } 26523ba6841SJoseph Chen 26623ba6841SJoseph Chen static void tests_dump_file(const char *path, void *data, int len) 26723ba6841SJoseph Chen { 26823ba6841SJoseph Chen FILE *file = fopen(path, "wb"); 26923ba6841SJoseph Chen if (!file) 27023ba6841SJoseph Chen return; 27123ba6841SJoseph Chen fwrite(data, len, 1, file); 27223ba6841SJoseph Chen fclose(file); 27323ba6841SJoseph Chen } 27423ba6841SJoseph Chen 27523ba6841SJoseph Chen static bool load_content(resource_content *content) 27623ba6841SJoseph Chen { 27723ba6841SJoseph Chen if (content->load_addr) 27823ba6841SJoseph Chen return true; 27923ba6841SJoseph Chen int blocks = fix_blocks(content->content_size); 28023ba6841SJoseph Chen content->load_addr = malloc(blocks * BLOCK_SIZE); 28123ba6841SJoseph Chen if (!content->load_addr) 28223ba6841SJoseph Chen return false; 28323ba6841SJoseph Chen if (!StorageReadLba(get_ptn_offset() + content->content_offset, 28423ba6841SJoseph Chen content->load_addr, blocks)) { 28523ba6841SJoseph Chen free_content(content); 28623ba6841SJoseph Chen return false; 28723ba6841SJoseph Chen } 28823ba6841SJoseph Chen 28923ba6841SJoseph Chen tests_dump_file(content->path, content->load_addr, content->content_size); 29023ba6841SJoseph Chen return true; 29123ba6841SJoseph Chen } 29223ba6841SJoseph Chen 29323ba6841SJoseph Chen static bool load_content_data(resource_content *content, int offset_block, 29423ba6841SJoseph Chen void *data, int blocks) 29523ba6841SJoseph Chen { 29623ba6841SJoseph Chen if (!StorageReadLba(get_ptn_offset() + content->content_offset + offset_block, 29723ba6841SJoseph Chen data, blocks)) { 29823ba6841SJoseph Chen return false; 29923ba6841SJoseph Chen } 30023ba6841SJoseph Chen tests_dump_file(content->path, data, blocks * BLOCK_SIZE); 30123ba6841SJoseph Chen return true; 30223ba6841SJoseph Chen } 30323ba6841SJoseph Chen 30423ba6841SJoseph Chen static bool get_entry(const char *file_path, index_tbl_entry *entry) 30523ba6841SJoseph Chen { 30623ba6841SJoseph Chen bool ret = false; 30723ba6841SJoseph Chen char buf[BLOCK_SIZE]; 30823ba6841SJoseph Chen resource_ptn_header header; 30923ba6841SJoseph Chen if (!StorageReadLba(get_ptn_offset(), buf, 1)) { 31023ba6841SJoseph Chen LOGE("Failed to read header!"); 31123ba6841SJoseph Chen goto end; 31223ba6841SJoseph Chen } 31323ba6841SJoseph Chen memcpy(&header, buf, sizeof(header)); 31423ba6841SJoseph Chen 31523ba6841SJoseph Chen if (memcmp(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic))) { 31623ba6841SJoseph Chen LOGE("Not a resource image(%s)!", image_path); 31723ba6841SJoseph Chen goto end; 31823ba6841SJoseph Chen } 31923ba6841SJoseph Chen /* test on pc, switch for be. */ 32023ba6841SJoseph Chen fix_header(&header); 32123ba6841SJoseph Chen 32223ba6841SJoseph Chen /* TODO: support header_size & tbl_entry_size */ 32323ba6841SJoseph Chen if (header.resource_ptn_version != RESOURCE_PTN_VERSION || 32423ba6841SJoseph Chen header.header_size != RESOURCE_PTN_HDR_SIZE || 32523ba6841SJoseph Chen header.index_tbl_version != INDEX_TBL_VERSION || 32623ba6841SJoseph Chen header.tbl_entry_size != INDEX_TBL_ENTR_SIZE) { 32723ba6841SJoseph Chen LOGE("Not supported in this version!"); 32823ba6841SJoseph Chen goto end; 32923ba6841SJoseph Chen } 33023ba6841SJoseph Chen 33123ba6841SJoseph Chen int i; 33223ba6841SJoseph Chen for (i = 0; i < header.tbl_entry_num; i++) { 33323ba6841SJoseph Chen /* TODO: support tbl_entry_size */ 33423ba6841SJoseph Chen if (!StorageReadLba( 33523ba6841SJoseph Chen get_ptn_offset() + header.header_size + i * header.tbl_entry_size, 33623ba6841SJoseph Chen buf, 1)) { 33723ba6841SJoseph Chen LOGE("Failed to read index entry:%d!", i); 33823ba6841SJoseph Chen goto end; 33923ba6841SJoseph Chen } 34023ba6841SJoseph Chen memcpy(entry, buf, sizeof(*entry)); 34123ba6841SJoseph Chen 34223ba6841SJoseph Chen if (memcmp(entry->tag, INDEX_TBL_ENTR_TAG, sizeof(entry->tag))) { 34323ba6841SJoseph Chen LOGE("Something wrong with index entry:%d!", i); 34423ba6841SJoseph Chen goto end; 34523ba6841SJoseph Chen } 34623ba6841SJoseph Chen 34723ba6841SJoseph Chen if (!strncmp(entry->path, file_path, sizeof(entry->path))) 34823ba6841SJoseph Chen break; 34923ba6841SJoseph Chen } 35023ba6841SJoseph Chen if (i == header.tbl_entry_num) { 35123ba6841SJoseph Chen LOGE("Cannot find %s!", file_path); 35223ba6841SJoseph Chen goto end; 35323ba6841SJoseph Chen } 35423ba6841SJoseph Chen /* test on pc, switch for be. */ 35523ba6841SJoseph Chen fix_entry(entry); 35623ba6841SJoseph Chen 35723ba6841SJoseph Chen printf("Found entry:\n\tpath:%s\n\toffset:%d\tsize:%d\n", entry->path, 35823ba6841SJoseph Chen entry->content_offset, entry->content_size); 35923ba6841SJoseph Chen 36023ba6841SJoseph Chen ret = true; 36123ba6841SJoseph Chen end: 36223ba6841SJoseph Chen return ret; 36323ba6841SJoseph Chen } 36423ba6841SJoseph Chen 36523ba6841SJoseph Chen static bool get_content(resource_content *content) 36623ba6841SJoseph Chen { 36723ba6841SJoseph Chen bool ret = false; 36823ba6841SJoseph Chen index_tbl_entry entry; 36923ba6841SJoseph Chen if (!get_entry(content->path, &entry)) 37023ba6841SJoseph Chen goto end; 37123ba6841SJoseph Chen content->content_offset = entry.content_offset; 37223ba6841SJoseph Chen content->content_size = entry.content_size; 37323ba6841SJoseph Chen ret = true; 37423ba6841SJoseph Chen end: 37523ba6841SJoseph Chen return ret; 37623ba6841SJoseph Chen } 37723ba6841SJoseph Chen 37823ba6841SJoseph Chen static int load_file(const char *file_path, int offset_block, int blocks) 37923ba6841SJoseph Chen { 38023ba6841SJoseph Chen printf("Try to load:%s", file_path); 38123ba6841SJoseph Chen if (blocks) { 38223ba6841SJoseph Chen printf(", offset block:%d, blocks:%d\n", offset_block, blocks); 38323ba6841SJoseph Chen } else { 38423ba6841SJoseph Chen printf("\n"); 38523ba6841SJoseph Chen } 38623ba6841SJoseph Chen bool ret = false; 38723ba6841SJoseph Chen resource_content content; 38823ba6841SJoseph Chen snprintf(content.path, sizeof(content.path), "%s", file_path); 38923ba6841SJoseph Chen content.load_addr = 0; 39023ba6841SJoseph Chen if (!get_content(&content)) { 39123ba6841SJoseph Chen goto end; 39223ba6841SJoseph Chen } 39323ba6841SJoseph Chen if (!blocks) { 39423ba6841SJoseph Chen if (!load_content(&content)) { 39523ba6841SJoseph Chen goto end; 39623ba6841SJoseph Chen } 39723ba6841SJoseph Chen } else { 39823ba6841SJoseph Chen void *data = malloc(blocks * BLOCK_SIZE); 39923ba6841SJoseph Chen if (!data) 40023ba6841SJoseph Chen goto end; 40123ba6841SJoseph Chen if (!load_content_data(&content, offset_block, data, blocks)) { 40223ba6841SJoseph Chen goto end; 40323ba6841SJoseph Chen } 40423ba6841SJoseph Chen } 40523ba6841SJoseph Chen ret = true; 40623ba6841SJoseph Chen end: 40723ba6841SJoseph Chen free_content(&content); 40823ba6841SJoseph Chen return ret; 40923ba6841SJoseph Chen } 41023ba6841SJoseph Chen 41123ba6841SJoseph Chen /**********************load test end************************/ 41223ba6841SJoseph Chen /**********************anim test************************/ 41323ba6841SJoseph Chen 41423ba6841SJoseph Chen static bool parse_level_conf(const char *arg, anim_level_conf *level_conf) 41523ba6841SJoseph Chen { 41623ba6841SJoseph Chen memset(level_conf, 0, sizeof(anim_level_conf)); 41723ba6841SJoseph Chen char *buf = NULL; 41823ba6841SJoseph Chen buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_CONF); 41923ba6841SJoseph Chen if (buf) { 42023ba6841SJoseph Chen level_conf->max_level = atoi(buf + strlen(OPT_CHARGE_ANIM_LEVEL_CONF)); 42123ba6841SJoseph Chen } else { 42223ba6841SJoseph Chen LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_CONF); 42323ba6841SJoseph Chen return false; 42423ba6841SJoseph Chen } 42523ba6841SJoseph Chen buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_NUM); 42623ba6841SJoseph Chen if (buf) { 42723ba6841SJoseph Chen level_conf->num = atoi(buf + strlen(OPT_CHARGE_ANIM_LEVEL_NUM)); 42823ba6841SJoseph Chen if (level_conf->num <= 0) { 42923ba6841SJoseph Chen return false; 43023ba6841SJoseph Chen } 43123ba6841SJoseph Chen } else { 43223ba6841SJoseph Chen LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_NUM); 43323ba6841SJoseph Chen return false; 43423ba6841SJoseph Chen } 43523ba6841SJoseph Chen buf = strstr(arg, OPT_CHARGE_ANIM_DELAY); 43623ba6841SJoseph Chen if (buf) { 43723ba6841SJoseph Chen level_conf->delay = atoi(buf + strlen(OPT_CHARGE_ANIM_DELAY)); 43823ba6841SJoseph Chen } 43923ba6841SJoseph Chen buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_PFX); 44023ba6841SJoseph Chen if (buf) { 44123ba6841SJoseph Chen snprintf(level_conf->prefix, sizeof(level_conf->prefix), "%s", 44223ba6841SJoseph Chen buf + strlen(OPT_CHARGE_ANIM_LEVEL_PFX)); 44323ba6841SJoseph Chen } else { 44423ba6841SJoseph Chen LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_PFX); 44523ba6841SJoseph Chen return false; 44623ba6841SJoseph Chen } 44723ba6841SJoseph Chen 44823ba6841SJoseph Chen LOGD("Found conf:\nmax_level:%d, num:%d, delay:%d, prefix:%s", 44923ba6841SJoseph Chen level_conf->max_level, level_conf->num, level_conf->delay, 45023ba6841SJoseph Chen level_conf->prefix); 45123ba6841SJoseph Chen return true; 45223ba6841SJoseph Chen } 45323ba6841SJoseph Chen 45423ba6841SJoseph Chen static int test_charge(int argc, char **argv) 45523ba6841SJoseph Chen { 45623ba6841SJoseph Chen const char *desc; 45723ba6841SJoseph Chen if (argc > 0) { 45823ba6841SJoseph Chen desc = argv[0]; 45923ba6841SJoseph Chen } else { 46023ba6841SJoseph Chen desc = DEF_CHARGE_DESC_PATH; 46123ba6841SJoseph Chen } 46223ba6841SJoseph Chen 46323ba6841SJoseph Chen resource_content content; 46423ba6841SJoseph Chen snprintf(content.path, sizeof(content.path), "%s", desc); 46523ba6841SJoseph Chen content.load_addr = 0; 46623ba6841SJoseph Chen if (!get_content(&content)) { 46723ba6841SJoseph Chen goto end; 46823ba6841SJoseph Chen } 46923ba6841SJoseph Chen if (!load_content(&content)) { 47023ba6841SJoseph Chen goto end; 47123ba6841SJoseph Chen } 47223ba6841SJoseph Chen 47323ba6841SJoseph Chen char *buf = (char *)content.load_addr; 47423ba6841SJoseph Chen char *end = buf + content.content_size - 1; 47523ba6841SJoseph Chen *end = '\0'; 47623ba6841SJoseph Chen LOGD("desc:\n%s", buf); 47723ba6841SJoseph Chen 47823ba6841SJoseph Chen int pos = 0; 47923ba6841SJoseph Chen while (1) { 48023ba6841SJoseph Chen char *line = (char *)memchr(buf + pos, '\n', strlen(buf + pos)); 48123ba6841SJoseph Chen if (!line) 48223ba6841SJoseph Chen break; 48323ba6841SJoseph Chen *line = '\0'; 48423ba6841SJoseph Chen LOGD("splite:%s", buf + pos); 48523ba6841SJoseph Chen pos += (strlen(buf + pos) + 1); 48623ba6841SJoseph Chen } 48723ba6841SJoseph Chen 48823ba6841SJoseph Chen int delay = 900; 48923ba6841SJoseph Chen int only_current_level = false; 49023ba6841SJoseph Chen anim_level_conf *level_confs = NULL; 49123ba6841SJoseph Chen int level_conf_pos = 0; 49223ba6841SJoseph Chen int level_conf_num = 0; 49323ba6841SJoseph Chen 49423ba6841SJoseph Chen while (true) { 49523ba6841SJoseph Chen if (buf >= end) 49623ba6841SJoseph Chen break; 49723ba6841SJoseph Chen const char *arg = buf; 49823ba6841SJoseph Chen buf += (strlen(buf) + 1); 49923ba6841SJoseph Chen 50023ba6841SJoseph Chen LOGD("parse arg:%s", arg); 50123ba6841SJoseph Chen if (!memcmp(arg, OPT_CHARGE_ANIM_LEVEL_CONF, 50223ba6841SJoseph Chen strlen(OPT_CHARGE_ANIM_LEVEL_CONF))) { 50323ba6841SJoseph Chen if (!level_confs) { 50423ba6841SJoseph Chen LOGE("Found level conf before levels!"); 50523ba6841SJoseph Chen goto end; 50623ba6841SJoseph Chen } 50723ba6841SJoseph Chen if (level_conf_pos >= level_conf_num) { 50823ba6841SJoseph Chen LOGE("Too many level confs!(%d >= %d)", level_conf_pos, level_conf_num); 50923ba6841SJoseph Chen goto end; 51023ba6841SJoseph Chen } 51123ba6841SJoseph Chen if (!parse_level_conf(arg, level_confs + level_conf_pos)) { 51223ba6841SJoseph Chen LOGE("Failed to parse level conf:%s", arg); 51323ba6841SJoseph Chen goto end; 51423ba6841SJoseph Chen } 51523ba6841SJoseph Chen level_conf_pos++; 51623ba6841SJoseph Chen } else if (!memcmp(arg, OPT_CHARGE_ANIM_DELAY, 51723ba6841SJoseph Chen strlen(OPT_CHARGE_ANIM_DELAY))) { 51823ba6841SJoseph Chen delay = atoi(arg + strlen(OPT_CHARGE_ANIM_DELAY)); 51923ba6841SJoseph Chen LOGD("Found delay:%d", delay); 52023ba6841SJoseph Chen } else if (!memcmp(arg, OPT_CHARGE_ANIM_LOOP_CUR, 52123ba6841SJoseph Chen strlen(OPT_CHARGE_ANIM_LOOP_CUR))) { 52223ba6841SJoseph Chen only_current_level = 52323ba6841SJoseph Chen !memcmp(arg + strlen(OPT_CHARGE_ANIM_LOOP_CUR), "true", 4); 52423ba6841SJoseph Chen LOGD("Found only_current_level:%d", only_current_level); 52523ba6841SJoseph Chen } else if (!memcmp(arg, OPT_CHARGE_ANIM_LEVELS, 52623ba6841SJoseph Chen strlen(OPT_CHARGE_ANIM_LEVELS))) { 52723ba6841SJoseph Chen if (level_conf_num) { 52823ba6841SJoseph Chen goto end; 52923ba6841SJoseph Chen } 53023ba6841SJoseph Chen level_conf_num = atoi(arg + strlen(OPT_CHARGE_ANIM_LEVELS)); 53123ba6841SJoseph Chen if (!level_conf_num) { 53223ba6841SJoseph Chen goto end; 53323ba6841SJoseph Chen } 53423ba6841SJoseph Chen level_confs = 53523ba6841SJoseph Chen (anim_level_conf *)malloc(level_conf_num * sizeof(anim_level_conf)); 53623ba6841SJoseph Chen LOGD("Found levels:%d", level_conf_num); 53723ba6841SJoseph Chen } else { 53823ba6841SJoseph Chen LOGE("Unknown arg:%s", arg); 53923ba6841SJoseph Chen goto end; 54023ba6841SJoseph Chen } 54123ba6841SJoseph Chen } 54223ba6841SJoseph Chen 54323ba6841SJoseph Chen if (level_conf_pos != level_conf_num || !level_conf_num) { 54423ba6841SJoseph Chen LOGE("Something wrong with level confs!"); 54523ba6841SJoseph Chen goto end; 54623ba6841SJoseph Chen } 54723ba6841SJoseph Chen 54823ba6841SJoseph Chen int i = 0, j = 0; 54923ba6841SJoseph Chen for (i = 0; i < level_conf_num; i++) { 55023ba6841SJoseph Chen if (!level_confs[i].delay) { 55123ba6841SJoseph Chen level_confs[i].delay = delay; 55223ba6841SJoseph Chen } 55323ba6841SJoseph Chen if (!level_confs[i].delay) { 55423ba6841SJoseph Chen LOGE("Missing delay in level conf:%d", i); 55523ba6841SJoseph Chen goto end; 55623ba6841SJoseph Chen } 55723ba6841SJoseph Chen for (j = 0; j < i; j++) { 55823ba6841SJoseph Chen if (level_confs[j].max_level == level_confs[i].max_level) { 55923ba6841SJoseph Chen LOGE("Dup level conf:%d", i); 56023ba6841SJoseph Chen goto end; 56123ba6841SJoseph Chen } 56223ba6841SJoseph Chen if (level_confs[j].max_level > level_confs[i].max_level) { 56323ba6841SJoseph Chen anim_level_conf conf = level_confs[i]; 56423ba6841SJoseph Chen memmove(level_confs + j + 1, level_confs + j, 56523ba6841SJoseph Chen (i - j) * sizeof(anim_level_conf)); 56623ba6841SJoseph Chen level_confs[j] = conf; 56723ba6841SJoseph Chen } 56823ba6841SJoseph Chen } 56923ba6841SJoseph Chen } 57023ba6841SJoseph Chen 57123ba6841SJoseph Chen printf("Parse anim desc(%s):\n", desc); 57223ba6841SJoseph Chen printf("only_current_level=%d\n", only_current_level); 57323ba6841SJoseph Chen printf("level conf:\n"); 57423ba6841SJoseph Chen for (i = 0; i < level_conf_num; i++) { 57523ba6841SJoseph Chen printf("\tmax=%d, delay=%d, num=%d, prefix=%s\n", level_confs[i].max_level, 57623ba6841SJoseph Chen level_confs[i].delay, level_confs[i].num, level_confs[i].prefix); 57723ba6841SJoseph Chen } 57823ba6841SJoseph Chen 57923ba6841SJoseph Chen end: 58023ba6841SJoseph Chen free_content(&content); 58123ba6841SJoseph Chen return 0; 58223ba6841SJoseph Chen } 58323ba6841SJoseph Chen 58423ba6841SJoseph Chen /**********************anim test end************************/ 58523ba6841SJoseph Chen /**********************append file************************/ 58623ba6841SJoseph Chen 58723ba6841SJoseph Chen static const char *PROG = NULL; 58823ba6841SJoseph Chen static resource_ptn_header header; 58923ba6841SJoseph Chen static bool just_print = false; 59023ba6841SJoseph Chen static char root_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0"; 59123ba6841SJoseph Chen 59223ba6841SJoseph Chen static void version(void) 59323ba6841SJoseph Chen { 59423ba6841SJoseph Chen printf("%s (cjf@rock-chips.com)\t" VERSION "\n", PROG); 59523ba6841SJoseph Chen } 59623ba6841SJoseph Chen 59723ba6841SJoseph Chen static void usage(void) 59823ba6841SJoseph Chen { 59923ba6841SJoseph Chen printf("Usage: %s [options] [FILES]\n", PROG); 60023ba6841SJoseph Chen printf("Tools for Rockchip's resource image.\n"); 60123ba6841SJoseph Chen version(); 60223ba6841SJoseph Chen printf("Options:\n"); 60323ba6841SJoseph Chen printf("\t" OPT_PACK "\t\t\tPack image from given files.\n"); 60423ba6841SJoseph Chen printf("\t" OPT_UNPACK "\t\tUnpack given image to current dir.\n"); 60523ba6841SJoseph Chen printf("\t" OPT_IMAGE "path" 60623ba6841SJoseph Chen "\t\tSpecify input/output image path.\n"); 60723ba6841SJoseph Chen printf("\t" OPT_PRINT "\t\t\tJust print informations.\n"); 60823ba6841SJoseph Chen printf("\t" OPT_VERBOSE "\t\tDisplay more runtime informations.\n"); 60923ba6841SJoseph Chen printf("\t" OPT_HELP "\t\t\tDisplay this information.\n"); 61023ba6841SJoseph Chen printf("\t" OPT_VERSION "\t\tDisplay version information.\n"); 61123ba6841SJoseph Chen printf("\t" OPT_ROOT "path" 61223ba6841SJoseph Chen "\t\tSpecify resources' root dir.\n"); 61323ba6841SJoseph Chen } 61423ba6841SJoseph Chen 61523ba6841SJoseph Chen static int pack_image(int file_num, const char **files); 61623ba6841SJoseph Chen static int unpack_image(const char *unpack_dir); 61723ba6841SJoseph Chen 61823ba6841SJoseph Chen enum ACTION { 61923ba6841SJoseph Chen ACTION_PACK, 62023ba6841SJoseph Chen ACTION_UNPACK, 62123ba6841SJoseph Chen ACTION_TEST_LOAD, 62223ba6841SJoseph Chen ACTION_TEST_CHARGE, 62323ba6841SJoseph Chen }; 62423ba6841SJoseph Chen 62523ba6841SJoseph Chen int main(int argc, char **argv) 62623ba6841SJoseph Chen { 62723ba6841SJoseph Chen PROG = fix_path(argv[0]); 62823ba6841SJoseph Chen 62923ba6841SJoseph Chen enum ACTION action = ACTION_PACK; 63023ba6841SJoseph Chen 63123ba6841SJoseph Chen argc--, argv++; 63223ba6841SJoseph Chen while (argc > 0 && argv[0][0] == '-') { 63323ba6841SJoseph Chen /* it's a opt arg. */ 63423ba6841SJoseph Chen const char *arg = argv[0]; 63523ba6841SJoseph Chen argc--, argv++; 63623ba6841SJoseph Chen if (!strcmp(OPT_VERBOSE, arg)) { 63723ba6841SJoseph Chen g_debug = true; 63823ba6841SJoseph Chen } else if (!strcmp(OPT_HELP, arg)) { 63923ba6841SJoseph Chen usage(); 64023ba6841SJoseph Chen return 0; 64123ba6841SJoseph Chen } else if (!strcmp(OPT_VERSION, arg)) { 64223ba6841SJoseph Chen version(); 64323ba6841SJoseph Chen return 0; 64423ba6841SJoseph Chen } else if (!strcmp(OPT_PRINT, arg)) { 64523ba6841SJoseph Chen just_print = true; 64623ba6841SJoseph Chen } else if (!strcmp(OPT_PACK, arg)) { 64723ba6841SJoseph Chen action = ACTION_PACK; 64823ba6841SJoseph Chen } else if (!strcmp(OPT_UNPACK, arg)) { 64923ba6841SJoseph Chen action = ACTION_UNPACK; 65023ba6841SJoseph Chen } else if (!strcmp(OPT_TEST_LOAD, arg)) { 65123ba6841SJoseph Chen action = ACTION_TEST_LOAD; 65223ba6841SJoseph Chen } else if (!strcmp(OPT_TEST_CHARGE, arg)) { 65323ba6841SJoseph Chen action = ACTION_TEST_CHARGE; 65423ba6841SJoseph Chen } else if (!memcmp(OPT_IMAGE, arg, strlen(OPT_IMAGE))) { 65523ba6841SJoseph Chen snprintf(image_path, sizeof(image_path), "%s", arg + strlen(OPT_IMAGE)); 65623ba6841SJoseph Chen } else if (!memcmp(OPT_ROOT, arg, strlen(OPT_ROOT))) { 65723ba6841SJoseph Chen snprintf(root_path, sizeof(root_path), "%s", arg + strlen(OPT_ROOT)); 65823ba6841SJoseph Chen } else { 65923ba6841SJoseph Chen LOGE("Unknown opt:%s", arg); 66023ba6841SJoseph Chen usage(); 66123ba6841SJoseph Chen return -1; 66223ba6841SJoseph Chen } 66323ba6841SJoseph Chen } 66423ba6841SJoseph Chen 66523ba6841SJoseph Chen if (!image_path[0]) { 66623ba6841SJoseph Chen snprintf(image_path, sizeof(image_path), "%s", DEFAULT_IMAGE_PATH); 66723ba6841SJoseph Chen } 66823ba6841SJoseph Chen 66923ba6841SJoseph Chen switch (action) { 67023ba6841SJoseph Chen case ACTION_PACK: { 67123ba6841SJoseph Chen int file_num = argc; 67223ba6841SJoseph Chen const char **files = (const char **)argv; 67323ba6841SJoseph Chen if (!file_num) { 67423ba6841SJoseph Chen LOGE("No file to pack!"); 67523ba6841SJoseph Chen return 0; 67623ba6841SJoseph Chen } 67723ba6841SJoseph Chen LOGD("try to pack %d files.", file_num); 67823ba6841SJoseph Chen return pack_image(file_num, files); 67923ba6841SJoseph Chen } 68023ba6841SJoseph Chen case ACTION_UNPACK: { 68123ba6841SJoseph Chen return unpack_image(argc > 0 ? argv[0] : DEFAULT_UNPACK_DIR); 68223ba6841SJoseph Chen } 68323ba6841SJoseph Chen case ACTION_TEST_LOAD: { 68423ba6841SJoseph Chen return test_load(argc, argv); 68523ba6841SJoseph Chen } 68623ba6841SJoseph Chen case ACTION_TEST_CHARGE: { 68723ba6841SJoseph Chen return test_charge(argc, argv); 68823ba6841SJoseph Chen } 68923ba6841SJoseph Chen } 69023ba6841SJoseph Chen /* not reach here. */ 69123ba6841SJoseph Chen return -1; 69223ba6841SJoseph Chen } 69323ba6841SJoseph Chen 69423ba6841SJoseph Chen /************unpack code****************/ 69523ba6841SJoseph Chen static bool mkdirs(char *path) 69623ba6841SJoseph Chen { 69723ba6841SJoseph Chen char *tmp = path; 69823ba6841SJoseph Chen char *pos = NULL; 69923ba6841SJoseph Chen char buf[MAX_INDEX_ENTRY_PATH_LEN]; 70023ba6841SJoseph Chen bool ret = true; 70123ba6841SJoseph Chen while ((pos = memchr(tmp, '/', strlen(tmp)))) { 70223ba6841SJoseph Chen strcpy(buf, path); 70323ba6841SJoseph Chen buf[pos - path] = '\0'; 70423ba6841SJoseph Chen tmp = pos + 1; 70523ba6841SJoseph Chen LOGD("mkdir:%s", buf); 70623ba6841SJoseph Chen if (!mkdir(buf, 0755)) { 70723ba6841SJoseph Chen ret = false; 70823ba6841SJoseph Chen } 70923ba6841SJoseph Chen } 71023ba6841SJoseph Chen if (!ret) 71123ba6841SJoseph Chen LOGD("Failed to mkdir(%s)!", path); 71223ba6841SJoseph Chen return ret; 71323ba6841SJoseph Chen } 71423ba6841SJoseph Chen 71523ba6841SJoseph Chen static bool dump_file(FILE *file, const char *unpack_dir, 71623ba6841SJoseph Chen index_tbl_entry entry) 71723ba6841SJoseph Chen { 71823ba6841SJoseph Chen LOGD("try to dump entry:%s", entry.path); 71923ba6841SJoseph Chen bool ret = false; 72023ba6841SJoseph Chen FILE *out_file = NULL; 72123ba6841SJoseph Chen long int pos = 0; 72223ba6841SJoseph Chen char path[MAX_INDEX_ENTRY_PATH_LEN * 2 + 1]; 72323ba6841SJoseph Chen if (just_print) { 72423ba6841SJoseph Chen ret = true; 72523ba6841SJoseph Chen goto done; 72623ba6841SJoseph Chen } 72723ba6841SJoseph Chen 72823ba6841SJoseph Chen pos = ftell(file); 72923ba6841SJoseph Chen snprintf(path, sizeof(path), "%s/%s", unpack_dir, entry.path); 73023ba6841SJoseph Chen mkdirs(path); 73123ba6841SJoseph Chen out_file = fopen(path, "wb"); 73223ba6841SJoseph Chen if (!out_file) { 73323ba6841SJoseph Chen LOGE("Failed to create:%s", path); 73423ba6841SJoseph Chen goto end; 73523ba6841SJoseph Chen } 73623ba6841SJoseph Chen long int offset = entry.content_offset * BLOCK_SIZE; 73723ba6841SJoseph Chen fseek(file, offset, SEEK_SET); 73823ba6841SJoseph Chen if (offset != ftell(file)) { 73923ba6841SJoseph Chen LOGE("Failed to read content:%s", entry.path); 74023ba6841SJoseph Chen goto end; 74123ba6841SJoseph Chen } 74223ba6841SJoseph Chen char buf[BLOCK_SIZE]; 74323ba6841SJoseph Chen int n; 74423ba6841SJoseph Chen int len = entry.content_size; 74523ba6841SJoseph Chen while (len > 0) { 74623ba6841SJoseph Chen n = len > BLOCK_SIZE ? BLOCK_SIZE : len; 74723ba6841SJoseph Chen if (!fread(buf, n, 1, file)) { 74823ba6841SJoseph Chen LOGE("Failed to read content:%s", entry.path); 74923ba6841SJoseph Chen goto end; 75023ba6841SJoseph Chen } 75123ba6841SJoseph Chen if (!fwrite(buf, n, 1, out_file)) { 75223ba6841SJoseph Chen LOGE("Failed to write:%s", entry.path); 75323ba6841SJoseph Chen goto end; 75423ba6841SJoseph Chen } 75523ba6841SJoseph Chen len -= n; 75623ba6841SJoseph Chen } 75723ba6841SJoseph Chen done: 75823ba6841SJoseph Chen ret = true; 75923ba6841SJoseph Chen end: 76023ba6841SJoseph Chen if (out_file) 76123ba6841SJoseph Chen fclose(out_file); 76223ba6841SJoseph Chen if (pos) 76323ba6841SJoseph Chen fseek(file, pos, SEEK_SET); 76423ba6841SJoseph Chen return ret; 76523ba6841SJoseph Chen } 76623ba6841SJoseph Chen 76723ba6841SJoseph Chen static int unpack_image(const char *dir) 76823ba6841SJoseph Chen { 76923ba6841SJoseph Chen FILE *image_file = NULL; 77023ba6841SJoseph Chen bool ret = false; 77123ba6841SJoseph Chen char unpack_dir[MAX_INDEX_ENTRY_PATH_LEN]; 77223ba6841SJoseph Chen if (just_print) 77323ba6841SJoseph Chen dir = "."; 77423ba6841SJoseph Chen snprintf(unpack_dir, sizeof(unpack_dir), "%s", dir); 77523ba6841SJoseph Chen if (!strlen(unpack_dir)) { 77623ba6841SJoseph Chen goto end; 77723ba6841SJoseph Chen } else if (unpack_dir[strlen(unpack_dir) - 1] == '/') { 77823ba6841SJoseph Chen unpack_dir[strlen(unpack_dir) - 1] = '\0'; 77923ba6841SJoseph Chen } 78023ba6841SJoseph Chen 78123ba6841SJoseph Chen mkdir(unpack_dir, 0755); 78223ba6841SJoseph Chen image_file = fopen(image_path, "rb"); 78323ba6841SJoseph Chen char buf[BLOCK_SIZE]; 78423ba6841SJoseph Chen if (!image_file) { 78523ba6841SJoseph Chen LOGE("Failed to open:%s", image_path); 78623ba6841SJoseph Chen goto end; 78723ba6841SJoseph Chen } 78823ba6841SJoseph Chen if (!fread(buf, BLOCK_SIZE, 1, image_file)) { 78923ba6841SJoseph Chen LOGE("Failed to read header!"); 79023ba6841SJoseph Chen goto end; 79123ba6841SJoseph Chen } 79223ba6841SJoseph Chen memcpy(&header, buf, sizeof(header)); 79323ba6841SJoseph Chen 79423ba6841SJoseph Chen if (memcmp(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic))) { 79523ba6841SJoseph Chen LOGE("Not a resource image(%s)!", image_path); 79623ba6841SJoseph Chen goto end; 79723ba6841SJoseph Chen } 79823ba6841SJoseph Chen /* switch for be. */ 79923ba6841SJoseph Chen fix_header(&header); 80023ba6841SJoseph Chen 80123ba6841SJoseph Chen printf("Dump header:\n"); 80223ba6841SJoseph Chen printf("partition version:%d.%d\n", header.resource_ptn_version, 80323ba6841SJoseph Chen header.index_tbl_version); 80423ba6841SJoseph Chen printf("header size:%d\n", header.header_size); 80523ba6841SJoseph Chen printf("index tbl:\n\toffset:%d\tentry size:%d\tentry num:%d\n", 80623ba6841SJoseph Chen header.tbl_offset, header.tbl_entry_size, header.tbl_entry_num); 80723ba6841SJoseph Chen 80823ba6841SJoseph Chen /* TODO: support header_size & tbl_entry_size */ 80923ba6841SJoseph Chen if (header.resource_ptn_version != RESOURCE_PTN_VERSION || 81023ba6841SJoseph Chen header.header_size != RESOURCE_PTN_HDR_SIZE || 81123ba6841SJoseph Chen header.index_tbl_version != INDEX_TBL_VERSION || 81223ba6841SJoseph Chen header.tbl_entry_size != INDEX_TBL_ENTR_SIZE) { 81323ba6841SJoseph Chen LOGE("Not supported in this version!"); 81423ba6841SJoseph Chen goto end; 81523ba6841SJoseph Chen } 81623ba6841SJoseph Chen 81723ba6841SJoseph Chen printf("Dump Index table:\n"); 81823ba6841SJoseph Chen index_tbl_entry entry; 81923ba6841SJoseph Chen int i; 82023ba6841SJoseph Chen for (i = 0; i < header.tbl_entry_num; i++) { 82123ba6841SJoseph Chen /* TODO: support tbl_entry_size */ 82223ba6841SJoseph Chen if (!fread(buf, BLOCK_SIZE, 1, image_file)) { 82323ba6841SJoseph Chen LOGE("Failed to read index entry:%d!", i); 82423ba6841SJoseph Chen goto end; 82523ba6841SJoseph Chen } 82623ba6841SJoseph Chen memcpy(&entry, buf, sizeof(entry)); 82723ba6841SJoseph Chen 82823ba6841SJoseph Chen if (memcmp(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag))) { 82923ba6841SJoseph Chen LOGE("Something wrong with index entry:%d!", i); 83023ba6841SJoseph Chen goto end; 83123ba6841SJoseph Chen } 83223ba6841SJoseph Chen /* switch for be. */ 83323ba6841SJoseph Chen fix_entry(&entry); 83423ba6841SJoseph Chen 83523ba6841SJoseph Chen printf("entry(%d):\n\tpath:%s\n\toffset:%d\tsize:%d\n", i, entry.path, 83623ba6841SJoseph Chen entry.content_offset, entry.content_size); 83723ba6841SJoseph Chen if (!dump_file(image_file, unpack_dir, entry)) { 83823ba6841SJoseph Chen goto end; 83923ba6841SJoseph Chen } 84023ba6841SJoseph Chen } 84123ba6841SJoseph Chen printf("Unack %s to %s successed!\n", image_path, unpack_dir); 84223ba6841SJoseph Chen ret = true; 84323ba6841SJoseph Chen end: 84423ba6841SJoseph Chen if (image_file) 84523ba6841SJoseph Chen fclose(image_file); 84623ba6841SJoseph Chen return ret ? 0 : -1; 84723ba6841SJoseph Chen } 84823ba6841SJoseph Chen 84923ba6841SJoseph Chen /************unpack code end****************/ 85023ba6841SJoseph Chen /************pack code****************/ 85123ba6841SJoseph Chen 85223ba6841SJoseph Chen static inline size_t get_file_size(const char *path) 85323ba6841SJoseph Chen { 85423ba6841SJoseph Chen LOGD("try to get size(%s)...", path); 85523ba6841SJoseph Chen struct stat st; 85623ba6841SJoseph Chen if (stat(path, &st) < 0) { 85723ba6841SJoseph Chen LOGE("Failed to get size:%s", path); 85823ba6841SJoseph Chen return -1; 85923ba6841SJoseph Chen } 86023ba6841SJoseph Chen LOGD("path:%s, size:%ld", path, st.st_size); 86123ba6841SJoseph Chen return st.st_size; 86223ba6841SJoseph Chen } 86323ba6841SJoseph Chen 864*5e817a0eSJoseph Chen static int write_file(int offset_block, const char *src_path, 865*5e817a0eSJoseph Chen char hash[], int hash_size) 86623ba6841SJoseph Chen { 86723ba6841SJoseph Chen LOGD("try to write file(%s) to offset:%d...", src_path, offset_block); 868*5e817a0eSJoseph Chen char *buf = NULL; 86923ba6841SJoseph Chen int ret = -1; 87023ba6841SJoseph Chen size_t file_size; 87123ba6841SJoseph Chen FILE *src_file = fopen(src_path, "rb"); 87223ba6841SJoseph Chen if (!src_file) { 87323ba6841SJoseph Chen LOGE("Failed to open:%s", src_path); 87423ba6841SJoseph Chen goto end; 87523ba6841SJoseph Chen } 87623ba6841SJoseph Chen 87723ba6841SJoseph Chen file_size = get_file_size(src_path); 87823ba6841SJoseph Chen if (file_size < 0) { 87923ba6841SJoseph Chen goto end; 88023ba6841SJoseph Chen } 88123ba6841SJoseph Chen 882*5e817a0eSJoseph Chen buf = calloc(file_size, 1); 883*5e817a0eSJoseph Chen if (!buf) 88423ba6841SJoseph Chen goto end; 885*5e817a0eSJoseph Chen 886*5e817a0eSJoseph Chen if (!fread(buf, file_size, 1, src_file)) 88723ba6841SJoseph Chen goto end; 888*5e817a0eSJoseph Chen 889*5e817a0eSJoseph Chen if (!write_data(offset_block, buf, file_size)) 890*5e817a0eSJoseph Chen goto end; 891*5e817a0eSJoseph Chen 892*5e817a0eSJoseph Chen if (hash_size == 20) 893*5e817a0eSJoseph Chen sha1_csum((const unsigned char *)buf, file_size, 894*5e817a0eSJoseph Chen (unsigned char *)hash); 895*5e817a0eSJoseph Chen else if (hash_size == 32) 896*5e817a0eSJoseph Chen sha256_csum((const unsigned char *)buf, file_size, 897*5e817a0eSJoseph Chen (unsigned char *)hash); 898*5e817a0eSJoseph Chen else 899*5e817a0eSJoseph Chen goto end; 900*5e817a0eSJoseph Chen 901*5e817a0eSJoseph Chen ret = file_size; 90223ba6841SJoseph Chen end: 90323ba6841SJoseph Chen if (src_file) 90423ba6841SJoseph Chen fclose(src_file); 905*5e817a0eSJoseph Chen if (buf) 906*5e817a0eSJoseph Chen free(buf); 907*5e817a0eSJoseph Chen 90823ba6841SJoseph Chen return ret; 90923ba6841SJoseph Chen } 91023ba6841SJoseph Chen 91123ba6841SJoseph Chen static bool write_header(const int file_num) 91223ba6841SJoseph Chen { 91323ba6841SJoseph Chen LOGD("try to write header..."); 91423ba6841SJoseph Chen memcpy(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic)); 91523ba6841SJoseph Chen header.resource_ptn_version = RESOURCE_PTN_VERSION; 91623ba6841SJoseph Chen header.index_tbl_version = INDEX_TBL_VERSION; 91723ba6841SJoseph Chen header.header_size = RESOURCE_PTN_HDR_SIZE; 91823ba6841SJoseph Chen header.tbl_offset = header.header_size; 91923ba6841SJoseph Chen header.tbl_entry_size = INDEX_TBL_ENTR_SIZE; 92023ba6841SJoseph Chen header.tbl_entry_num = file_num; 92123ba6841SJoseph Chen 92223ba6841SJoseph Chen /* switch for le. */ 92323ba6841SJoseph Chen resource_ptn_header hdr = header; 92423ba6841SJoseph Chen fix_header(&hdr); 92523ba6841SJoseph Chen return write_data(0, &hdr, sizeof(hdr)); 92623ba6841SJoseph Chen } 92723ba6841SJoseph Chen 92823ba6841SJoseph Chen static bool write_index_tbl(const int file_num, const char **files) 92923ba6841SJoseph Chen { 93023ba6841SJoseph Chen LOGD("try to write index table..."); 93123ba6841SJoseph Chen bool ret = false; 93223ba6841SJoseph Chen bool foundFdt = false; 93323ba6841SJoseph Chen int offset = 93423ba6841SJoseph Chen header.header_size + header.tbl_entry_size * header.tbl_entry_num; 93523ba6841SJoseph Chen index_tbl_entry entry; 936*5e817a0eSJoseph Chen char hash[20]; /* sha1 */ 93723ba6841SJoseph Chen int i; 938*5e817a0eSJoseph Chen 939*5e817a0eSJoseph Chen memcpy(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag)); 94023ba6841SJoseph Chen for (i = 0; i < file_num; i++) { 94123ba6841SJoseph Chen size_t file_size = get_file_size(files[i]); 94223ba6841SJoseph Chen if (file_size < 0) 94323ba6841SJoseph Chen goto end; 94423ba6841SJoseph Chen entry.content_size = file_size; 94523ba6841SJoseph Chen entry.content_offset = offset; 94623ba6841SJoseph Chen 947*5e817a0eSJoseph Chen if (write_file(offset, files[i], hash, sizeof(hash)) < 0) 94823ba6841SJoseph Chen goto end; 94923ba6841SJoseph Chen 950*5e817a0eSJoseph Chen memcpy(entry.hash, hash, sizeof(hash)); 951*5e817a0eSJoseph Chen entry.hash_size = sizeof(hash); 952*5e817a0eSJoseph Chen 95323ba6841SJoseph Chen LOGD("try to write index entry(%s)...", files[i]); 95423ba6841SJoseph Chen 95523ba6841SJoseph Chen /* switch for le. */ 95623ba6841SJoseph Chen fix_entry(&entry); 95723ba6841SJoseph Chen memset(entry.path, 0, sizeof(entry.path)); 95823ba6841SJoseph Chen const char *path = files[i]; 95923ba6841SJoseph Chen if (root_path[0]) { 96023ba6841SJoseph Chen if (!strncmp(path, root_path, strlen(root_path))) { 96123ba6841SJoseph Chen path += strlen(root_path); 96223ba6841SJoseph Chen if (path[0] == '/') 96323ba6841SJoseph Chen path++; 96423ba6841SJoseph Chen } 96523ba6841SJoseph Chen } 96623ba6841SJoseph Chen path = fix_path(path); 96723ba6841SJoseph Chen if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX), DTD_SUBFIX)) { 96823ba6841SJoseph Chen if (!foundFdt) { 96923ba6841SJoseph Chen /* use default path. */ 97023ba6841SJoseph Chen LOGD("mod fdt path:%s -> %s...", files[i], FDT_PATH); 97123ba6841SJoseph Chen path = FDT_PATH; 97223ba6841SJoseph Chen foundFdt = true; 97323ba6841SJoseph Chen } 97423ba6841SJoseph Chen } 97523ba6841SJoseph Chen snprintf(entry.path, sizeof(entry.path), "%s", path); 97623ba6841SJoseph Chen offset += fix_blocks(file_size); 97723ba6841SJoseph Chen if (!write_data(header.header_size + i * header.tbl_entry_size, &entry, 97823ba6841SJoseph Chen sizeof(entry))) 97923ba6841SJoseph Chen goto end; 98023ba6841SJoseph Chen } 98123ba6841SJoseph Chen ret = true; 98223ba6841SJoseph Chen end: 98323ba6841SJoseph Chen return ret; 98423ba6841SJoseph Chen } 98523ba6841SJoseph Chen 98623ba6841SJoseph Chen static int pack_image(int file_num, const char **files) 98723ba6841SJoseph Chen { 98823ba6841SJoseph Chen bool ret = false; 98923ba6841SJoseph Chen FILE *image_file = fopen(image_path, "wb"); 99023ba6841SJoseph Chen if (!image_file) { 99123ba6841SJoseph Chen LOGE("Failed to create:%s", image_path); 99223ba6841SJoseph Chen goto end; 99323ba6841SJoseph Chen } 99423ba6841SJoseph Chen fclose(image_file); 99523ba6841SJoseph Chen 99623ba6841SJoseph Chen /* prepare files */ 99723ba6841SJoseph Chen int i = 0; 99823ba6841SJoseph Chen int pos = 0; 99923ba6841SJoseph Chen const char *tmp; 100023ba6841SJoseph Chen for (i = 0; i < file_num; i++) { 100123ba6841SJoseph Chen if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX), DTD_SUBFIX)) { 100223ba6841SJoseph Chen /* dtb files for kernel. */ 100323ba6841SJoseph Chen tmp = files[pos]; 100423ba6841SJoseph Chen files[pos] = files[i]; 100523ba6841SJoseph Chen files[i] = tmp; 100623ba6841SJoseph Chen pos++; 100723ba6841SJoseph Chen } else if (!strcmp(fix_path(image_path), fix_path(files[i]))) { 100823ba6841SJoseph Chen /* not to pack image itself! */ 100923ba6841SJoseph Chen tmp = files[file_num - 1]; 101023ba6841SJoseph Chen files[file_num - 1] = files[i]; 101123ba6841SJoseph Chen files[i] = tmp; 101223ba6841SJoseph Chen file_num--; 101323ba6841SJoseph Chen } 101423ba6841SJoseph Chen } 101523ba6841SJoseph Chen 101623ba6841SJoseph Chen if (!write_header(file_num)) { 101723ba6841SJoseph Chen LOGE("Failed to write header!"); 101823ba6841SJoseph Chen goto end; 101923ba6841SJoseph Chen } 102023ba6841SJoseph Chen if (!write_index_tbl(file_num, files)) { 102123ba6841SJoseph Chen LOGE("Failed to write index table!"); 102223ba6841SJoseph Chen goto end; 102323ba6841SJoseph Chen } 102423ba6841SJoseph Chen printf("Pack to %s successed!\n", image_path); 102523ba6841SJoseph Chen ret = true; 102623ba6841SJoseph Chen end: 102723ba6841SJoseph Chen return ret ? 0 : -1; 102823ba6841SJoseph Chen } 102923ba6841SJoseph Chen 103023ba6841SJoseph Chen /************pack code end****************/ 1031