Created
August 22, 2024 16:50
-
-
Save jsmolina/514eb9bef04569578b053231cfc6babd to your computer and use it in GitHub Desktop.
Simplest ever static files compacter for games onto one datafile. Use dat.c as a commandline utility to generate data.dat file, use dat_manager to uncompress on runtime.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <dirent.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
// Code based on mills32 Little-Game-Engine-for-VGA-EGA | |
struct dirent *direntry; | |
struct stat s; | |
unsigned char nfiles = 0; | |
DIR *folder; | |
int check_ext(unsigned char *name){ | |
int type = 0; | |
int len = strlen((const char*)name); | |
unsigned long *ext = (unsigned long*) &name[len-4]; | |
switch (ext[0]){ | |
//file extensions | |
case 0x504D422E: | |
case 0x706D622E: printf("A BMP\n"); type = 1; break; | |
case 0x584D542E: | |
case 0x786D742E: printf("A TMX\n"); type = 2; break; | |
case 0x4D47562E: | |
case 0x6D67762E: printf("A VGM\n"); type = 3; break; | |
} | |
return type; | |
} | |
int main(int argc, char **argv) { | |
unsigned short filesize = 0x0000; | |
unsigned long dat_offset = 32 + 2048; | |
unsigned long file_pos = 0; | |
unsigned char i, arg; | |
unsigned char ssize = 0; | |
unsigned char *extract_file; | |
unsigned char number = argc-1; | |
FILE *dat; | |
FILE *file; | |
unsigned char *buffer = (unsigned char*) calloc(1,65535); | |
unsigned char is_folder = 0; | |
printf("- Static files compacter (based on Mills32 code) starting..."); | |
if (!argv[1]) {printf("\nusage\n- Create dat: makedat file1 file2 ...\n- List dat: makedat -l FILE.DAT\n"); return 0;} | |
if (argc > 64) {printf("\nOnly 64 files are supported\n"); return 0;} | |
extract_file = (unsigned char*)argv[1]; | |
if ((extract_file[0] == '-')&&(extract_file[1] == 'l')) { | |
printf("\nFiles in dat:\n"); | |
unsigned char *name = (unsigned char*)argv[2]; | |
if (!argv[2]) {printf("\nSpecify a DAT file: -e FILE.DAT\n"); return 1;} | |
dat = fopen((const char*)name,"rb"); | |
if (!dat) {printf("Can't open the file %s!\n", name); return 1;} | |
fseek(dat, 22, SEEK_SET); | |
fread(&number,1,1,dat); | |
for (i=1; i<number+1; i++) { | |
int type = 0; | |
fseek(dat, 32*i, SEEK_SET); | |
memset(buffer,0,16); | |
//Read file name | |
fread(buffer,1,16,dat); | |
printf("- %s\n",buffer); | |
} | |
fclose(dat); | |
return 0; | |
} | |
printf("\n"); | |
//Is it a folder? | |
stat(argv[1],&s); | |
if (s.st_mode & S_IFDIR) is_folder = 1; | |
//CREATE FILE | |
dat = fopen("DATA.DAT","wb"); | |
fprintf(dat,"LDAT LT-ENGINE FILES: "); | |
fseek(dat, 22, SEEK_SET); fwrite(&number,1,1,dat); | |
if (!is_folder){ | |
for (arg=1; arg<argc; arg++) { | |
int i = 0; | |
int namepos = 0; | |
int type = 0; | |
int index = 0; | |
char line[128]; | |
unsigned char start_map_data = 0; | |
unsigned char *name = (unsigned char*)argv[arg]; | |
//if dropped file (windows) remove path | |
for (i = 0; i < strlen((const char*)name);i++){if (name[i] == 0x5C) namepos = i+1;} | |
memmove(&name[0],&name[namepos],16); | |
//Print file name | |
fseek(dat, arg*32, SEEK_SET); | |
fprintf(dat,"%s",name); | |
if ((strlen((const char*)name))>12){printf("\nCan't use names bigger than 8 characters %s\n",name); return 0;} | |
//Check file type | |
type = check_ext(name); | |
//if (!type){printf("file format not recognized %s\n",name);return 0;} | |
//Read file to insert | |
file = fopen((const char*)name,"rb"); | |
if (!file) {printf("\nCan't find %s\n",name); return 0;} | |
fseek(file, 0, SEEK_END); | |
filesize = ftell(file); | |
rewind(file); | |
fread(buffer,filesize,1,file); | |
//Write file offset in data, and file size | |
file_pos = dat_offset; | |
fseek(dat, (arg*32)+16, SEEK_SET); | |
fwrite(&file_pos,4,1,dat); | |
fwrite(&filesize,2,1,dat); | |
//Write actual file | |
fseek(dat,file_pos, SEEK_SET); | |
fwrite(buffer,filesize,1,dat); | |
dat_offset += filesize; | |
fclose(file); | |
} | |
} else { | |
//READ FOLDER | |
chdir(argv[1]); | |
folder = opendir("."); | |
nfiles = 1; | |
while((direntry = readdir(folder)) != NULL){ | |
stat(direntry->d_name,&s); | |
if (!(s.st_mode & S_IFDIR)) { | |
int i = 0; | |
int namepos = 0; | |
int type = 0; | |
int index = 0; | |
char line[128]; | |
unsigned char start_map_data = 0; | |
unsigned char *name = (unsigned char*)direntry->d_name; | |
//if dropped file (windows) remove path | |
for (i = 0; i < strlen((const char*)name);i++){ | |
if (name[i] == 0x5C) namepos = i+1; | |
} | |
memmove(&name[0],&name[namepos],16); | |
//Print file name | |
fseek(dat, nfiles*32, SEEK_SET); | |
fprintf(dat,"%s",name); | |
if ((strlen((const char*)name))>12){printf("\nCan't use names bigger than 8 characters %s\n",name); return 0;} | |
//Check file type | |
type = check_ext(name); | |
//if (!type){printf("file format not recognized %s\n",name);return 0;} | |
//Read file to insert | |
file = fopen((const char*)name,"rb"); | |
if (!file) {printf("\nCan't find %s\n",name); return 0;} | |
switch (type){ | |
case 0: | |
case 1: | |
case 3://BMP VGM or unknown | |
fseek(file, 0, SEEK_END); | |
filesize = ftell(file); | |
rewind(file); | |
fread(buffer,filesize,1,file); | |
break; | |
case 2://store tmx maps more efficiently | |
while(!start_map_data){ //read lines | |
memset(line, 0, 64); | |
fgets(line, 64, file); | |
if((line[2] == '<')&&(line[3] == 'd')) start_map_data = 1;//<data encoding="csv"> | |
} | |
start_map_data = 0; | |
filesize = ftell(file); | |
//Read header | |
fseek(file, 0, SEEK_SET); | |
fread(buffer,filesize,1,file); | |
//read map in bytes | |
for (index = 0; index < 256*19; index++){ | |
unsigned char tile = 0; | |
fscanf(file, "%c,",&tile);if (!tile) tile++; | |
buffer[filesize++] = tile; | |
} | |
//advance to bkg map | |
while(!start_map_data){ //read lines | |
memset(line, 0, 64); | |
fgets(line, 64, file); | |
if((line[2] == '<')&&(line[3] == 'd')) start_map_data = 1;//<data encoding="csv"> | |
} | |
//paste lines | |
sprintf((char*)&buffer[filesize],"\n</data>\n </layer>\n <layer id=\"2\" name=\"col\" width=\"256\" height=\"19\">\n <data encoding=\"csv\">\n"); | |
filesize+= 94; | |
//read bkg map in bytes | |
for (index = 0; index < 256*19; index++){ | |
unsigned char tile = 0; | |
fscanf(file, "%c,",&tile);if (!tile) tile++; | |
buffer[filesize++] = tile; | |
} | |
//paste end | |
sprintf((char*)&buffer[filesize],"\n</data>\n </layer>\n</map>\n"); | |
filesize+= 26; | |
break; | |
} | |
file_pos = dat_offset; | |
//Write file offset in data, and file size | |
fseek(dat, (nfiles*32)+16, SEEK_SET); | |
fwrite(&file_pos,sizeof(dat_offset),1,dat); | |
fwrite(&filesize,sizeof(filesize),1,dat); | |
//Write actual file | |
fseek(dat,file_pos, SEEK_SET); | |
fwrite(buffer,filesize,1,dat); | |
dat_offset += filesize; | |
nfiles++; | |
} | |
} | |
} | |
fclose(dat); | |
printf("- DATA.DAT CREATED\n"); | |
free(buffer); | |
buffer = NULL; | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <dirent.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/stat.h> | |
#include <unistd.h> | |
struct dirent *direntry; | |
struct stat s; | |
unsigned char nfiles = 0; | |
DIR *folder; | |
struct stat st = {0}; | |
int check_ext(unsigned char *name) { | |
int type = 0; | |
int len = strlen((const char *)name); | |
unsigned long *ext = (unsigned long *)&name[len - 4]; | |
switch (ext[0]) { | |
// file extensions | |
case 0x504D422E: | |
case 0x706D622E: | |
printf("A BMP\n"); | |
type = 1; | |
break; | |
case 0x584D542E: | |
case 0x786D742E: | |
printf("A TMX\n"); | |
type = 2; | |
break; | |
case 0x4D47562E: | |
case 0x6D67762E: | |
printf("A VGM\n"); | |
type = 3; | |
break; | |
} | |
return type; | |
} | |
unsigned int extract_data() { | |
unsigned short filesize = 0x0000; | |
unsigned long dat_offset = 32 + 2048; | |
unsigned long file_pos = 0; | |
unsigned char i, arg; | |
unsigned char ssize = 0; | |
unsigned char extract = 0; | |
unsigned char *extract_file; | |
unsigned int number = 0; | |
FILE *dat; | |
FILE *file; | |
unsigned char *filename = (unsigned char *)calloc(1, 65535); | |
// EXTRACT FILES | |
dat = fopen("DATA.DAT", "rb"); | |
if (stat("data", &st) == -1) { | |
mkdir("data", 0700); | |
} | |
chdir("data"); | |
fseek(dat, 22, SEEK_SET); | |
fread(&number, 1, 1, dat); | |
for (i = 1; i < number + 1; i++) { | |
int type = 0; | |
fseek(dat, 32 * i, SEEK_SET); | |
memset(filename, 0, 16); | |
// Read file name | |
fread(filename, 1, 16, dat); | |
printf("Extracting: %s\n", filename); | |
// Read data offset | |
fread(&dat_offset, 4, 1, dat); | |
// Check file type | |
type = check_ext(filename); | |
// read file size | |
fread(&filesize, 2, 1, dat); | |
// Go to data offset | |
fseek(dat, dat_offset, SEEK_SET); | |
// Open file | |
file = fopen((const char *)filename, "wb"); | |
// write file | |
fread(filename, filesize, 1, dat); | |
fwrite(filename, filesize, 1, file); | |
fclose(file); | |
} | |
fclose(dat); | |
free(filename); | |
filename = NULL; | |
return 0; | |
} | |
void cleanup_data() { | |
chdir(".."); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef DAT_MANAGER | |
#define DAT_MANAGER | |
unsigned int extract_data(); | |
void cleanup_data(); | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment