/tools/resource_tool/resource_tool.c

https://github.com/rkchrome/uboot · C · 482 lines · 415 code · 49 blank · 18 comment · 84 complexity · 21f07cd07e04558871114a227626c649 MD5 · raw file

  1. #include "resource_tool.h"
  2. #include <sys/stat.h>
  3. #include <time.h>
  4. #include <errno.h>
  5. static const char* PROG = NULL;
  6. static resource_ptn_header header;
  7. static bool just_print = false;
  8. char image_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0";
  9. char root_path[MAX_INDEX_ENTRY_PATH_LEN] = "\0";
  10. static void version() {
  11. printf("%s (cjf@rock-chips.com)\t" VERSION "\n", PROG);
  12. }
  13. static void usage() {
  14. printf("Usage: %s [options] [FILES]\n", PROG);
  15. printf("Tools for Rockchip's resource image.\n");
  16. version();
  17. printf("Options:\n");
  18. printf("\t" OPT_PACK "\t\t\tPack image from given files.\n");
  19. printf("\t" OPT_UNPACK "\t\tUnpack given image to current dir.\n");
  20. printf("\t" OPT_IMAGE "path" "\t\tSpecify input/output image path.\n");
  21. printf("\t" OPT_PRINT "\t\t\tJust print informations.\n");
  22. printf("\t" OPT_VERBOSE "\t\tDisplay more runtime informations.\n");
  23. printf("\t" OPT_HELP "\t\t\tDisplay this information.\n");
  24. printf("\t" OPT_VERSION "\t\tDisplay version information.\n");
  25. printf("\t" OPT_ROOT "path" "\t\tSpecify resources' root dir.\n");
  26. }
  27. static int pack_image(int file_num, const char** files);
  28. static int unpack_image(const char* unpack_dir);
  29. int fix_blocks(size_t size) {
  30. return (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
  31. }
  32. const char* fix_path(const char* path) {
  33. if (!memcmp(path, "./", 2)) {
  34. return path + 2;
  35. }
  36. return path;
  37. }
  38. enum ACTION {
  39. ACTION_PACK,
  40. ACTION_UNPACK,
  41. ACTION_TEST_LOAD,
  42. ACTION_TEST_CHARGE,
  43. };
  44. int main(int argc, char** argv) {
  45. PROG = fix_path(argv[0]);
  46. bool pack = true;
  47. enum ACTION action = ACTION_PACK;
  48. argc--, argv++;
  49. while (argc > 0 && argv[0][0] == '-') {
  50. //it's a opt arg.
  51. const char* arg = argv[0];
  52. argc--, argv++;
  53. if (!strcmp(OPT_VERBOSE, arg)) {
  54. g_debug = true;
  55. } else if (!strcmp(OPT_HELP, arg)) {
  56. usage();
  57. return 0;
  58. } else if (!strcmp(OPT_VERSION, arg)) {
  59. version();
  60. return 0;
  61. } else if (!strcmp(OPT_PRINT, arg)) {
  62. just_print = true;
  63. } else if (!strcmp(OPT_PACK, arg)) {
  64. action = ACTION_PACK;
  65. } else if (!strcmp(OPT_UNPACK, arg)) {
  66. action = ACTION_UNPACK;
  67. } else if (!strcmp(OPT_TEST_LOAD, arg)) {
  68. action = ACTION_TEST_LOAD;
  69. } else if (!strcmp(OPT_TEST_CHARGE, arg)) {
  70. action = ACTION_TEST_CHARGE;
  71. } else if (!memcmp(OPT_IMAGE, arg, strlen(OPT_IMAGE))) {
  72. snprintf(image_path, sizeof(image_path),
  73. "%s", arg + strlen(OPT_IMAGE));
  74. } else if (!memcmp(OPT_ROOT, arg, strlen(OPT_ROOT))) {
  75. snprintf(root_path, sizeof(root_path),
  76. "%s", arg + strlen(OPT_ROOT));
  77. } else {
  78. LOGE("Unknown opt:%s", arg);
  79. usage();
  80. return -1;
  81. }
  82. }
  83. if (!image_path[0]) {
  84. snprintf(image_path, sizeof(image_path), "%s", DEFAULT_IMAGE_PATH);
  85. }
  86. switch (action) {
  87. case ACTION_PACK:
  88. {
  89. int file_num = argc;
  90. const char** files = (const char**)argv;
  91. if (!file_num) {
  92. LOGE("No file to pack!");
  93. return 0;
  94. }
  95. LOGD("try to pack %d files.", file_num);
  96. return pack_image(file_num, files);
  97. }
  98. case ACTION_UNPACK:
  99. {
  100. return unpack_image(argc > 0? argv[0] : DEFAULT_UNPACK_DIR);
  101. }
  102. case ACTION_TEST_LOAD:
  103. {
  104. return test_load(argc, argv);
  105. }
  106. case ACTION_TEST_CHARGE:
  107. {
  108. return test_charge(argc, argv);
  109. }
  110. }
  111. //not reach here.
  112. return -1;
  113. }
  114. uint16_t switch_short(uint16_t x)
  115. {
  116. uint16_t val;
  117. uint8_t *p = (uint8_t *)(&x);
  118. val = (*p++ & 0xff) << 0;
  119. val |= (*p & 0xff) << 8;
  120. return val;
  121. }
  122. uint32_t switch_int(uint32_t x)
  123. {
  124. uint32_t val;
  125. uint8_t *p = (uint8_t *)(&x);
  126. val = (*p++ & 0xff) << 0;
  127. val |= (*p++ & 0xff) << 8;
  128. val |= (*p++ & 0xff) << 16;
  129. val |= (*p & 0xff) << 24;
  130. return val;
  131. }
  132. void fix_header(resource_ptn_header* header) {
  133. //switch for be.
  134. header->resource_ptn_version = switch_short(header->resource_ptn_version);
  135. header->index_tbl_version = switch_short(header->index_tbl_version);
  136. header->tbl_entry_num = switch_int(header->tbl_entry_num);
  137. }
  138. void fix_entry(index_tbl_entry* entry) {
  139. //switch for be.
  140. entry->content_offset = switch_int(entry->content_offset);
  141. entry->content_size = switch_int(entry->content_size);
  142. }
  143. /************unpack code****************/
  144. static bool mkdirs(char* path) {
  145. char* tmp = path;
  146. char* pos = NULL;
  147. char buf[MAX_INDEX_ENTRY_PATH_LEN];
  148. bool ret = true;
  149. while(pos = memchr(tmp, '/', strlen(tmp))) {
  150. strcpy(buf, path);
  151. buf[pos - path] = '\0';
  152. tmp = pos + 1;
  153. LOGD("mkdir:%s", buf);
  154. if (!mkdir(buf, 0)) {
  155. ret = false;
  156. }
  157. }
  158. if (!ret)
  159. LOGD("Failed to mkdir(%s)!", path);
  160. return ret;
  161. }
  162. static bool dump_file(FILE* file, const char* unpack_dir,
  163. index_tbl_entry entry) {
  164. LOGD("try to dump entry:%s", entry.path);
  165. bool ret = false;
  166. FILE* out_file = NULL;
  167. long int pos = 0;
  168. char path[MAX_INDEX_ENTRY_PATH_LEN];
  169. if (just_print) {
  170. ret = true;
  171. goto done;
  172. }
  173. pos = ftell(file);
  174. snprintf(path, sizeof(path), "%s/%s", unpack_dir, entry.path);
  175. mkdirs(path);
  176. out_file = fopen(path, "wb");
  177. if (!out_file) {
  178. LOGE("Failed to create:%s", path);
  179. goto end;
  180. }
  181. long int offset = entry.content_offset * BLOCK_SIZE;
  182. fseek(file, offset, SEEK_SET);
  183. if (offset != ftell(file)) {
  184. LOGE("Failed to read content:%s", entry.path);
  185. goto end;
  186. }
  187. char buf[BLOCK_SIZE];
  188. int n;
  189. int len = entry.content_size;
  190. while (len > 0) {
  191. n = len > BLOCK_SIZE ? BLOCK_SIZE : len;
  192. if (!fread(buf, n, 1, file)) {
  193. LOGE("Failed to read content:%s", entry.path);
  194. goto end;
  195. }
  196. if (!fwrite(buf, n, 1, out_file)) {
  197. LOGE("Failed to write:%s", entry.path);
  198. goto end;
  199. }
  200. len -= n;
  201. }
  202. done:
  203. ret = true;
  204. end:
  205. if (out_file)
  206. fclose(out_file);
  207. if (pos)
  208. fseek(file, pos, SEEK_SET);
  209. return ret;
  210. }
  211. static int unpack_image(const char* dir) {
  212. bool ret = false;
  213. char unpack_dir[MAX_INDEX_ENTRY_PATH_LEN];
  214. if (just_print)
  215. dir = ".";
  216. snprintf(unpack_dir, sizeof(unpack_dir), "%s", dir);
  217. if (!strlen(unpack_dir)) {
  218. goto end;
  219. } else if (unpack_dir[strlen(unpack_dir) - 1] == '/') {
  220. unpack_dir[strlen(unpack_dir) - 1] = '\0';
  221. }
  222. mkdir(unpack_dir, 0);
  223. FILE* image_file = fopen(image_path, "rb");
  224. char buf[BLOCK_SIZE];
  225. if (!image_file) {
  226. LOGE("Failed to open:%s", image_path);
  227. goto end;
  228. }
  229. if (!fread(buf, BLOCK_SIZE, 1, image_file)) {
  230. LOGE("Failed to read header!");
  231. goto end;
  232. }
  233. memcpy(&header, buf, sizeof(header));
  234. if (memcmp(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic))) {
  235. LOGE("Not a resource image(%s)!", image_path);
  236. goto end;
  237. }
  238. //switch for be.
  239. fix_header(&header);
  240. printf("Dump header:\n");
  241. printf("partition version:%d.%d\n",
  242. header.resource_ptn_version, header.index_tbl_version);
  243. printf("header size:%d\n", header.header_size);
  244. printf("index tbl:\n\toffset:%d\tentry size:%d\tentry num:%d\n",
  245. header.tbl_offset, header.tbl_entry_size, header.tbl_entry_num);
  246. //TODO: support header_size & tbl_entry_size
  247. if (header.resource_ptn_version != RESOURCE_PTN_VERSION
  248. || header.header_size != RESOURCE_PTN_HDR_SIZE
  249. || header.index_tbl_version != INDEX_TBL_VERSION
  250. || header.tbl_entry_size != INDEX_TBL_ENTR_SIZE) {
  251. LOGE("Not supported in this version!");
  252. goto end;
  253. }
  254. printf("Dump Index table:\n");
  255. index_tbl_entry entry;
  256. int i;
  257. for (i = 0; i < header.tbl_entry_num; i++) {
  258. //TODO: support tbl_entry_size
  259. if (!fread(buf, BLOCK_SIZE, 1, image_file)) {
  260. LOGE("Failed to read index entry:%d!", i);
  261. goto end;
  262. }
  263. memcpy(&entry, buf, sizeof(entry));
  264. if (memcmp(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag))) {
  265. LOGE("Something wrong with index entry:%d!", i);
  266. goto end;
  267. }
  268. //switch for be.
  269. fix_entry(&entry);
  270. printf("entry(%d):\n\tpath:%s\n\toffset:%d\tsize:%d\n",
  271. i, entry.path, entry.content_offset, entry.content_size);
  272. if (!dump_file(image_file, unpack_dir, entry)) {
  273. goto end;
  274. }
  275. }
  276. printf("Unack %s to %s successed!\n", image_path, unpack_dir);
  277. ret = true;
  278. end:
  279. if (image_file)
  280. fclose(image_file);
  281. return ret ? 0 : -1;
  282. }
  283. /************unpack code end****************/
  284. /************pack code****************/
  285. static inline size_t get_file_size(const char* path) {
  286. LOGD("try to get size(%s)...", path);
  287. struct stat st;
  288. if(stat(path, &st) < 0) {
  289. LOGE("Failed to get size:%s", path);
  290. return -1;
  291. }
  292. LOGD("path:%s, size:%d", path, st.st_size);
  293. return st.st_size;
  294. }
  295. static int write_file(int offset_block, const char* src_path) {
  296. LOGD("try to write file(%s) to offset:%d...", src_path, offset_block);
  297. char buf[BLOCK_SIZE];
  298. int ret = -1;
  299. size_t file_size;
  300. int blocks;
  301. FILE* src_file = fopen(src_path, "rb");
  302. if (!src_file) {
  303. LOGE("Failed to open:%s", src_path);
  304. goto end;
  305. }
  306. file_size = get_file_size(src_path);
  307. if(file_size < 0) {
  308. goto end;
  309. }
  310. blocks = fix_blocks(file_size);
  311. int i;
  312. for (i = 0; i < blocks; i++) {
  313. memset(buf, 0, sizeof(buf));
  314. if (!fread(buf, 1, BLOCK_SIZE, src_file)) {
  315. LOGE("Failed to read:%s", src_path);
  316. goto end;
  317. }
  318. if (!write_data(offset_block + i, buf, BLOCK_SIZE)) {
  319. goto end;
  320. }
  321. }
  322. done:
  323. ret = blocks;
  324. end:
  325. if (src_file)
  326. fclose(src_file);
  327. return ret;
  328. }
  329. static bool write_header(const int file_num) {
  330. LOGD("try to write header...");
  331. memcpy(header.magic, RESOURCE_PTN_HDR_MAGIC, sizeof(header.magic));
  332. header.resource_ptn_version = RESOURCE_PTN_VERSION;
  333. header.index_tbl_version = INDEX_TBL_VERSION;
  334. header.header_size = RESOURCE_PTN_HDR_SIZE;
  335. header.tbl_offset = header.header_size;
  336. header.tbl_entry_size = INDEX_TBL_ENTR_SIZE;
  337. header.tbl_entry_num = file_num;
  338. //switch for le.
  339. resource_ptn_header hdr = header;
  340. fix_header(&hdr);
  341. return write_data(0, &hdr, sizeof(hdr));
  342. }
  343. static bool write_index_tbl(const int file_num, const char** files) {
  344. LOGD("try to write index table...");
  345. bool ret = false;
  346. bool foundFdt = false;
  347. int offset = header.header_size +
  348. header.tbl_entry_size * header.tbl_entry_num;
  349. index_tbl_entry entry;
  350. memcpy(entry.tag, INDEX_TBL_ENTR_TAG, sizeof(entry.tag));
  351. int i;
  352. for (i = 0; i < file_num; i++) {
  353. size_t file_size = get_file_size(files[i]);
  354. if (file_size < 0)
  355. goto end;
  356. entry.content_size = file_size;
  357. entry.content_offset = offset;
  358. if (write_file(offset, files[i]) < 0)
  359. goto end;
  360. LOGD("try to write index entry(%s)...", files[i]);
  361. //switch for le.
  362. fix_entry(&entry);
  363. memset(entry.path, 0, sizeof(entry.path));
  364. const char* path = files[i];
  365. if (root_path[0]) {
  366. if (!strncmp(path, root_path, strlen(root_path))) {
  367. path += strlen(root_path);
  368. if (path[0] == '/')
  369. path++;
  370. }
  371. }
  372. path = fix_path(path);
  373. if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX),
  374. DTD_SUBFIX)) {
  375. if (!foundFdt) {
  376. //use default path.
  377. LOGD("mod fdt path:%s -> %s...", files[i], FDT_PATH);
  378. path = FDT_PATH;
  379. foundFdt = true;
  380. }
  381. }
  382. snprintf(entry.path, sizeof(entry.path), "%s", path);
  383. offset += fix_blocks(file_size);
  384. if (!write_data(header.header_size + i * header.tbl_entry_size,
  385. &entry, sizeof(entry)))
  386. goto end;
  387. }
  388. ret = true;
  389. end:
  390. return ret;
  391. }
  392. static int pack_image(int file_num, const char** files) {
  393. bool ret = false;
  394. FILE* image_file = fopen(image_path, "wb");
  395. if (!image_file) {
  396. LOGE("Failed to create:%s", image_path);
  397. goto end;
  398. }
  399. fclose(image_file);
  400. //prepare files
  401. int i = 0;
  402. int pos = 0;
  403. const char* tmp;
  404. for (i = 0; i < file_num; i++) {
  405. if (!strcmp(files[i] + strlen(files[i]) - strlen(DTD_SUBFIX),
  406. DTD_SUBFIX)) {
  407. //dtb files for kernel.
  408. tmp = files[pos];
  409. files[pos] = files[i];
  410. files[i] = tmp;
  411. pos++;
  412. } else if (!strcmp(fix_path(image_path), fix_path(files[i]))) {
  413. //not to pack image itself!
  414. tmp = files[file_num - 1];
  415. files[file_num - 1] = files[i];
  416. files[i] = tmp;
  417. file_num --;
  418. }
  419. }
  420. if (!write_header(file_num)) {
  421. LOGE("Failed to write header!");
  422. goto end;
  423. }
  424. if (!write_index_tbl(file_num, files)) {
  425. LOGE("Failed to write index table!");
  426. goto end;
  427. }
  428. printf("Pack to %s successed!\n", image_path);
  429. ret = true;
  430. end:
  431. return ret ? 0 : -1;
  432. }
  433. /************pack code end****************/