一个资源打包工具完整代码

#include 
#include 

static char g_mem[5 * 1024 * 1024];

#define MORE	17

#define min(a, b) ((a) < (b) ? (a) : (b))

typedef struct _ResMap
{
    char *pName;
    int iPos;
    int iLen;
    int iOrgLen;
    char *pData;
    int iDstBegin;
} ResMap;

typedef struct _Item
{
    ResMap *rm;
    int next;
} Item;

int ReadFile(char *pName)
{
    FILE *pFile = fopen(pName, "rb");
    int n = 0;
    char *p = g_mem;
    while (1)
    {
        n = fread(p, 1, 10240, pFile);
        if (n == 0)
            break;
        p += n;
    }
    fclose(pFile);
    return p - g_mem;
}

int Hash(char *str, int n)
{
    unsigned int val = 0;
    n += MORE;
    for (; *str; ++str)
    {
        val = val * 31 + *str;
    }
    return val % n;
}

static char g_hex[] = "0123456789abcdef";

void ChangeHex(char *pFileName, ResMap *pMapBuf, int iIsLast, int *piFrom)
{
    int iLen = ReadFile(pFileName);
    int nlen = strlen(pFileName) + 1;
    int iRstLen = (iLen + nlen) * 5;
    char *pMem = malloc(iRstLen);
    char *pCur = pMem;
    unsigned char *pSrc = (unsigned char *)g_mem;
    
    int i = 0;
    for (i = 0; i < nlen; i++, pCur += 5) 
    {
  	 	pCur[0] = '0';
        pCur[1] = 'x';
        pCur[2] = g_hex[(pFileName[i] >> 4) & 0xf];
        pCur[3] = g_hex[pFileName[i] & 0xf];
        pCur[4] = ',';
    }
    
    for (i = 0; i < iLen; i++, pCur += 5)
    {
        pCur[0] = '0';
        pCur[1] = 'x';
        pCur[2] = g_hex[(pSrc[i] >> 4) & 0xf];
        pCur[3] = g_hex[pSrc[i] & 0xf];
        pCur[4] = ',';
    }
    iLen += nlen;
    iRstLen -= (iIsLast ? 1 : 0);
    pMapBuf->pName = pFileName;
    pMapBuf->iLen = iRstLen;
    pMapBuf->pData = pMem;
    pMapBuf->iOrgLen = iLen;
    pMapBuf->iDstBegin = *piFrom;
    *piFrom += iLen;
}

void WriteHead(FILE *pC)
{
    char *p = "#include \n\n"
			  "typedef struct _ResMap {\n"
              "	int iPos;\n"
              "	int iDatLen;\n"
              "	short sNameLen;\n"
              "	short sNext;\n"
              "} ResMap;\n\n";
    fwrite(p, strlen(p), 1, pC);
}

void WriteFunc(FILE *pC, int n)
{
    char *p = "static int Hash(const char *str)\n"
              "{\n"
              "	unsigned int val = 0;\n"
              "	for (; *str; ++str)\n"
              "		val = val * 31 + *str;\n"
              "	return val % ";
    fwrite(p, strlen(p), 1, pC);
    char buf[10];
    sprintf(buf, "%d;\n", n + MORE);
    fwrite(buf, strlen(buf), 1, pC);

    p = "}\n\n"
        "void * LoadRes(const char* pName, int *piLen)\n"
        "{\n"
        "	int i = 0;\n"
        "	if (!pName || !piLen)\n"
        "	    return 0;\n\n"
        "	i = Hash(pName);\n"
        "	*piLen = 0;\n\n"
        "	 while (i != -1) {\n"
        "		if (! g_map[i].iDatLen)\n"
        "			return 0;\n"
        "		char *pExName = g_dat + g_map[i].iPos;\n"
        "	    if (strcmp(pName, pExName) == 0) {\n"
        " 		     *piLen = g_map[i].iDatLen;\n"
        "	         return (g_dat + g_map[i].iPos + g_map[i].sNameLen);\n"
        "		}\n"
        "		i = g_map[i].sNext;\n"
        "	}\n"
        "	return 0;\n"
        "}\n\n\n";
    fwrite(p, strlen(p), 1, pC);
}

void WriteCnt(FILE *pC, ResMap *pMap, int iResNum)
{
    int i = 0;
    char *p = "static char g_dat[] = {";
    fwrite(p, strlen(p), 1, pC);

    for (; i < iResNum; i++)
    {
        int len = pMap->iLen;
        char *dat = pMap->pData;
        while (len > 0) {
        	fwrite("\n\t", 2, 1, pC);
	        fwrite(dat, min(len, 80), 1, pC); 
			len -= 80;
			dat += 80;
        }
        ++pMap;
    }
    fwrite("\n};\n\n", 4, 1, pC);
}

