Blame winpr/libwinpr/utils/ini.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * .ini config file
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit Service 5a9772
#include <errno.h>
Packit 1fb8d4
#include <winpr/wtypes.h>
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/ini.h>
Packit 1fb8d4
Packit Service 5a9772
struct _wIniFileKey
Packit 1fb8d4
{
Packit Service 5a9772
	char* name;
Packit Service 5a9772
	char* value;
Packit Service 5a9772
};
Packit Service 5a9772
typedef struct _wIniFileKey wIniFileKey;
Packit Service 5a9772
Packit Service 5a9772
struct _wIniFileSection
Packit Service 5a9772
{
Packit Service 5a9772
	char* name;
Packit Service 5a9772
	size_t nKeys;
Packit Service 5a9772
	size_t cKeys;
Packit Service 5a9772
	wIniFileKey** keys;
Packit Service 5a9772
};
Packit Service 5a9772
typedef struct _wIniFileSection wIniFileSection;
Packit Service 5a9772
Packit Service 5a9772
struct _wIniFile
Packit Service 5a9772
{
Packit Service 5a9772
	FILE* fp;
Packit Service 5a9772
	char* line;
Packit Service 5a9772
	char* nextLine;
Packit Service 5a9772
	size_t lineLength;
Packit Service 5a9772
	char* tokctx;
Packit Service 5a9772
	char* buffer;
Packit Service 5a9772
	char* filename;
Packit Service 5a9772
	BOOL readOnly;
Packit Service 5a9772
	size_t nSections;
Packit Service 5a9772
	size_t cSections;
Packit Service 5a9772
	wIniFileSection** sections;
Packit Service 5a9772
};
Packit Service 5a9772
Packit Service 5a9772
static BOOL IniFile_Load_NextLine(wIniFile* ini, char* str)
Packit Service 5a9772
{
Packit Service 5a9772
	size_t length = 0;
Packit 1fb8d4
	ini->nextLine = strtok_s(str, "\n", &ini->tokctx);
Packit 1fb8d4
Packit 1fb8d4
	if (ini->nextLine)
Packit Service 5a9772
		length = strlen(ini->nextLine);
Packit 1fb8d4
Packit 1fb8d4
	if (length > 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (ini->nextLine[length - 1] == '\r')
Packit 1fb8d4
		{
Packit 1fb8d4
			ini->nextLine[length - 1] = '\0';
Packit 1fb8d4
			length--;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (length < 1)
Packit 1fb8d4
			ini->nextLine = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (ini->nextLine) ? TRUE : FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL IniFile_Load_String(wIniFile* ini, const char* iniString)
Packit 1fb8d4
{
Packit Service 5a9772
	size_t fileSize;
Packit Service 5a9772
	if (!ini || !iniString)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit 1fb8d4
	ini->line = NULL;
Packit 1fb8d4
	ini->nextLine = NULL;
Packit 1fb8d4
	ini->buffer = NULL;
Packit Service 5a9772
	fileSize = strlen(iniString);
Packit 1fb8d4
Packit 1fb8d4
	if (fileSize < 1)
Packit Service 5a9772
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	ini->buffer = (char*)malloc(fileSize + 2);
Packit 1fb8d4
Packit 1fb8d4
	if (!ini->buffer)
Packit Service 5a9772
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	CopyMemory(ini->buffer, iniString, fileSize);
Packit 1fb8d4
	ini->buffer[fileSize] = '\n';
Packit 1fb8d4
	ini->buffer[fileSize + 1] = '\0';
Packit 1fb8d4
	IniFile_Load_NextLine(ini, ini->buffer);
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL IniFile_Open_File(wIniFile* ini, const char* filename)
Packit 1fb8d4
{
Packit Service 5a9772
	if (!ini || !filename)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit 1fb8d4
	if (ini->readOnly)
Packit 1fb8d4
		ini->fp = fopen(filename, "rb");
Packit 1fb8d4
	else
Packit 1fb8d4
		ini->fp = fopen(filename, "w+b");
Packit 1fb8d4
Packit 1fb8d4
	if (!ini->fp)
Packit Service 5a9772
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL IniFile_Load_File(wIniFile* ini, const char* filename)
Packit 1fb8d4
{
Packit 1fb8d4
	INT64 fileSize;
Packit 1fb8d4
Packit Service 5a9772
	if (!IniFile_Open_File(ini, filename))
Packit Service 5a9772
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (_fseeki64(ini->fp, 0, SEEK_END) < 0)
Packit 1fb8d4
		goto out_file;
Packit 1fb8d4
Packit 1fb8d4
	fileSize = _ftelli64(ini->fp);
Packit 1fb8d4
Packit 1fb8d4
	if (fileSize < 0)
Packit 1fb8d4
		goto out_file;
Packit 1fb8d4
Packit 1fb8d4
	if (_fseeki64(ini->fp, 0, SEEK_SET) < 0)
Packit 1fb8d4
		goto out_file;
Packit 1fb8d4
Packit 1fb8d4
	ini->line = NULL;
Packit 1fb8d4
	ini->nextLine = NULL;
Packit 1fb8d4
	ini->buffer = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (fileSize < 1)
Packit 1fb8d4
		goto out_file;
Packit 1fb8d4
Packit Service 5a9772
	ini->buffer = (char*)malloc((size_t)fileSize + 2);
Packit 1fb8d4
Packit 1fb8d4
	if (!ini->buffer)
Packit 1fb8d4
		goto out_file;
Packit 1fb8d4
Packit Service 5a9772
	if (fread(ini->buffer, (size_t)fileSize, 1, ini->fp) != 1)
Packit 1fb8d4
		goto out_buffer;
Packit 1fb8d4
Packit 1fb8d4
	fclose(ini->fp);
Packit 1fb8d4
	ini->fp = NULL;
Packit 1fb8d4
	ini->buffer[fileSize] = '\n';
Packit 1fb8d4
	ini->buffer[fileSize + 1] = '\0';
Packit 1fb8d4
	IniFile_Load_NextLine(ini, ini->buffer);
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
out_buffer:
Packit 1fb8d4
	free(ini->buffer);
Packit 1fb8d4
	ini->buffer = NULL;
Packit 1fb8d4
out_file:
Packit 1fb8d4
	fclose(ini->fp);
Packit 1fb8d4
	ini->fp = NULL;
Packit Service 5a9772
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void IniFile_Load_Finish(wIniFile* ini)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!ini)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	if (ini->buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(ini->buffer);
Packit 1fb8d4
		ini->buffer = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL IniFile_Load_HasNextLine(wIniFile* ini)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!ini)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return (ini->nextLine) ? TRUE : FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static char* IniFile_Load_GetNextLine(wIniFile* ini)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!ini)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	ini->line = ini->nextLine;
Packit Service 5a9772
	ini->lineLength = strlen(ini->line);
Packit 1fb8d4
	IniFile_Load_NextLine(ini, NULL);
Packit 1fb8d4
	return ini->line;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void IniFile_Key_Free(wIniFileKey* key)
Packit 1fb8d4
{
Packit Service 5a9772
	if (!key)
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	free(key->name);
Packit Service 5a9772
	free(key->value);
Packit Service 5a9772
	free(key);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static wIniFileKey* IniFile_Key_New(const char* name, const char* value)
Packit Service 5a9772
{
Packit Service 5a9772
	wIniFileKey* key;
Packit Service 5a9772
Packit Service 5a9772
	if (!name || !value)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	key = malloc(sizeof(wIniFileKey));
Packit 1fb8d4
Packit 1fb8d4
	if (key)
Packit 1fb8d4
	{
Packit 1fb8d4
		key->name = _strdup(name);
Packit 1fb8d4
		key->value = _strdup(value);
Packit 1fb8d4
Packit 1fb8d4
		if (!key->name || !key->value)
Packit 1fb8d4
		{
Packit Service 5a9772
			IniFile_Key_Free(key);
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return key;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static wIniFileSection* IniFile_Section_New(const char* name)
Packit 1fb8d4
{
Packit Service 5a9772
	wIniFileSection* section;
Packit 1fb8d4
Packit Service 5a9772
	if (!name)
Packit Service 5a9772
		return NULL;
Packit 1fb8d4
Packit Service 5a9772
	section = malloc(sizeof(wIniFileSection));
Packit 1fb8d4
Packit 1fb8d4
	if (!section)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	section->name = _strdup(name);
Packit 1fb8d4
Packit 1fb8d4
	if (!section->name)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(section);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	section->nKeys = 0;
Packit 1fb8d4
	section->cKeys = 64;
Packit Service 5a9772
	section->keys = (wIniFileKey**)calloc(section->cKeys, sizeof(wIniFileKey*));
Packit 1fb8d4
Packit 1fb8d4
	if (!section->keys)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(section->name);
Packit 1fb8d4
		free(section);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return section;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void IniFile_Section_Free(wIniFileSection* section)
Packit 1fb8d4
{
Packit Service 5a9772
	size_t index;
Packit 1fb8d4
Packit 1fb8d4
	if (!section)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	free(section->name);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < section->nKeys; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		IniFile_Key_Free(section->keys[index]);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(section->keys);
Packit 1fb8d4
	free(section);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name)
Packit 1fb8d4
{
Packit Service 5a9772
	size_t index;
Packit 1fb8d4
	wIniFileSection* section = NULL;
Packit 1fb8d4
Packit Service 5a9772
	if (!ini || !name)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit 1fb8d4
	for (index = 0; index < ini->nSections; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (_stricmp(name, ini->sections[index]->name) == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			section = ini->sections[index];
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return section;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static wIniFileSection* IniFile_AddSection(wIniFile* ini, const char* name)
Packit 1fb8d4
{
Packit 1fb8d4
	wIniFileSection* section;
Packit 1fb8d4
Packit Service 5a9772
	if (!ini || !name)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	section = IniFile_GetSection(ini, name);
Packit 1fb8d4
Packit 1fb8d4
	if (!section)
Packit 1fb8d4
	{
Packit 1fb8d4
		if ((ini->nSections + 1) >= (ini->cSections))
Packit 1fb8d4
		{
Packit Service 5a9772
			size_t new_size;
Packit 1fb8d4
			wIniFileSection** new_sect;
Packit 1fb8d4
			new_size = ini->cSections * 2;
Packit Service 5a9772
			new_sect =
Packit Service 5a9772
			    (wIniFileSection**)realloc(ini->sections, sizeof(wIniFileSection*) * new_size);
Packit 1fb8d4
Packit 1fb8d4
			if (!new_sect)
Packit 1fb8d4
				return NULL;
Packit 1fb8d4
Packit 1fb8d4
			ini->cSections = new_size;
Packit 1fb8d4
			ini->sections = new_sect;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		section = IniFile_Section_New(name);
Packit 1fb8d4
		ini->sections[ini->nSections] = section;
Packit 1fb8d4
		ini->nSections++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return section;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static wIniFileKey* IniFile_GetKey(wIniFile* ini, wIniFileSection* section, const char* name)
Packit 1fb8d4
{
Packit Service 5a9772
	size_t index;
Packit 1fb8d4
	wIniFileKey* key = NULL;
Packit 1fb8d4
Packit Service 5a9772
	if (!ini || !section || !name)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit 1fb8d4
	for (index = 0; index < section->nKeys; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (_stricmp(name, section->keys[index]->name) == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			key = section->keys[index];
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return key;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static wIniFileKey* IniFile_AddKey(wIniFile* ini, wIniFileSection* section, const char* name,
Packit Service 5a9772
                                   const char* value)
Packit 1fb8d4
{
Packit 1fb8d4
	wIniFileKey* key;
Packit 1fb8d4
Packit Service 5a9772
	if (!section || !name || !value)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	key = IniFile_GetKey(ini, section, name);
Packit 1fb8d4
Packit 1fb8d4
	if (!key)
Packit 1fb8d4
	{
Packit 1fb8d4
		if ((section->nKeys + 1) >= (section->cKeys))
Packit 1fb8d4
		{
Packit Service 5a9772
			size_t new_size;
Packit 1fb8d4
			wIniFileKey** new_key;
Packit 1fb8d4
			new_size = section->cKeys * 2;
Packit Service 5a9772
			new_key = (wIniFileKey**)realloc(section->keys, sizeof(wIniFileKey*) * new_size);
Packit 1fb8d4
Packit 1fb8d4
			if (!new_key)
Packit 1fb8d4
				return NULL;
Packit 1fb8d4
Packit 1fb8d4
			section->cKeys = new_size;
Packit 1fb8d4
			section->keys = new_key;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		key = IniFile_Key_New(name, value);
Packit 1fb8d4
Packit 1fb8d4
		if (!key)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		section->keys[section->nKeys] = key;
Packit 1fb8d4
		section->nKeys++;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		free(key->value);
Packit 1fb8d4
		key->value = _strdup(value);
Packit 1fb8d4
Packit 1fb8d4
		if (!key->value)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return key;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static int IniFile_Load(wIniFile* ini)
Packit 1fb8d4
{
Packit 1fb8d4
	char* line;
Packit 1fb8d4
	char* name;
Packit 1fb8d4
	char* value;
Packit 1fb8d4
	char* separator;
Packit Service 5a9772
	char *beg, *end;
Packit 1fb8d4
	wIniFileSection* section = NULL;
Packit 1fb8d4
Packit Service 5a9772
	if (!ini)
Packit Service 5a9772
		return -1;
Packit Service 5a9772
Packit 1fb8d4
	while (IniFile_Load_HasNextLine(ini))
Packit 1fb8d4
	{
Packit 1fb8d4
		line = IniFile_Load_GetNextLine(ini);
Packit 1fb8d4
Packit 1fb8d4
		if (line[0] == ';')
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit 1fb8d4
		if (line[0] == '[')
Packit 1fb8d4
		{
Packit 1fb8d4
			beg = &line[1];
Packit 1fb8d4
			end = strchr(line, ']');
Packit 1fb8d4
Packit 1fb8d4
			if (!end)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
Packit 1fb8d4
			*end = '\0';
Packit 1fb8d4
			IniFile_AddSection(ini, beg);
Packit 1fb8d4
			section = ini->sections[ini->nSections - 1];
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			separator = strchr(line, '=');
Packit Service 5a9772
Packit Service 5a9772
			if (separator == NULL)
Packit Service 5a9772
				return -1;
Packit Service 5a9772
Packit 1fb8d4
			end = separator;
Packit 1fb8d4
Packit 1fb8d4
			while ((&end[-1] > line) && ((end[-1] == ' ') || (end[-1] == '\t')))
Packit 1fb8d4
				end--;
Packit 1fb8d4
Packit 1fb8d4
			*end = '\0';
Packit 1fb8d4
			name = line;
Packit 1fb8d4
			beg = separator + 1;
Packit 1fb8d4
Packit 1fb8d4
			while (*beg && ((*beg == ' ') || (*beg == '\t')))
Packit 1fb8d4
				beg++;
Packit 1fb8d4
Packit 1fb8d4
			if (*beg == '"')
Packit 1fb8d4
				beg++;
Packit 1fb8d4
Packit 1fb8d4
			end = &line[ini->lineLength];
Packit 1fb8d4
Packit 1fb8d4
			while ((end > beg) && ((end[-1] == ' ') || (end[-1] == '\t')))
Packit 1fb8d4
				end--;
Packit 1fb8d4
Packit 1fb8d4
			if (end[-1] == '"')
Packit 1fb8d4
				end[-1] = '\0';
Packit 1fb8d4
Packit 1fb8d4
			value = beg;
Packit 1fb8d4
Packit 1fb8d4
			if (!IniFile_AddKey(ini, section, name, value))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	IniFile_Load_Finish(ini);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int IniFile_ReadBuffer(wIniFile* ini, const char* buffer)
Packit 1fb8d4
{
Packit Service 5a9772
	BOOL status;
Packit Service 5a9772
	if (!ini || !buffer)
Packit Service 5a9772
		return -1;
Packit Service 5a9772
Packit 1fb8d4
	ini->readOnly = TRUE;
Packit 1fb8d4
	ini->filename = NULL;
Packit 1fb8d4
	status = IniFile_Load_String(ini, buffer);
Packit 1fb8d4
Packit Service 5a9772
	if (!status)
Packit Service 5a9772
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	return IniFile_Load(ini);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int IniFile_ReadFile(wIniFile* ini, const char* filename)
Packit 1fb8d4
{
Packit 1fb8d4
	ini->readOnly = TRUE;
Packit 1fb8d4
	free(ini->filename);
Packit 1fb8d4
	ini->filename = _strdup(filename);
Packit 1fb8d4
Packit 1fb8d4
	if (!ini->filename)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	if (!IniFile_Load_File(ini, filename))
Packit Service 5a9772
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	return IniFile_Load(ini);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
char** IniFile_GetSectionNames(wIniFile* ini, int* count)
Packit 1fb8d4
{
Packit 1fb8d4
	char* p;
Packit Service 5a9772
	size_t index;
Packit Service 5a9772
	size_t length;
Packit Service 5a9772
	size_t nameLength;
Packit 1fb8d4
	char** sectionNames;
Packit 1fb8d4
	wIniFileSection* section = NULL;
Packit Service 5a9772
Packit Service 5a9772
	if (!ini || !count)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	if (ini->nSections > INT_MAX)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit 1fb8d4
	length = (sizeof(char*) * ini->nSections) + sizeof(char);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < ini->nSections; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		section = ini->sections[index];
Packit Service 5a9772
		nameLength = strlen(section->name);
Packit 1fb8d4
		length += (nameLength + 1);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	sectionNames = (char**)malloc(length);
Packit 1fb8d4
Packit 1fb8d4
	if (!sectionNames)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit Service 5a9772
	p = (char*)&((BYTE*)sectionNames)[sizeof(char*) * ini->nSections];
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < ini->nSections; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		sectionNames[index] = p;
Packit 1fb8d4
		section = ini->sections[index];
Packit Service 5a9772
		nameLength = strlen(section->name);
Packit 1fb8d4
		CopyMemory(p, section->name, nameLength + 1);
Packit 1fb8d4
		p += (nameLength + 1);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	*p = '\0';
Packit Service 5a9772
	*count = (int)ini->nSections;
Packit 1fb8d4
	return sectionNames;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, int* count)
Packit 1fb8d4
{
Packit 1fb8d4
	char* p;
Packit Service 5a9772
	size_t index;
Packit Service 5a9772
	size_t length;
Packit Service 5a9772
	size_t nameLength;
Packit 1fb8d4
	char** keyNames;
Packit 1fb8d4
	wIniFileKey* pKey = NULL;
Packit 1fb8d4
	wIniFileSection* pSection = NULL;
Packit Service 5a9772
Packit Service 5a9772
	if (!ini || !section || !count)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit 1fb8d4
	pSection = IniFile_GetSection(ini, section);
Packit 1fb8d4
Packit 1fb8d4
	if (!pSection)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit Service 5a9772
	if (pSection->nKeys > INT_MAX)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit 1fb8d4
	length = (sizeof(char*) * pSection->nKeys) + sizeof(char);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < pSection->nKeys; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		pKey = pSection->keys[index];
Packit Service 5a9772
		nameLength = strlen(pKey->name);
Packit 1fb8d4
		length += (nameLength + 1);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	keyNames = (char**)malloc(length);
Packit 1fb8d4
Packit 1fb8d4
	if (!keyNames)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit Service 5a9772
	p = (char*)&((BYTE*)keyNames)[sizeof(char*) * pSection->nKeys];
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < pSection->nKeys; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		keyNames[index] = p;
Packit 1fb8d4
		pKey = pSection->keys[index];
Packit Service 5a9772
		nameLength = strlen(pKey->name);
Packit 1fb8d4
		CopyMemory(p, pKey->name, nameLength + 1);
Packit 1fb8d4
		p += (nameLength + 1);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	*p = '\0';
Packit Service 5a9772
	*count = (int)pSection->nKeys;
Packit 1fb8d4
	return keyNames;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key)
Packit 1fb8d4
{
Packit 1fb8d4
	const char* value = NULL;
Packit 1fb8d4
	wIniFileKey* pKey = NULL;
Packit 1fb8d4
	wIniFileSection* pSection = NULL;
Packit 1fb8d4
	pSection = IniFile_GetSection(ini, section);
Packit 1fb8d4
Packit 1fb8d4
	if (!pSection)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	pKey = IniFile_GetKey(ini, pSection, key);
Packit 1fb8d4
Packit 1fb8d4
	if (!pKey)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit Service 5a9772
	value = (const char*)pKey->value;
Packit 1fb8d4
	return value;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key)
Packit 1fb8d4
{
Packit Service 5a9772
	int err;
Packit 1fb8d4
	long value = 0;
Packit 1fb8d4
	wIniFileKey* pKey = NULL;
Packit 1fb8d4
	wIniFileSection* pSection = NULL;
Packit 1fb8d4
	pSection = IniFile_GetSection(ini, section);
Packit 1fb8d4
Packit 1fb8d4
	if (!pSection)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	pKey = IniFile_GetKey(ini, pSection, key);
Packit 1fb8d4
Packit 1fb8d4
	if (!pKey)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit Service 5a9772
	err = errno;
Packit Service 5a9772
	errno = 0;
Packit 1fb8d4
	value = strtol(pKey->value, NULL, 0);
Packit Service 5a9772
	if ((value < INT_MIN) || (value > INT_MAX) || (errno != 0))
Packit Service 5a9772
	{
Packit Service 5a9772
		errno = err;
Packit Service 5a9772
		return 0;
Packit Service 5a9772
	}
Packit Service 5a9772
	return (int)value;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key,
Packit 1fb8d4
                              const char* value)
Packit 1fb8d4
{
Packit 1fb8d4
	wIniFileKey* pKey = NULL;
Packit 1fb8d4
	wIniFileSection* pSection = NULL;
Packit 1fb8d4
	pSection = IniFile_GetSection(ini, section);
Packit 1fb8d4
Packit 1fb8d4
	if (!pSection)
Packit 1fb8d4
		pSection = IniFile_AddSection(ini, section);
Packit 1fb8d4
Packit 1fb8d4
	if (!pSection)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	pKey = IniFile_AddKey(ini, pSection, key, value);
Packit 1fb8d4
Packit 1fb8d4
	if (!pKey)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value)
Packit 1fb8d4
{
Packit 1fb8d4
	char strVal[128];
Packit 1fb8d4
	wIniFileKey* pKey = NULL;
Packit 1fb8d4
	wIniFileSection* pSection = NULL;
Packit 1fb8d4
	sprintf_s(strVal, sizeof(strVal), "%d", value);
Packit 1fb8d4
	pSection = IniFile_GetSection(ini, section);
Packit 1fb8d4
Packit 1fb8d4
	if (!pSection)
Packit 1fb8d4
		pSection = IniFile_AddSection(ini, section);
Packit 1fb8d4
Packit 1fb8d4
	if (!pSection)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	pKey = IniFile_AddKey(ini, pSection, key, strVal);
Packit 1fb8d4
Packit 1fb8d4
	if (!pKey)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
char* IniFile_WriteBuffer(wIniFile* ini)
Packit 1fb8d4
{
Packit Service 5a9772
	size_t i, j;
Packit 1fb8d4
	size_t offset;
Packit 1fb8d4
	size_t size;
Packit 1fb8d4
	char* buffer;
Packit 1fb8d4
	wIniFileKey* key;
Packit 1fb8d4
	wIniFileSection* section;
Packit 1fb8d4
	size = 0;
Packit 1fb8d4
Packit Service 5a9772
	if (!ini)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit 1fb8d4
	for (i = 0; i < ini->nSections; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		section = ini->sections[i];
Packit 1fb8d4
		size += (strlen(section->name) + 3);
Packit 1fb8d4
Packit 1fb8d4
		for (j = 0; j < section->nKeys; j++)
Packit 1fb8d4
		{
Packit 1fb8d4
			key = section->keys[j];
Packit 1fb8d4
			size += (strlen(key->name) + strlen(key->value) + 2);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		size += 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	size += 1;
Packit 1fb8d4
	buffer = malloc(size + 1);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	offset = 0;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < ini->nSections; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		section = ini->sections[i];
Packit 1fb8d4
		sprintf_s(&buffer[offset], size - offset, "[%s]\n", section->name);
Packit 1fb8d4
		offset += (strlen(section->name) + 3);
Packit 1fb8d4
Packit 1fb8d4
		for (j = 0; j < section->nKeys; j++)
Packit 1fb8d4
		{
Packit 1fb8d4
			key = section->keys[j];
Packit 1fb8d4
			sprintf_s(&buffer[offset], size - offset, "%s=%s\n", key->name, key->value);
Packit 1fb8d4
			offset += (strlen(key->name) + strlen(key->value) + 2);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		sprintf_s(&buffer[offset], size - offset, "\n");
Packit 1fb8d4
		offset += 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	buffer[offset] = '\0';
Packit 1fb8d4
	return buffer;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int IniFile_WriteFile(wIniFile* ini, const char* filename)
Packit 1fb8d4
{
Packit Service 5a9772
	size_t length;
Packit 1fb8d4
	char* buffer;
Packit 1fb8d4
	int ret = 1;
Packit 1fb8d4
	buffer = IniFile_WriteBuffer(ini);
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	length = strlen(buffer);
Packit 1fb8d4
	ini->readOnly = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!filename)
Packit 1fb8d4
		filename = ini->filename;
Packit 1fb8d4
Packit Service 5a9772
	if (!IniFile_Open_File(ini, filename))
Packit 1fb8d4
	{
Packit 1fb8d4
		free(buffer);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (fwrite((void*)buffer, length, 1, ini->fp) != 1)
Packit 1fb8d4
		ret = -1;
Packit 1fb8d4
Packit 1fb8d4
	fclose(ini->fp);
Packit 1fb8d4
	free(buffer);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
wIniFile* IniFile_New(void)
Packit 1fb8d4
{
Packit Service 5a9772
	wIniFile* ini = (wIniFile*)calloc(1, sizeof(wIniFile));
Packit 1fb8d4
Packit 1fb8d4
	if (ini)
Packit 1fb8d4
	{
Packit 1fb8d4
		ini->nSections = 0;
Packit 1fb8d4
		ini->cSections = 64;
Packit Service 5a9772
		ini->sections = (wIniFileSection**)calloc(ini->cSections, sizeof(wIniFileSection*));
Packit 1fb8d4
Packit 1fb8d4
		if (!ini->sections)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(ini);
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return ini;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void IniFile_Free(wIniFile* ini)
Packit 1fb8d4
{
Packit Service 5a9772
	size_t index;
Packit 1fb8d4
Packit 1fb8d4
	if (!ini)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	free(ini->filename);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < ini->nSections; index++)
Packit 1fb8d4
		IniFile_Section_Free(ini->sections[index]);
Packit 1fb8d4
Packit 1fb8d4
	free(ini->sections);
Packit Service 5a9772
	free(ini->buffer);
Packit 1fb8d4
	free(ini);
Packit 1fb8d4
}