/* seborrhea-dirlist-zzip.m,
 *
 * This directory listing lists all the files inside a zip file, using
 * Zziplib.  It does NOT look inside directories.
 */

#ifndef NO_ZZIP

#include <assert.h>
#include <stdlib.h>
#include "dirlist-zzip.h"
#include "seborrhea.h"


@implementation ZzipDirectoryList
- free
{
    if (zfp) {
	zzip_fclose(zfp);
	zfp = NULL;
    }

    return [super free];
}

- (ZZIP_DIR *) openDirectory:(const char *)dirname
{
    assert(dirname);
    return zzip_opendir_ext_io(dirname, ZZIP_ONLYZIP, 0, 0);
}

- (void) closeDirectory:(ZZIP_DIR *)zz_dir
{
    if (zz_dir)
	zzip_closedir(zz_dir);
}

- (BOOL) scanDirectory:(const char *)dirname
{
    ZZIP_DIR *zz_dir;
    ZZIP_DIRENT *zz_dirent;
    assert(dirname);
    assert(not entries && nentries == 0);

    zz_dir = [self openDirectory:dirname];
    if (not zz_dir)
	return NO;

    while ((zz_dirent = zzip_readdir(zz_dir))) {
	/* No filters. */
	entries = realloc(entries, (nentries+1)*sizeof(dirent_t));
	assert(entries);

	entries[nentries].d_type = DT_UNKNOWN;
	strncpy(entries[nentries].d_name, zz_dirent->d_name, sizeof entries[nentries].d_name);
	entries[nentries].loaded = NO;
	entries[nentries].st_size = zz_dirent->st_size;
	nentries++;
    }
    [self closeDirectory:zz_dir];

    [self sort];
    working_directory = strdup(dirname);
    return YES;
}

+ (BOOL) isReal { return NO; }

- (void *) openFile:(const char *)filename
{
    assert(filename);
    zfp = zzip_freopen(filename, "rti", zfp);
    return zfp;
}

- (void) closeFile:(void *)file
{
    ZZIP_FILE *fp = file;

    /* If the file was opened by us (fp == zfp), don't close since we
       are using reopen.  zfp will be closed when we are freed. */
    if (fp && fp != zfp)
	zzip_fclose(fp);
}

- (void *) openFile:(const char *)filename :(unsigned int)index :(void **)buffer :(unsigned int *)buffer_size
{
    zzip_size_t read_size;
    assert(filename && buffer && buffer_size);

    zfp = zzip_freopen(filename, "rbi", zfp);
    if (not zfp)
	return NULL;

    *buffer_size = entries[index].st_size;
    *buffer = malloc(*buffer_size);
    assert(*buffer);

    read_size = zzip_fread(*buffer, 1, *buffer_size, zfp);
    assert(read_size == *buffer_size);
    return *buffer;
}
@end

#endif
