xref: /rk3399_rockchip-uboot/tools/rockchip/resource_tool.c (revision 5e817a0ea4271df00a147e77316f36f286ff9a56)
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