diff options
author | Tao Huang <huangtao@rock-chips.com> | 2018-08-21 20:48:32 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-08-23 17:25:52 +0800 |
commit | cb7b8c10f268b6976d3947c8c732562c2ec00426 (patch) | |
tree | f0fc9114399e21061a44a668bb5468b02ae496c0 /scripts | |
parent | 8f873910def024837f70d52e3d7d3bcbc21f7c96 (diff) |
rk: add scripts/resource_tool.c
From u-boot d1463f4aaddc ("tools: resource_tool: Use not stripped version").
Merge all C files to one resource_tool.c
Change-Id: I25fffb9a817c9e4e5260db3afca644cb8ba06a18
Signed-off-by: Tao Huang <huangtao@rock-chips.com>
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/resource_tool.c | 1029 |
1 files changed, 1029 insertions, 0 deletions
diff --git a/scripts/resource_tool.c b/scripts/resource_tool.c new file mode 100644 index 000000000000..3309b426e5f9 --- /dev/null +++ b/scripts/resource_tool.c @@ -0,0 +1,1029 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2008-2015 Fuzhou Rockchip Electronics Co., Ltd + */ + +#include <errno.h> +#include <memory.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <time.h> + +//#define DEBUG + +static bool g_debug = +#ifdef DEBUG + true; +#else + false; +#endif //DEBUG + +#define LOGE(fmt, args...) \ + fprintf(stderr, "E/%s(%d): " fmt "\n", __func__, __LINE__, ##args) +#define LOGD(fmt, args...) \ + do { \ + if (g_debug) \ + fprintf(stderr, "D/%s(%d): " fmt "\n", __func__, \ + __LINE__, ##args); \ +} while (0) + +//sync with ./board/rockchip/rk30xx/rkloader.c #define FDT_PATH +#define FDT_PATH "rk-kernel.dtb" +#define DTD_SUBFIX ".dtb" + +#define DEFAULT_IMAGE_PATH "resource.img" +#define DEFAULT_UNPACK_DIR "out" +#define BLOCK_SIZE 512 + +#define RESOURCE_PTN_HDR_SIZE 1 +#define INDEX_TBL_ENTR_SIZE 1 + +#define RESOURCE_PTN_VERSION 0 +#define INDEX_TBL_VERSION 0 + +#define RESOURCE_PTN_HDR_MAGIC "RSCE" +typedef struct { + char magic[4]; //tag, "RSCE" + uint16_t resource_ptn_version; + uint16_t index_tbl_version; + uint8_t header_size; //blocks, size of ptn header. + uint8_t tbl_offset; //blocks, offset of index table. + uint8_t tbl_entry_size; //blocks, size of index table's entry. + uint32_t tbl_entry_num; //numbers of index table's entry. +} resource_ptn_header; + +#define INDEX_TBL_ENTR_TAG "ENTR" +#define MAX_INDEX_ENTRY_PATH_LEN 256 +typedef struct { + char tag[4]; //tag, "ENTR" + char path[MAX_INDEX_ENTRY_PATH_LEN]; + uint32_t content_offset; //blocks, offset of resource content. + uint32_t content_size; //bytes, size of resource content. +} index_tbl_entry; + +#define OPT_VERBOSE "--verbose" +#define OPT_HELP "--help" +#define OPT_VERSION "--version" +#define OPT_PRINT "--print" +#define OPT_PACK "--pack" +#define OPT_UNPACK "--unpack" +#define OPT_TEST_LOAD "--test_load" +#define OPT_TEST_CHARGE "--test_charge" +#define OPT_IMAGE "--image=" +#define OPT_ROOT "--root=" + +#define VERSION "2014-5-31 14:43:42" + +typedef struct { + char path[MAX_INDEX_ENTRY_PATH_LEN]; + uint32_t content_offset; //blocks, offset of resource content. + uint32_t content_size; //bytes, size of resource content. + void *load_addr; +} resource_content; + +typedef struct { + int max_level; + int num; + int delay; + char prefix[MAX_INDEX_ENTRY_PATH_LEN]; +} anim_level_conf; + +#define DEF_CHARGE_DESC_PATH "charge_anim_desc.txt" + +#define OPT_CHARGE_ANIM_DELAY "delay=" +#define OPT_CHARGE_ANIM_LOOP_CUR "only_current_level=" +#define OPT_CHARGE_ANIM_LEVELS "levels=" +#define OPT_CHARGE_ANIM_LEVEL_CONF "max_level=" +#define OPT_CHARGE_ANIM_LEVEL_NUM "num=" +#define OPT_CHARGE_ANIM_LEVEL_PFX "prefix=" + +static char image_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0"; + +static int fix_blocks(size_t size) +{ + return (size + BLOCK_SIZE - 1) / BLOCK_SIZE; +} + +static const char *fix_path(const char *path) +{ + if (!memcmp(path, "./", 2)) { + return path + 2; + } + return path; +} + +static uint16_t switch_short(uint16_t x) +{ + uint16_t val; + uint8_t *p = (uint8_t *)(&x); + + val = (*p++ & 0xff) << 0; + val |= (*p & 0xff) << 8; + + return val; +} + +static uint32_t switch_int(uint32_t x) +{ + uint32_t val; + uint8_t *p = (uint8_t *)(&x); + + val = (*p++ & 0xff) << 0; + val |= (*p++ & 0xff) << 8; + val |= (*p++ & 0xff) << 16; + val |= (*p & 0xff) << 24; + + return val; +} + +static void fix_header(resource_ptn_header *header) +{ + //switch for be. + header->resource_ptn_version = + switch_short(header->resource_ptn_version); + header->index_tbl_version = switch_short(header->index_tbl_version); + header->tbl_entry_num = switch_int(header->tbl_entry_num); +} + +static void fix_entry(index_tbl_entry *entry) +{ + //switch for be. + entry->content_offset = switch_int(entry->content_offset); + entry->content_size = switch_int(entry->content_size); +} + +static int inline get_ptn_offset(void) +{ + return 0; +} + +static bool StorageWriteLba(int offset_block, void *data, int blocks) +{ + bool ret = false; + FILE *file = fopen(image_path, "rb+"); + if (!file) + goto end; + int offset = offset_block * BLOCK_SIZE; + fseek(file, offset, SEEK_SET); + if (offset != ftell(file)) { + LOGE("Failed to seek %s to %d!", image_path, offset); + goto end; + } + if (!fwrite(data, blocks * BLOCK_SIZE, 1, file)) { + LOGE("Failed to write %s!", image_path); + goto end; + } + ret = true; +end: + if (file) + fclose(file); + return ret; +} + +static bool StorageReadLba(int offset_block, void *data, int blocks) +{ + bool ret = false; + FILE *file = fopen(image_path, "rb"); + if (!file) + goto end; + int offset = offset_block * BLOCK_SIZE; + fseek(file, offset, SEEK_SET); + if (offset != ftell(file)) { + goto end; + } + if (!fread(data, blocks * BLOCK_SIZE, 1, file)) { + goto end; + } + ret = true; +end: + if (file) + fclose(file); + return ret; +} + +static bool write_data(int offset_block, void *data, size_t len) +{ + bool ret = false; + if (!data) + goto end; + int blocks = len / BLOCK_SIZE; + if (blocks && !StorageWriteLba(offset_block, data, blocks)) { + goto end; + } + int left = len % BLOCK_SIZE; + if (left) { + char buf[BLOCK_SIZE] = "\0"; + memcpy(buf, data + blocks * BLOCK_SIZE, left); + if (!StorageWriteLba(offset_block + blocks, buf, 1)) + goto end; + } + ret = true; +end: + return ret; +} + +/**********************load test************************/ +static int load_file(const char *file_path, int offset_block, int blocks); + +static int test_load(int argc, char **argv) +{ + if (argc < 1) { + LOGE("Nothing to load!"); + return -1; + } + const char *file_path; + int offset_block = 0; + int blocks = 0; + if (argc > 0) { + file_path = (const char *)fix_path(argv[0]); + argc--, argv++; + } + if (argc > 0) { + offset_block = atoi(argv[0]); + argc--, argv++; + } + if (argc > 0) { + blocks = atoi(argv[0]); + } + return load_file(file_path, offset_block, blocks); +} + +static void free_content(resource_content *content) +{ + if (content->load_addr) { + free(content->load_addr); + content->load_addr = 0; + } +} + +static void tests_dump_file(const char *path, void *data, int len) +{ + FILE *file = fopen(path, "wb"); + if (!file) + return; + fwrite(data, len, 1, file); + fclose(file); +} + +static bool load_content(resource_content *content) +{ + if (content->load_addr) + return true; + int blocks = fix_blocks(content->content_size); + content->load_addr = malloc(blocks * BLOCK_SIZE); + if (!content->load_addr) + return false; + if (!StorageReadLba(get_ptn_offset() + content->content_offset, + content->load_addr, blocks)) { + free_content(content); + return false; + } + + tests_dump_file(content->path, content->load_addr, + content->content_size); + return true; +} + +static bool load_content_data(resource_content *content, int offset_block, + void *data, int blocks) +{ + if (!StorageReadLba(get_ptn_offset() + content->content_offset + + offset_block, + data, blocks)) { + return false; + } + tests_dump_file(content->path, data, blocks * BLOCK_SIZE); + return true; +} + +static bool get_entry(const char *file_path, index_tbl_entry *entry) +{ + bool ret = false; + char buf[BLOCK_SIZE]; + resource_ptn_header header; + if (!StorageReadLba(get_ptn_offset(), buf, 1)) { + LOGE("Failed to read header!"); + goto end; + } + memcpy(&header, buf, sizeof(header)); + + if (memcmp(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic))) { + LOGE("Not a resource image(%s)!", image_path); + goto end; + } + //test on pc, switch for be. + fix_header(&header); + + //TODO: support header_size & tbl_entry_size + if (header.resource_ptn_version != RESOURCE_PTN_VERSION || + header.header_size != RESOURCE_PTN_HDR_SIZE || + header.index_tbl_version != INDEX_TBL_VERSION || + header.tbl_entry_size != INDEX_TBL_ENTR_SIZE) { + LOGE("Not supported in this version!"); + goto end; + } + + int i; + for (i = 0; i < header.tbl_entry_num; i++) { + //TODO: support tbl_entry_size + if (!StorageReadLba(get_ptn_offset() + header.header_size + + i * header.tbl_entry_size, + buf, 1)) { + LOGE("Failed to read index entry:%d!", i); + goto end; + } + memcpy(entry, buf, sizeof(*entry)); + + if (memcmp(entry->tag, INDEX_TBL_ENTR_TAG, sizeof(entry->tag))) { + LOGE("Something wrong with index entry:%d!", i); + goto end; + } + + if (!strncmp(entry->path, file_path, sizeof(entry->path))) + break; + } + if (i == header.tbl_entry_num) { + LOGE("Cannot find %s!", file_path); + goto end; + } + //test on pc, switch for be. + fix_entry(entry); + + printf("Found entry:\n\tpath:%s\n\toffset:%d\tsize:%d\n", + entry->path, entry->content_offset, entry->content_size); + + ret = true; +end: + return ret; +} + +static bool get_content(resource_content *content) +{ + bool ret = false; + index_tbl_entry entry; + if (!get_entry(content->path, &entry)) + goto end; + content->content_offset = entry.content_offset; + content->content_size = entry.content_size; + ret = true; +end: + return ret; +} + +static int load_file(const char *file_path, int offset_block, int blocks) +{ + printf("Try to load:%s", file_path); + if (blocks) { + printf(", offset block:%d, blocks:%d\n", offset_block, blocks); + } else { + printf("\n"); + } + bool ret = false; + resource_content content; + snprintf(content.path, sizeof(content.path), "%s", file_path); + content.load_addr = 0; + if (!get_content(&content)) { + goto end; + } + if (!blocks) { + if (!load_content(&content)) { + goto end; + } + } else { + void *data = malloc(blocks * BLOCK_SIZE); + if (!data) + goto end; + if (!load_content_data(&content, offset_block, data, blocks)) { + goto end; + } + } + ret = true; +end: + free_content(&content); + return ret; +} + +/**********************load test end************************/ +/**********************anim test************************/ + +static bool parse_level_conf(const char *arg, anim_level_conf *level_conf) +{ + memset(level_conf, 0, sizeof(anim_level_conf)); + char *buf = NULL; + buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_CONF); + if (buf) { + level_conf->max_level = + atoi(buf + strlen(OPT_CHARGE_ANIM_LEVEL_CONF)); + } else { + LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_CONF); + return false; + } + buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_NUM); + if (buf) { + level_conf->num = atoi(buf + strlen(OPT_CHARGE_ANIM_LEVEL_NUM)); + if (level_conf->num <= 0) { + return false; + } + } else { + LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_NUM); + return false; + } + buf = strstr(arg, OPT_CHARGE_ANIM_DELAY); + if (buf) { + level_conf->delay = atoi(buf + strlen(OPT_CHARGE_ANIM_DELAY)); + } + buf = strstr(arg, OPT_CHARGE_ANIM_LEVEL_PFX); + if (buf) { + snprintf(level_conf->prefix, sizeof(level_conf->prefix), + "%s", buf + strlen(OPT_CHARGE_ANIM_LEVEL_PFX)); + } else { + LOGE("Not found:%s", OPT_CHARGE_ANIM_LEVEL_PFX); + return false; + } + + LOGD("Found conf:\nmax_level:%d, num:%d, delay:%d, prefix:%s", + level_conf->max_level, level_conf->num, + level_conf->delay, level_conf->prefix); + return true; +} + +static int test_charge(int argc, char **argv) +{ + const char *desc; + if (argc > 0) { + desc = argv[0]; + } else { + desc = DEF_CHARGE_DESC_PATH; + } + + resource_content content; + snprintf(content.path, sizeof(content.path), "%s", desc); + content.load_addr = 0; + if (!get_content(&content)) { + goto end; + } + if (!load_content(&content)) { + goto end; + } + + char *buf = (char *)content.load_addr; + char *end = buf + content.content_size - 1; + *end = '\0'; + LOGD("desc:\n%s", buf); + + int pos = 0; + while (1) { + char *line = (char *)memchr(buf + pos, '\n', strlen(buf + pos)); + if (!line) + break; + *line = '\0'; + LOGD("splite:%s", buf + pos); + pos += (strlen(buf + pos) + 1); + } + + int delay = 900; + int only_current_level = false; + anim_level_conf *level_confs = NULL; + int level_conf_pos = 0; + int level_conf_num = 0; + + while (true) { + if (buf >= end) + break; + const char *arg = buf; + buf += (strlen(buf) + 1); + + LOGD("parse arg:%s", arg); + if (!memcmp(arg, OPT_CHARGE_ANIM_LEVEL_CONF, + strlen(OPT_CHARGE_ANIM_LEVEL_CONF))) { + if (!level_confs) { + LOGE("Found level conf before levels!"); + goto end; + } + if (level_conf_pos >= level_conf_num) { + LOGE("Too many level confs!(%d >= %d)", + level_conf_pos, level_conf_num); + goto end; + } + if (!parse_level_conf(arg, + level_confs + level_conf_pos)) { + LOGE("Failed to parse level conf:%s", arg); + goto end; + } + level_conf_pos++; + } else if (!memcmp(arg, OPT_CHARGE_ANIM_DELAY, + strlen(OPT_CHARGE_ANIM_DELAY))) { + delay = atoi(arg + strlen(OPT_CHARGE_ANIM_DELAY)); + LOGD("Found delay:%d", delay); + } else if (!memcmp(arg, OPT_CHARGE_ANIM_LOOP_CUR, + strlen(OPT_CHARGE_ANIM_LOOP_CUR))) { + only_current_level = + !memcmp(arg + strlen(OPT_CHARGE_ANIM_LOOP_CUR), + "true", 4); + LOGD("Found only_current_level:%d", only_current_level); + } else if (!memcmp(arg, OPT_CHARGE_ANIM_LEVELS, + strlen(OPT_CHARGE_ANIM_LEVELS))) { + if (level_conf_num) { + goto end; + } + level_conf_num = + atoi(arg + strlen(OPT_CHARGE_ANIM_LEVELS)); + if (!level_conf_num) { + goto end; + } + level_confs = + (anim_level_conf *) malloc(level_conf_num * + sizeof(anim_level_conf)); + LOGD("Found levels:%d", level_conf_num); + } else { + LOGE("Unknown arg:%s", arg); + goto end; + } + } + + if (level_conf_pos != level_conf_num || !level_conf_num) { + LOGE("Something wrong with level confs!"); + goto end; + } + + int i = 0, j = 0; + for (i = 0; i < level_conf_num; i++) { + if (!level_confs[i].delay) { + level_confs[i].delay = delay; + } + if (!level_confs[i].delay) { + LOGE("Missing delay in level conf:%d", i); + goto end; + } + for (j = 0; j < i; j++) { + if (level_confs[j].max_level == + level_confs[i].max_level) { + LOGE("Dup level conf:%d", i); + goto end; + } + if (level_confs[j].max_level > level_confs[i].max_level) { + anim_level_conf conf = level_confs[i]; + memmove(level_confs + j + 1, level_confs + j, + (i - j) * sizeof(anim_level_conf)); + level_confs[j] = conf; + } + } + } + + printf("Parse anim desc(%s):\n", desc); + printf("only_current_level=%d\n", only_current_level); + printf("level conf:\n"); + for (i = 0; i < level_conf_num; i++) { + printf("\tmax=%d, delay=%d, num=%d, prefix=%s\n", + level_confs[i].max_level, level_confs[i].delay, + level_confs[i].num, level_confs[i].prefix); + } + +end: + free_content(&content); + return 0; +} + +/**********************anim test end************************/ +/**********************append file************************/ + +static const char *PROG = NULL; +static resource_ptn_header header; +static bool just_print = false; +static char root_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0"; + +static void version(void) +{ + printf("%s (cjf@rock-chips.com)\t" VERSION "\n", PROG); +} + +static void usage(void) +{ + printf("Usage: %s [options] [FILES]\n", PROG); + printf("Tools for Rockchip's resource image.\n"); + version(); + printf("Options:\n"); + printf("\t" OPT_PACK "\t\t\tPack image from given files.\n"); + printf("\t" OPT_UNPACK "\t\tUnpack given image to current dir.\n"); + printf("\t" OPT_IMAGE "path" "\t\tSpecify input/output image path.\n"); + printf("\t" OPT_PRINT "\t\t\tJust print informations.\n"); + printf("\t" OPT_VERBOSE "\t\tDisplay more runtime informations.\n"); + printf("\t" OPT_HELP "\t\t\tDisplay this information.\n"); + printf("\t" OPT_VERSION "\t\tDisplay version information.\n"); + printf("\t" OPT_ROOT "path" "\t\tSpecify resources' root dir.\n"); +} + +static int pack_image(int file_num, const char **files); +static int unpack_image(const char *unpack_dir); + +enum ACTION { + ACTION_PACK, + ACTION_UNPACK, + ACTION_TEST_LOAD, + ACTION_TEST_CHARGE, +}; + +int main(int argc, char **argv) +{ + PROG = fix_path(argv[0]); + + enum ACTION action = ACTION_PACK; + + argc--, argv++; + while (argc > 0 && argv[0][0] == '-') { + //it's a opt arg. + const char *arg = argv[0]; + argc--, argv++; + if (!strcmp(OPT_VERBOSE, arg)) { + g_debug = true; + } else if (!strcmp(OPT_HELP, arg)) { + usage(); + return 0; + } else if (!strcmp(OPT_VERSION, arg)) { + version(); + return 0; + } else if (!strcmp(OPT_PRINT, arg)) { + just_print = true; + } else if (!strcmp(OPT_PACK, arg)) { + action = ACTION_PACK; + } else if (!strcmp(OPT_UNPACK, arg)) { + action = ACTION_UNPACK; + } else if (!strcmp(OPT_TEST_LOAD, arg)) { + action = ACTION_TEST_LOAD; + } else if (!strcmp(OPT_TEST_CHARGE, arg)) { + action = ACTION_TEST_CHARGE; + } else if (!memcmp(OPT_IMAGE, arg, strlen(OPT_IMAGE))) { + snprintf(image_path, sizeof(image_path), + "%s", arg + strlen(OPT_IMAGE)); + } else if (!memcmp(OPT_ROOT, arg, strlen(OPT_ROOT))) { + snprintf(root_path, sizeof(root_path), + "%s", arg + strlen(OPT_ROOT)); + } else { + LOGE("Unknown opt:%s", arg); + usage(); + return -1; + } + } + + if (!image_path[0]) { + snprintf(image_path, sizeof(image_path), "%s", + DEFAULT_IMAGE_PATH); + } + + switch (action) { + case ACTION_PACK: + { + int file_num = argc; + const char **files = (const char **)argv; + if (!file_num) { + LOGE("No file to pack!"); + return 0; + } + LOGD("try to pack %d files.", file_num); + return pack_image(file_num, files); + } + case ACTION_UNPACK: + { + return unpack_image(argc > + 0 ? argv[0] : DEFAULT_UNPACK_DIR); + } + case ACTION_TEST_LOAD: + { + return test_load(argc, argv); + } + case ACTION_TEST_CHARGE: + { + return test_charge(argc, argv); + } + } + //not reach here. + return -1; +} + +/************unpack code****************/ +static bool mkdirs(char *path) +{ + char *tmp = path; + char *pos = NULL; + char buf[MAX_INDEX_ENTRY_PATH_LEN]; + bool ret = true; + while ((pos = memchr(tmp, '/', strlen(tmp)))) { + strcpy(buf, path); + buf[pos - path] = '\0'; + tmp = pos + 1; + LOGD("mkdir:%s", buf); + if (!mkdir(buf, 0755)) { + ret = false; + } + } + if (!ret) + LOGD("Failed to mkdir(%s)!", path); + return ret; +} + +static bool dump_file(FILE *file, const char *unpack_dir, index_tbl_entry entry) +{ + LOGD("try to dump entry:%s", entry.path); + bool ret = false; + FILE *out_file = NULL; + long int pos = 0; + char path[MAX_INDEX_ENTRY_PATH_LEN * 2 + 1]; + if (just_print) { + ret = true; + goto done; + } + + pos = ftell(file); + snprintf(path, sizeof(path), "%s/%s", unpack_dir, entry.path); + mkdirs(path); + out_file = fopen(path, "wb"); + if (!out_file) { + LOGE("Failed to create:%s", path); + goto end; + } + long int offset = entry.content_offset * BLOCK_SIZE; + fseek(file, offset, SEEK_SET); + if (offset != ftell(file)) { + LOGE("Failed to read content:%s", entry.path); + goto end; + } + char buf[BLOCK_SIZE]; + int n; + int len = entry.content_size; + while (len > 0) { + n = len > BLOCK_SIZE ? BLOCK_SIZE : len; + if (!fread(buf, n, 1, file)) { + LOGE("Failed to read content:%s", entry.path); + goto end; + } + if (!fwrite(buf, n, 1, out_file)) { + LOGE("Failed to write:%s", entry.path); + goto end; + } + len -= n; + } +done: + ret = true; +end: + if (out_file) + fclose(out_file); + if (pos) + fseek(file, pos, SEEK_SET); + return ret; +} + +static int unpack_image(const char *dir) +{ + FILE *image_file = NULL; + bool ret = false; + char unpack_dir[MAX_INDEX_ENTRY_PATH_LEN]; + if (just_print) + dir = "."; + snprintf(unpack_dir, sizeof(unpack_dir), "%s", dir); + if (!strlen(unpack_dir)) { + goto end; + } else if (unpack_dir[strlen(unpack_dir) - 1] == '/') { + unpack_dir[strlen(unpack_dir) - 1] = '\0'; + } + + mkdir(unpack_dir, 0755); + image_file = fopen(image_path, "rb"); + char buf[BLOCK_SIZE]; + if (!image_file) { + LOGE("Failed to open:%s", image_path); + goto end; + } + if (!fread(buf, BLOCK_SIZE, 1, image_file)) { + LOGE("Failed to read header!"); + goto end; + } + memcpy(&header, buf, sizeof(header)); + + if (memcmp(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic))) { + LOGE("Not a resource image(%s)!", image_path); + goto end; + } + //switch for be. + fix_header(&header); + + printf("Dump header:\n"); + printf("partition version:%d.%d\n", + header.resource_ptn_version, header.index_tbl_version); + printf("header size:%d\n", header.header_size); + printf("index tbl:\n\toffset:%d\tentry size:%d\tentry num:%d\n", + header.tbl_offset, header.tbl_entry_size, header.tbl_entry_num); + + //TODO: support header_size & tbl_entry_size + if (header.resource_ptn_version != RESOURCE_PTN_VERSION || + header.header_size != RESOURCE_PTN_HDR_SIZE || + header.index_tbl_version != INDEX_TBL_VERSION || + header.tbl_entry_size != INDEX_TBL_ENTR_SIZE) { + LOGE("Not supported in this version!"); + goto end; + } + + printf("Dump Index table:\n"); + index_tbl_entry entry; + int i; + for (i = 0; i < header.tbl_entry_num; i++) { + //TODO: support tbl_entry_size + if (!fread(buf, BLOCK_SIZE, 1, image_file)) { + LOGE("Failed to read index entry:%d!", i); + goto end; + } + memcpy(&entry, buf, sizeof(entry)); + + if (memcmp(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag))) { + LOGE("Something wrong with index entry:%d!", i); + goto end; + } + //switch for be. + fix_entry(&entry); + + printf("entry(%d):\n\tpath:%s\n\toffset:%d\tsize:%d\n", + i, entry.path, entry.content_offset, entry.content_size); + if (!dump_file(image_file, unpack_dir, entry)) { + goto end; + } + } + printf("Unack %s to %s successed!\n", image_path, unpack_dir); + ret = true; +end: + if (image_file) + fclose(image_file); + return ret ? 0 : -1; +} + +/************unpack code end****************/ +/************pack code****************/ + +static inline size_t get_file_size(const char *path) +{ + LOGD("try to get size(%s)...", path); + struct stat st; + if (stat(path, &st) < 0) { + LOGE("Failed to get size:%s", path); + return -1; + } + LOGD("path:%s, size:%ld", path, st.st_size); + return st.st_size; +} + +static int write_file(int offset_block, const char *src_path) +{ + LOGD("try to write file(%s) to offset:%d...", src_path, offset_block); + char buf[BLOCK_SIZE]; + int ret = -1; + size_t file_size; + int blocks; + FILE *src_file = fopen(src_path, "rb"); + if (!src_file) { + LOGE("Failed to open:%s", src_path); + goto end; + } + + file_size = get_file_size(src_path); + if (file_size < 0) { + goto end; + } + blocks = fix_blocks(file_size); + + int i; + for (i = 0; i < blocks; i++) { + memset(buf, 0, sizeof(buf)); + if (!fread(buf, 1, BLOCK_SIZE, src_file)) { + LOGE("Failed to read:%s", src_path); + goto end; + } + if (!write_data(offset_block + i, buf, BLOCK_SIZE)) { + goto end; + } + } + ret = blocks; +end: + if (src_file) + fclose(src_file); + return ret; +} + +static bool write_header(const int file_num) +{ + LOGD("try to write header..."); + memcpy(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic)); + header.resource_ptn_version = RESOURCE_PTN_VERSION; + header.index_tbl_version = INDEX_TBL_VERSION; + header.header_size = RESOURCE_PTN_HDR_SIZE; + header.tbl_offset = header.header_size; + header.tbl_entry_size = INDEX_TBL_ENTR_SIZE; + header.tbl_entry_num = file_num; + + //switch for le. + resource_ptn_header hdr = header; + fix_header(&hdr); + return write_data(0, &hdr, sizeof(hdr)); +} + +static bool write_index_tbl(const int file_num, const char **files) +{ + LOGD("try to write index table..."); + bool ret = false; + bool foundFdt = false; + int offset = header.header_size + + header.tbl_entry_size * header.tbl_entry_num; + index_tbl_entry entry; + memcpy(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag)); + int i; + for (i = 0; i < file_num; i++) { + size_t file_size = get_file_size(files[i]); + if (file_size < 0) + goto end; + entry.content_size = file_size; + entry.content_offset = offset; + + if (write_file(offset, files[i]) < 0) + goto end; + + LOGD("try to write index entry(%s)...", files[i]); + + //switch for le. + fix_entry(&entry); + memset(entry.path, 0, sizeof(entry.path)); + const char *path = files[i]; + if (root_path[0]) { + if (!strncmp(path, root_path, strlen(root_path))) { + path += strlen(root_path); + if (path[0] == '/') + path++; + } + } + path = fix_path(path); + if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX), + DTD_SUBFIX)) { + if (!foundFdt) { + //use default path. + LOGD("mod fdt path:%s -> %s...", files[i], + FDT_PATH); + path = FDT_PATH; + foundFdt = true; + } + } + snprintf(entry.path, sizeof(entry.path), "%s", path); + offset += fix_blocks(file_size); + if (!write_data(header.header_size + i * header.tbl_entry_size, + &entry, sizeof(entry))) + goto end; + } + ret = true; +end: + return ret; +} + +static int pack_image(int file_num, const char **files) +{ + bool ret = false; + FILE *image_file = fopen(image_path, "wb"); + if (!image_file) { + LOGE("Failed to create:%s", image_path); + goto end; + } + fclose(image_file); + + //prepare files + int i = 0; + int pos = 0; + const char *tmp; + for (i = 0; i < file_num; i++) { + if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX), + DTD_SUBFIX)) { + //dtb files for kernel. + tmp = files[pos]; + files[pos] = files[i]; + files[i] = tmp; + pos++; + } else if (!strcmp(fix_path(image_path), fix_path(files[i]))) { + //not to pack image itself! + tmp = files[file_num - 1]; + files[file_num - 1] = files[i]; + files[i] = tmp; + file_num--; + } + } + + if (!write_header(file_num)) { + LOGE("Failed to write header!"); + goto end; + } + if (!write_index_tbl(file_num, files)) { + LOGE("Failed to write index table!"); + goto end; + } + printf("Pack to %s successed!\n", image_path); + ret = true; +end: + return ret ? 0 : -1; +} + +/************pack code end****************/ |