a91b0145创建于 2022年8月3日历史提交
#include "pak_pack.h"

bool pakUnpack(uint8_t *buffer, char *outputPath) {

    MyPakHeader myHeader;

    if (!pakParseHeader(buffer, &myHeader)) {

        return false;

    }

    PakFile *files = pakGetFiles(buffer);

    if (files == NULL) {

        return false;

    }



    char fileNameBuf[FILENAME_MAX];

    memset(fileNameBuf, 0, FILENAME_MAX);

    char pathBuf[PATH_MAX + 2];

    memset(pathBuf, 0, PATH_MAX);



#ifdef _WIN32

    CreateDirectory(outputPath, NULL);

#else

    mkdir(outputPath, 0777);

#endif

    char *pakIndexStr = calloc(PAK_BUFFER_BLOCK_SIZE, sizeof(char));

    if (pakIndexStr == NULL) {

        free(files);

        return false;

    }

    uint32_t offset = 0;

    uint32_t length = PAK_BUFFER_BLOCK_SIZE;

    offset +=

        sprintf(pakIndexStr + offset, PAK_INDEX_GLOBAL_TAG "\r\nversion=%u\r\n",

                myHeader.version);

    offset += sprintf(pakIndexStr + offset,

                      "encoding=%u\r\n\r\n" PAK_INDEX_RES_TAG "\r\n",

                      myHeader.encoding);

    for (uint32_t i = 0; i < myHeader.resource_count; i++) {

        sprintf(fileNameBuf, "%u%s", files[i].id, pakGetFileType(files[i]));

        offset += sprintf(pakIndexStr + offset, "%u=%s\r\n", files[i].id,

                          fileNameBuf);

        if (length - offset < PAK_BUFFER_MIN_FREE_SIZE) {

            pakIndexStr = realloc(pakIndexStr, length + PAK_BUFFER_BLOCK_SIZE);

            length += PAK_BUFFER_BLOCK_SIZE;

        }

        sprintf(pathBuf, "%s/%s", outputPath, fileNameBuf);

        writeFile(pathBuf, files[i]);

    }

    PakAlias *aliasBuf = NULL;

    if (myHeader.alias_count > 0) {

        offset +=

            sprintf(pakIndexStr + offset, "\r\n" PAK_INDEX_ALIAS_TAG "\r\n");

        aliasBuf = (PakAlias *)(buffer + myHeader.size +

                                (myHeader.resource_count + 1) * PAK_ENTRY_SIZE);

    }

    for (unsigned int i = 0; i < myHeader.alias_count; i++) {

        offset += sprintf(pakIndexStr + offset, "%u=%u\r\n",

                          aliasBuf->resource_id, aliasBuf->entry_index);

        aliasBuf++;

        if (length - offset < PAK_BUFFER_MIN_FREE_SIZE) {

            pakIndexStr = realloc(pakIndexStr, length + PAK_BUFFER_BLOCK_SIZE);

            length += PAK_BUFFER_BLOCK_SIZE;

        }

    }

    PakFile pakIndexBuf;

    // puts(pakIndexStr);

    pakIndexBuf.buffer = pakIndexStr;

    pakIndexBuf.size = offset;

    sprintf(pathBuf, "%s/pak_index.ini", outputPath);

    writeFile(pathBuf, pakIndexBuf);

    freeFile(pakIndexBuf);

    free(files);

    return true;

}



uint32_t countChar(const char *string, uint32_t length, char toCount) {

    uint32_t count = 0;

    for (uint32_t i = 0; i < length; i++) {

        if (string[i] == toCount)

            count++;

    }

    return count;

}



