Guest User

Untitled

a guest
Dec 17th, 2015
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
VB.NET 20.04 KB | None | 0 0
  1. ' ***********************************************************************
  2. ' Author   : Elektro
  3. ' Modified : 17-December-2015
  4. ' ***********************************************************************
  5.  
  6. #Region " Imports "
  7.  
  8. Imports System
  9. Imports System.Collections.Generic
  10. Imports System.ComponentModel
  11. Imports System.Diagnostics
  12. Imports System.IO
  13. Imports System.Linq
  14. Imports System.Text
  15.  
  16. #End Region
  17.  
  18. #Region " INI Manager "
  19.  
  20. Namespace Types
  21.  
  22.     ''' ----------------------------------------------------------------------------------------------------
  23.     ''' <summary>
  24.     ''' Manages an INI file to build sections and keys, to save or load application settings.
  25.     ''' </summary>
  26.     ''' ----------------------------------------------------------------------------------------------------
  27.     Public NotInheritable Class IniManager : Implements IDisposable
  28.  
  29. #Region " Private Fields "
  30.  
  31.         ''' ----------------------------------------------------------------------------------------------------
  32.         ''' <summary>
  33.         ''' The INI <see cref="FileStream"/>.
  34.         ''' </summary>
  35.         ''' ----------------------------------------------------------------------------------------------------
  36.         Private fs As FileStream
  37.  
  38. #End Region
  39.  
  40. #Region " Properties "
  41.  
  42.         ''' ----------------------------------------------------------------------------------------------------
  43.         ''' <summary>
  44.         ''' Gets the initialization file (INI) path.
  45.         ''' </summary>
  46.         ''' ----------------------------------------------------------------------------------------------------
  47.         ''' <value>
  48.         ''' The initialization file (INI) path.
  49.         ''' </value>
  50.         ''' ----------------------------------------------------------------------------------------------------
  51.         Public ReadOnly Property FilePath As String
  52.             <DebuggerStepThrough>
  53.             Get
  54.                 Return Me.filepathB
  55.             End Get
  56.         End Property
  57.         ''' ----------------------------------------------------------------------------------------------------
  58.         ''' <summary>
  59.         ''' ( Backing field )
  60.         ''' The initialization file (INI) path.
  61.         ''' </summary>
  62.         ''' ----------------------------------------------------------------------------------------------------
  63.         Private ReadOnly filepathB As String
  64.  
  65.         ''' ----------------------------------------------------------------------------------------------------
  66.         ''' <summary>
  67.         ''' Gets the initialization file (INI) encoding.
  68.         ''' </summary>
  69.         ''' ----------------------------------------------------------------------------------------------------
  70.         ''' <value>
  71.         ''' The initialization file (INI) encoding.
  72.         ''' </value>
  73.         ''' ----------------------------------------------------------------------------------------------------
  74.         Public ReadOnly Property Encoding As Encoding
  75.             <DebuggerStepThrough>
  76.             Get
  77.                 Return Me.encodingB
  78.             End Get
  79.         End Property
  80.         ''' ----------------------------------------------------------------------------------------------------
  81.         ''' <summary>
  82.         ''' ( Backing field )
  83.         ''' The initialization file (INI) encoding.
  84.         ''' </summary>
  85.         ''' ----------------------------------------------------------------------------------------------------
  86.         Private ReadOnly encodingB As Encoding
  87.  
  88.         ''' ----------------------------------------------------------------------------------------------------
  89.         ''' <summary>
  90.         ''' Gets or sets the initialization file (INI) sections.
  91.         ''' </summary>
  92.         ''' ----------------------------------------------------------------------------------------------------
  93.         ''' <value>
  94.         ''' The initialization file (INI) sections.
  95.         ''' </value>
  96.         ''' ----------------------------------------------------------------------------------------------------
  97.         Public Property Sections As IniSectionCollection
  98.             <DebuggerStepThrough>
  99.             Get
  100.                 Return Me.sectionsB
  101.             End Get
  102.             <DebuggerStepThrough>
  103.             Set(ByVal value As IniSectionCollection)
  104.                 Me.sectionsB = value
  105.             End Set
  106.         End Property
  107.         ''' ----------------------------------------------------------------------------------------------------
  108.         ''' <summary>
  109.         ''' ( Backing field )
  110.         ''' The initialization file (INI) sections.
  111.         ''' </summary>
  112.         ''' ----------------------------------------------------------------------------------------------------
  113.         Private sectionsB As IniSectionCollection
  114.  
  115.         ''' ----------------------------------------------------------------------------------------------------
  116.         ''' <summary>
  117.         ''' Gets the initialization file (INI) section names.
  118.         ''' </summary>
  119.         ''' ----------------------------------------------------------------------------------------------------
  120.         ''' <value>
  121.         ''' The initialization file (INI) section names.
  122.         ''' </value>
  123.         ''' ----------------------------------------------------------------------------------------------------
  124.         Public ReadOnly Property SectionNames As String()
  125.             <DebuggerStepThrough>
  126.             Get
  127.                 Return Me.GetIniSectionNames()
  128.             End Get
  129.         End Property
  130.  
  131. #End Region
  132.  
  133. #Region " Constructors "
  134.  
  135.         ''' ----------------------------------------------------------------------------------------------------
  136.         ''' <summary>
  137.         ''' Prevents a default instance of the <see cref="IniManager"/> class from being created.
  138.         ''' </summary>
  139.         ''' ----------------------------------------------------------------------------------------------------
  140.         <DebuggerNonUserCode>
  141.         Private Sub New()
  142.         End Sub
  143.  
  144.         ''' ----------------------------------------------------------------------------------------------------
  145.         ''' <summary>
  146.         ''' Initializes a new instance of the <see cref="IniManager"/> class.
  147.         ''' </summary>
  148.         ''' ----------------------------------------------------------------------------------------------------
  149.         ''' <param name="filepath">
  150.         ''' The initialization file (INI) path.
  151.         ''' </param>
  152.         '''
  153.         ''' <param name="enc">
  154.         ''' The encoding to read/write the INI file.
  155.         ''' </param>
  156.         ''' ----------------------------------------------------------------------------------------------------
  157.         <DebuggerStepThrough>
  158.         Public Sub New(ByVal filepath As String,
  159.                        Optional ByVal enc As Encoding = Nothing)
  160.  
  161.             Me.New(New FileInfo(filepath), enc)
  162.  
  163.         End Sub
  164.  
  165.         ''' ----------------------------------------------------------------------------------------------------
  166.         ''' <summary>
  167.         ''' Initializes a new instance of the <see cref="IniManager"/> class.
  168.         ''' </summary>
  169.         ''' ----------------------------------------------------------------------------------------------------
  170.         ''' <param name="fileinfo">
  171.         ''' The initialization file (INI).
  172.         ''' </param>
  173.         '''
  174.         ''' <param name="enc">
  175.         ''' The encoding to read/write the INI file.
  176.         ''' </param>
  177.         ''' ----------------------------------------------------------------------------------------------------
  178.         <DebuggerStepThrough>
  179.         Public Sub New(ByVal fileinfo As FileInfo,
  180.                        Optional ByVal enc As Encoding = Nothing)
  181.  
  182.             If String.IsNullOrEmpty(fileinfo.Name) Then
  183.                 Throw New ArgumentNullException(paramName:="fileinfo")
  184.  
  185.             Else
  186.                 If (enc Is Nothing) Then
  187.                     enc = Global.System.Text.Encoding.Default
  188.                 End If
  189.  
  190.                 Me.filepathB = fileinfo.FullName
  191.                 Me.encodingB = enc
  192.  
  193.                 Me.fs = New FileStream(fileinfo.FullName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, bufferSize:=4096)
  194.                 Me.sectionsB = Me.GetIniSections()
  195.  
  196.             End If
  197.  
  198.         End Sub
  199.  
  200. #End Region
  201.  
  202. #Region " Operator Overloads "
  203.  
  204.         ''' ----------------------------------------------------------------------------------------------------
  205.         ''' <summary>
  206.         ''' Returns a <see cref="System.String"/> that represents this instance.
  207.         ''' </summary>
  208.         ''' ----------------------------------------------------------------------------------------------------
  209.         ''' <returns>
  210.         ''' A <see cref="System.String"/> that represents this instance.
  211.         ''' </returns>
  212.         ''' ----------------------------------------------------------------------------------------------------
  213.         <DebuggerStepThrough>
  214.         Public Overrides Function ToString() As String
  215.  
  216.             Return Me.BuildIniContent()
  217.  
  218.         End Function
  219.  
  220. #End Region
  221.  
  222. #Region " Public Methods "
  223.  
  224.         ''' ----------------------------------------------------------------------------------------------------
  225.         ''' <summary>
  226.         ''' Clears the INI content.
  227.         ''' </summary>
  228.         ''' ----------------------------------------------------------------------------------------------------
  229.         <DebuggerStepThrough>
  230.         Public Sub Clear()
  231.  
  232.             Me.fs.Seek(0, SeekOrigin.Begin)
  233.             Me.fs.SetLength(0)
  234.  
  235.             Me.sectionsB.Clear()
  236.  
  237.         End Sub
  238.  
  239.         ''' ----------------------------------------------------------------------------------------------------
  240.         ''' <summary>
  241.         ''' Saves the INI changes to file.
  242.         ''' </summary>
  243.         ''' ----------------------------------------------------------------------------------------------------
  244.         <DebuggerStepThrough>
  245.         Public Sub Save()
  246.  
  247.             Using ms As New MemoryStream
  248.  
  249.                 Using sw As New StreamWriter(ms, Me.encodingB, bufferSize:=4096)
  250.  
  251.                     sw.Write(Me.BuildIniContent)
  252.                     sw.Flush()
  253.  
  254.                     ms.Seek(0, SeekOrigin.Begin)
  255.                     ms.CopyTo(Me.fs)
  256.  
  257.                     Me.fs.Seek(0, SeekOrigin.Begin)
  258.  
  259.                 End Using
  260.  
  261.             End Using
  262.  
  263.         End Sub
  264.  
  265. #End Region
  266.  
  267. #Region " Private Methods "
  268.  
  269.         ''' ----------------------------------------------------------------------------------------------------
  270.         ''' <summary>
  271.         ''' Gets the initialization file (INI) sections.
  272.         ''' </summary>
  273.         ''' ----------------------------------------------------------------------------------------------------
  274.         ''' <returns>
  275.         ''' An <see cref="IniSectionCollection"/> collection that contains the INI sections.
  276.         ''' </returns>
  277.         ''' ----------------------------------------------------------------------------------------------------
  278.         <DebuggerStepThrough>
  279.         Private Function GetIniSections() As IniSectionCollection
  280.  
  281.             Dim content As List(Of String) =
  282.                 Me.GetIniContent.Split({Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries).ToList
  283.  
  284.             Dim sectionName As String = ""
  285.             Dim section As IniSection
  286.             Dim sections As New IniSectionCollection()
  287.  
  288.             Dim keyName As String = ""
  289.             Dim keyValue As String = ""
  290.             Dim keyComment As New StringBuilder
  291.  
  292.             Dim searchSectionNameFunc As Predicate(Of String) =
  293.                 Function(line As String)
  294.                     Return (line.TrimStart Like "[[]?*[]]*")
  295.                 End Function
  296.  
  297.             Dim sectionStartIndex As Integer
  298.             ' Dim sectionEndIndex As Integer
  299.             Dim keyStartIndex As Integer
  300.  
  301.             Do While True
  302.  
  303.                 sectionStartIndex = content.FindIndex(sectionStartIndex, searchSectionNameFunc)
  304.                 ' sectionEndIndex = content.FindIndex(sectionStartIndex + 1, searchSectionNameFunc)
  305.  
  306.                 If (sectionStartIndex <> -1) Then
  307.  
  308.                     sectionName = content(sectionStartIndex).Trim({"["c, "]"c, " "c})
  309.                     section = New IniSection(sectionName)
  310.                     keyStartIndex = (sectionStartIndex + 1)
  311.  
  312.                     Do While True
  313.  
  314.                         If (content.Count > keyStartIndex) Then
  315.  
  316.                             Dim line As String = content(keyStartIndex).Trim
  317.  
  318.                             ' If line is not like "[section name]"...
  319.                             If Not (line Like "[[]?*[]]*") Then
  320.  
  321.                                 ' If line is like "name=value"...
  322.                                 If (line Like "?*[=]?*") Then
  323.                                     keyName = line.Substring(0, line.IndexOf("="c)).TrimEnd
  324.                                     keyvalue = line.Substring(line.IndexOf("="c) + 1).TrimStart
  325.  
  326.                                 ElseIf line.StartsWith(";"c, StringComparison.Ordinal) Then
  327.                                     keyComment.AppendLine(line.TrimStart(";"c))
  328.                                     keyStartIndex += 1
  329.                                     Continue Do
  330.  
  331.                                 Else ' line is not like "name=value" neither is not a comment-line...
  332.                                     keyName = line.TrimEnd("="c)
  333.                                     keyValue = String.Empty
  334.  
  335.                                 End If
  336.  
  337.                                 section.Keys.Add(New IniKey(keyName, keyValue, keyComment.ToString.TrimEnd))
  338.  
  339.                                 keyName = ""
  340.                                 keyValue = ""
  341.                                 keyComment.Clear()
  342.  
  343.                             Else ' line is like "[section name]"
  344.                                 Exit Do
  345.  
  346.                             End If
  347.                             keyStartIndex += 1
  348.  
  349.                         Else ' (content.Count <= keyStartIndex)
  350.                             Exit Do
  351.  
  352.                         End If
  353.  
  354.                     Loop
  355.  
  356.                     sections.Add(section)
  357.                     sectionStartIndex += 1
  358.  
  359.                 Else
  360.                     Exit Do
  361.  
  362.                 End If
  363.  
  364.             Loop
  365.  
  366.             Return sections
  367.  
  368.         End Function
  369.  
  370.         ''' ----------------------------------------------------------------------------------------------------
  371.         ''' <summary>
  372.         ''' Gets the INI section names.
  373.         ''' </summary>
  374.         ''' ----------------------------------------------------------------------------------------------------
  375.         ''' <returns>
  376.         ''' The INI section names.
  377.         ''' </returns>
  378.         ''' ----------------------------------------------------------------------------------------------------
  379.         <DebuggerStepThrough>
  380.         Private Function GetIniSectionNames() As String()
  381.  
  382.             Return (From section As IniSection In Me.sectionsB
  383.                     Select section.Name).ToArray
  384.  
  385.         End Function
  386.  
  387.         ''' ----------------------------------------------------------------------------------------------------
  388.         ''' <summary>
  389.         ''' Builds the new INI content
  390.         ''' </summary>
  391.         ''' ----------------------------------------------------------------------------------------------------
  392.         <DebuggerStepThrough>
  393.         Private Function BuildIniContent() As String
  394.  
  395.             Dim sb As New StringBuilder
  396.  
  397.             For Each section As IniSection In Me.sectionsB
  398.  
  399.                 ' Write section name.
  400.                 sb.AppendLine(String.Format("[{0}]", section.Name))
  401.  
  402.                 If section.Keys.Any Then
  403.  
  404.                     ' Get section keys.
  405.                     For Each key As IniKey In section.Keys
  406.  
  407.                         If Not String.IsNullOrEmpty(key.CommentLine) Then
  408.  
  409.                             ' Get commentline(s).
  410.                             Dim commentLines As String() =
  411.                                 key.CommentLine.Split({Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
  412.  
  413.                             ' Fix commentlines starting character.
  414.                             For Each commentLine As String In commentLines
  415.  
  416.                                 If Not commentLine.StartsWith(";"c, StringComparison.InvariantCulture) Then
  417.                                     commentLine = commentLine.Insert(0, ";"c)
  418.                                 End If
  419.  
  420.                                 ' Write commentline.
  421.                                 sb.AppendLine(commentLine)
  422.  
  423.                             Next commentLine
  424.  
  425.                         End If
  426.  
  427.                         ' Write key.
  428.                         sb.AppendLine(String.Format("{0}={1}", key.Name, key.Value))
  429.  
  430.                     Next key
  431.  
  432.                 Else
  433.                     sb.AppendLine()
  434.  
  435.                 End If
  436.  
  437.                 sb.AppendLine()
  438.  
  439.             Next section
  440.  
  441.             Return sb.ToString.TrimEnd
  442.  
  443.         End Function
  444.  
  445.         ''' ----------------------------------------------------------------------------------------------------
  446.         ''' <summary>
  447.         ''' Gets the INI content as string.
  448.         ''' </summary>
  449.         ''' ----------------------------------------------------------------------------------------------------
  450.         <DebuggerStepThrough>
  451.         Private Function GetIniContent() As String
  452.  
  453.             Using ms As New MemoryStream()
  454.  
  455.                 Me.fs.CopyTo(ms, bufferSize:=4096)
  456.                 Me.fs.Seek(0, SeekOrigin.Begin)
  457.                 ms.Seek(0, SeekOrigin.Begin)
  458.  
  459.                 Using sr As New StreamReader(ms, Me.encodingB, detectEncodingFromByteOrderMarks:=False, bufferSize:=4096)
  460.                     Return sr.ReadToEnd
  461.                 End Using
  462.  
  463.             End Using
  464.  
  465.         End Function
  466.  
  467. #End Region
  468.  
  469. #Region " IDisposable Implementation "
  470.  
  471.         ''' ----------------------------------------------------------------------------------------------------
  472.         ''' <summary>
  473.         ''' To detect redundant calls when disposing.
  474.         ''' </summary>
  475.         ''' ----------------------------------------------------------------------------------------------------
  476.         Private isDisposed As Boolean
  477.  
  478.         ''' ----------------------------------------------------------------------------------------------------
  479.         ''' <summary>
  480.         ''' Releases all the resources used by this instance.
  481.         ''' </summary>
  482.         ''' ----------------------------------------------------------------------------------------------------
  483.         <DebuggerStepThrough>
  484.         Public Sub Dispose() Implements IDisposable.Dispose
  485.  
  486.             Me.Dispose(isDisposing:=True)
  487.             GC.SuppressFinalize(obj:=Me)
  488.  
  489.         End Sub
  490.  
  491.         ''' ----------------------------------------------------------------------------------------------------
  492.         ''' <summary>
  493.         ''' Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  494.         ''' Releases unmanaged and - optionally - managed resources.
  495.         ''' </summary>
  496.         ''' ----------------------------------------------------------------------------------------------------
  497.         ''' <param name="isDisposing">
  498.         ''' <see langword="True"/>  to release both managed and unmanaged resources;
  499.         ''' <see langword="False"/> to release only unmanaged resources.
  500.         ''' </param>
  501.         ''' ----------------------------------------------------------------------------------------------------
  502.         <DebuggerStepThrough>
  503.         Private Sub Dispose(ByVal isDisposing As Boolean)
  504.  
  505.             If (Not Me.isDisposed) AndAlso (isDisposing) Then
  506.  
  507.                 Me.fs.Dispose()
  508.                 Me.fs = Nothing
  509.  
  510.                 Me.sectionsB.Clear()
  511.                 Me.sectionsB = Nothing
  512.  
  513.             End If
  514.  
  515.             Me.isDisposed = True
  516.  
  517.         End Sub
  518.  
  519. #End Region
  520.  
  521.     End Class
  522.  
  523. End Namespace
  524.  
  525. #End Region
Add Comment
Please, Sign In to add comment