示例#1
0
static multicart_open_error load_socket(multicart_load_state *state, xml_data_node *socket_node)
{
	const char *id;
	const char *uses;
	const multicart_resource *resource;
	multicart_socket *socket;
	multicart_socket **next_socket;

	/* get the 'id' and 'uses' attributes; error if not present */
	id = xml_get_attribute_string(socket_node, "id", NULL);
	uses = xml_get_attribute_string(socket_node, "uses", NULL);
	if ((id == NULL) || (uses == NULL))
		return MCERR_XML_ERROR;

	/* find the resource */
	for (resource = state->multicart->resources; resource != NULL; resource = resource->next)
	{
		if (!strcmp(uses, resource->id))
			break;
	}
	if (resource == NULL)
		return MCERR_INVALID_RESOURCE_REF;

	/* create the socket */
	socket = (multicart_socket *)pool_malloc_lib(state->multicart->data->pool, sizeof(*socket));
	if (socket == NULL)
		return MCERR_OUT_OF_MEMORY;
	memset(socket, 0, sizeof(*socket));
	socket->resource = resource;
	socket->ptr = resource->ptr;

	/* copy id */
	socket->id = pool_strdup_lib(state->multicart->data->pool, id);
	if (socket->id == NULL)
		return MCERR_OUT_OF_MEMORY;

	/* which pointer should I use? */
	if (resource->ptr != NULL)
	{
		/* use the resource's ptr */
		socket->ptr = resource->ptr;
	}
	else
	{
		/* allocate bytes for this socket */
		socket->ptr = pool_malloc_lib(state->multicart->data->pool, resource->length);
		if (socket->ptr == NULL)
			return MCERR_OUT_OF_MEMORY;

		/* ...and clear it */
		memset(socket->ptr, 0xCD, resource->length);
	}

	/* append the resource */
	for (next_socket = &state->sockets; *next_socket; next_socket = &(*next_socket)->next)
		;
	*next_socket = socket;

	return MCERR_NONE;
}
示例#2
0
static multicart_open_error load_ram_resource(emu_options &options, multicart_load_state *state, xml_data_node *resource_node,
	multicart_resource *resource)
{
	const char *length_string;
	const char *ram_type;
	const char *ram_filename;

	astring *ram_pathname;

	/* locate the 'length' attribute */
	length_string = xml_get_attribute_string(resource_node, "length", NULL);
	if (length_string == NULL)
		return MCERR_MISSING_RAM_LENGTH;

	/* ...and parse it */
	resource->length = ram_parse_string(length_string);
	if (resource->length <= 0)
		return MCERR_INVALID_RAM_SPEC;

	/* allocate bytes for this resource */
	resource->ptr = pool_malloc_lib(state->multicart->data->pool, resource->length);
	if (resource->ptr == NULL)
		return MCERR_OUT_OF_MEMORY;

	/* Is this a persistent RAM resource? Then try to load it. */
	ram_type = xml_get_attribute_string(resource_node, "type", NULL);
	if (ram_type != NULL)
	{
		if (strcmp(ram_type, "persistent")==0)
		{
			astring tmp;

			/* Get the file name. */
			ram_filename = xml_get_attribute_string(resource_node, "file", NULL);
			if (ram_filename==NULL)
				return MCERR_XML_ERROR;

			ram_pathname = astring_assemble_3(&tmp, state->multicart->gamedrv_name, PATH_SEPARATOR, ram_filename);

			/* Save the file name so that we can write the contents on unloading.
               If the RAM resource has no filename, we know that it was volatile only. */
			resource->filename = pool_strdup_lib(state->multicart->data->pool, astring_c(ram_pathname));

			if (resource->filename == NULL)
				return MCERR_OUT_OF_MEMORY;

			image_battery_load_by_name(options, resource->filename, resource->ptr, resource->length, 0x00);
		}
		/* else this type is volatile, in which case we just have
            a memory expansion */
	}
	return MCERR_NONE;
}
示例#3
0
static multicart_open_error load_resource(emu_options &options, multicart_load_state *state, xml_data_node *resource_node,
	multicart_resource_type resource_type)
{
	const char *id;
	multicart_open_error err;
	multicart_resource *resource;
	multicart_resource **next_resource;

	/* get the 'id' attribute; error if not present */
	id = xml_get_attribute_string(resource_node, "id", NULL);
	if (id == NULL)
		return MCERR_XML_ERROR;

	/* allocate memory for the resource */
	resource = (multicart_resource *)pool_malloc_lib(state->multicart->data->pool, sizeof(*resource));
	if (resource == NULL)
		return MCERR_OUT_OF_MEMORY;
	memset(resource, 0, sizeof(*resource));
	resource->type = resource_type;

	/* copy id */
	resource->id = pool_strdup_lib(state->multicart->data->pool, id);
	if (resource->id == NULL)
		return MCERR_OUT_OF_MEMORY;

	switch(resource->type)
	{
		case MULTICART_RESOURCE_TYPE_ROM:
			err = load_rom_resource(state, resource_node, resource);
			if (err != MCERR_NONE)
				return err;
			break;

		case MULTICART_RESOURCE_TYPE_RAM:
			err = load_ram_resource(options, state, resource_node, resource);
			if (err != MCERR_NONE)
				return err;
			break;

		default:
			return MCERR_UNKNOWN_RESOURCE_TYPE;
	}

	/* append the resource */
	for (next_resource = &state->resources; *next_resource; next_resource = &(*next_resource)->next)
		;
	*next_resource = resource;

	return MCERR_NONE;
}
示例#4
0
文件: opresolv.cpp 项目: Fulg/mame
optreserr_t option_resolution_add_param(option_resolution *resolution, const char *param, const char *value)
{
	int i;
	int must_resolve;
	optreserr_t err;
	const char *option_specification;
	struct option_resolution_entry *entry = nullptr;

	for (i = 0; i < resolution->option_count; i++)
	{
		if (!strcmp(param, resolution->entries[i].guide_entry->identifier))
		{
			entry = &resolution->entries[i];
			break;
		}
	}
	if (!entry)
		return OPTIONRESOLUTION_ERROR_PARAMNOTFOUND;

	if (entry->state != RESOLUTION_ENTRY_STATE_UNSPECIFIED)
		return OPTIONRESOLUTION_ERROR_PARAMALREADYSPECIFIED;

	switch(entry->guide_entry->option_type) {
	case OPTIONTYPE_INT:
		entry->u.int_value = atoi(value);
		entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED;
		must_resolve = TRUE;
		break;

	case OPTIONTYPE_STRING:
		entry->u.str_value = pool_strdup_lib(resolution->pool, value);
		if (!entry->u.str_value)
		{
			err = OPTIONRESOLUTION_ERROR_OUTOFMEMORY;
			goto done;
		}
		entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED;
		must_resolve = FALSE;
		break;

	case OPTIONTYPE_ENUM_BEGIN:
		for (i = 1; entry->guide_entry[i].option_type == OPTIONTYPE_ENUM_VALUE; i++)
		{
			if (!core_stricmp(value, entry->guide_entry[i].identifier))
			{
				entry->u.int_value = entry->guide_entry[i].parameter;
				entry->state = RESOLUTION_ENTRY_STATE_SPECIFIED;
				break;
			}
		}
		if (entry->state != RESOLUTION_ENTRY_STATE_SPECIFIED)
		{
			err = OPTIONRESOLUTION_ERROR_BADPARAM;
			goto done;
		}
		must_resolve = TRUE;
		break;

	default:
		err = OPTIONRESOLTUION_ERROR_INTERNAL;
		assert(0);
		goto done;
	}

	/* do a resolution step if necessary */
	if (must_resolve)
	{
		option_specification = lookup_in_specification(resolution->specification, entry->guide_entry);
		err = resolve_single_param(option_specification, &entry->u.int_value, nullptr, 0);
		if (err)
			goto done;

		/* did we not get a real value? */
		if (entry->u.int_value < 0)
		{
			err = OPTIONRESOLUTION_ERROR_PARAMNOTSPECIFIED;
			goto done;
		}
	}

	err = OPTIONRESOLUTION_ERROR_SUCCESS;

done:
	return err;
}
示例#5
0
文件: library.c 项目: cdenix/psmame
char *imgtool_library_strdup(imgtool_library *library, const char *s)
{
	return pool_strdup_lib(library->pool, s);
}
示例#6
0
multicart_open_error multicart_open(emu_options &options, const char *filename, const char *gamedrv, multicart_load_flags load_flags, multicart_t **cart)
{
	multicart_open_error err;
	zip_error ziperr;
	object_pool *pool;
	multicart_load_state state = {0, };
	const zip_file_header *header;
	const char *pcb_type;
	char *layout_text = NULL;

	/* allocate an object pool */
	pool = pool_alloc_lib(NULL);
	if (pool == NULL)
	{
		err = MCERR_OUT_OF_MEMORY;
		goto done;
	}

	/* allocate the multicart */
	state.multicart = (multicart_t*)pool_malloc_lib(pool, sizeof(*state.multicart));
	if (state.multicart == NULL)
	{
		err = MCERR_OUT_OF_MEMORY;
		goto done;
	}
	memset(state.multicart, 0, sizeof(*state.multicart));

	/* allocate the multicart's private data */
	state.multicart->data = (multicart_private*)pool_malloc_lib(pool, sizeof(*state.multicart->data));
	if (state.multicart->data == NULL)
	{
		err = MCERR_OUT_OF_MEMORY;
		goto done;
	}
	memset(state.multicart->data, 0, sizeof(*state.multicart->data));
	state.multicart->data->pool = pool;
	pool = NULL;

	/* open the ZIP file */
	ziperr = zip_file_open(filename, &state.zip);
	if (ziperr != ZIPERR_NONE)
	{
		err = MCERR_NOT_MULTICART;
		goto done;
	}

	/* find the layout.xml file */
	header = find_file(state.zip, "layout.xml");
	if (header == NULL)
	{
		err = MCERR_MISSING_LAYOUT;
		goto done;
	}

	/* reserve space for the layout text */
	layout_text = (char*)malloc(header->uncompressed_length + 1);
	if (layout_text == NULL)
	{
		err = MCERR_OUT_OF_MEMORY;
		goto done;
	}

	/* uncompress the layout text */
	ziperr = zip_file_decompress(state.zip, layout_text, header->uncompressed_length);
	if (ziperr != ZIPERR_NONE)
	{
		err = MCERR_ZIP_ERROR;
		goto done;
	}
	layout_text[header->uncompressed_length] = '\0';

	/* parse the layout text */
	state.layout_xml = xml_string_read(layout_text, NULL);
	if (state.layout_xml == NULL)
	{
		err = MCERR_XML_ERROR;
		goto done;
	}

	/* locate the PCB node */
	if (!find_pcb_and_resource_nodes(state.layout_xml, &state.pcb_node, &state.resources_node))
	{
		err = MCERR_NO_PCB_OR_RESOURCES;
		goto done;
	}

	/* get the PCB resource_type */
	pcb_type = xml_get_attribute_string(state.pcb_node, "type", "");
	state.multicart->pcb_type = pool_strdup_lib(state.multicart->data->pool, pcb_type);
	if (state.multicart->pcb_type == NULL)
	{
		err = MCERR_OUT_OF_MEMORY;
		goto done;
	}

	state.multicart->gamedrv_name = pool_strdup_lib(state.multicart->data->pool, gamedrv);
	if (state.multicart->gamedrv_name == NULL)
	{
		err = MCERR_OUT_OF_MEMORY;
		goto done;
	}

	/* do we have to load resources? */
	if (load_flags & MULTICART_FLAGS_LOAD_RESOURCES)
	{
		err = load_all_resources(options, &state);
		if (err != MCERR_NONE)
			goto done;

		err = load_all_sockets(&state);
		if (err != MCERR_NONE)
			goto done;
	}

	err = MCERR_NONE;

done:
	if (pool != NULL)
		pool_free_lib(pool);
	if (state.zip != NULL)
		zip_file_close(state.zip);
	if (layout_text != NULL)
		free(layout_text);
	if (state.layout_xml != NULL)
		xml_file_free(state.layout_xml);

	if ((err != MCERR_NONE) && (state.multicart != NULL))
	{
		multicart_close(options, state.multicart);
		state.multicart = NULL;
	}
	*cart = state.multicart;
	return err;
}
示例#7
0
文件: library.cpp 项目: RalfVB/mame
char *library::imgtool_library_strdup(const char *s)
{
	return pool_strdup_lib(m_pool, s);
}
示例#8
0
文件: messdocs.c 项目: cdenix/psmame
int messdocs(const char *toc_filename, const char *dest_dir, const char *help_project_filename,
	const char *help_contents_filename, const char *help_filename)
{
	char buf[4096];
	struct messdocs_state state;
	int len;
	int done;
	FILE *in;
	FILE *chm_hhp;
	int i;
	char *s;
	XML_Memory_Handling_Suite memcallbacks;

	memset(&state, 0, sizeof(state));
	state.m_pool = pool_alloc_lib(NULL);

	/* open the DOC */
	in = fopen(toc_filename, "r");
	if (!in)
	{
		fprintf(stderr, "Cannot open TOC file '%s'\n", toc_filename);
		goto error;
	}

	/* figure out the TOC directory */
	state.m_toc_dir = pool_strdup_lib(state.m_pool, toc_filename);
	if (!state.m_toc_dir)
		goto outofmemory;
	for (i = strlen(state.m_toc_dir) - 1; (i > 0) && !osd_is_path_separator(state.m_toc_dir[i]); i--)
		state.m_toc_dir[i] = '\0';

	/* clean the target directory */
	rmdir_recursive(dest_dir);
	osd_mkdir(dest_dir);

	/* create the help contents file */
	s = (char*)pool_malloc_lib(state.m_pool, strlen(dest_dir) + 1 + strlen(help_project_filename) + 1);
	if (!s)
		goto outofmemory;
	strcpy(s, dest_dir);
	strcat(s, PATH_SEPARATOR);
	strcat(s, help_contents_filename);
	state.m_chm_toc = fopen(s, "w");
	state.m_dest_dir = dest_dir;
	if (!state.m_chm_toc)
	{
		fprintf(stderr, "Cannot open file %s\n", s);
		goto error;
	}

	fprintf(state.m_chm_toc, "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\"\n");
	fprintf(state.m_chm_toc, "<HTML>\n");
	fprintf(state.m_chm_toc, "<HEAD>\n");
	fprintf(state.m_chm_toc, "</HEAD>\n");
	fprintf(state.m_chm_toc, "<BODY>\n");
	fprintf(state.m_chm_toc, "<OBJECT type=\"text/site properties\">\n");
	fprintf(state.m_chm_toc, "\t<param name=\"Window Styles\" value=\"0x800625\">\n");
	fprintf(state.m_chm_toc, "\t<param name=\"ImageType\" value=\"Folder\">\n");
	fprintf(state.m_chm_toc, "\t<param name=\"Font\" value=\"Arial,8,0\">\n");
	fprintf(state.m_chm_toc, "</OBJECT>\n");
	fprintf(state.m_chm_toc, "<UL>\n");

	/* create the XML parser */
	memcallbacks.malloc_fcn = expat_malloc;
	memcallbacks.realloc_fcn = expat_realloc;
	memcallbacks.free_fcn = expat_free;
	state.m_parser = XML_ParserCreate_MM(NULL, &memcallbacks, NULL);
	if (!state.m_parser)
		goto outofmemory;

	XML_SetUserData(state.m_parser, &state);
	XML_SetElementHandler(state.m_parser, start_handler, end_handler);
	XML_SetCharacterDataHandler(state.m_parser, data_handler);

	do
	{
		len = (int) fread(buf, 1, sizeof(buf), in);
		done = feof(in);

		if (XML_Parse(state.m_parser, buf, len, done) == XML_STATUS_ERROR)
		{
			process_error(&state, NULL, NULL);
			break;
		}
	}
	while(!done);

	fprintf(state.m_chm_toc, "</UL>\n");
	fprintf(state.m_chm_toc, "</BODY></HTML>");
	fclose(state.m_chm_toc);

	/* create the help project file */
	s = (char*)pool_malloc_lib(state.m_pool, strlen(dest_dir) + 1 + strlen(help_project_filename) + 1);
	if (!s)
		goto outofmemory;
	strcpy(s, dest_dir);
	strcat(s, PATH_SEPARATOR);
	strcat(s, help_project_filename);
	chm_hhp = fopen(s, "w");
	if (!chm_hhp)
	{
		fprintf(stderr, "Cannot open file %s\n", s);
		goto error;
	}

	fprintf(chm_hhp, "[OPTIONS]\n");
	fprintf(chm_hhp, "Compiled file=%s\n", help_filename);
	fprintf(chm_hhp, "Contents file=%s\n", help_contents_filename);
	fprintf(chm_hhp, "Default topic=%s\n", state.m_default_topic);
	fprintf(chm_hhp, "Language=0x409 English (United States)\n");
	fprintf(chm_hhp, "Title=%s\n", state.m_title);
	fprintf(chm_hhp, "\n");
	fclose(chm_hhp);

	/* finish up */
	XML_ParserFree(state.m_parser);
	fclose(in);
	pool_free_lib(state.m_pool);
	return state.m_error ? -1 : 0;

outofmemory:
	fprintf(stderr, "Out of memory");
error:
	if (state.m_chm_toc) fclose(state.m_chm_toc);
	if (in)	fclose(in);
	return -1;
}
示例#9
0
文件: messdocs.c 项目: cdenix/psmame
static void start_handler(void *data, const XML_Char *tagname, const XML_Char **attributes)
{
	const char *title;
	const char *name;
	const char *filepath;
	const char *srcpath;
	const char *destpath;
	const char *datfile_foldername;
	struct system_info *sysinfo_array;
	int sys_count;
	char buf[512];
	const char *sysname;
	char sysfilename[512];
	char *datfile_path = NULL;
	char *s;
	FILE *datfile = NULL;
	FILE *sysfile = NULL;
	int lineno = 0;
	int i;
	int ul = FALSE;

	struct messdocs_state *state = (struct messdocs_state *) data;

	if (state->m_depth == 0)
	{
		/* help tag */
		if (strcmp(tagname, "help"))
		{
			process_error(state, NULL, "Expected tag 'help'");
			return;
		}

		title = find_attribute(attributes, "title");
		if (title)
			state->m_title = pool_strdup_lib(state->m_pool, title);
	}
	else if (!strcmp(tagname, "topic"))
	{
		/* topic tag */
		name = find_attribute(attributes, "text");
		filepath = find_attribute(attributes, "filepath");

		/* output TOC info */
		fprintf(state->m_chm_toc, "\t<LI> <OBJECT type=\"text/sitemap\">\n");
		fprintf(state->m_chm_toc, "\t\t<param name=\"Name\"  value=\"%s\">\n", name);
		fprintf(state->m_chm_toc, "\t\t<param name=\"Local\" value=\"%s\">\n", filepath);
		fprintf(state->m_chm_toc, "\t\t</OBJECT>\n");

		/* copy file */
		copy_file_to_dest(state->m_dest_dir, state->m_toc_dir, filepath);

		if (!state->m_default_topic)
			state->m_default_topic = pool_strdup_lib(state->m_pool, filepath);
	}
	else if (!strcmp(tagname, "folder"))
	{
		/* folder tag */
		name = find_attribute(attributes, "text");
		fprintf(state->m_chm_toc, "\t<LI> <OBJECT type=\"text/sitemap\">\n");
		fprintf(state->m_chm_toc, "\t\t<param name=\"Name\" value=\"%s\">\n", name);
		fprintf(state->m_chm_toc, "\t\t</OBJECT>\n");
		fprintf(state->m_chm_toc, "\t\t<UL>\n");
	}
	else if (!strcmp(tagname, "file"))
	{
		/* file tag */
		filepath = find_attribute(attributes, "filepath");
		copy_file_to_dest(state->m_dest_dir, state->m_toc_dir, filepath);
	}
	else if (!strcmp(tagname, "datfile"))
	{
		/* datfile tag */
		srcpath = find_attribute(attributes, "srcpath");
		destpath = find_attribute(attributes, "destpath");
		datfile_foldername = find_attribute(attributes, "text");

		datfile_path = make_path(state->m_toc_dir, srcpath);
		datfile = fopen(datfile_path, "r");
		if (!datfile)
		{
			process_error(state, NULL, "Cannot open datfile '%s'\n", datfile_path);
			return;
		}

		snprintf(buf, ARRAY_LENGTH(buf), "%s", state->m_dest_dir);
		combine_path(buf, ARRAY_LENGTH(buf), destpath);
		osd_mkdir(buf);

		sysinfo_array = NULL;
		sys_count = 0;
		sysname = NULL;

		while(!feof(datfile))
		{
			fgets(buf, ARRAY_LENGTH(buf), datfile);
			s = strchr(buf, '\n');
			if (s)
				*s = '\0';
			rtrim(buf);

			switch(buf[0]) {
			case '$':
				if (!strncmp(buf, "$info", 5))
				{
					/* $info */
					s = strchr(buf, '=');
					s = s ? s + 1 : &buf[strlen(buf)];

					sysinfo_array = (system_info*)pool_realloc_lib(state->m_pool, sysinfo_array, sizeof(*sysinfo_array) * (sys_count + 1));
					if (!sysinfo_array)
						goto outofmemory;
					sysinfo_array[sys_count].name = pool_strdup_lib(state->m_pool, s);
					sysinfo_array[sys_count].desc = NULL;

					sysname = sysinfo_array[sys_count].name;
					sys_count++;

					snprintf(sysfilename, sizeof(sysfilename), "%s%s%s%s%s.htm", state->m_dest_dir, PATH_SEPARATOR, destpath, PATH_SEPARATOR, s);

					if (sysfile)
						fclose(sysfile);
					sysfile = fopen(sysfilename, "w");
					lineno = 0;
				}
				else if (!strncmp(buf, "$bio", 4))
				{
					/* $bio */
				}
				else if (!strncmp(buf, "$end", 4))
				{
					/* $end */
				}
				break;
			case '#':
			case '\0':
				/* comments */
				break;
			default:
				/* normal line */
				if (!sysfile)
					break;

				html_encode(buf, ARRAY_LENGTH(buf));

				if (!strncmp(buf, "======", 6) && lineno == 0)
				{
					char *heading = (char*)malloc(strlen(buf) + 1);
					memset(heading, 0, strlen(buf) + 1);
					strncpy(heading, buf + 6, strlen(buf) - 12);
					fprintf(sysfile, "<h1>%s</h1>\n", heading);
					fprintf(sysfile, "<p><i>(directory: %s)</i></p>\n", sysname);

					if (!sysinfo_array[sys_count-1].desc)
						sysinfo_array[sys_count-1].desc = pool_strdup_lib(state->m_pool, heading);

					free(heading);
				}
				else if (buf[0] == '=')
				{
					int count;
					char *heading = (char*)malloc(strlen(buf) + 1);
					memset(heading, 0, strlen(buf) + 1);

					if (ul)
					{
						fprintf(sysfile, "</ul>");
						ul = FALSE;
					}

					for (count = 0; buf[count] == '='; count++);

					strncpy(heading, buf + count, strlen(buf) - count*2);
					fprintf(sysfile, "<h%d>%s</h%d>\n", 7-count, heading, 7-count);
					free(heading);
				}
				else if (!strncmp(buf, "  * ", 4))
				{
					if (!ul)
					{
						fprintf(sysfile, "<ul>");
					}

					ul = TRUE;

					fprintf(sysfile, "<li>%s</li>", buf + 4);
				}
				else
				{
					if (ul)
					{
						fprintf(sysfile, "</ul>");
						ul = FALSE;
					}
					fprintf(sysfile, "%s\n", buf);
				}
				lineno++;
				break;
			}
		}

		/* now write out all toc */
		qsort(sysinfo_array, sys_count, sizeof(*sysinfo_array), str_compare);

		fprintf(state->m_chm_toc, "\t<LI> <OBJECT type=\"text/sitemap\">\n");
		fprintf(state->m_chm_toc, "\t\t<param name=\"Name\" value=\"%s\">\n", datfile_foldername);
		fprintf(state->m_chm_toc, "\t\t</OBJECT>\n");
		fprintf(state->m_chm_toc, "\t\t<UL>\n");

		for (i = 0; i < sys_count; i++)
		{
			fprintf(state->m_chm_toc, "\t<LI> <OBJECT type=\"text/sitemap\">\n");
			fprintf(state->m_chm_toc, "\t\t<param name=\"Name\" value=\"%s\">\n", sysinfo_array[i].desc);
			fprintf(state->m_chm_toc, "\t\t<param name=\"Local\" value=\"%s%s%s.htm\">\n", destpath, PATH_SEPARATOR, sysinfo_array[i].name);
			fprintf(state->m_chm_toc, "\t\t</OBJECT>\n");
		}

		fprintf(state->m_chm_toc, "\t\t</UL>\n");
	}

	state->m_depth++;

outofmemory:
	if (datfile_path)
		free(datfile_path);
	if (datfile)
		fclose(datfile);
	if (sysfile)
		fclose(sysfile);
}