void WriteTail(FILE *pC, Item *pIt, int iResNum)
{
    char tmp[100];
    char name[100];
    int iMn = iResNum + MORE;
    sprintf(tmp, "static ResMap g_map[] = {");
    fwrite(tmp, strlen(tmp), 1, pC);
    int i = 0, line = 0;
	fwrite("\n\t", 2, 1, pC);
    for (; i < iMn; i++)
    {
        char *p = (i == iMn - 1) ? "" : ",";
        if (pIt->rm)
        {
        	int iLen = strlen(pIt->rm->pName) + 1;
            sprintf(tmp, "{0x%x,0x%x,0x%x,%d}%s", pIt->rm->iDstBegin, pIt->rm->iOrgLen - iLen, iLen, pIt->next, p);
        }
        else
        {
            sprintf(tmp, "{0}%s", p);
        }
        line += strlen(tmp);
        if (line > 80) {
        	fwrite("\n\t", 2, 1, pC);
        	line = strlen(tmp);
        }
        fwrite(tmp, strlen(tmp), 1, pC);
        ++pIt;
    }
    fwrite("\n};\n\n\n", 6, 1, pC);
}


static char ** GetFileName(int *pNum)
{
    char **pList = malloc(1000 * sizeof(char *));;
    char buf[100];
    *pNum = 0;
    char *p = g_mem;
    int len = ReadFile("r.txt");
    p[len] = '\0';

    while (sscanf(p, "%s\n", buf) > 0)
    {
        pList[*pNum] = malloc(strlen(buf) + 1);
        strcpy(pList[*pNum], buf);
        if (*buf == '\0')
            break;
        (*pNum)++;
        p += strlen(buf) + 1;
    }

    return pList;
}

int FindPos(Item *pIt, int start, char *name)
{
    if (strcmp(pIt[start].rm->pName, name) == 0)
        return -1;

    int i = start, old ;

    while (1)
    {
        int mi = pIt[i].next;
        if (mi == -1)
        {
            old = i;
            break;
        }
        i = mi;
    }
    i = 0;
    while (1)
    {
        if (! pIt[i].rm)
            break;
        i++;
    }
    pIt[old].next = i;

    return i;
}

int main()
{
    int n = 0;
    int mn = 0;
    char **pNames = GetFileName(&n);
    ResMap *pMap = malloc(sizeof(ResMap) * n);
    mn = n + MORE;
    Item *pIt = malloc(sizeof(Item) * mn);
    memset(pIt, 0, sizeof(Item) * mn);
    int i = 0, from = 0;

    for (; i < mn; i++)
        pIt[i].next = -1;

    for (i = 0; i < n; i++)
    {
        ChangeHex(pNames[i], pMap + i, i == n - 1, &from);

        int v = Hash(pNames[i], n);
        if (! pIt[v].rm)
        {
            pIt[v].rm = pMap + i;
        }
    }

    for (i = 0; i < n; i++)
    {
        int v = Hash(pNames[i], n);
        int pos = FindPos(pIt, v, pNames[i]);

        if (pos != -1)
        {
            pIt[pos].rm = pMap + i;
        }
    }
    
    FILE *pC = fopen("R.c", "wb");

    WriteHead(pC);

    WriteCnt(pC, pMap, n);

    WriteTail(pC, pIt, n);
    WriteFunc(pC, n);

    fclose(pC);
   
    return 0;
}


本程序从r.txt中读取需要打包的资源文件名, 最终生成了一个R.c文件

将R.c与其它c文件一起编译即可。

r.txt文件格式如下所示:

abc.png

def.jpg

.....

每个文件名占一行。


生成的R.c文件内容大概是这样子的:

#include 

typedef struct _ResMap {
	int iPos;
	int iDatLen;
	short sNameLen;
	short sNext;
} ResMap;

static char g_dat[] = {
	0x6d,0x61,0x69,0x6e,0x2e,0x63,0x00,0x23,0x69,0x6e,0x63,0x6c,0x75,0x64,0x65,0x20,
	0x3c,0x73,0x74,0x64,0x69,0x6f,0x2e,0x68,0x3e,0x0d,0x0a,0x23,0x69,0x6e,0x63,0x6c,
	0x75,0x64,0x65,0x20,0x3c,0x73,0x74,0x72,0x69,0x6e,.....
};


static ResMap g_map[] = {
	{0x8b90,0x32ef,0x7,-1},{0},{0x1ab4,0x70d3,0x9,0},{0},{0},{0},{0},{0},{0},{0},
	{0},{0x0,0x1aad,0x7,-1},{0},{0},{0},{0xbe86,0x19,0x2,-1},.....
};

static int Hash(const char *str)
{
	unsigned int val = 0;
	for (; *str; ++str)
		val = val * 31 + *str;
	return val % 21;
}

void * LoadRes(const char* pName, int *piLen)
{
	int i = 0;
	if (!pName || !piLen)
	    return 0;

	i = Hash(pName);
	*piLen = 0;

	 while (i != -1) {
		if (! g_map[i].iDatLen)
			return 0;
		char *pExName = g_dat + g_map[i].iPos;
	    if (strcmp(pName, pExName) == 0) {
 		     *piLen = g_map[i].iDatLen;
	         return (g_dat + g_map[i].iPos + g_map[i].sNameLen);
		}
		i = g_map[i].sNext;
	}
	return 0;
}

通过LoadRes即可得到资源的内容, 时间复杂度接近于O(1)





你可能感兴趣的:(C/C++)