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