// ==++==
// 
//   
//    Copyright (c) 2002 Microsoft Corporation.  All rights reserved.
//   
//    The use and distribution terms for this software are contained in the file
//    named license.txt, which can be found in the root of this distribution.
//    By using this software in any fashion, you are agreeing to be bound by the
//    terms of this license.
//   
//    You must not remove this notice, or any other, from this software.
//   
// 
// ==--==
// ===========================================================================
// File: IniFile.CPP
// 
// A simple API for reading/writing .ini files
//
// It is not designed to be 100% replacement for Win32's Read[Private]ProfileString/
// Write[Private]ProfileString.
//
// It does not provide any smart caching nor locking. It is up to the caller
// to provide it. Also, the grammar for the .ini files probably differs 
// in corner cases.
// ===========================================================================

void WINAPI WriteWinvnProfile();

#ifndef _INIFILE_H
#define _INIFILE_H

#include <windows.h>
#include <stdlib.h>
#include <TCHAR.H>



//#include "winvn.h"

//#define CONFIG_FILE_NAME   _T("\\rotor.ini")

// The underlaying datastructure is a DOM-like tree
struct 	ININODE
{
	struct ININODE * pNext;
	struct ININODE * pChild;
	DWORD   dwSize;
	BYTE    Value[1];
};

// Smart buffer
class CBlobBuilder
{
	BYTE* m_pData; // the data storage
	ULONG m_nSize; // the current size of the string
	ULONG m_nData; // the size of the allocated data storage
	bool  m_fError; // an out-of-memory error occured

private:
	BYTE* Ensure(DWORD nNewData);

public:
	void Init();
	void Destroy();
	void Append(LPCVOID pData, ULONG nSize);
	void AppendChar(TCHAR ch);
	void AppendString(const TCHAR* pString, DWORD dwLength);
	void AppendNewLine();
	void AppendNode(const ININODE* pNode);
	bool IsError() const { return m_fError; };
	PVOID GetBuffer() 	{ return m_pData; };
	ULONG GetSize() { return m_nSize; };
};

// The ini file implementation

class IniFile
{
	enum Action
	{
		CREATE_NODE,
		DELETE_NODE,
		FIND_NODE,
	};

	// the root ININODE
	ININODE* m_pRoot;
	BOOL m_fDirty;

protected:
	// create a free floating ININODE with the given value
	ININODE* CreateNode(LPCVOID pValue, DWORD dwSize);
	// destroy ININODE and all its childs
	void DestroyNode(ININODE* pNode);
 // does a ININODE hold the given value?
	static BOOL Equal(const ININODE* pNode, LPCVOID pValue, DWORD dwSize);
 // find a ININODE with the given value, create one if it does not exist
 //  and fCreate is specified
	ININODE* GetNode(ININODE** ppNode, LPCVOID pValue, DWORD dwSize, Action action);
 // find a ININODE with the given string value, create one if it does not exist
 //  and fCreate is specified
	ININODE* GetNode(ININODE** ppNode, LPCTSTR pszValue, Action action);

public:
	IniFile();
	~IniFile();

	inline static bool IsJunk(int c) { return c < 0x20; };
	inline static bool IsEndOfLine(int c) { return (c == '\n') || (c == '\r'); };
	BOOL Load(LPCTSTR pszFileName);
	BOOL Save(LPCTSTR pszFileName, BOOL fForce);
	DWORD ReadString( LPCTSTR pszSection,LPCTSTR pszKey, LPTSTR pszValue, DWORD dwBufLength);
	BOOL WriteString( LPCTSTR pszSection, LPCTSTR pszKey, LPCTSTR pszValue);
	BOOL GetString( LPCTSTR pszSection, LPCTSTR pszKey, LPTSTR pszValue, DWORD dwBufLength);

	BOOL WriteInt( LPCTSTR pszSection, LPCTSTR pszKey, int nValue);
	BOOL WriteUInt( LPCTSTR pszSection, LPCTSTR pszKey, UINT uValue);

}; //Class IniFile



#endif //_INIFILE_H 
