static pak_file_t *pak_open(const char *file, const char *mode) { if (!file || !mode) return NULL; switch (*mode) { case 'r': return pak_open_read (file); case 'w': return pak_open_write(file); } return NULL; }
void make_pak(char *input, char *output, bool compress, bool verbose) { time_last = time(NULL); DIR* dir; struct dirent * dent; char* basepath = input; dir = opendir(basepath); if (!dir) { exit(EXIT_FAILURE); } pak_handle_t* handle = pak_open_write(output); printf("Building entry, string and data files..."); fflush(stdout); char dataTempNam[FILENAME_MAX]; gen_random(dataTempNam, 44); char dataTempPath[FILENAME_MAX]; memset(dataTempPath, 0, FILENAME_MAX); sprintf(dataTempPath, "/tmp/%s.data", dataTempNam); char stringTempPath[FILENAME_MAX]; memset(stringTempPath, 0, FILENAME_MAX); sprintf(stringTempPath, "/tmp/%s.string", dataTempNam); char entryTempPath[FILENAME_MAX]; memset(entryTempPath, 0, FILENAME_MAX); sprintf(entryTempPath, "/tmp/%s.entry", dataTempNam); FILE* dataFile = fopen(dataTempPath, "wb"); FILE* entryFile = fopen(entryTempPath, "wb"); FILE* stringFile = fopen(stringTempPath, "wb"); uint64_t idx = 0; while ((dent = readdir(dir)) != NULL) { if ((time(NULL) - time_last) > 1) { printf("."); fflush(stdout); time_last = time(NULL); } if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue; curpath[0] = '\0'; strcat(curpath, basepath); idx = pak_file_or_dir(dent, idx, entryFile, stringFile, dataFile, compress, verbose); } printf("\nBuilding pak...\n"); closedir(dir); fclose(dataFile); fclose(stringFile); fclose(entryFile); // now to build the file // first reopen the temp data struct stat64 st; entryFile = fopen(entryTempPath, "rb"); stringFile = fopen(stringTempPath, "rb"); dataFile = fopen(dataTempPath, "rb"); // read entry table stat64(entryTempPath, &st); size_t entryTableSize = st.st_size; size_t entryCount = entryTableSize / sizeof(pak_entry_t); char* entryTableBuf = malloc(entryTableSize); fread(entryTableBuf, 1, entryTableSize, entryFile); // read string table stat64(stringTempPath, &st); size_t stringTableSize = st.st_size; char* stringTableBuf = malloc(stringTableSize); fread(stringTableBuf, 1, stringTableSize, stringFile); // read data table stat64(dataTempPath, &st); size_t dataTableSize = st.st_size; // close files fclose(entryFile); fclose(stringFile); // TODO: Make this manageable pak_set_entry_start(handle, (sizeof(pak_header_t) + 31) & ~31); pak_set_entry_count(handle, entryCount); pak_set_string_table_offset(handle, (handle->header->entry_start + entryTableSize + 31) & ~31); pak_set_string_table_size(handle, stringTableSize); pak_set_data_offset(handle, (handle->header->string_table_offset + stringTableSize + 31) & ~31); // pad buffers size_t paddedEntryBufSize = (entryTableSize + 31) & ~31; char* paddedEntryBuf = malloc(paddedEntryBufSize); pak_clear(paddedEntryBuf, paddedEntryBufSize); memcpy(paddedEntryBuf, entryTableBuf, entryTableSize); free(entryTableBuf); size_t paddedStringBufSize = (stringTableSize + 31) & ~31; char* paddedStringBuf = malloc(paddedStringBufSize); pak_clear(paddedStringBuf, paddedStringBufSize); memcpy(paddedStringBuf, stringTableBuf, stringTableSize); free(stringTableBuf); // write pak FILE* pak = handle->file; if (pak) { fwrite(handle->header, 1, sizeof(pak_header_t), pak); fseeko64(pak, (sizeof(pak_header_t) + 31) & ~31, SEEK_SET); fwrite(paddedEntryBuf, 1, paddedEntryBufSize, pak); fwrite(paddedStringBuf, 1, paddedStringBufSize, pak); size_t bytesRead = 0; size_t blockSize = BUF_SIZ; while(bytesRead < dataTableSize) { if (blockSize > dataTableSize - bytesRead) blockSize = dataTableSize - bytesRead; char buf[blockSize]; size_t nextReadSize = fread(buf, 1, blockSize, dataFile); if (nextReadSize <= 0) break; // error or early EOF! fwrite(buf, 1, nextReadSize, pak); bytesRead += nextReadSize; } } fclose(dataFile); printf("Stored %" PRIu64 " files (%s)\n", pak_get_entry_count(handle), (compress ? "compressed" : "uncompressed")); pak_close(handle); free(paddedEntryBuf); free(paddedStringBuf); remove(entryTempPath); remove(stringTempPath); remove(dataTempPath); }