/// <summary>
        /// <inheritdoc cref="PrivateProfileSection(bool)"/>
        /// </summary>
        /// <param name="contents">
        /// INI ファイル (初期化ファイル) のセクション全体。
        /// </param>
        /// <param name="ignoreDuplicatedEntry">
        /// <inheritdoc cref="PrivateProfileSection(bool)"/>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="contents"/> に <c>null</c> が指定されました。
        /// </exception>
        /// <exception cref="ArgumentException">
        /// <paramref name="contents"/> の要素に <c>null</c> または不正な値が含まれます。
        /// </exception>
        public PrivateProfileSection(string[] contents, bool ignoreDuplicatedEntry = false) : this(ignoreDuplicatedEntry)
        {
            // Validation (Null Check):
            if (contents is null)
            {
                throw new ArgumentNullException(nameof(contents));
            }

            // APPEND Lines
            for (int i = 0; i < contents.Length; i++)
            {
                // Validation (Null Check):
                if (contents[i] is null)
                {
                    throw new ArgumentException(Resources.PrivateProfileInvalidFormatErrorMessage, nameof(contents));
                }

                // NEW Line
                var line = new PrivateProfileLine(contents[i]);

                // Validation (Line Type) & Null Section Insertion:
                if (i == 0)
                {
                    // No Validation for 1st content (Line)

                    // Check Line Type of 1st content (Line)
                    if (line.LineType != PrivateProfileLineType.Section)
                    {
                        // Insert Null Section as 1st element
                        this.Append(new PrivateProfileLine(null));
                    }
                }
                else
                {
                    // Validation (Line Type) for other content (Line):
                    if (line.LineType != PrivateProfileLineType.Entry && line.LineType != PrivateProfileLineType.Other)
                    {
                        throw new ArgumentException(Resources.PrivateProfileInvalidLineTypeErrorMessage, nameof(contents));
                    }
                }

                // APPEND Line
                this.Append(line);
            }
        }
        // ----------------------------------------------------------------------------------------------------
        // Static Method(s)
        // ----------------------------------------------------------------------------------------------------

        /// <summary>
        /// INI ファイル (初期化ファイル) からセクションを読み込みます。
        /// </summary>
        /// <param name="reader">
        /// このセクションを読み込む INI ファイルの <see cref="StreamReader"/> を指定します。
        /// </param>
        /// <param name="firstLine">
        /// このセクションの最初の 1 行を指定します。
        /// </param>
        /// <param name="nextLine">
        /// このセクションの次にセクションがある場合に、そのセクションの最初の 1 ラインが格納されます。
        /// このセクションが最後のセクションだった場合は <c>null</c> が格納されます。
        /// </param>
        /// <param name="ignoreDuplicatedEntry">
        /// エントリのキーが重複しているセクションを読み込むことを許可する場合に <c>true</c> を指定します。
        /// 既定は <c>false</c> です。
        /// </param>
        /// <returns>
        /// 読み込みに成功した場合は、読み込んだセクション (<see cref="PrivateProfileSection"/>) を返します。
        /// 読み込みに失敗した場合は <c>null</c> を返します。
        /// </returns>
        public static PrivateProfileSection Read(TextReader reader, string firstLine, out string nextLine, bool ignoreDuplicatedEntry = false)
        {
            // Validation (Null Check):
            if (reader is null)
            {
                throw new ArgumentNullException(nameof(reader));
            }
            if (firstLine is null)
            {
                throw new ArgumentNullException(nameof(firstLine));
            }

            // Initialize value(s)
            nextLine = null;
            var raw_line = firstLine;

            // Initialize Section (NOT NEW)
            PrivateProfileSection section = null;

#if DEBUG
            Debug.WriteLine("Start reading the Section.", DebugInfo.ShortName);
#endif
            // MAIN LOOP: START
            while (raw_line != null) // instead of (!reader.EndOfStream)
            {
                // NEW Line
                var line = new PrivateProfileLine(raw_line);

                // Check only for 1st Line
                if (section is null)
                {
                    // NEW Section; because Section is NOT yet initialized.
                    section = new PrivateProfileSection(ignoreDuplicatedEntry);

                    // Check LineType (Null Section Check)
                    if (line.LineType != PrivateProfileLineType.Section)
                    {
                        // Insert Line for Null Section
                        section.Append(new PrivateProfileLine(null));

                        // ADD SECTION
                        section.Append(line);

                        // Check NEXT Line
                        if ((raw_line = reader.ReadLine()) == null)
                        {
                            break;
                        }

                        // Read NEXT Line
                        line = new PrivateProfileLine(raw_line);
                    }
                }

                // ADD SECTION or ENTRY (or, Go to NEXT Section)
                switch (line.LineType)
                {
                // SECTION Line:
                case PrivateProfileLineType.Section:

                    // Check if Section Name is for Current or NEXT Section
                    if (section.lines.Count == 0)
                    {
                        // CURRENT Section:

                        // ADD SECTION
                        section.Append(line);
                        break;
                    }
                    else
                    {
                        // NEXT Section: Current Section has ended.
#if DEBUG
                        Debug.Write("End reading Section " + (section.Name is null ? "(null)" : $"\"{section.Name}\""), DebugInfo.ShortName);
                        Debug.WriteLine($", because NEXT Section \"{line.SectionName}\" was found.");
#endif
                        // SET 1st Line of NEXT Section
                        nextLine = raw_line;

                        // RETURN CURRENT Section
                        return(section);
                    }

                // ENTRY Line:
                case PrivateProfileLineType.Entry:

                    // ADD ENTRY
                    section.Append(line);
                    break;

                // ENTRY Line (Blank Line or Comment Line):
                case PrivateProfileLineType.Other:

                    // ADD ENTRY
                    section.Append(line);
                    break;

                default:
                    throw new NotSupportedException();
                }

                // Read NEXT Line
                raw_line = reader.ReadLine();
            }
            // MAIN LOOP: END
#if DEBUG
            Debug.WriteLine("End reading Section " + (section.Name is null ? "(null)" : $"\"{section.Name}\"") + ".", DebugInfo.ShortName);
#endif

            // RETURN
            return(section);
        }
        /// <summary>
        /// このセクションに新しい <see cref="PrivateProfileLine"/> クラスを追加します。
        /// </summary>
        /// <param name="line">
        /// 追加する <see cref="PrivateProfileLine"/> クラス
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="line"/> に <c>null</c> が指定されました。
        /// </exception>
        public void Append(PrivateProfileLine line)
        {
            // Validation (Null Check):
            if (line is null)
            {
                throw new ArgumentNullException(nameof(line));
            }

            // Validations:
            if (this.lines.Count == 0)
            {
                // for 1st Line

                // Validation (Line Type):
                if (line.LineType != PrivateProfileLineType.Section)
                {
                    throw new ArgumentException(Resources.PrivateProfileInvalidLineTypeErrorMessage, nameof(line));
                }
            }
            else
            {
                // for 2nd Line and after

                // Validation (Line Type)
                if (line.LineType != PrivateProfileLineType.Entry && line.LineType != PrivateProfileLineType.Other)
                {
                    throw new ArgumentException(Resources.PrivateProfileInvalidLineTypeErrorMessage, nameof(line));
                }

                // Validation (Key Existence)
                if ((line.LineType == PrivateProfileLineType.Entry) && this.entries.ContainsKey(line.Key))
                {
                    if (!this.IgnoreDuplicatedEntry)
                    {
                        // Throw Exception
                        throw new ArgumentException(Resources.PrivateProfileKeyAlreadyExistsErrorMessage, nameof(line));
                    }
                    else
                    {
#if DEBUG
                        Debug.Write(string.IsNullOrEmpty(this.Name) ? "Null Section" : $"Section \"{this.Name}\"", DebugInfo.ShortName);
                        Debug.WriteLine($": Appending line \"{line.RawLine}\" is skipped, because duplicated.");
#endif

                        // RETURN (Do Nothing)
                        return;
                    }
                }
            }

            // APPEND Line
            this.lines.Add(line);

            // UPDATE Entries (Cash)
            if (line.LineType == PrivateProfileLineType.Entry)
            {
                this.entries.Add(line.Key, line.Value);
            }

#if DEBUG
            Debug.Write(string.IsNullOrEmpty(this.Name) ? "Null Section" : $"Section \"{this.Name}\"", DebugInfo.ShortName);
            Debug.Write(": Append Line " + (line.RawLine is null ? "(null)" : $"\"{line.RawLine}\""));
            Debug.Write($" (LineType = {line.LineType}");

            switch (line.LineType)
            {
            case PrivateProfileLineType.NotInitialized:
                throw new InvalidOperationException();

            case PrivateProfileLineType.Section:

                // Section
                Debug.WriteLine($", Section = \"{line.SectionName}\")");
                break;

            case PrivateProfileLineType.Entry:

                // Entry
                Debug.WriteLine(", Key = {0}, Value = {1})", $"\"{line.Key}\"", line.Value is null ? "null" : $"\"{line.Value}\"");
                break;

            case PrivateProfileLineType.Other:

                // Other
                Debug.WriteLine(")");
                break;

            default:
                throw new NotSupportedException();
            }
#endif
        }
