2005-01-12 11:59:11 -08:00
|
|
|
/*
|
|
|
|
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
|
|
|
|
*/
|
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
#include "Eet.h"
|
2003-02-02 17:07:58 -08:00
|
|
|
#include "Eet_private.h"
|
2002-12-02 15:39:26 -08:00
|
|
|
|
2004-08-28 01:41:19 -07:00
|
|
|
#ifdef HAVE_REALPATH
|
|
|
|
#undef HAVE_REALPATH
|
|
|
|
#endif
|
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
#define EET_MAGIC_FILE 0x1ee7ff00
|
|
|
|
#define EET_MAGIC_FILE_HEADER 0x1ee7ff01
|
|
|
|
|
|
|
|
typedef struct _Eet_File_Header Eet_File_Header;
|
|
|
|
typedef struct _Eet_File_Node Eet_File_Node;
|
|
|
|
typedef struct _Eet_File_Directory Eet_File_Directory;
|
|
|
|
|
|
|
|
struct _Eet_File
|
|
|
|
{
|
|
|
|
int magic;
|
|
|
|
int references;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
char *path;
|
|
|
|
char *real_path;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
FILE *fp;
|
|
|
|
Eet_File_Mode mode;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
int writes_pending : 1;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
Eet_File_Header *header;
|
|
|
|
};
|
2004-10-20 23:16:55 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
struct _Eet_File_Header
|
|
|
|
{
|
|
|
|
int magic;
|
|
|
|
Eet_File_Directory *directory;
|
|
|
|
};
|
2004-10-20 23:16:55 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
struct _Eet_File_Directory
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
int size;
|
|
|
|
Eet_File_Node **nodes;
|
2002-12-02 15:39:26 -08:00
|
|
|
};
|
2004-10-20 23:16:55 -07:00
|
|
|
|
2005-05-25 20:57:57 -07:00
|
|
|
struct _Eet_File_Node
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
char *name;
|
|
|
|
int offset;
|
|
|
|
int compression;
|
2002-12-02 15:39:26 -08:00
|
|
|
int size;
|
2005-05-25 20:57:57 -07:00
|
|
|
int data_size;
|
|
|
|
void *data;
|
|
|
|
Eet_File_Node *next; /* FIXME: make buckets linked lists */
|
2002-12-02 15:39:26 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* NB: all int's are stored in network byte order on disk */
|
|
|
|
/* file format: */
|
|
|
|
int magic; /* magic number ie 0x1ee7ff00 */
|
|
|
|
int num_directory_entries; /* number of directory entries to follow */
|
|
|
|
int bytes_directory_entries; /* bytes of directory entries to follow */
|
2005-05-22 21:32:04 -07:00
|
|
|
struct
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
int offset; /* bytes offset into file for data chunk */
|
|
|
|
int flags; /* flags - for now 0 = uncompressed, 1 = compressed */
|
|
|
|
int size; /* size of the data chunk */
|
|
|
|
int data_size; /* size of the (uncompressed) data chunk */
|
|
|
|
int name_size; /* length in bytes of the name field */
|
|
|
|
char name[name_size]; /* name string (variable length) */
|
|
|
|
} directory[num_directory_entries];
|
|
|
|
/* and now startes the data stream... */
|
2005-05-22 21:32:04 -07:00
|
|
|
#endif
|
2002-12-02 15:39:26 -08:00
|
|
|
|
|
|
|
/* prototypes of internal calls */
|
|
|
|
static Eet_File *eet_cache_find(char *real_path, Eet_File **cache, int cache_num);
|
|
|
|
static void eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num);
|
|
|
|
static void eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num);
|
|
|
|
static int eet_string_match(char *s1, char *s2);
|
|
|
|
static int eet_hash_gen(char *key, int hash_size);
|
|
|
|
static void eet_flush(Eet_File *ef);
|
|
|
|
|
|
|
|
/* cache. i don't expect this to ever be large, so arrays will do */
|
|
|
|
static int eet_writers_num = 0;
|
|
|
|
static Eet_File **eet_writers = NULL;
|
|
|
|
static int eet_readers_num = 0;
|
|
|
|
static Eet_File **eet_readers = NULL;
|
2004-01-17 07:58:40 -08:00
|
|
|
static int eet_initcount = 0;
|
2002-12-02 15:39:26 -08:00
|
|
|
|
|
|
|
/* find an eet file in the currently in use cache */
|
|
|
|
static Eet_File *
|
|
|
|
eet_cache_find(char *real_path, Eet_File **cache, int cache_num)
|
|
|
|
{
|
|
|
|
int i;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* walk list */
|
|
|
|
for (i = 0; i < cache_num; i++)
|
|
|
|
{
|
|
|
|
/* if matches real path - return it */
|
|
|
|
if (eet_string_match(cache[i]->real_path, real_path)) return cache[i];
|
|
|
|
}
|
|
|
|
/* not found */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add to end of cache */
|
|
|
|
static void
|
|
|
|
eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num)
|
|
|
|
{
|
|
|
|
Eet_File **new_cache;
|
|
|
|
int new_cache_num;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
new_cache_num = *cache_num;
|
|
|
|
new_cache = *cache;
|
|
|
|
new_cache_num++;
|
|
|
|
new_cache = realloc(new_cache, new_cache_num * sizeof(Eet_File *));
|
2004-10-20 23:16:55 -07:00
|
|
|
if (!new_cache)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "BAD ERROR! Eet realloc of cache list failed. Abort\n");
|
|
|
|
abort();
|
|
|
|
}
|
2002-12-02 15:39:26 -08:00
|
|
|
if (!new_cache) return;
|
|
|
|
new_cache[new_cache_num - 1] = ef;
|
|
|
|
*cache = new_cache;
|
2005-05-22 21:32:04 -07:00
|
|
|
*cache_num = new_cache_num;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* delete from cache */
|
|
|
|
static void
|
|
|
|
eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num)
|
|
|
|
{
|
|
|
|
Eet_File **new_cache;
|
|
|
|
int new_cache_num;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
new_cache_num = *cache_num;
|
|
|
|
new_cache = *cache;
|
2004-10-20 23:16:55 -07:00
|
|
|
if (new_cache_num <= 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2002-12-02 15:39:26 -08:00
|
|
|
for (i = 0; i < new_cache_num; i++)
|
|
|
|
{
|
|
|
|
if (new_cache[i] == ef) break;
|
|
|
|
}
|
2004-10-20 23:16:55 -07:00
|
|
|
if (i >= new_cache_num)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2002-12-02 15:39:26 -08:00
|
|
|
new_cache_num--;
|
2005-05-22 21:32:04 -07:00
|
|
|
for (j = i; j < new_cache_num; j++) new_cache[j] = new_cache[j + 1];
|
2003-09-24 00:08:57 -07:00
|
|
|
if (new_cache_num > 0)
|
|
|
|
{
|
|
|
|
new_cache = realloc(new_cache, new_cache_num * sizeof(Eet_File *));
|
2004-10-20 23:16:55 -07:00
|
|
|
if (!new_cache)
|
|
|
|
{
|
2004-10-20 23:18:02 -07:00
|
|
|
fprintf(stderr, "BAD ERROR! Eet realloc of cache list failed. Abort\n");
|
2004-10-20 23:16:55 -07:00
|
|
|
abort();
|
|
|
|
}
|
2003-09-24 00:08:57 -07:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
free(new_cache);
|
|
|
|
new_cache = NULL;
|
|
|
|
}
|
2005-05-22 21:32:04 -07:00
|
|
|
*cache_num = new_cache_num;
|
2002-12-02 15:39:26 -08:00
|
|
|
*cache = new_cache;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* internal string match. bails out at first mismatch - not comparing all */
|
|
|
|
/* bytes in strings */
|
|
|
|
static int
|
|
|
|
eet_string_match(char *s1, char *s2)
|
|
|
|
{
|
|
|
|
/* both null- no match */
|
|
|
|
if ((!s1) || (!s2)) return 0;
|
|
|
|
/* go thru - first mismatch - exit with 0 */
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if (*s1 != *s2) return 0;
|
|
|
|
s1++;
|
|
|
|
s2++;
|
2005-05-22 21:32:04 -07:00
|
|
|
}
|
2002-12-02 15:39:26 -08:00
|
|
|
while ((*s1) || (*s2));
|
|
|
|
/* got this far. match */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* caluclate hash table entry valu with bitmask size of hash_size */
|
|
|
|
static int
|
|
|
|
eet_hash_gen(char *key, int hash_size)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
int hash_num = 0, i;
|
2002-12-02 15:39:26 -08:00
|
|
|
unsigned char *ptr;
|
|
|
|
const int masks[9] =
|
|
|
|
{
|
|
|
|
0x00,
|
|
|
|
0x01,
|
|
|
|
0x03,
|
|
|
|
0x07,
|
|
|
|
0x0f,
|
|
|
|
0x1f,
|
|
|
|
0x3f,
|
|
|
|
0x7f,
|
|
|
|
0xff
|
|
|
|
};
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* no string - index 0 */
|
|
|
|
if (!key) return 0;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* calc hash num */
|
2005-05-25 20:57:57 -07:00
|
|
|
for (i = 0, ptr = (unsigned char *)key; *ptr; ptr++, i++)
|
|
|
|
hash_num ^= ((int)(*ptr) | ((int)(*ptr) << 8)) >> (i % 8);
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* mask it */
|
|
|
|
hash_num &= masks[hash_size];
|
|
|
|
/* return it */
|
|
|
|
return hash_num;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* flush out writes to an eet file */
|
|
|
|
static void
|
|
|
|
eet_flush(Eet_File *ef)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
int i, count, size, num, offset;
|
2002-12-02 15:39:26 -08:00
|
|
|
int head[3];
|
|
|
|
unsigned long int i1, i2;
|
2005-05-25 20:57:57 -07:00
|
|
|
Eet_File_Node *efn;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
|
|
|
/* check to see its' an eet file pointer */
|
2002-12-02 15:39:26 -08:00
|
|
|
if ((!ef) || (ef->magic != EET_MAGIC_FILE))
|
|
|
|
return;
|
2003-01-12 20:31:00 -08:00
|
|
|
if (!ef->header) return;
|
|
|
|
if (!ef->header->directory) return;
|
2005-03-03 09:26:46 -08:00
|
|
|
if ((ef->mode != EET_FILE_MODE_WRITE) && (ef->mode != EET_FILE_MODE_READ_WRITE)) return;
|
2002-12-02 15:39:26 -08:00
|
|
|
if (!ef->writes_pending) return;
|
|
|
|
|
|
|
|
/* calculate total size in bytes of directory block */
|
|
|
|
size = 0;
|
|
|
|
count = 0;
|
2005-05-25 23:15:48 -07:00
|
|
|
num = (1 << ef->header->directory->size);
|
2002-12-02 15:39:26 -08:00
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
if (efn->compression >= 0)
|
2005-05-22 21:32:04 -07:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
size += 20 + strlen(efn->name);
|
2004-12-16 01:30:15 -08:00
|
|
|
count++;
|
|
|
|
}
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* caluclate offsets per entry */
|
|
|
|
offset = 0;
|
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
if (efn->compression >= 0)
|
2004-12-16 01:30:15 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
efn->offset = 12 + size + offset;
|
|
|
|
offset += efn->size;
|
2004-12-16 01:30:15 -08:00
|
|
|
}
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* go thru and write the header */
|
|
|
|
i1 = (unsigned long int)EET_MAGIC_FILE;
|
|
|
|
i2 = htonl(i1);
|
|
|
|
head[0] = (int)i2;
|
|
|
|
i1 = (unsigned long int)count;
|
|
|
|
i2 = htonl(i1);
|
|
|
|
head[1] = (int)i2;
|
|
|
|
i1 = (unsigned long int)size;
|
|
|
|
i2 = htonl(i1);
|
|
|
|
head[2] = (int)i2;
|
|
|
|
fseek(ef->fp, 0, SEEK_SET);
|
|
|
|
if (fwrite(head, 12, 1, ef->fp) != 1) return;
|
|
|
|
offset = 12;
|
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
if (efn->compression >= 0)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
2005-05-25 23:15:48 -07:00
|
|
|
unsigned char *buf;
|
|
|
|
int buf_size;
|
|
|
|
int name_size;
|
|
|
|
|
2005-05-25 20:57:57 -07:00
|
|
|
name_size = strlen(efn->name);
|
2004-12-01 20:25:25 -08:00
|
|
|
buf_size = 20 + name_size;
|
|
|
|
buf = malloc(buf_size);
|
|
|
|
if (!buf) return;
|
2005-05-25 20:57:57 -07:00
|
|
|
i1 = (unsigned long int)efn->offset;
|
2004-12-01 20:25:25 -08:00
|
|
|
i2 = htonl(i1);
|
|
|
|
*((int *)(buf + 0)) = (int)i2;
|
2005-05-25 20:57:57 -07:00
|
|
|
i1 = (unsigned long int)efn->compression;
|
2004-12-01 20:25:25 -08:00
|
|
|
i2 = htonl(i1);
|
|
|
|
*((int *)(buf + 4)) = (int)i2;
|
2005-05-25 20:57:57 -07:00
|
|
|
i1 = (unsigned long int)efn->size;
|
2004-12-01 20:25:25 -08:00
|
|
|
i2 = htonl(i1);
|
|
|
|
*((int *)(buf + 8)) = (int)i2;
|
2005-05-25 20:57:57 -07:00
|
|
|
i1 = (unsigned long int)efn->data_size;
|
2004-12-01 20:25:25 -08:00
|
|
|
i2 = htonl(i1);
|
|
|
|
*((int *)(buf + 12)) = (int)i2;
|
|
|
|
i1 = (unsigned long int)name_size;
|
|
|
|
i2 = htonl(i1);
|
|
|
|
*((int *)(buf + 16)) = (int)i2;
|
2005-05-25 20:57:57 -07:00
|
|
|
memcpy(buf + 20, efn->name, name_size);
|
2005-05-22 21:32:04 -07:00
|
|
|
if (fwrite(buf, buf_size, 1, ef->fp) != 1)
|
2004-12-01 20:25:25 -08:00
|
|
|
{
|
|
|
|
free(buf);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
offset += buf_size;
|
2002-12-02 15:39:26 -08:00
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* write data */
|
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
if (efn->compression >= 0)
|
2004-12-16 01:30:15 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
if (fwrite(efn->data, efn->size, 1, ef->fp) != 1)
|
2004-12-16 01:30:15 -08:00
|
|
|
return;
|
|
|
|
}
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* no more writes pending */
|
|
|
|
ef->writes_pending = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Eet_File *
|
2005-01-17 00:27:23 -08:00
|
|
|
eet_open(const char *file, Eet_File_Mode mode)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
Eet_File *ef;
|
|
|
|
char buf[PATH_MAX];
|
2003-01-12 22:22:02 -08:00
|
|
|
|
|
|
|
if (!file) return NULL;
|
2004-07-14 09:37:29 -07:00
|
|
|
|
2005-03-31 23:26:09 -08:00
|
|
|
// printf("open %s\n", file);
|
2004-07-14 09:37:29 -07:00
|
|
|
#ifdef HAVE_REALPATH
|
2002-12-02 15:39:26 -08:00
|
|
|
/* in case this is a symlink... find out where it REALLY points */
|
2005-05-22 21:32:04 -07:00
|
|
|
if (!realpath(file, buf))
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
if (mode == EET_FILE_MODE_READ) return NULL;
|
|
|
|
}
|
2004-07-14 09:37:29 -07:00
|
|
|
#else
|
|
|
|
strncpy(buf, file, sizeof(buf));
|
|
|
|
buf[sizeof(buf) - 1] = 0;
|
|
|
|
#endif
|
2002-12-02 15:39:26 -08:00
|
|
|
|
|
|
|
/* find the current file handle in cache*/
|
|
|
|
ef = NULL;
|
|
|
|
if (mode == EET_FILE_MODE_READ)
|
|
|
|
ef = eet_cache_find(buf, eet_readers, eet_readers_num);
|
2005-03-03 09:26:46 -08:00
|
|
|
else if ((mode == EET_FILE_MODE_WRITE) || (mode == EET_FILE_MODE_READ_WRITE))
|
2002-12-02 15:39:26 -08:00
|
|
|
ef = eet_cache_find(buf, eet_writers, eet_writers_num);
|
|
|
|
/* we found one */
|
|
|
|
if (ef)
|
|
|
|
{
|
|
|
|
/* reference it up and return it */
|
|
|
|
ef->references++;
|
|
|
|
return ef;
|
|
|
|
}
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* allocate struct for eet file and have it zero'd out */
|
2005-05-25 20:57:57 -07:00
|
|
|
ef = calloc(1, sizeof(Eet_File));
|
2002-12-02 15:39:26 -08:00
|
|
|
if (!ef) return NULL;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* fill some of the members */
|
|
|
|
ef->path = strdup(file);
|
|
|
|
ef->real_path = strdup(buf);
|
|
|
|
ef->magic = EET_MAGIC_FILE;
|
|
|
|
ef->references = 1;
|
|
|
|
ef->mode = mode;
|
|
|
|
|
|
|
|
/* try open the file based on mode */
|
2005-03-03 09:26:46 -08:00
|
|
|
if ((ef->mode == EET_FILE_MODE_READ) || (ef->mode == EET_FILE_MODE_READ_WRITE))
|
2004-10-22 06:57:49 -07:00
|
|
|
ef->fp = fopen(ef->path, "rb");
|
2002-12-02 15:39:26 -08:00
|
|
|
else if (ef->mode == EET_FILE_MODE_WRITE)
|
|
|
|
{
|
|
|
|
/* opening for write - delete old copy of file right away */
|
|
|
|
unlink(ef->real_path);
|
2004-10-22 06:57:49 -07:00
|
|
|
ef->fp = fopen(ef->path, "wb");
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eet_close(ef);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* if we can't open - bail out */
|
|
|
|
if (!ef->fp)
|
|
|
|
{
|
|
|
|
eet_close(ef);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2004-10-19 20:13:44 -07:00
|
|
|
/* if we opened for read or read-write */
|
2005-05-25 20:57:57 -07:00
|
|
|
// printf("OPEN!\n");
|
2005-03-03 09:26:46 -08:00
|
|
|
if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
unsigned char buf[12];
|
|
|
|
unsigned char *dyn_buf, *p;
|
|
|
|
unsigned long int i1, i2;
|
|
|
|
int num_entries, byte_entries, i;
|
|
|
|
size_t count;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* build header table if read mode */
|
|
|
|
/* geat header */
|
|
|
|
count = fread(buf, 12, 1, ef->fp);
|
|
|
|
if (count != 1)
|
|
|
|
{
|
|
|
|
eet_close(ef);
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* get magic no */
|
2003-07-10 16:18:42 -07:00
|
|
|
memcpy(&i1, buf + 0, sizeof(int));
|
2002-12-02 15:39:26 -08:00
|
|
|
i2 = ntohl(i1);
|
|
|
|
if (i2 != EET_MAGIC_FILE)
|
|
|
|
{
|
|
|
|
eet_close(ef);
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* get entries count and byte count */
|
2003-07-10 16:18:42 -07:00
|
|
|
memcpy(&i1, buf + 4, sizeof(int));
|
2002-12-02 15:39:26 -08:00
|
|
|
i2 = ntohl(i1);
|
|
|
|
num_entries = (int)i2;
|
2003-07-10 16:18:42 -07:00
|
|
|
memcpy(&i1, buf + 8, sizeof(int));
|
2002-12-02 15:39:26 -08:00
|
|
|
i2 = ntohl(i1);
|
|
|
|
byte_entries = (int)i2;
|
|
|
|
/* we cant have <= 0 values here - invalid */
|
|
|
|
if ((num_entries <= 0) || (byte_entries <= 0))
|
|
|
|
{
|
|
|
|
eet_close(ef);
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* we can't have more entires than minimum bytes for those! invalid! */
|
|
|
|
if ((num_entries * 20) > byte_entries)
|
|
|
|
{
|
|
|
|
eet_close(ef);
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* allocate dynamic buffer for entire directory block */
|
|
|
|
dyn_buf = malloc(byte_entries);
|
|
|
|
if (!dyn_buf)
|
|
|
|
{
|
|
|
|
eet_close(ef);
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* allocate header */
|
2005-05-25 20:57:57 -07:00
|
|
|
ef->header = calloc(1, sizeof(Eet_File_Header));
|
2002-12-02 15:39:26 -08:00
|
|
|
if (!ef->header)
|
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ef->header->magic = EET_MAGIC_FILE_HEADER;
|
|
|
|
/* allocate directory block in ram */
|
2005-05-25 20:57:57 -07:00
|
|
|
ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
|
2002-12-02 15:39:26 -08:00
|
|
|
if (!ef->header->directory)
|
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* 8 bit hash table (256 buckets) */
|
|
|
|
ef->header->directory->size = 8;
|
|
|
|
/* allocate base hash table */
|
2005-05-25 20:57:57 -07:00
|
|
|
ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
|
|
|
|
if (!ef->header->directory->nodes)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* actually read the directory block - all of it, into ram */
|
|
|
|
count = fread(dyn_buf, byte_entries, 1, ef->fp);
|
|
|
|
if (count != 1)
|
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* parse directory block */
|
|
|
|
p = dyn_buf;
|
2005-05-25 20:57:57 -07:00
|
|
|
// printf("entries: %i\n", num_entries);
|
2002-12-02 15:39:26 -08:00
|
|
|
for (i = 0; i < num_entries; i++)
|
|
|
|
{
|
|
|
|
int offset;
|
|
|
|
int flags;
|
|
|
|
int size;
|
|
|
|
int data_size;
|
|
|
|
int name_size;
|
|
|
|
char *name;
|
|
|
|
int hash;
|
2005-05-25 20:57:57 -07:00
|
|
|
Eet_File_Node *efn;
|
2004-10-19 20:13:44 -07:00
|
|
|
void *data = NULL;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* out directory block is inconsistent - we have oveerun our */
|
2005-05-22 21:32:04 -07:00
|
|
|
/* dynamic block buffer before we finished scanning dir entries */
|
2002-12-02 15:39:26 -08:00
|
|
|
if (p >= (dyn_buf + byte_entries))
|
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* get entrie header */
|
2003-07-10 16:18:42 -07:00
|
|
|
memcpy(&i1, p + 0, sizeof(int));
|
2002-12-02 15:39:26 -08:00
|
|
|
i2 = ntohl(i1);
|
|
|
|
offset = (int)i2;
|
2003-07-10 16:18:42 -07:00
|
|
|
memcpy(&i1, p + 4, sizeof(int));
|
2002-12-02 15:39:26 -08:00
|
|
|
i2 = ntohl(i1);
|
|
|
|
flags = (int)i2;
|
2003-07-10 16:18:42 -07:00
|
|
|
memcpy(&i1, p + 8, sizeof(int));
|
2002-12-02 15:39:26 -08:00
|
|
|
i2 = ntohl(i1);
|
|
|
|
size = (int)i2;
|
2003-07-10 16:18:42 -07:00
|
|
|
memcpy(&i1, p + 12, sizeof(int));
|
2002-12-02 15:39:26 -08:00
|
|
|
i2 = ntohl(i1);
|
|
|
|
data_size = (int)i2;
|
2003-07-10 16:18:42 -07:00
|
|
|
memcpy(&i1, p + 16, sizeof(int));
|
2002-12-02 15:39:26 -08:00
|
|
|
i2 = ntohl(i1);
|
|
|
|
name_size = (int)i2;
|
|
|
|
/* invalid size */
|
|
|
|
if (size <= 0)
|
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* invalid name_size */
|
|
|
|
if (name_size <= 0)
|
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* reading name would mean falling off end of dyn_buf - invalid */
|
|
|
|
if ((p + 16 + name_size) > (dyn_buf + byte_entries))
|
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* allocate name string */
|
|
|
|
name = malloc(name_size + 1);
|
|
|
|
if (!name)
|
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* copy name in and terminate it */
|
2005-05-22 21:32:04 -07:00
|
|
|
strncpy(name, (char *)p + 20, name_size);
|
2002-12-02 15:39:26 -08:00
|
|
|
name[name_size] = 0;
|
|
|
|
/* get hask bucket it should go in */
|
|
|
|
hash = eet_hash_gen(name, ef->header->directory->size);
|
2005-05-25 20:57:57 -07:00
|
|
|
efn = calloc(1, sizeof(Eet_File_Node));
|
|
|
|
if (!efn)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
free(dyn_buf);
|
|
|
|
eet_close(ef);
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-05-25 20:57:57 -07:00
|
|
|
efn->next = ef->header->directory->nodes[hash];
|
|
|
|
ef->header->directory->nodes[hash] = efn;
|
|
|
|
efn->name = name;
|
|
|
|
efn->offset = offset;
|
|
|
|
efn->compression = flags;
|
|
|
|
efn->size = size;
|
|
|
|
efn->data_size = data_size;
|
2004-10-19 20:13:44 -07:00
|
|
|
|
|
|
|
/* read-only mode, so currently we have no data loaded */
|
|
|
|
if (mode == EET_FILE_MODE_READ)
|
2005-05-25 20:57:57 -07:00
|
|
|
efn->data = NULL;
|
2004-10-19 20:13:44 -07:00
|
|
|
/* read-write mode - read everything into ram */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
data = malloc(size);
|
|
|
|
if (data)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
if (fseek(ef->fp, efn->offset, SEEK_SET) < 0)
|
2004-10-19 20:13:44 -07:00
|
|
|
{
|
|
|
|
free(data);
|
|
|
|
data = NULL;
|
|
|
|
/* XXX die gracefully somehow */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (fread(data, size, 1, ef->fp) != 1)
|
|
|
|
{
|
|
|
|
free(data);
|
|
|
|
data = NULL;
|
|
|
|
/* XXX die gracefully somehow */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-05-25 20:57:57 -07:00
|
|
|
efn->data = data;
|
2004-10-19 20:13:44 -07:00
|
|
|
}
|
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* advance */
|
|
|
|
p += 20 + name_size;
|
|
|
|
}
|
|
|
|
/* done - free dynamic buffer */
|
|
|
|
free(dyn_buf);
|
|
|
|
}
|
2004-10-19 20:13:44 -07:00
|
|
|
|
|
|
|
/* we need to delete the original file in read-write mode and re-open for writing */
|
2005-03-03 09:26:46 -08:00
|
|
|
if (ef->mode == EET_FILE_MODE_READ_WRITE)
|
2004-10-19 20:13:44 -07:00
|
|
|
{
|
|
|
|
fclose(ef->fp);
|
|
|
|
unlink(ef->real_path);
|
2004-10-22 06:57:49 -07:00
|
|
|
ef->fp = fopen(ef->path, "wb");
|
2004-10-19 20:13:44 -07:00
|
|
|
}
|
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* add to cache */
|
|
|
|
if (ef->mode == EET_FILE_MODE_READ)
|
|
|
|
eet_cache_add(ef, &eet_readers, &eet_readers_num);
|
2005-03-03 09:26:46 -08:00
|
|
|
else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
|
2002-12-02 15:39:26 -08:00
|
|
|
eet_cache_add(ef, &eet_writers, &eet_writers_num);
|
|
|
|
return ef;
|
|
|
|
}
|
|
|
|
|
2005-02-07 10:10:20 -08:00
|
|
|
Eet_File_Mode
|
|
|
|
eet_mode_get(Eet_File *ef)
|
|
|
|
{
|
2005-05-22 21:32:04 -07:00
|
|
|
/* check to see its' an eet file pointer */
|
2005-02-07 10:10:20 -08:00
|
|
|
if ((!ef) || (ef->magic != EET_MAGIC_FILE))
|
|
|
|
return EET_FILE_MODE_INVALID;
|
|
|
|
else
|
|
|
|
return ef->mode;
|
|
|
|
}
|
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
void
|
|
|
|
eet_close(Eet_File *ef)
|
|
|
|
{
|
2005-05-22 21:32:04 -07:00
|
|
|
/* check to see its' an eet file pointer */
|
2002-12-02 15:39:26 -08:00
|
|
|
if ((!ef) || (ef->magic != EET_MAGIC_FILE))
|
|
|
|
return;
|
|
|
|
/* deref */
|
|
|
|
ef->references--;
|
|
|
|
/* if its still referenced - dont go any further */
|
|
|
|
if (ef->references > 0) return;
|
|
|
|
/* remove from cache */
|
|
|
|
if (ef->mode == EET_FILE_MODE_READ)
|
|
|
|
eet_cache_del(ef, &eet_readers, &eet_readers_num);
|
2005-03-03 09:26:46 -08:00
|
|
|
else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
|
2002-12-02 15:39:26 -08:00
|
|
|
eet_cache_del(ef, &eet_writers, &eet_writers_num);
|
|
|
|
/* flush any writes */
|
|
|
|
eet_flush(ef);
|
|
|
|
|
|
|
|
/* free up members */
|
|
|
|
if (ef->fp) fclose(ef->fp);
|
|
|
|
if (ef->path) free(ef->path);
|
|
|
|
if (ef->real_path) free(ef->real_path);
|
|
|
|
|
|
|
|
/* free up data */
|
2005-05-22 21:32:04 -07:00
|
|
|
if (ef->header)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
if (ef->header->directory)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
if (ef->header->directory->nodes)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
int i, num;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2005-05-25 20:57:57 -07:00
|
|
|
num = (1 << ef->header->directory->size);
|
2002-12-02 15:39:26 -08:00
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
Eet_File_Node *efn;
|
|
|
|
|
|
|
|
while ((efn = ef->header->directory->nodes[i]))
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
if (efn->name) free(efn->name);
|
|
|
|
if (efn->data) free(efn->data);
|
|
|
|
ef->header->directory->nodes[i] = efn->next;
|
|
|
|
free(efn);
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
}
|
2005-05-25 20:57:57 -07:00
|
|
|
free(ef->header->directory->nodes);
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
free(ef->header->directory);
|
|
|
|
}
|
|
|
|
free(ef->header);
|
|
|
|
}
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* zero out ram for struct - caution tactic against stale memory use */
|
|
|
|
memset(ef, 0, sizeof(Eet_File));
|
|
|
|
/* free it */
|
|
|
|
free(ef);
|
|
|
|
}
|
|
|
|
|
|
|
|
void *
|
|
|
|
eet_read(Eet_File *ef, char *name, int *size_ret)
|
|
|
|
{
|
|
|
|
void *data = NULL;
|
2005-05-25 20:57:57 -07:00
|
|
|
int size = 0, tmp_size;
|
|
|
|
int hash;
|
|
|
|
Eet_File_Node *efn;
|
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* check to see its' an eet file pointer */
|
2005-02-03 09:20:29 -08:00
|
|
|
if ((!ef) || (ef->magic != EET_MAGIC_FILE) || (!name) ||
|
|
|
|
((ef->mode != EET_FILE_MODE_READ) &&
|
2005-03-03 09:26:46 -08:00
|
|
|
(ef->mode != EET_FILE_MODE_READ_WRITE)))
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
if (size_ret) *size_ret = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
2003-01-12 20:31:00 -08:00
|
|
|
/* no header, return NULL */
|
|
|
|
if (!ef->header) return NULL;
|
|
|
|
/* no directory, return NULL */
|
|
|
|
if (!ef->header->directory) return NULL;
|
2005-02-03 09:20:29 -08:00
|
|
|
/* get hash bucket this should be in */
|
|
|
|
hash = eet_hash_gen(name, ef->header->directory->size);
|
2002-12-02 15:39:26 -08:00
|
|
|
/* hunt hash bucket */
|
2005-05-25 20:57:57 -07:00
|
|
|
for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
/* if it matches */
|
2005-05-25 20:57:57 -07:00
|
|
|
if (eet_string_match(efn->name, name))
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
/* uncompressed data */
|
2005-05-25 20:57:57 -07:00
|
|
|
if (efn->compression == 0)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
/* get size */
|
2005-05-25 20:57:57 -07:00
|
|
|
size = efn->size;
|
2002-12-02 15:39:26 -08:00
|
|
|
/* allocate data */
|
|
|
|
data = malloc(size);
|
|
|
|
if (data)
|
|
|
|
{
|
|
|
|
/* if we alreayd have the data in ram... copy that */
|
2005-05-25 20:57:57 -07:00
|
|
|
if (efn->data)
|
|
|
|
memcpy(data, efn->data, efn->size);
|
2002-12-02 15:39:26 -08:00
|
|
|
/* or get data from disk */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* seek to data location */
|
2005-05-25 20:57:57 -07:00
|
|
|
if (fseek(ef->fp, efn->offset, SEEK_SET) < 0)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
free(data);
|
|
|
|
data = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* read it */
|
|
|
|
if (fread(data, size, 1, ef->fp) != 1)
|
|
|
|
{
|
|
|
|
free(data);
|
|
|
|
data = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* compressed data */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
void *tmp_data;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* get size of data in file */
|
2005-05-25 20:57:57 -07:00
|
|
|
tmp_size = efn->size;
|
2002-12-02 15:39:26 -08:00
|
|
|
tmp_data = malloc(tmp_size);
|
|
|
|
if (!tmp_data) break;
|
|
|
|
/* get size uncompressed */
|
2005-05-25 20:57:57 -07:00
|
|
|
size = efn->data_size;
|
2002-12-02 15:39:26 -08:00
|
|
|
/* allocate data */
|
|
|
|
data = malloc(size);
|
|
|
|
if (data)
|
|
|
|
{
|
|
|
|
uLongf dlen;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* if we already have the data in ram... copy that */
|
2005-05-25 20:57:57 -07:00
|
|
|
if (efn->data)
|
|
|
|
memcpy(tmp_data, efn->data, tmp_size);
|
2002-12-02 15:39:26 -08:00
|
|
|
/* or get data from disk */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* seek to data location */
|
2005-05-25 20:57:57 -07:00
|
|
|
if (fseek(ef->fp, efn->offset, SEEK_SET) < 0)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
free(tmp_data);
|
|
|
|
free(data);
|
|
|
|
data = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* read it */
|
|
|
|
if (fread(tmp_data, tmp_size, 1, ef->fp) != 1)
|
|
|
|
{
|
|
|
|
free(tmp_data);
|
|
|
|
free(data);
|
|
|
|
data = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* decompress it */
|
|
|
|
dlen = size;
|
2005-05-22 21:32:04 -07:00
|
|
|
if (uncompress((Bytef *)data, &dlen,
|
2002-12-02 15:39:26 -08:00
|
|
|
tmp_data, (uLongf)tmp_size))
|
|
|
|
{
|
|
|
|
free(tmp_data);
|
|
|
|
free(data);
|
|
|
|
data = NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(tmp_data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* fill in return values */
|
|
|
|
*size_ret = size;
|
|
|
|
/* update access time */
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
eet_write(Eet_File *ef, char *name, void *data, int size, int compress)
|
|
|
|
{
|
|
|
|
int data_size;
|
2005-05-25 20:57:57 -07:00
|
|
|
int hash;
|
|
|
|
Eet_File_Node *efn;
|
2002-12-02 15:39:26 -08:00
|
|
|
char *name2;
|
|
|
|
void *data2;
|
2004-10-19 20:13:44 -07:00
|
|
|
int exists_already = 0;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
|
|
|
/* check to see its' an eet file pointer */
|
2005-05-25 20:57:57 -07:00
|
|
|
if ((!ef) || (ef->magic != EET_MAGIC_FILE) || (!name) || (!data) ||
|
|
|
|
(size <= 0) || ((ef->mode != EET_FILE_MODE_WRITE) &&
|
|
|
|
(ef->mode != EET_FILE_MODE_READ_WRITE)))
|
2002-12-02 15:39:26 -08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!ef->header)
|
|
|
|
{
|
|
|
|
/* allocate header */
|
2005-05-25 20:57:57 -07:00
|
|
|
ef->header = calloc(1, sizeof(Eet_File_Header));
|
2002-12-02 15:39:26 -08:00
|
|
|
if (!ef->header) return 0;
|
|
|
|
ef->header->magic = EET_MAGIC_FILE_HEADER;
|
|
|
|
/* allocate directory block in ram */
|
2005-05-25 20:57:57 -07:00
|
|
|
ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
|
2002-12-02 15:39:26 -08:00
|
|
|
if (!ef->header->directory) return 0;
|
|
|
|
/* 8 bit hash table (256 buckets) */
|
|
|
|
ef->header->directory->size = 8;
|
|
|
|
/* allocate base hash table */
|
2005-05-25 20:57:57 -07:00
|
|
|
ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
|
|
|
|
if (!ef->header->directory->nodes) return 0;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
/* figure hash bucket */
|
|
|
|
hash = eet_hash_gen(name, ef->header->directory->size);
|
|
|
|
/* dup name */
|
|
|
|
name2 = strdup(name);
|
|
|
|
if (!name2) return 0;
|
|
|
|
/* dup data */
|
|
|
|
data_size = size;
|
2002-12-14 17:32:13 -08:00
|
|
|
/* have bigger buffer for compress */
|
2005-05-26 03:02:10 -07:00
|
|
|
if (compress) data_size = 12 + ((size * 101) / 100);
|
2002-12-02 15:39:26 -08:00
|
|
|
data2 = malloc(data_size);
|
|
|
|
if (!data2)
|
|
|
|
{
|
|
|
|
free(name2);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* if we want to compress */
|
2005-05-26 03:02:10 -07:00
|
|
|
if (compress)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
uLongf buflen;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* compress the data with max compression */
|
2002-12-14 17:32:13 -08:00
|
|
|
buflen = (uLongf)data_size;
|
2005-05-26 03:22:56 -07:00
|
|
|
if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
|
|
|
|
(uLong)size, 9) != Z_OK)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
free(name2);
|
|
|
|
free(data2);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* record compressed chunk size */
|
|
|
|
data_size = (int)buflen;
|
2005-05-22 21:32:04 -07:00
|
|
|
if (data_size >= size)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
compress = 0;
|
|
|
|
data_size = size;
|
|
|
|
}
|
2002-12-14 17:32:13 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
void *data3;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-14 17:32:13 -08:00
|
|
|
data3 = realloc(data2, data_size);
|
|
|
|
if (data3) data2 = data3;
|
|
|
|
}
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
if (!compress)
|
|
|
|
memcpy(data2, data, size);
|
2004-10-19 20:13:44 -07:00
|
|
|
|
|
|
|
/* Does this node already exist? */
|
2005-03-03 09:26:46 -08:00
|
|
|
if (ef->mode == EET_FILE_MODE_READ_WRITE)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
|
2004-10-19 20:13:44 -07:00
|
|
|
{
|
|
|
|
/* if it matches */
|
2005-05-25 20:57:57 -07:00
|
|
|
if (eet_string_match(efn->name, name))
|
2004-10-19 20:13:44 -07:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
free(efn->data);
|
2005-05-26 03:03:03 -07:00
|
|
|
efn->compression = !!compress;
|
2005-05-25 20:57:57 -07:00
|
|
|
efn->size = data_size;
|
|
|
|
efn->data_size = size;
|
|
|
|
efn->data = data2;
|
2004-10-19 20:13:44 -07:00
|
|
|
exists_already = 1;
|
2005-01-09 20:26:50 -08:00
|
|
|
free(name2);
|
2004-12-01 20:25:25 -08:00
|
|
|
break;
|
2004-10-19 20:13:44 -07:00
|
|
|
}
|
|
|
|
}
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
2004-10-19 20:13:44 -07:00
|
|
|
if (!exists_already)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
efn = calloc(1, sizeof(Eet_File_Node));
|
|
|
|
if (!efn)
|
2004-10-19 20:13:44 -07:00
|
|
|
{
|
|
|
|
free(name2);
|
|
|
|
free(data2);
|
|
|
|
return 0;
|
|
|
|
}
|
2005-05-25 20:57:57 -07:00
|
|
|
efn->next = ef->header->directory->nodes[hash];
|
|
|
|
ef->header->directory->nodes[hash] = efn;
|
|
|
|
efn->name = name2;
|
|
|
|
efn->offset = 0;
|
|
|
|
efn->compression = compress;
|
|
|
|
efn->size = data_size;
|
|
|
|
efn->data_size = size;
|
|
|
|
efn->data = data2;
|
2004-10-19 20:13:44 -07:00
|
|
|
}
|
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* flags that writes are pending */
|
|
|
|
ef->writes_pending = 1;
|
2003-06-16 06:39:42 -07:00
|
|
|
return data_size;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
|
2004-12-01 20:25:25 -08:00
|
|
|
int
|
|
|
|
eet_delete(Eet_File *ef, char *name)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
int hash;
|
2004-12-01 20:25:25 -08:00
|
|
|
int exists_already = 0;
|
2005-05-25 20:57:57 -07:00
|
|
|
Eet_File_Node *efn, *pefn;
|
|
|
|
|
2005-05-22 21:32:04 -07:00
|
|
|
/* check to see its' an eet file pointer */
|
2005-01-12 06:23:16 -08:00
|
|
|
if ((!ef) || (ef->magic != EET_MAGIC_FILE) || (!name))
|
2004-12-01 20:25:25 -08:00
|
|
|
return 0;
|
|
|
|
|
2005-01-12 11:59:11 -08:00
|
|
|
/* deleting keys is only possible in RW mode */
|
2005-03-03 09:26:46 -08:00
|
|
|
if (ef->mode != EET_FILE_MODE_READ_WRITE) return 0;
|
2005-01-12 11:59:11 -08:00
|
|
|
|
2004-12-01 20:25:25 -08:00
|
|
|
if (!ef->header) return 0;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2004-12-01 20:25:25 -08:00
|
|
|
/* figure hash bucket */
|
|
|
|
hash = eet_hash_gen(name, ef->header->directory->size);
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2004-12-01 20:25:25 -08:00
|
|
|
/* Does this node already exist? */
|
2005-05-25 20:57:57 -07:00
|
|
|
for (pefn = NULL, efn = ef->header->directory->nodes[hash]; efn; pefn = efn, efn = efn->next)
|
2004-12-01 20:25:25 -08:00
|
|
|
{
|
2005-01-12 11:59:11 -08:00
|
|
|
/* if it matches */
|
2005-05-25 20:57:57 -07:00
|
|
|
if (eet_string_match(efn->name, name))
|
2004-12-01 20:25:25 -08:00
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
if (efn->name) free(efn->name);
|
|
|
|
if (efn->data) free(efn->data);
|
|
|
|
if (efn == ef->header->directory->nodes[hash])
|
|
|
|
ef->header->directory->nodes[hash] = efn->next;
|
|
|
|
else
|
|
|
|
pefn->next = efn->next;
|
|
|
|
free(efn);
|
2005-01-12 11:59:11 -08:00
|
|
|
exists_already = 1;
|
|
|
|
break;
|
2004-12-01 20:25:25 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* flags that writes are pending */
|
|
|
|
if (exists_already) ef->writes_pending = 1;
|
|
|
|
/* update access time */
|
|
|
|
return exists_already;
|
|
|
|
}
|
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
char **
|
|
|
|
eet_list(Eet_File *ef, char *glob, int *count_ret)
|
|
|
|
{
|
|
|
|
char **list_ret = NULL;
|
|
|
|
int list_count = 0;
|
|
|
|
int list_count_alloc = 0;
|
2005-05-26 02:43:23 -07:00
|
|
|
int i, num;
|
2005-05-25 20:57:57 -07:00
|
|
|
Eet_File_Node *efn;
|
2002-12-02 15:39:26 -08:00
|
|
|
|
2005-05-22 21:32:04 -07:00
|
|
|
/* check to see its' an eet file pointer */
|
2003-01-12 20:31:00 -08:00
|
|
|
if ((!ef) || (ef->magic != EET_MAGIC_FILE) || (!glob) ||
|
2005-02-07 10:11:49 -08:00
|
|
|
(!ef->header) || (!ef->header->directory) ||
|
|
|
|
((ef->mode != EET_FILE_MODE_READ) &&
|
2005-03-03 09:26:46 -08:00
|
|
|
(ef->mode != EET_FILE_MODE_READ_WRITE)))
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
if (count_ret) *count_ret = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* loop through all entries */
|
2005-05-25 20:57:57 -07:00
|
|
|
num = (1 << ef->header->directory->size);
|
2002-12-02 15:39:26 -08:00
|
|
|
for (i = 0; i < num; i++)
|
|
|
|
{
|
2005-05-25 20:57:57 -07:00
|
|
|
for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
/* if the entry matches the input glob */
|
2005-05-25 20:57:57 -07:00
|
|
|
if (!fnmatch(glob, efn->name, 0))
|
2002-12-02 15:39:26 -08:00
|
|
|
{
|
|
|
|
char **new_list;
|
2005-05-22 21:32:04 -07:00
|
|
|
|
2002-12-02 15:39:26 -08:00
|
|
|
/* add it to our list */
|
|
|
|
list_count++;
|
|
|
|
/* only realloc in 32 entry chunks */
|
|
|
|
if (list_count > list_count_alloc)
|
|
|
|
{
|
|
|
|
list_count_alloc += 32;
|
|
|
|
new_list = realloc(list_ret, list_count_alloc * (sizeof(char *)));
|
|
|
|
if (!new_list)
|
|
|
|
{
|
|
|
|
free(list_ret);
|
|
|
|
if (count_ret) *count_ret = 0;
|
2005-05-22 21:32:04 -07:00
|
|
|
return NULL;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
list_ret = new_list;
|
|
|
|
}
|
|
|
|
/* put pointer of name string in */
|
2005-05-25 20:57:57 -07:00
|
|
|
list_ret[list_count - 1] = efn->name;
|
2002-12-02 15:39:26 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* return count and list */
|
2005-05-22 21:32:04 -07:00
|
|
|
if (count_ret) *count_ret = list_count;
|
2002-12-02 15:39:26 -08:00
|
|
|
return list_ret;
|
|
|
|
}
|
2004-01-17 06:58:50 -08:00
|
|
|
|
2004-01-17 07:58:40 -08:00
|
|
|
int eet_init(void)
|
2004-01-17 06:58:50 -08:00
|
|
|
{
|
2004-01-17 07:58:40 -08:00
|
|
|
return ++eet_initcount;
|
|
|
|
}
|
|
|
|
|
|
|
|
int eet_shutdown(void)
|
|
|
|
{
|
|
|
|
if (--eet_initcount == 0)
|
|
|
|
_eet_memfile_shutdown();
|
|
|
|
|
|
|
|
return eet_initcount;
|
2004-01-17 06:58:50 -08:00
|
|
|
}
|