196 lines
7 KiB
C
196 lines
7 KiB
C
#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;
|
|
}
|