/*
 *
 * (c) 2005-2009 Laurent Vivier <Laurent@vivier.eu>
 *
 * This file has been copied from EMILE, http://emile.sf.net
 *
 */

#include "libiso9660.h"

static inline int iso9660_is_directory(struct iso_directory_record * idr)
{
	return ((idr->flags[0] & 2) != 0);
}

static iso9660_DIR* iso9660_opendir_node(iso9660_VOLUME *volume, struct iso_directory_record *node)
{
	iso9660_DIR *dir;

	dir = (iso9660_DIR*)malloc(sizeof(iso9660_DIR));
	if (dir == NULL)
		return NULL;

	dir->extent = isonum_733((char *)node->extent);
	dir->len = isonum_733((char *)node->size);
	dir->index =  sizeof (dir->buffer);
	dir->volume = volume;

	return dir;
}

static struct iso_directory_record* idr_new(struct iso_directory_record* idr)
{
	struct iso_directory_record* result;
	int size = sizeof(*idr) + (int)idr->name_len[0];

	result = (struct iso_directory_record*)malloc(size);
	memcpy(result, idr, size);

	return result;
}

static struct iso_directory_record * seek_name(iso9660_VOLUME *volume,
					       struct iso_directory_record *idr,
					       char *name)
{
	struct iso_directory_record *result;
	char name_buf[256];
	iso9660_DIR *dir;

	dir = iso9660_opendir_node(volume, idr);
	if (dir == NULL)
		return NULL;

	while ((idr = iso9660_readdir(dir)) != NULL)
	{
		iso9660_name(volume, idr, name_buf);
		if (strcasecmp(name, name_buf) == 0)
		{
			result = idr_new(idr);
			iso9660_closedir(dir);
			return result;
		}
	}
	iso9660_closedir(dir);
	return NULL;
}

struct iso_directory_record* iso9660_get_node(
		iso9660_VOLUME *volume,
		struct iso_directory_record *dirnode,
		const char *path)
{
	struct iso_directory_record* result;
	struct iso_directory_record* current;
	char name[256];
	int i;

	current = idr_new(dirnode);
	while(1)
	{
		/* ignore head '\' */

		while (*path && *path == '\\')
			path++;

		if (*path == 0)
			break;

		/* extract first path component */

		i = 0;
		while (*path && *path != '\\')
			name[i++] = *path++;
		name[i] = 0;

		/* seek first component in current directory */

		result = seek_name(volume, current, name);
		if (result == NULL)
			return NULL;

		free(current);
		current = result;
	}
	return current;
}

iso9660_DIR* iso9660_opendir(iso9660_VOLUME *volume, const char *name)
{
	iso9660_DIR *dir;
	struct iso_directory_record *node;

	node = iso9660_get_root_node((iso9660_VOLUME*)volume);
	if (node == NULL)
		return NULL;

	node = iso9660_get_node((iso9660_VOLUME*)volume, node, name);
	if (node == NULL)
		return NULL;
	if (!iso9660_is_directory(node)) {
		free(node);
		return NULL;
	}

	dir = iso9660_opendir_node((iso9660_VOLUME*)volume, node);

	free(node);

	dir->volume = (iso9660_VOLUME*)volume;

	return dir;
}