diff options
author | Davide Beatrici <git@davidebeatrici.dev> | 2021-03-10 00:06:53 +0300 |
---|---|---|
committer | Davide Beatrici <git@davidebeatrici.dev> | 2021-03-10 00:06:53 +0300 |
commit | c798511e419ededd0cbe34a09f2aaca5111d9576 (patch) | |
tree | 040b3dde21f4e86509087330b8b40e7fe6d1ee82 | |
parent | afe882a6739dcb0efba5cc9fabd7647b98a9fbba (diff) |
Introduce HamcoreBuild(), for building archives
-rwxr-xr-x | FileSystem.c | 55 | ||||
-rwxr-xr-x | FileSystem.h | 8 | ||||
-rw-r--r-- | Hamcore.c | 187 | ||||
-rw-r--r-- | Hamcore.h | 2 | ||||
-rw-r--r-- | Memory.c | 13 | ||||
-rw-r--r-- | Memory.h | 2 |
6 files changed, 263 insertions, 4 deletions
diff --git a/FileSystem.c b/FileSystem.c index b691746..cb64fe5 100755 --- a/FileSystem.c +++ b/FileSystem.c @@ -1,13 +1,17 @@ #include "FileSystem.h" -FILE *FileOpen(const char *path) +#include <string.h> + +#include <sys/stat.h> + +FILE *FileOpen(const char *path, const bool write) { if (!path) { return NULL; } - return fopen(path, "rb"); + return fopen(path, write ? "wb" : "rb"); } bool FileClose(FILE *file) @@ -30,6 +34,16 @@ bool FileRead(FILE *file, void *dst, const size_t size) return fread(dst, 1, size, file) == size; } +bool FileWrite(FILE *file, const void *src, const size_t size) +{ + if (!file || !src || size == 0) + { + return false; + } + + return fwrite(src, 1, size, file) == size; +} + bool FileSeek(FILE *file, const size_t offset) { if (!file) @@ -39,3 +53,40 @@ bool FileSeek(FILE *file, const size_t offset) return fseek(file, offset, SEEK_SET) == 0; } + +size_t FileSize(const char *path) +{ + if (!path) + { + return 0; + } + + struct stat st; + if (stat(path, &st) == -1) + { + return 0; + } + + return st.st_size; +} + +const char *PathRelativeToBase(const char *full, const char *base) +{ + if (!full || !base) + { + return NULL; + } + + if (strstr(full, base) != &full[0]) + { + return NULL; + } + + full += strlen(base); + if (full[0] == '/') + { + ++full; + } + + return full; +} diff --git a/FileSystem.h b/FileSystem.h index 3d61408..b4092c7 100755 --- a/FileSystem.h +++ b/FileSystem.h @@ -4,10 +4,16 @@ #include <stdbool.h> #include <stdio.h> -FILE *FileOpen(const char *path); +FILE *FileOpen(const char *path, const bool write); bool FileClose(FILE *file); bool FileRead(FILE *file, void *dst, const size_t size); +bool FileWrite(FILE *file, const void *src, const size_t size); + bool FileSeek(FILE *file, const size_t offset); +size_t FileSize(const char *path); + +const char *PathRelativeToBase(const char *full, const char *base); + #endif @@ -8,6 +8,12 @@ #include <zlib.h> +typedef struct COMPRESSED_FILE +{ + void *Data; + HAMCORE_FILE File; +} COMPRESSED_FILE; + HAMCORE *HamcoreOpen(const char *path) { if (!path) @@ -18,7 +24,7 @@ HAMCORE *HamcoreOpen(const char *path) HAMCORE *hamcore = malloc(sizeof(HAMCORE)); memset(hamcore, 0, sizeof(HAMCORE)); - hamcore->File = FileOpen(path); + hamcore->File = FileOpen(path, false); if (!hamcore->File) { free(hamcore); @@ -190,3 +196,182 @@ FINAL: free(buf); return ok; } + +bool HamcoreBuild(const char *dst_path, const char *base_path, const char **src_paths, const size_t num) +{ + if (!dst_path || !src_paths || num == 0) + { + return false; + } + + COMPRESSED_FILE *compressed_files = calloc(num, sizeof(COMPRESSED_FILE)); + + void *buffer = NULL; + size_t buffer_size = 0; + + for (size_t i = 0; i < num; ++i) + { + const char *path = src_paths[i]; + if (!path) + { + continue; + } + + FILE *handle = FileOpen(path, false); + if (!handle) + { + fprintf(stderr, "HamcoreBuild(): Failed to open \"%s\", skipping...\n", path); + continue; + } + + COMPRESSED_FILE *compressed_file = &compressed_files[i]; + HAMCORE_FILE *file = &compressed_file->File; + + file->OriginalSize = FileSize(path); + void *content = malloc(file->OriginalSize); + int ret = FileRead(handle, content, file->OriginalSize); + FileClose(handle); + + if (!ret) + { + fprintf(stderr, "HamcoreBuild(): Failed to read \"%s\", skipping...\n", path); + free(content); + continue; + } + + const size_t wanted_size = CompressionBufferSize(file->OriginalSize); + if (buffer_size < wanted_size) + { + const size_t prev_size = buffer_size; + buffer_size = wanted_size; + buffer = realloc(buffer, buffer_size); + memset(buffer + prev_size, 0, buffer_size - prev_size); + } + + file->Size = buffer_size; + ret = compress(buffer, (uLongf *)&file->Size, content, (uLong)file->OriginalSize); + free(content); + + if (ret != Z_OK) + { + fprintf(stderr, "HamcoreBuild(): Failed to compress \"%s\" with error %d, skipping...\n", path, ret); + file->Size = 0; + continue; + } + + const char *relative_path = base_path ? PathRelativeToBase(path, base_path) : path; + if (!relative_path) + { + fprintf(stderr, "HamcoreBuild(): Failed to get relative path for \"%s\", skipping...\n", path); + file->Size = 0; + continue; + } + + const size_t path_size = strlen(relative_path) + 1; + file->Path = malloc(path_size); + memcpy(file->Path, relative_path, path_size); + + compressed_file->Data = malloc(file->Size); + memcpy(compressed_file->Data, buffer, file->Size); + } + + size_t offset = HAMCORE_HEADER_SIZE; + // Number of files + offset += sizeof(uint32_t); + + // File table + for (size_t i = 0; i < num; ++i) + { + const HAMCORE_FILE *file = &compressed_files[i].File; + if (file->Size == 0) + { + continue; + } + + // Path (length + string) + offset += sizeof(uint32_t) + strlen(file->Path); + // Original size + offset += sizeof(uint32_t); + // Size + offset += sizeof(uint32_t); + // Offset + offset += sizeof(uint32_t); + } + + for (size_t i = 0; i < num; ++i) + { + HAMCORE_FILE *file = &compressed_files[i].File; + if (file->Size == 0) + { + continue; + } + + file->Offset = offset; + offset += file->Size; + } + + if (buffer_size < offset) + { + buffer_size = offset; + buffer = realloc(buffer, buffer_size); + } + + void *ptr = buffer; + WriteAndSeek(&ptr, HAMCORE_HEADER_DATA, HAMCORE_HEADER_SIZE); + uint32_t tmp = BigEndian32((uint32_t)num); + WriteAndSeek(&ptr, &tmp, sizeof(tmp)); + + for (size_t i = 0; i < num; ++i) + { + const HAMCORE_FILE *file = &compressed_files[i].File; + if (file->Size == 0) + { + continue; + } + + const size_t path_length = strlen(file->Path); + tmp = BigEndian32((uint32_t)path_length + 1); + WriteAndSeek(&ptr, &tmp, sizeof(tmp)); + WriteAndSeek(&ptr, file->Path, path_length); + free(file->Path); + + tmp = BigEndian32((uint32_t)file->OriginalSize); + WriteAndSeek(&ptr, &tmp, sizeof(tmp)); + + tmp = BigEndian32((uint32_t)file->Size); + WriteAndSeek(&ptr, &tmp, sizeof(tmp)); + + tmp = BigEndian32((uint32_t)file->Offset); + WriteAndSeek(&ptr, &tmp, sizeof(tmp)); + } + + for (size_t i = 0; i < num; ++i) + { + COMPRESSED_FILE *compressed_file = &compressed_files[i]; + WriteAndSeek(&ptr, compressed_file->Data, compressed_file->File.Size); + free(compressed_file->Data); + } + + free(compressed_files); + + bool ok = false; + + FILE *handle = FileOpen(dst_path, true); + if (!handle) + { + fprintf(stderr, "HamcoreBuild(): Failed to open \"%s\"!\n", dst_path); + goto FINAL; + } + + if (!FileWrite(handle, buffer, buffer_size)) + { + fprintf(stderr, "HamcoreBuild(): Failed to write \"%s\"!\n", dst_path); + goto FINAL; + } + + ok = true; +FINAL: + FileClose(handle); + free(buffer); + return ok; +} @@ -34,4 +34,6 @@ void HamcoreClose(HAMCORE *hamcore); const HAMCORE_FILE *HamcoreFind(const HAMCORE *hamcore, const char *path); bool HamcoreRead(HAMCORE *hamcore, void *dst, const HAMCORE_FILE *file); +bool HamcoreBuild(const char *dst_path, const char *base_path, const char **src_paths, const size_t num); + #endif @@ -1,5 +1,7 @@ #include "Memory.h" +#include <string.h> + size_t CompressionBufferSize(const size_t original_size) { return original_size * 2 + 256; } uint32_t Swap32(const uint32_t value) @@ -11,3 +13,14 @@ uint32_t Swap32(const uint32_t value) ((uint8_t *)&swapped)[3] = ((uint8_t *)&value)[0]; return swapped; } + +void WriteAndSeek(void **dst, const void *src, const size_t size) +{ + if (!dst || !*dst) + { + return; + } + + memcpy(*dst, src, size); + *dst += size; +} @@ -14,4 +14,6 @@ size_t CompressionBufferSize(const size_t original_size); uint32_t Swap32(const uint32_t value); +void WriteAndSeek(void **dst, const void *src, const size_t size); + #endif |