本文介紹作者寫的一個小工具,簡單的代碼中包含了C語言對字串的處理技巧,對文字檔的簡單解析,二進位檔案的資料複製的方法,以及格式化輸出文字檔的樣本。
工具的輸入是如下內容的設定檔:
;資源管理員配置指令碼;以行為單位,每行不能超過255個字元;空行和以;開頭的注釋行會被忽略掉;每行都關聯一個資源檔,資源序號從0開始,依次遞增.\img\img128x128.bin.\snd\start.wav.\img\sheis1.bin.\snd\balloon.wav.\img\sheis2.bin
工具的原始碼貼在這裡:
#include <ctype.h>#include <string.h>#include <stdlib.h>#include <stdio.h>/* 定義相關檔案名稱 */#define CONFIG_FILE_NAME ("config.txt")#define RESPAK_FILE_NAME ("resmm.bin")#define ADDRS_C_FILE_NAME ("resmm_addrs.c")/* 定義配置行最大的字元數 */#define LINE_CHARS (255)/* 定義複製檔案資料時的緩衝區大小 */#define BUF_SIZE (8 * 1024)/* 從配置行提取檔案名稱 */static char* extract_file_name(const char* line, char* file_name){ /* 過濾配置行左邊的空格符 */ while(isspace(*line++)){}; line--; /* 忽略空行和注釋行 */ if((*line == '\0') || (*line == ';')) return NULL; /* 提取檔案名稱,並去掉右邊的空格符 */ strcpy(file_name, line); { char* p = file_name + strlen(file_name) - 1; while(isspace(*p--)){}; p++; p++; *p = '\0'; } return file_name;}/* 掃描有效檔案數 */static int scan_file_count(FILE* cf){ char line[LINE_CHARS + 1]; char file_name[LINE_CHARS + 1]; int count = 0; while(!feof(cf)) { fgets(line, LINE_CHARS, cf); if(extract_file_name(line, file_name) != NULL) count++; } return count;}/* 複製檔案資料 */static size_t copy_file_datas(FILE* pf, FILE* rf){ unsigned char buf[BUF_SIZE]; size_t total = 0; size_t len; do{ len = fread(buf, sizeof(unsigned char), BUF_SIZE, rf); fwrite(buf, sizeof(unsigned char), len, pf); total += len; }while(len == BUF_SIZE); return total;}/* 主函數 */int main(int argc, char* argv[]){ FILE* cf; FILE* pf; FILE* rf; int count; size_t* lens; size_t len; unsigned int addr; char line[LINE_CHARS + 1]; char file_name[LINE_CHARS + 1]; int i; /* 開啟設定檔,並掃描有效檔案數 */ if((cf = fopen(CONFIG_FILE_NAME, "rt")) == NULL) { printf("Can\'t open %s!\n", CONFIG_FILE_NAME); return -1; } count = scan_file_count(cf); fseek(cf, 0L, SEEK_SET); /* 開啟資源套件檔案 */ if((pf = fopen(RESPAK_FILE_NAME, "wb")) == NULL) { printf("Can\'t create %s!\n", RESPAK_FILE_NAME); fclose(cf); return -1; } /* 複製打包資源檔,並統計其大小 */ if((lens = (size_t*)malloc(sizeof(size_t) * count)) == NULL) { printf("No enough memory!\n"); fclose(pf); fclose(cf); return -1; } i = 0; while(!feof(cf)) { fgets(line, LINE_CHARS, cf); if(extract_file_name(line, file_name) != NULL) { if((rf = fopen(file_name, "rb")) == NULL) { printf("Can\'t open %s!\n", file_name); fclose(pf); fclose(cf); return -1; } if((len = copy_file_datas(pf, rf)) == 0) { printf("File %s is empty!\n", file_name); fclose(pf); fclose(cf); return -1; } lens[i++] = len; fclose(rf); } } fclose(pf); fclose(cf); /* 開啟地址描述的C語言源檔案 */ if((cf = fopen(ADDRS_C_FILE_NAME, "wt")) == NULL) { printf("Can\'t open %s!\n", ADDRS_C_FILE_NAME); return -1; } /* 把各個資源的地址和長度資訊寫入C語言數組 */ fprintf(cf, "#define RES_COUNT\t(%d)\n\n", count); fprintf(cf, "static const INT32U addrs[RES_COUNT] = \n{\n"); addr = 0; for(i = 0; i < count; i++) { fprintf(cf, "\t\t0x%08x,\n", addr); addr += lens[i]; } fprintf(cf, "};\n\n"); fprintf(cf, "static const INT32U lens[RES_COUNT] = \n{\n"); for(i = 0; i < count; i++) fprintf(cf, "\t\t0x%08x,\n", lens[i]); fprintf(cf, "};"); fclose(cf); free(lens); return 0;}
格式化輸出的文字檔是這樣的:
#define RES_COUNT(5)static const INT32U addrs[RES_COUNT] = {0x00000000,0x00008000,0x0000889a,0x0001089a,0x0001219a,};static const INT32U lens[RES_COUNT] = {0x00008000,0x0000089a,0x00008000,0x00001900,0x00008000,};