PakFile pakPack(PakFile pakIndex, char *path) { // TODO

    MyPakHeader myHeader;

    memset(&myHeader, 0, sizeof(myHeader));

    char *pakIndexBuf = pakIndex.buffer;



    PakFile pakFile = NULL_File;

    PakFile *resFiles = NULL;

    PakAlias *pakAlias = NULL;



    uint32_t count = 0;

    uint32_t offset = sizeof(PAK_INDEX_GLOBAL_TAG) - 1;

    sscanf(pakIndexBuf + offset, " version=%u%n", &myHeader.version, &count);

    if (count == 0) {

        goto PAK_PACK_END;

    }

    offset += count;

#pragma GCC diagnostic push

#pragma GCC diagnostic ignored "-Wformat"

#pragma GCC diagnostic ignored "-Wformat-extra-args"

    sscanf(pakIndexBuf + offset, " encoding=%hhu%n", &myHeader.encoding,

           &count);

#pragma GCC diagnostic pop

    //	printf("version=%u\nencoding=%u\n", myHeader.version,

    // myHeader.encoding);

    if (myHeader.version == 5) {

        myHeader.size = PAK_HEADER_SIZE_V5;

    } else if (myHeader.version == 4) {

        myHeader.size = PAK_HEADER_SIZE_V4;

    } else {

        puts(PAK_ERROR_UNKNOWN_VER);

        goto PAK_PACK_END;

    }

    char *pakIndexEnd = pakIndexBuf + pakIndex.size - 1;

    char *pakEntryIndex =

        strstr(pakIndexBuf, PAK_INDEX_RES_TAG) + sizeof(PAK_INDEX_RES_TAG) - 1;

    char *pakAliasIndex = strstr(pakIndexBuf, PAK_INDEX_ALIAS_TAG);

    if (myHeader.version == 4 || pakAliasIndex == NULL) {

        myHeader.alias_count = 0;

        pakAliasIndex = pakIndexEnd;

    } else {

        pakAliasIndex += sizeof(PAK_INDEX_ALIAS_TAG) - 1;

        myHeader.alias_count =

                (uint16_t) countChar(pakAliasIndex, pakIndexEnd - pakAliasIndex, '=');

    }

    myHeader.resource_count =

        countChar(pakEntryIndex, pakAliasIndex - pakEntryIndex, '=');



    // printf("resource_count=%u\nalias_count=%u\n", myHeader.resource_count,

    // myHeader.alias_count);



    char fileNameBuf[FILENAME_MAX];

    memset(fileNameBuf, 0, FILENAME_MAX);

    char pathBuf[PATH_MAX];

    memset(pathBuf, 0, PATH_MAX);

    resFiles = calloc(myHeader.resource_count, sizeof(PakFile));

    if (resFiles == NULL) {

        goto PAK_PACK_END;

    }



    offset = 0;

    for (uint32_t i = 0; i < myHeader.resource_count; i++) {

        uint32_t id = 0;

        sscanf(pakEntryIndex + offset, " %u=%s%n ", &id, fileNameBuf, &count);

        if (count == 0 || sprintf(pathBuf, "%s%s", path, fileNameBuf) == 0) {

            puts(PAK_ERROR_BROKEN_INDEX);

            myHeader.resource_count = i;

            goto PAK_PACK_END;

        }

        offset += count;

        resFiles[i] = readFile(pathBuf);

        if (resFiles[i].buffer == NULL) {

            puts(PAK_ERROR_BROKEN_INDEX);

            myHeader.resource_count = i;

            goto PAK_PACK_END;

        }

        resFiles[i].id = (uint16_t) id;

        //	printf("id=%u\tfile_name=%s\tpath=%s\tsize=%u\n",id,

        // fileNameBuf, pathBuf, resFiles[i].size);

    }

    if (myHeader.alias_count > 0) {

        offset = 0;

        pakAlias = calloc(myHeader.alias_count, sizeof(PakAlias));

        if (pakAlias == NULL) {

            goto PAK_PACK_END;

        }

        for (uint32_t i = 0; i < myHeader.alias_count; i++) {

            sscanf(pakAliasIndex + offset, " %hu=%hu%n ",

                   &pakAlias[i].resource_id, &pakAlias[i].entry_index, &count);

            if (count == 0) {

                puts(PAK_ERROR_BROKEN_INDEX);

                goto PAK_PACK_END;

            }

            offset += count;

            //	printf("resource_id=%hu\tentry_index=%hu\n",pakAlias[i].resource_id,

            // pakAlias[i].entry_index);

        }

    }

    pakFile = pakPackFiles(&myHeader, resFiles, pakAlias);

    printf("\nresource_count = %u\nalias_count = %u\n", myHeader.resource_count,

           myHeader.alias_count);

    printf("version = %u\nencoding = %u\n", myHeader.version, myHeader.encoding);

    printf("\n.pak size: %u", pakFile.size);

    printf(" bytes\n");

PAK_PACK_END:

    if (resFiles != NULL) {

        for (uint32_t i = 0; i < myHeader.resource_count; i++) {

            if (resFiles[i].buffer != NULL)

                free(resFiles[i].buffer);

        }

        free(resFiles);

    }

    if (pakAlias != NULL)

        free(pakAlias);

    return pakFile;

}