[Add] Started to work on cacheing the packfile.
This commit is contained in:
parent
22b3f2085e
commit
ba26575890
240
src/pack.c
240
src/pack.c
@ -33,8 +33,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct Packfile
|
|
||||||
*
|
|
||||||
* @brief Abstracts around packfiles.
|
* @brief Abstracts around packfiles.
|
||||||
*/
|
*/
|
||||||
struct Packfile_s {
|
struct Packfile_s {
|
||||||
@ -46,8 +44,36 @@ struct Packfile_s {
|
|||||||
uint32_t pos; /**< Cursor position. */
|
uint32_t pos; /**< Cursor position. */
|
||||||
uint32_t start; /**< File start. */
|
uint32_t start; /**< File start. */
|
||||||
uint32_t end; /**< File end. */
|
uint32_t end; /**< File end. */
|
||||||
|
|
||||||
|
uint32_t flags; /**< Special control flags. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allows much faster creation of packfiles.
|
||||||
|
*/
|
||||||
|
struct Packcache_s {
|
||||||
|
#ifdef _POSIX_SOURCE
|
||||||
|
int fd; /**< File descriptor. */
|
||||||
|
#else
|
||||||
|
FILE* fp; /* For non-posix. */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char** index; /**< Cached index for faster lookups. */
|
||||||
|
uint32_t* start; /**< Cached index starts. */
|
||||||
|
uint32_t* nindex; /**< Number of index entries. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Helper defines. */
|
||||||
|
#ifdef _POSIX_SOURCE
|
||||||
|
#define READ(f, b, n) if(read((f)->fd, (b), (n)) != (n)) { \
|
||||||
|
ERR("Fewer bytes read then expected"); \
|
||||||
|
return NULL; }
|
||||||
|
#else
|
||||||
|
#define READ(f, b, n) if(fread((b), 1, (n),(f)->fp) != (n)) { \
|
||||||
|
ERR("Fewer bytes read then expected"); \
|
||||||
|
return NULL; }
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef DEBUG /* This will be spammy. */
|
#undef DEBUG /* This will be spammy. */
|
||||||
#define DEBUG(str, args...) do{;} while(0)
|
#define DEBUG(str, args...) do{;} while(0)
|
||||||
|
|
||||||
@ -62,9 +88,142 @@ struct Packfile_s {
|
|||||||
|
|
||||||
const uint64_t magic = 0x25524573; /**< File magic number: sER% */
|
const uint64_t magic = 0x25524573; /**< File magic number: sER% */
|
||||||
|
|
||||||
|
/* Flags. */
|
||||||
|
#define PACKFILE_FROMCACHE (1<<0) /**< Packfile comes from a packcache. */
|
||||||
|
|
||||||
|
static off_t getfilesize(const char* filename);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open a packfile as a cache.
|
||||||
|
* @param packfile Name of the packfile to cache.
|
||||||
|
* @return NULL if an error occured or the Packcache.
|
||||||
|
*/
|
||||||
|
Packcache_t* pack_openCache(const char* packfile) {
|
||||||
|
int j;
|
||||||
|
uint32_t i;
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
Packcache_t* cache;
|
||||||
|
|
||||||
|
/* Allocate memory. */
|
||||||
|
cache = calloc(1, sizeof(Packcache_t));
|
||||||
|
if(cache == NULL) {
|
||||||
|
ERR("Out of memory.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open file. */
|
||||||
|
#ifdef _POSIX_SOURCE
|
||||||
|
cache->fd = open(packfile, O_RDONLY);
|
||||||
|
if(cache->fd == -1) {
|
||||||
|
#else
|
||||||
|
cache->fp = fopen(packfile, "rb");
|
||||||
|
if(cache->fp == NULL) {
|
||||||
|
#endif
|
||||||
|
ERR("Error opening %s: %s", packfile, strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* Check for validity. */
|
||||||
|
READ(cache, buf, sizeof(magic));
|
||||||
|
if(memcmp(buf, &magic, sizeof(magic))) {
|
||||||
|
ERR("File %s is not a valid packfile", packfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the number of files and allocate memory. */
|
||||||
|
READ(cache, &cache->nindex, 4);
|
||||||
|
cache->index = calloc(cache->nindex, sizeof(char*));
|
||||||
|
cache->start = calloc(cache->nindex, sizeof(uint32_t));
|
||||||
|
|
||||||
|
/* Read index. */
|
||||||
|
for(i = 0; i < cache->nindex; i++) { /* Start to search files. */
|
||||||
|
j = 0;
|
||||||
|
READ(cache, &buf[j], 1); /* Get the name. */
|
||||||
|
while(buf[j++] != '\0')
|
||||||
|
READ(cache, &buf[j], 1);
|
||||||
|
|
||||||
|
cache->index[i] = strdup(buf);
|
||||||
|
READ(cache, &cache->start[i], 4);
|
||||||
|
DEBUG("'%s' found at %d", filename, cache->start[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Return the built cache. */
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Close a Packcache.
|
||||||
|
* @param cache Packcache to close.
|
||||||
|
*/
|
||||||
|
void pack_closeCache(Packcache_t* cache) {
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
/* Close file. */
|
||||||
|
#ifdef _POSIX_SOURCE
|
||||||
|
close(cache->fd);
|
||||||
|
#else
|
||||||
|
fclose(cache->fp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Free memory. */
|
||||||
|
if(cache->nindex > 0) {
|
||||||
|
for(i = 0; i < cache->nindex; i++)
|
||||||
|
free(cache->index[i]);
|
||||||
|
free(cache->index);
|
||||||
|
free(cache->start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open a packfile from a Packcache.
|
||||||
|
* @param cache Packcache to create Packfile from.
|
||||||
|
* @param filename Name of the file to open in the Cache.
|
||||||
|
* @return A packfile for filename from cache.
|
||||||
|
*/
|
||||||
|
Packfile_t* pack_openFromCache(Packcache_t* cache, const char* filename) {
|
||||||
|
uint32_t i;
|
||||||
|
Packfile_t* file;
|
||||||
|
|
||||||
|
file = calloc(1, sizeof(Packfile_t));
|
||||||
|
|
||||||
|
for(i = 0; i < cache->nindex; i++) {
|
||||||
|
if(strcmp(cache->index[i], filename)==0) {
|
||||||
|
/* Copy file. */
|
||||||
|
#ifdef _POSIX_SOURCE
|
||||||
|
file->fd = dup(cache->fd);
|
||||||
|
#else
|
||||||
|
file->fp = cache->fp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Copy information. */
|
||||||
|
file->flags |= PACKFILE_FROMCACHE;
|
||||||
|
file->start = cache->start[i];
|
||||||
|
|
||||||
|
/* Seek. */
|
||||||
|
if(file->start) { /* Go to the beginning of the file. */
|
||||||
|
#ifdef _POSIX_SOURCE
|
||||||
|
if((uint32_t)lseek(file->fd, file->start, SEEK_SET) != file->start) {
|
||||||
|
#else
|
||||||
|
fseek(file->fp, file->start, SEEK_SET);
|
||||||
|
if(errno) {
|
||||||
|
#endif
|
||||||
|
ERR("Failure to seek to file start: %s", strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
READ(file, &file->end, 4);
|
||||||
|
DEBUG("\t%d bytes", file->end);
|
||||||
|
file->pos = file->start;
|
||||||
|
file->end += file->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fn static off_t getfilesize(const char* filename)
|
|
||||||
*
|
|
||||||
* @brief Get the file size.
|
* @brief Get the file size.
|
||||||
* @param filename File to get the size of.
|
* @param filename File to get the size of.
|
||||||
* @return The size of the file.
|
* @return The size of the file.
|
||||||
@ -269,15 +428,6 @@ int pack_files(const char* outfile, const char** infiles, const uint32_t nfiles)
|
|||||||
}
|
}
|
||||||
#undef WRITE
|
#undef WRITE
|
||||||
|
|
||||||
#ifdef _POSIX_SOURCE
|
|
||||||
#define READ(b,n) if(read(file->fd, (b), (n))!=(n)) { \
|
|
||||||
ERR("Fewer bytes read than expected."); \
|
|
||||||
free(buf); return NULL; }
|
|
||||||
#else
|
|
||||||
#define READ(b,n) if(fread((b), 1, (n), file->fp)!=(n)) { \
|
|
||||||
ERR("Fewer bytes read then expected"); \
|
|
||||||
free(buf); return NULL; }
|
|
||||||
#endif
|
|
||||||
/**
|
/**
|
||||||
* @brief Open a file in the packfile for reading.
|
* @brief Open a file in the packfile for reading.
|
||||||
* @param file Packfile to store data into.
|
* @param file Packfile to store data into.
|
||||||
@ -288,13 +438,12 @@ int pack_files(const char* outfile, const char** infiles, const uint32_t nfiles)
|
|||||||
Packfile_t* pack_open(const char* packfile, const char* filename) {
|
Packfile_t* pack_open(const char* packfile, const char* filename) {
|
||||||
int j;
|
int j;
|
||||||
uint32_t nfiles, i;
|
uint32_t nfiles, i;
|
||||||
char* buf = malloc(PATH_MAX);
|
char buf[PATH_MAX];
|
||||||
Packfile_t* file;
|
Packfile_t* file;
|
||||||
|
|
||||||
/* Allocate memory. */
|
/* Allocate memory. */
|
||||||
file = malloc(sizeof(Packfile_t));
|
file = malloc(sizeof(Packfile_t));
|
||||||
memset(file, 0, sizeof(Packfile_t));
|
memset(file, 0, sizeof(Packfile_t));
|
||||||
buf = malloc(PATH_MAX);
|
|
||||||
|
|
||||||
#ifdef _POSIX_SOURCE
|
#ifdef _POSIX_SOURCE
|
||||||
file->fd = open(packfile, O_RDONLY);
|
file->fd = open(packfile, O_RDONLY);
|
||||||
@ -307,23 +456,23 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
READ(buf, sizeof(magic)); /* Make sure it's a packfile. */
|
READ(file, buf, sizeof(magic)); /* Make sure it's a packfile. */
|
||||||
if(memcmp(buf, &magic, sizeof(magic))) {
|
if(memcmp(buf, &magic, sizeof(magic))) {
|
||||||
ERR("File %s is not a valid packfile", filename);
|
ERR("File %s is not a valid packfile", filename);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
READ(&nfiles, 4);
|
READ(file, &nfiles, 4);
|
||||||
for(i = 0; i < nfiles; i++) {
|
for(i = 0; i < nfiles; i++) {
|
||||||
/* Start to search files. */
|
/* Start to search files. */
|
||||||
j = 0;
|
j = 0;
|
||||||
READ(&buf[j], 1); /* Get the name. */
|
READ(file, &buf[j], 1); /* Get the name. */
|
||||||
while(buf[j++] != '\0')
|
while(buf[j++] != '\0')
|
||||||
READ(&buf[j], 1);
|
READ(file, &buf[j], 1);
|
||||||
|
|
||||||
if(strcmp(filename, buf) == 0) {
|
if(strcmp(filename, buf) == 0) {
|
||||||
/* We found the file. */
|
/* We found the file. */
|
||||||
READ(&file->start, 4);
|
READ(file, &file->start, 4);
|
||||||
DEBUG("'%s' found at %d", filename, file->start);
|
DEBUG("'%s' found at %d", filename, file->start);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -333,7 +482,6 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
|
|||||||
fseek(file->fp, 4, SEEK_CUR);
|
fseek(file->fp, 4, SEEK_CUR);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
free(buf);
|
|
||||||
|
|
||||||
if(file->start) {
|
if(file->start) {
|
||||||
/* Go to the beginning of the file. */
|
/* Go to the beginning of the file. */
|
||||||
@ -346,7 +494,7 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
|
|||||||
ERR("Failure to seek to file start: %s", strerror(errno));
|
ERR("Failure to seek to file start: %s", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
READ(&file->end, 4);
|
READ(file, &file->end, 4);
|
||||||
DEBUG("\t%d bytes", file->end);
|
DEBUG("\t%d bytes", file->end);
|
||||||
file->pos = file->start;
|
file->pos = file->start;
|
||||||
file->end += file->start;
|
file->end += file->start;
|
||||||
@ -356,7 +504,6 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
|
|||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
#undef READ
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Reads data from a packfile.
|
* @brief Reads data from a packfile.
|
||||||
@ -368,12 +515,12 @@ Packfile_t* pack_open(const char* packfile, const char* filename) {
|
|||||||
* @return Bytes to read or -1 on error.
|
* @return Bytes to read or -1 on error.
|
||||||
*/
|
*/
|
||||||
ssize_t pack_read(Packfile_t* file, void* buf, size_t count) {
|
ssize_t pack_read(Packfile_t* file, void* buf, size_t count) {
|
||||||
|
int bytes;
|
||||||
|
|
||||||
if(file->pos + count > file->end)
|
if(file->pos + count > file->end)
|
||||||
count = file->end - file->pos; /* Can't go past the end! */
|
count = file->end - file->pos; /* Can't go past the end! */
|
||||||
if(count == 0) return 0;
|
if(count == 0) return 0;
|
||||||
|
|
||||||
int bytes;
|
|
||||||
|
|
||||||
#ifdef _POSIX_SOURCE
|
#ifdef _POSIX_SOURCE
|
||||||
if((bytes = read(file->fd, buf, count)) == -1) {
|
if((bytes = read(file->fd, buf, count)) == -1) {
|
||||||
#else
|
#else
|
||||||
@ -538,66 +685,52 @@ void* pack_readfile(const char* packfile, const char* filename, uint32_t* filesi
|
|||||||
* @param nfiles Stores the amount of files in packfile.
|
* @param nfiles Stores the amount of files in packfile.
|
||||||
* @return An array of filenames in packfile.
|
* @return An array of filenames in packfile.
|
||||||
*/
|
*/
|
||||||
#ifdef _POSIX_SOURCE
|
|
||||||
#define READ(b,n) if(read(fd, (b), (n))!=(n)) { \
|
|
||||||
ERR("Too few bytes read"); \
|
|
||||||
return NULL; }
|
|
||||||
#else
|
|
||||||
#define READ(b,n) if(fread((b), 1, (n), fp) != (n)) { \
|
|
||||||
ERR("Too few bytes read"); \
|
|
||||||
return NULL; }
|
|
||||||
#endif
|
|
||||||
char** pack_listfiles(const char* packfile, uint32_t* nfiles) {
|
char** pack_listfiles(const char* packfile, uint32_t* nfiles) {
|
||||||
#ifdef _POSIX_SOURCE
|
|
||||||
int fd;
|
|
||||||
#else
|
|
||||||
FILE* fp;
|
|
||||||
#endif
|
|
||||||
int j;
|
int j;
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
Packfile_t file;
|
||||||
char** filenames;
|
char** filenames;
|
||||||
char* buf = malloc(sizeof(magic));
|
char* buf = malloc(sizeof(magic));
|
||||||
|
|
||||||
*nfiles = 0;
|
*nfiles = 0;
|
||||||
|
|
||||||
#ifdef _POSIX_SOURCE
|
#ifdef _POSIX_SOURCE
|
||||||
fd = open(packfile, O_RDONLY);
|
file.fd = open(packfile, O_RDONLY);
|
||||||
if(fd == -1) {
|
if(file.fd == -1) {
|
||||||
#else
|
#else
|
||||||
fp = fopen(packfile, "rb");
|
file.fp = fopen(packfile, "rb");
|
||||||
if(fp == NULL) {
|
if(file.fp == NULL) {
|
||||||
#endif
|
#endif
|
||||||
ERR("opening %s: %s", packfile, strerror(errno));
|
ERR("opening %s: %s", packfile, strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
READ(buf, sizeof(magic)); /* Make sure it is a packfile. */
|
READ(&file, buf, sizeof(magic)); /* Make sure it's a packfile. */
|
||||||
if(memcmp(buf, &magic, sizeof(magic))) {
|
if(memcmp(buf, &magic, sizeof(magic))) {
|
||||||
ERR("File %s is not a valid packfile", packfile);
|
ERR("File %s is not a valid packfile", packfile);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
READ(nfiles, 4);
|
READ(&file, nfiles, 4);
|
||||||
filenames = malloc(((*nfiles)+1)*sizeof(char*));
|
filenames = malloc(((*nfiles)+1)*sizeof(char*));
|
||||||
for(i = 0; i < *nfiles; i++) {
|
for(i = 0; i < *nfiles; i++) {
|
||||||
/* Start searching files. */
|
/* Start searching files. */
|
||||||
j = 0;
|
j = 0;
|
||||||
filenames[i] = malloc(PATH_MAX * sizeof(char));
|
filenames[i] = malloc(PATH_MAX * sizeof(char));
|
||||||
READ(&filenames[i][j], 1); /* Get the name. */
|
READ(&file, &filenames[i][j], 1); /* Get the name. */
|
||||||
while(filenames[i][j++] != '\0')
|
while(filenames[i][j++] != '\0')
|
||||||
READ(&filenames[i][j], 1);
|
READ(&file, &filenames[i][j], 1);
|
||||||
READ(buf, 4); /* skip the location. */
|
READ(&file, buf, 4); /* skip the location. */
|
||||||
}
|
}
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
#ifdef _POSIX_SOURCE
|
#ifdef _POSIX_SOURCE
|
||||||
close(fd);
|
close(file.fd);
|
||||||
#else
|
#else
|
||||||
fclose(fp);
|
fclose(file.fp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return filenames;
|
return filenames;
|
||||||
}
|
}
|
||||||
#undef READ
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Closes a packfile.
|
* @brief Closes a packfile.
|
||||||
@ -609,7 +742,10 @@ int pack_close(Packfile_t* file) {
|
|||||||
#ifdef _POSIX_SOURCE
|
#ifdef _POSIX_SOURCE
|
||||||
i = close(file->fd);
|
i = close(file->fd);
|
||||||
#else
|
#else
|
||||||
i = fclose(file->fp);
|
if(file->flags & PACKFILE_FROMCACHE)
|
||||||
|
i = 0;
|
||||||
|
else
|
||||||
|
i = fclose(file->fp);
|
||||||
#endif
|
#endif
|
||||||
return (i) ? -1 : 0;
|
return (i) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
10
src/pack.h
10
src/pack.h
@ -9,6 +9,16 @@
|
|||||||
struct Packfile_s;
|
struct Packfile_s;
|
||||||
typedef struct Packfile_s Packfile_t;
|
typedef struct Packfile_s Packfile_t;
|
||||||
|
|
||||||
|
struct Packcache_s;
|
||||||
|
typedef struct Packcache_s Packcache_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packcache manipulation.
|
||||||
|
*/
|
||||||
|
Packcache_t* pack_openCache(const char* packfile);
|
||||||
|
void pack_closeCache(Packcache_t* cache);
|
||||||
|
Packfile_t* pack_openFromCache(Packcache_t* cache, const char* filename);
|
||||||
|
|
||||||
/* Packfile manipulation. Automatically allocated and freed (with open and close). */
|
/* Packfile manipulation. Automatically allocated and freed (with open and close). */
|
||||||
|
|
||||||
/* Basic. */
|
/* Basic. */
|
||||||
|
Loading…
Reference in New Issue
Block a user