From e2436e091812ebe7cc66e369c8624839107d8071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E5=85=B4=E9=80=B8?= <853974536@qq.com> Date: Tue, 30 May 2023 02:20:18 +0800 Subject: [PATCH] CPyMO Tool Pack API (#43) * add cpymo_tool_package_packer api * rewrite cpymo pack in cpymo tool pack api * stricter pack api --- cpymo-tool/cpymo_tool_package.c | 218 ++++++++++++++++---------------- cpymo-tool/cpymo_tool_package.h | 31 +++++ 2 files changed, 140 insertions(+), 109 deletions(-) create mode 100644 cpymo-tool/cpymo_tool_package.h diff --git a/cpymo-tool/cpymo_tool_package.c b/cpymo-tool/cpymo_tool_package.c index f86ada0b..4a7c9bbc 100644 --- a/cpymo-tool/cpymo_tool_package.c +++ b/cpymo-tool/cpymo_tool_package.c @@ -1,4 +1,5 @@ #include "cpymo_tool_prelude.h" +#include "cpymo_tool_package.h" #include #include #include @@ -12,13 +13,12 @@ static error_t cpymo_tool_unpack(const char *pak_path, const char *extension, co error_t err = cpymo_package_open(&pkg, pak_path); if (err != CPYMO_ERR_SUCC) return err; - uint32_t max_length = 0; - for (uint32_t i = 0; i < pkg.file_count; ++i) + for (uint32_t i = 0; i < pkg.file_count; ++i) if (pkg.files[i].file_length > max_length) max_length = pkg.files[i].file_length; - + char *buf = malloc(max_length); if (buf == NULL) { cpymo_package_close(&pkg); @@ -73,136 +73,136 @@ static error_t cpymo_tool_unpack(const char *pak_path, const char *extension, co return CPYMO_ERR_SUCC; } -static error_t cpymo_tool_pack(const char *out_pack_path, const char **files_to_pack, uint32_t file_count) +error_t cpymo_tool_package_packer_open( + cpymo_tool_package_packer *packer, + const char *path, + size_t max_files_count) { - cpymo_package_index *index = malloc(sizeof(cpymo_package_index) * file_count); - if (index == NULL) return CPYMO_ERR_OUT_OF_MEM; - - uint32_t current_offset = sizeof(uint32_t) + file_count * sizeof(cpymo_package_index); - uint32_t max_length = 0; + packer->current_file_count = 0; + packer->data_section_start_offset = + sizeof(uint32_t) + max_files_count * sizeof(cpymo_package_index); + packer->index_section_start_offset = sizeof(uint32_t); + packer->max_file_count = max_files_count; + + packer->stream = fopen(path, "wb"); + if (packer->stream == NULL) + return CPYMO_ERR_CAN_NOT_OPEN_FILE; - for (uint32_t i = 0; i < file_count; ++i) { - const char *path = files_to_pack[i]; - FILE *file = fopen(path, "rb"); - if (file == NULL) { - printf("Can not open file %s\n", path); - free(index); - return CPYMO_ERR_CAN_NOT_OPEN_FILE; + for (long i = 0; i < packer->data_section_start_offset; ++i) { + if (fputc(0, packer->stream) == EOF) { + fclose(packer->stream); + return CPYMO_ERR_BAD_FILE_FORMAT; } + } - #pragma warning(disable: 6386) - fseek(file, 0, SEEK_END); - index[i].file_length = (uint32_t)ftell(file); - fclose(file); + return CPYMO_ERR_SUCC; +} - index[i].file_offset = current_offset; +error_t cpymo_tool_package_packer_add_data( + cpymo_tool_package_packer *packer, + cpymo_str name, + void *data, + size_t len) +{ + if (packer->current_file_count >= packer->max_file_count) + return CPYMO_ERR_NO_MORE_CONTENT; - #pragma warning(disable: 6385) - current_offset += index[i].file_length; + if (fseek(packer->stream, packer->index_section_start_offset, SEEK_SET)) + return CPYMO_ERR_UNKNOWN; - if (index[i].file_length > max_length) - max_length = index[i].file_length; + char filename[32] = { '\0' }; + cpymo_str_copy(filename, sizeof(filename), name); + size_t written = fwrite(filename, sizeof(filename), 1, packer->stream); + if (written != 1) return CPYMO_ERR_UNKNOWN; - const char *filename_start1 = strrchr(path, '/') + 1; - const char *filename_start2 = strrchr(path, '\\') + 1; - const char *filename = filename_start1; + uint32_t index[2] = { + end_htole32(packer->data_section_start_offset), + end_htole32((uint32_t)len) + }; - if (filename_start2 > filename) filename = filename_start2; - if (path > filename) filename = path; + written = fwrite(index, sizeof(index), 1, packer->stream); + if (written != 1) return CPYMO_ERR_UNKNOWN; + long new_index_offset = ftell(packer->stream); - const char *ext_start = strrchr(filename, '.'); + if (fseek(packer->stream, packer->data_section_start_offset, SEEK_SET)) + return CPYMO_ERR_UNKNOWN; - size_t j = 0; - bool finished = false; - for (; j < 31; ++j) { - if (filename + j == ext_start || filename[j] == '\0') { - finished = true; - break; - } - else - index[i].file_name[j] = toupper(filename[j]); - } + written = fwrite(data, len, 1, packer->stream); + if (written != 1) return CPYMO_ERR_UNKNOWN; + long new_data_offset = ftell(packer->stream); - for (; j < 32; ++j) - index[i].file_name[j] = '\0'; + packer->current_file_count++; + packer->data_section_start_offset = new_data_offset; + packer->index_section_start_offset = new_index_offset; + return CPYMO_ERR_SUCC; +} - if (!finished) { - printf("[Warning] File name \"%s\" is too long!\n", index[i].file_name); +error_t cpymo_tool_package_packer_add_file( + cpymo_tool_package_packer *packer, + const char *file) +{ + const char *filename_start1 = strrchr(file, '/') + 1; + const char *filename_start2 = strrchr(file, '\\') + 1; + const char *filename = filename_start1; + if (filename_start2 > filename) filename = filename_start2; + if (file > filename) filename = file; + const char *ext_start = strrchr(filename, '.'); + + char filename_index[32] = { '\0' }; + + size_t j = 0; + bool finished = false; + for (size_t j = 0; j < 31; ++j) { + if (filename + j == ext_start || filename[j] == '\0') { + finished = true; + break; } - - index[i].file_length = end_htole32(index[i].file_length); - index[i].file_offset = end_htole32(index[i].file_offset); + else + filename_index[j] = toupper(filename[j]); } - char *buf = malloc(max_length); - if (buf == NULL) { - free(index); - return CPYMO_ERR_OUT_OF_MEM; - } + if (!finished) + printf("[Warning] File name \"%s\" is too long!\n", filename_index); - FILE *out_pak = fopen(out_pack_path, "wb"); - if (out_pak == NULL) { - printf("[Error] Can not open %s.\n", out_pack_path); - free(index); - return CPYMO_ERR_CAN_NOT_OPEN_FILE; - } + char *data = NULL; + size_t len; + error_t err = cpymo_utils_loadfile(file, &data, &len); + CPYMO_THROW(err); - uint32_t file_count_store = end_htole32(file_count); - size_t count = fwrite(&file_count_store, sizeof(uint32_t), 1, out_pak); - if (count != 1) { - printf("[Error] Can not write file_count to package.\n"); - free(index); - fclose(out_pak); - return CPYMO_ERR_UNKNOWN; - } + err = cpymo_tool_package_packer_add_data( + packer, cpymo_str_pure(filename_index), data, len); + free(data); + return err; +} - count = fwrite(index, sizeof(cpymo_package_index), file_count, out_pak); - free(index); +void cpymo_tool_package_packer_close( + cpymo_tool_package_packer *packer) +{ + uint32_t filecount_le32 = end_htole32((uint32_t)packer->current_file_count); + if (fseek(packer->stream, 0, SEEK_SET)) abort(); + if (fwrite(&filecount_le32, sizeof(filecount_le32), 1, packer->stream) != 1) + abort(); + if (fclose(packer->stream)) abort(); +} - if (count != file_count) { - printf("[Error] Can not write file index to package.\n"); - fclose(out_pak); - } +static error_t cpymo_tool_pack(const char *out_pack_path, const char **files_to_pack, uint32_t file_count) +{ + cpymo_tool_package_packer p; + error_t err = cpymo_tool_package_packer_open(&p, out_pack_path, file_count); + CPYMO_THROW(err); for (uint32_t i = 0; i < file_count; ++i) { - const char *path = files_to_pack[i]; - - FILE *f = fopen(path, "rb"); - if (f == NULL) { - printf("[Error] Can not open file %s.\n", path); - fclose(out_pak); - free(buf); - return CPYMO_ERR_CAN_NOT_OPEN_FILE; - } - - fseek(f, 0, SEEK_END); - uint32_t length = ftell(f); - fseek(f, 0, SEEK_SET); - - if (fread(buf, length, 1, f) != 1) { - printf("[Error] Can not read file %s.\n", path); - fclose(out_pak); - fclose(f); - free(buf); - return CPYMO_ERR_CAN_NOT_OPEN_FILE; - } - - fclose(f); - - if (fwrite(buf, length, 1, out_pak) != 1) { - printf("[Error] Can not write %s to package.\n", path); - fclose(out_pak); - free(buf); - return CPYMO_ERR_UNKNOWN; + printf("%s\n", files_to_pack[i]); + err = cpymo_tool_package_packer_add_file(&p, files_to_pack[i]); + if (err != CPYMO_ERR_SUCC) { + printf("[Error] Can not pack file: %s.\n", files_to_pack[i]); + cpymo_tool_package_packer_close(&p); + return err; } - - printf("%s\n", path); } - free(buf); - fclose(out_pak); - - printf("\n==> %s\n", out_pack_path); + cpymo_tool_package_packer_close(&p); + printf("==> %s\n", out_pack_path); return CPYMO_ERR_SUCC; } @@ -213,7 +213,7 @@ static error_t cpymo_tool_get_file_list(char *** files, size_t * count, const ch size_t ls_len; error_t err = cpymo_utils_loadfile(list_file, &ls_buf, &ls_len); CPYMO_THROW(err); - + cpymo_parser parser; cpymo_parser_init(&parser, ls_buf, ls_len); diff --git a/cpymo-tool/cpymo_tool_package.h b/cpymo-tool/cpymo_tool_package.h new file mode 100644 index 00000000..47345049 --- /dev/null +++ b/cpymo-tool/cpymo_tool_package.h @@ -0,0 +1,31 @@ +#ifndef INCLUDE_CPYMO_TOOL_PACKAGE +#define INCLUDE_CPYMO_TOOL_PACKAGE + +#include +#include "../cpymo/cpymo_str.h" + +typedef struct { + size_t max_file_count, current_file_count; + long index_section_start_offset, data_section_start_offset; + FILE *stream; +} cpymo_tool_package_packer; + +error_t cpymo_tool_package_packer_open( + cpymo_tool_package_packer *packer, + const char *path, + size_t max_files_count); + +error_t cpymo_tool_package_packer_add_data( + cpymo_tool_package_packer *packer, + cpymo_str name, + void *data, + size_t len); + +error_t cpymo_tool_package_packer_add_file( + cpymo_tool_package_packer *packer, + const char *file); + +void cpymo_tool_package_packer_close( + cpymo_tool_package_packer *packer); + +#endif