Exemplo n.º 4
0
        /// <summary>
        /// <inheritdoc cref="PrivateProfileLine()"/>
        /// </summary>
        /// <param name="line">
        /// INI ファイルの 1 ラインを指定します。
        /// </param>
        /// <remarks>
        /// <paramref name="line"/> に <c>null</c> を指定すると、名前のないセクション行が作成され、
        /// <see cref="PrivateProfileLine.LineType"/>, <see cref="PrivateProfileLine.SectionName"/> および <see cref="PrivateProfileLine.RawLine"/> には、
        /// それぞれ、<see cref="PrivateProfileLineType.Section"/>, <see cref="string.Empty"/> および <c>null</c> が設定されます。
        /// </remarks>
        public PrivateProfileLine(string line) : this()
        {
            // Validation (Null Check):
            // (None)

            // SET RawLine
            this.RawLine = line?.Trim();

            // SET LineType, Section, Key and Value
            if (line is null)
            {
                // for Null Section
                this.LineType     = PrivateProfileLineType.Section;
                this.section_name = string.Empty;
                this.key          = null;
                this.value        = null;
            }
            else
            {
                // for Normal Section

                // Initialize value(s)
                this.LineType     = PrivateProfileLineType.Other;
                this.section_name = null;
                this.key          = null;
                this.value        = null;

                // Remove Comment & Triming
                string body = PrivateProfileLine.Trim(line);

                // Parse Line
                if (!string.IsNullOrWhiteSpace(body))
                {
                    // Check SECTION
                    if (Regex.IsMatch(body, @"^\[.+\]$"))
                    {
                        // SECTION Line:
                        // SECTION was found!

                        // SET SECTION Name
                        this.section_name = body.Substring(1, body.Length - 2).Trim();

                        // SET Line Type
                        this.LineType = PrivateProfileLineType.Section;
                    }
                    else if (Regex.IsMatch(body, @"^\[[ \t]*\]$"))
                    {
                        // Invalid SECTION Line:

                        // ERROR
                        throw new FormatException();
                    }
                    else
                    {
                        // NOT SECTION Line:

                        // Check KEY
                        if (body.Contains(Char.ToString('=')))
                        {
                            // KEY and VALUE:

                            // Validation: No KEY;
                            if (body[0] == '=')
                            {
                                throw new FormatException();
                            }

                            // SET KEY and VALUE
                            this.key   = body.Substring(0, body.IndexOf('=')).Trim();
                            this.value = body.EndsWith("=", StringComparison.OrdinalIgnoreCase) ? string.Empty : body.Substring(body.IndexOf('=') + 1).Trim();
                        }
                        else
                        {
                            // KEY only:

                            // SET KEY and VALUE
                            this.key   = body.Trim();
                            this.value = null;
                        }

                        // SET Line Type
                        this.LineType = PrivateProfileLineType.Entry;
                    }
                }
            }
#if DEBUG
            Debug.Write($"Line \"{line}\" (LineType = {this.LineType}", DebugInfo.ShortName);
            Debug.WriteLine(", Section = {0}, Key = {1}, Value = {2})",
                            (this.section_name is null) ? "null" : $"\"{this.section_name}\"",
                            (this.key is null) ? "null" : $"\"{this.key}\"",
                            (this.value is null) ? "null" : $"\"{this.value}\"");
#endif
        }