From: <br...@us...> - 2008-10-31 21:44:29
|
Revision: 424 http://acmcontester.svn.sourceforge.net/acmcontester/?rev=424&view=rev Author: brus07 Date: 2008-10-31 21:44:07 +0000 (Fri, 31 Oct 2008) Log Message: ----------- Change IniFile class Modified Paths: -------------- ACMServer/trunk/ACMServer/Library/LibraryExtention/IniFile.cs Modified: ACMServer/trunk/ACMServer/Library/LibraryExtention/IniFile.cs =================================================================== --- ACMServer/trunk/ACMServer/Library/LibraryExtention/IniFile.cs 2008-10-23 21:06:35 UTC (rev 423) +++ ACMServer/trunk/ACMServer/Library/LibraryExtention/IniFile.cs 2008-10-31 21:44:07 UTC (rev 424) @@ -2,95 +2,682 @@ using System.IO; using System.Text; using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Globalization; namespace AcmContester.Library.LibraryExtention { /// <summary> - /// Class to read from INI files. Based loosely on the Delphi class of the same name. + /// Provides methods for reading and writing to an INI file. /// </summary> + /// <!--http://www.codeproject.com/KB/files/win32fileutilityclass.aspx--> public class IniFile { - private string fileName; + /// <summary> + /// The maximum size of a section in an ini file. + /// </summary> + /// <remarks> + /// This property defines the maximum size of the buffers + /// used to retreive data from an ini file. This value is + /// the maximum allowed by the win32 functions + /// GetPrivateProfileSectionNames() or + /// GetPrivateProfileString(). + /// </remarks> + public const int MaxSectionSize = 32767; // 32 KB + //The path of the file we are operating on. + private string m_path; + + #region P/Invoke declares + /// <summary> - /// Creates a new <see cref="IniFile"/> instance. + /// A static class that provides the win32 P/Invoke signatures + /// used by this class. /// </summary> - /// <param name="fileName">Name of the INI file.</param> - public IniFile(string fileName) + /// <remarks> + /// Note: In each of the declarations below, we explicitly set CharSet to + /// Auto. By default in C#, CharSet is set to Ansi, which reduces + /// performance on windows 2000 and above due to needing to convert strings + /// from Unicode (the native format for all .Net strings) to Ansi before + /// marshalling. Using Auto lets the marshaller select the Unicode version of + /// these functions when available. + /// </remarks> + [System.Security.SuppressUnmanagedCodeSecurity] + private static class NativeMethods { - if (!File.Exists(fileName)) - throw new FileNotFoundException(fileName + " does not exist", fileName); - this.fileName = fileName; + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern int GetPrivateProfileSectionNames(IntPtr lpszReturnBuffer, + uint nSize, + string lpFileName); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern uint GetPrivateProfileString(string lpAppName, + string lpKeyName, + string lpDefault, + StringBuilder lpReturnedString, + int nSize, + string lpFileName); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern uint GetPrivateProfileString(string lpAppName, + string lpKeyName, + string lpDefault, + [In, Out] char[] lpReturnedString, + int nSize, + string lpFileName); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern int GetPrivateProfileString(string lpAppName, + string lpKeyName, + string lpDefault, + IntPtr lpReturnedString, + uint nSize, + string lpFileName); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern int GetPrivateProfileInt(string lpAppName, + string lpKeyName, + int lpDefault, + string lpFileName); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto)] + public static extern int GetPrivateProfileSection(string lpAppName, + IntPtr lpReturnedString, + uint nSize, + string lpFileName); + + //We explicitly enable the SetLastError attribute here because + // WritePrivateProfileString returns errors via SetLastError. + // Failure to set this can result in errors being lost during + // the marshal back to managed code. + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern bool WritePrivateProfileString(string lpAppName, + string lpKeyName, + string lpString, + string lpFileName); + + } + #endregion - // native methods - [DllImport("kernel32")] - private static extern int GetPrivateProfileString(string section, - string key, string def, StringBuilder retVal, int size, string filePath); + /// <summary> + /// Initializes a new instance of the <see cref="IniFile"/> class. + /// </summary> + /// <param name="path">The ini file to read and write from.</param> + public IniFile(string path) + { + if (!File.Exists(path)) + throw new FileNotFoundException(path + " does not exist", path); - [DllImport("kernel32")] - private static extern int GetPrivateProfileSection(string section, IntPtr lpReturnedString, - int nSize, string lpFileName); + //Convert to the full path. Because of backward compatibility, + // the win32 functions tend to assume the path should be the + // root Windows directory if it is not specified. By calling + // GetFullPath, we make sure we are always passing the full path + // the win32 functions. + m_path = System.IO.Path.GetFullPath(path); + } - [DllImport("kernel32")] - private static extern long WritePrivateProfileString(string section, - string key, string val, string filePath); + /// <summary> + /// Gets the full path of ini file this object instance is operating on. + /// </summary> + /// <value>A file path.</value> + public string Path + { + get + { + return m_path; + } + } + private string[] GetArreyKeys(string sectionName, + string keyName) + { + string[] allKeys = this.GetKeyNames(sectionName); + List<string> list = new List<string>(); + for (int i = 0; i < allKeys.Length; i++) + { + if (allKeys[i].IndexOf(keyName + ".") == 0) + { + list.Add(allKeys[i]); + } + } + return list.ToArray(); + } + #region Get Value Methods + /// <summary> - /// Reads a string value from the INI file. + /// Gets the value of a setting in an ini file as a <see cref="T:System.String"/>. /// </summary> - /// <param name="section">Section to read.</param> - /// <param name="key">Key to read.</param> - public string ReadString(string section, string key) + /// <param name="sectionName">The name of the section to read from.</param> + /// <param name="keyName">The name of the key in section to read.</param> + /// <param name="defaultValue">The default value to return if the key + /// cannot be found.</param> + /// <returns>The value of the key, if found. Otherwise, returns + /// <paramref name="defaultValue"/></returns> + /// <remarks> + /// The retreived value must be less than 32KB in length. + /// </remarks> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> or <paramref name="keyName"/> are + /// a null reference (Nothing in VB) + /// </exception> + public string GetString(string sectionName, + string keyName, + string defaultValue) { - const int bufferSize = 255; - //TODO: jaksho bilshe za bufferSize todi Exception - StringBuilder temp = new StringBuilder(bufferSize); - GetPrivateProfileString(section, key, "", temp, bufferSize, fileName); - return temp.ToString(); + if (sectionName == null) + throw new ArgumentNullException("sectionName"); + + if (keyName == null) + throw new ArgumentNullException("keyName"); + + StringBuilder retval = new StringBuilder(IniFile.MaxSectionSize); + + NativeMethods.GetPrivateProfileString(sectionName, + keyName, + defaultValue, + retval, + IniFile.MaxSectionSize, + m_path); + + return retval.ToString(); } /// <summary> - /// Reads a whole section of the INI file. + /// Gets the value of a setting in an ini file as a <see cref="T:System.Int16"/>. /// </summary> - /// <param name="section">Section to read.</param> - public string[] ReadSection(string section) + /// <param name="sectionName">The name of the section to read from.</param> + /// <param name="keyName">The name of the key in section to read.</param> + /// <param name="defaultValue">The default value to return if the key + /// cannot be found.</param> + /// <returns>The value of the key, if found. Otherwise, returns + /// <paramref name="defaultValue"/>.</returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> or <paramref name="keyName"/> are + /// a null reference (Nothing in VB) + /// </exception> + public int GetInt16(string sectionName, + string keyName, + short defaultValue) { - const int bufferSize = 2048; - //TODO: jaksho bilshe za bufferSize todi Exception + int retval = GetInt32(sectionName, keyName, defaultValue); - StringBuilder returnedString = new StringBuilder(); + return Convert.ToInt16(retval); + } - IntPtr pReturnedString = Marshal.AllocCoTaskMem(bufferSize); + /// <summary> + /// Gets the value of a setting in an ini file as a <see cref="T:System.Int32"/>. + /// </summary> + /// <param name="sectionName">The name of the section to read from.</param> + /// <param name="keyName">The name of the key in section to read.</param> + /// <param name="defaultValue">The default value to return if the key + /// cannot be found.</param> + /// <returns>The value of the key, if found. Otherwise, returns + /// <paramref name="defaultValue"/></returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> or <paramref name="keyName"/> are + /// a null reference (Nothing in VB) + /// </exception> + public int GetInt32(string sectionName, + string keyName, + int defaultValue) + { + if (sectionName == null) + throw new ArgumentNullException("sectionName"); + + if (keyName == null) + throw new ArgumentNullException("keyName"); + + + return NativeMethods.GetPrivateProfileInt(sectionName, keyName, defaultValue, m_path); + } + + /// <summary> + /// Gets the value of a setting in an ini file as a <see cref="T:System.Double"/>. + /// </summary> + /// <param name="sectionName">The name of the section to read from.</param> + /// <param name="keyName">The name of the key in section to read.</param> + /// <param name="defaultValue">The default value to return if the key + /// cannot be found.</param> + /// <returns>The value of the key, if found. Otherwise, returns + /// <paramref name="defaultValue"/></returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> or <paramref name="keyName"/> are + /// a null reference (Nothing in VB) + /// </exception> + public double GetDouble(string sectionName, + string keyName, + double defaultValue) + { + string retval = GetString(sectionName, keyName, ""); + + if (retval == null || retval.Length == 0) + { + return defaultValue; + } + + return Convert.ToDouble(retval, CultureInfo.InvariantCulture); + } + + public string[] GetStringArray(string sectionName, + string keyName) + { + string[] keys = GetArreyKeys(sectionName, keyName); + string[] result = new string[keys.Length]; + for (int i = 0; i < keys.Length; i++) + { + result[i] = GetString(sectionName, keys[i], ""); + + } + return result; + } + + #endregion + + #region GetSectionValues Methods + + /// <summary> + /// Gets all of the values in a section as a list. + /// </summary> + /// <param name="sectionName"> + /// Name of the section to retrieve values from. + /// </param> + /// <returns> + /// A <see cref="List{T}"/> containing <see cref="KeyValuePair{T1, T2}"/> objects + /// that describe this section. Use this verison if a section may contain + /// multiple items with the same key value. If you know that a section + /// cannot contain multiple values with the same key name or you don't + /// care about the duplicates, use the more convenient + /// <see cref="GetSectionValues"/> function. + /// </returns> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> is a null reference (Nothing in VB) + /// </exception> + public List<KeyValuePair<string, string>> GetSectionValuesAsList(string sectionName) + { + List<KeyValuePair<string, string>> retval; + string[] keyValuePairs; + string key, value; + int equalSignPos; + + if (sectionName == null) + throw new ArgumentNullException("sectionName"); + + //Allocate a buffer for the returned section names. + IntPtr ptr = Marshal.AllocCoTaskMem(IniFile.MaxSectionSize); + try { - int bytesReturned = GetPrivateProfileSection(section, pReturnedString, bufferSize, fileName); + //Get the section key/value pairs into the buffer. + int len = NativeMethods.GetPrivateProfileSection(sectionName, + ptr, + IniFile.MaxSectionSize, + m_path); - //bytesReturned -1 to remove trailing \0 - for (int i = 0; i < bytesReturned - 1; i++) - returnedString.Append((char)Marshal.ReadByte(new IntPtr((uint)pReturnedString + (uint)i))); + keyValuePairs = ConvertNullSeperatedStringToStringArray(ptr, len); } finally { - Marshal.FreeCoTaskMem(pReturnedString); + //Free the buffer + Marshal.FreeCoTaskMem(ptr); } - string sectionData = returnedString.ToString(); - return sectionData.Split('\0'); + //Parse keyValue pairs and add them to the list. + retval = new List<KeyValuePair<string, string>>(keyValuePairs.Length); + + for (int i = 0; i < keyValuePairs.Length; ++i) + { + //Parse the "key=value" string into its constituent parts + equalSignPos = keyValuePairs[i].IndexOf('='); + + key = keyValuePairs[i].Substring(0, equalSignPos); + + value = keyValuePairs[i].Substring(equalSignPos + 1, + keyValuePairs[i].Length - equalSignPos - 1); + + retval.Add(new KeyValuePair<string, string>(key, value)); + } + + return retval; } /// <summary> - /// Write Data to the INI File + /// Gets all of the values in a section as a dictionary. /// </summary> - /// <PARAM name="Section"><Section name/PARAM> - /// <PARAM name="Key">Key Name</PARAM> - /// <PARAM name="Value">Value Name</PARAM> - public void WriteString(string section, string key, string value) + /// <param name="sectionName"> + /// Name of the section to retrieve values from. + /// </param> + /// <returns> + /// A <see cref="Dictionary{T, T}"/> containing the key/value + /// pairs found in this section. + /// </returns> + /// <remarks> + /// If a section contains more than one key with the same name, + /// this function only returns the first instance. If you need to + /// get all key/value pairs within a section even when keys have the + /// same name, use <see cref="GetSectionValuesAsList"/>. + /// </remarks> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> is a null reference (Nothing in VB) + /// </exception> + public Dictionary<string, string> GetSectionValues(string sectionName) { - WritePrivateProfileString(section, key, value, fileName); + List<KeyValuePair<string, string>> keyValuePairs; + Dictionary<string, string> retval; + + keyValuePairs = GetSectionValuesAsList(sectionName); + + //Convert list into a dictionary. + retval = new Dictionary<string, string>(keyValuePairs.Count); + + foreach (KeyValuePair<string, string> keyValuePair in keyValuePairs) + { + //Skip any key we have already seen. + if (!retval.ContainsKey(keyValuePair.Key)) + { + retval.Add(keyValuePair.Key, keyValuePair.Value); + } + } + + return retval; } + #endregion + + #region Get Key/Section Names + + /// <summary> + /// Gets the names of all keys under a specific section in the ini file. + /// </summary> + /// <param name="sectionName"> + /// The name of the section to read key names from. + /// </param> + /// <returns>An array of key names.</returns> + /// <remarks> + /// The total length of all key names in the section must be + /// less than 32KB in length. + /// </remarks> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> is a null reference (Nothing in VB) + /// </exception> + public string[] GetKeyNames(string sectionName) + { + int len; + string[] retval; + + if (sectionName == null) + throw new ArgumentNullException("sectionName"); + + //Allocate a buffer for the returned section names. + IntPtr ptr = Marshal.AllocCoTaskMem(IniFile.MaxSectionSize); + + try + { + //Get the section names into the buffer. + len = NativeMethods.GetPrivateProfileString(sectionName, + null, + null, + ptr, + IniFile.MaxSectionSize, + m_path); + + retval = ConvertNullSeperatedStringToStringArray(ptr, len); + } + finally + { + //Free the buffer + Marshal.FreeCoTaskMem(ptr); + } + + return retval; + } + + /// <summary> + /// Gets the names of all sections in the ini file. + /// </summary> + /// <returns>An array of section names.</returns> + /// <remarks> + /// The total length of all section names in the section must be + /// less than 32KB in length. + /// </remarks> + public string[] GetSectionNames() + { + string[] retval; + int len; + + //Allocate a buffer for the returned section names. + IntPtr ptr = Marshal.AllocCoTaskMem(IniFile.MaxSectionSize); + + try + { + //Get the section names into the buffer. + len = NativeMethods.GetPrivateProfileSectionNames(ptr, + IniFile.MaxSectionSize, m_path); + + retval = ConvertNullSeperatedStringToStringArray(ptr, len); + } + finally + { + //Free the buffer + Marshal.FreeCoTaskMem(ptr); + } + + return retval; + } + + /// <summary> + /// Converts the null seperated pointer to a string into a string array. + /// </summary> + /// <param name="ptr">A pointer to string data.</param> + /// <param name="valLength"> + /// Length of the data pointed to by <paramref name="ptr"/>. + /// </param> + /// <returns> + /// An array of strings; one for each null found in the array of characters pointed + /// at by <paramref name="ptr"/>. + /// </returns> + private static string[] ConvertNullSeperatedStringToStringArray(IntPtr ptr, int valLength) + { + string[] retval; + + if (valLength == 0) + { + //Return an empty array. + retval = new string[0]; + } + else + { + //Convert the buffer into a string. Decrease the length + //by 1 so that we remove the second null off the end. + string buff = Marshal.PtrToStringAuto(ptr, valLength - 1); + + //Parse the buffer into an array of strings by searching for nulls. + retval = buff.Split('\0'); + } + + return retval; + } + + #endregion + + #region Write Methods + + /// <summary> + /// Writes a <see cref="T:System.String"/> value to the ini file. + /// </summary> + /// <param name="sectionName">The name of the section to write to .</param> + /// <param name="keyName">The name of the key to write to.</param> + /// <param name="value">The string value to write</param> + /// <exception cref="T:System.ComponentModel.Win32Exception"> + /// The write failed. + /// </exception> + private void WriteValueInternal(string sectionName, string keyName, string value) + { + if (!NativeMethods.WritePrivateProfileString(sectionName, keyName, value, m_path)) + { + throw new System.ComponentModel.Win32Exception(); + } + } + + /// <summary> + /// Writes a <see cref="T:System.String"/> value to the ini file. + /// </summary> + /// <param name="sectionName">The name of the section to write to .</param> + /// <param name="keyName">The name of the key to write to.</param> + /// <param name="value">The string value to write</param> + /// <exception cref="T:System.ComponentModel.Win32Exception"> + /// The write failed. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> or <paramref name="keyName"/> or + /// <paramref name="value"/> are a null reference (Nothing in VB) + /// </exception> + public void WriteValue(string sectionName, string keyName, string value) + { + if (sectionName == null) + throw new ArgumentNullException("sectionName"); + + if (keyName == null) + throw new ArgumentNullException("keyName"); + + if (value == null) + throw new ArgumentNullException("value"); + + WriteValueInternal(sectionName, keyName, value); + } + + /// <summary> + /// Writes an <see cref="T:System.Int16"/> value to the ini file. + /// </summary> + /// <param name="sectionName">The name of the section to write to .</param> + /// <param name="keyName">The name of the key to write to.</param> + /// <param name="value">The value to write</param> + /// <exception cref="T:System.ComponentModel.Win32Exception"> + /// The write failed. + /// </exception> + public void WriteValue(string sectionName, string keyName, short value) + { + WriteValue(sectionName, keyName, (int)value); + } + + /// <summary> + /// Writes an <see cref="T:System.Int32"/> value to the ini file. + /// </summary> + /// <param name="sectionName">The name of the section to write to .</param> + /// <param name="keyName">The name of the key to write to.</param> + /// <param name="value">The value to write</param> + /// <exception cref="T:System.ComponentModel.Win32Exception"> + /// The write failed. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> or <paramref name="keyName"/> are + /// a null reference (Nothing in VB) + /// </exception> + public void WriteValue(string sectionName, string keyName, int value) + { + WriteValue(sectionName, keyName, value.ToString(CultureInfo.InvariantCulture)); + } + + /// <summary> + /// Writes an <see cref="T:System.Single"/> value to the ini file. + /// </summary> + /// <param name="sectionName">The name of the section to write to .</param> + /// <param name="keyName">The name of the key to write to.</param> + /// <param name="value">The value to write</param> + /// <exception cref="T:System.ComponentModel.Win32Exception"> + /// The write failed. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> or <paramref name="keyName"/> are + /// a null reference (Nothing in VB) + /// </exception> + public void WriteValue(string sectionName, string keyName, float value) + { + WriteValue(sectionName, keyName, value.ToString(CultureInfo.InvariantCulture)); + } + + /// <summary> + /// Writes an <see cref="T:System.Double"/> value to the ini file. + /// </summary> + /// <param name="sectionName">The name of the section to write to .</param> + /// <param name="keyName">The name of the key to write to.</param> + /// <param name="value">The value to write</param> + /// <exception cref="T:System.ComponentModel.Win32Exception"> + /// The write failed. + /// </exception> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> or <paramref name="keyName"/> are + /// a null reference (Nothing in VB) + /// </exception> + public void WriteValue(string sectionName, string keyName, double value) + { + WriteValue(sectionName, keyName, value.ToString(CultureInfo.InvariantCulture)); + } + + public void WriteStringArray(string sectionName, + string keyName, + string[] values) + { + //Delete contain keys in INI file + string[] containKeys = GetArreyKeys(sectionName, keyName); + for (int i = 0; i < containKeys.Length; i++) + DeleteKey(sectionName, containKeys[i]); + + //Write new element into INI file + for (int i = 0; i < values.Length; i++) + { + string newKey = keyName + "." + i.ToString(); + WriteValue(sectionName, newKey, values[i]); + } + + } + + #endregion + + #region Delete Methods + + /// <summary> + /// Deletes the specified key from the specified section. + /// </summary> + /// <param name="sectionName"> + /// Name of the section to remove the key from. + /// </param> + /// <param name="keyName"> + /// Name of the key to remove. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> or <paramref name="keyName"/> are + /// a null reference (Nothing in VB) + /// </exception> + public void DeleteKey(string sectionName, string keyName) + { + if (sectionName == null) + throw new ArgumentNullException("sectionName"); + + if (keyName == null) + throw new ArgumentNullException("keyName"); + + WriteValueInternal(sectionName, keyName, null); + } + + /// <summary> + /// Deletes a section from the ini file. + /// </summary> + /// <param name="sectionName"> + /// Name of the section to delete. + /// </param> + /// <exception cref="ArgumentNullException"> + /// <paramref name="sectionName"/> is a null reference (Nothing in VB) + /// </exception> + public void DeleteSection(string sectionName) + { + if (sectionName == null) + throw new ArgumentNullException("sectionName"); + + WriteValueInternal(sectionName, null, null); + } + + #endregion } - } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |