/// <summary> /// Adds a key to a concrete <see cref="PropertyCollection"/> instance, checking /// if duplicate keys are allowed in the configuration /// </summary> /// <param name="key"> /// Key name /// </param> /// <param name="value"> /// Key's value /// </param> /// <param name="keyDataCollection"> /// <see cref="Property"/> collection where the key should be inserted /// </param> /// <param name="sectionName"> /// Name of the section where the <see cref="PropertyCollection"/> is contained. /// Used only for logging purposes. /// </param> private void AddKeyToKeyValueCollection(string key, string value, PropertyCollection keyDataCollection, string sectionName) { // Check for duplicated keys if (keyDataCollection.Contains(key)) { // We already have a key with the same name defined in the current section HandleDuplicatedKeyInCollection(key, value, keyDataCollection, sectionName); } else { // Save the keys keyDataCollection.Add(key, value); } if (Configuration.ParseComments) { keyDataCollection.FindByKey(key).Comments = CurrentCommentListTemp; CurrentCommentListTemp.Clear(); } }
/// <summary> /// Proccess a string which contains an ini section.% /// </summary> /// <param name="currentLine"> /// The string to be processed /// </param> protected virtual bool ProcessSection(StringBuffer currentLine, IniData iniData) { if (currentLine.Count <= 0) { return(false); } var sectionStartRange = currentLine.FindSubstring(Scheme.SectionStartString); if (sectionStartRange.IsEmpty) { return(false); } var sectionEndRange = currentLine.FindSubstring(Scheme.SectionEndString, sectionStartRange.size); if (sectionEndRange.IsEmpty) { if (Configuration.SkipInvalidLines) { return(false); } var errorFormat = "No closing section value. Please see configuration option {0}.{1} to ignore this error."; var errorMsg = string.Format(errorFormat, nameof(Configuration), nameof(Configuration.SkipInvalidLines)); throw new ParsingException(errorMsg, _currentLineNumber, currentLine.DiscardChanges().ToString()); } var startIdx = sectionStartRange.start + Scheme.SectionStartString.Length; var endIdx = sectionEndRange.end - Scheme.SectionEndString.Length; currentLine.ResizeBetweenIndexes(startIdx, endIdx); if (Configuration.TrimSections) { currentLine.Trim(); } var sectionName = currentLine.ToString(); // Temporally save section name. _currentSectionNameTemp = sectionName; //Checks if the section already exists if (!Configuration.AllowDuplicateSections) { if (iniData.Sections.Contains(sectionName)) { if (Configuration.SkipInvalidLines) { return(false); } var errorFormat = "Duplicate section with name '{0}'. Please see configuration option {1}.{2} to ignore this error."; var errorMsg = string.Format(errorFormat, sectionName, nameof(Configuration), nameof(Configuration.SkipInvalidLines)); throw new ParsingException(errorMsg, _currentLineNumber, currentLine.DiscardChanges().ToString()); } } // If the section does not exists, add it to the ini data iniData.Sections.Add(sectionName); // Save comments read until now and assign them to this section if (Configuration.ParseComments) { var sections = iniData.Sections; var sectionData = sections.FindByName(sectionName); sectionData.Comments.AddRange(CurrentCommentListTemp); CurrentCommentListTemp.Clear(); } return(true); }
/// <summary> /// Parses a string containing valid ini data /// </summary> /// <param name="textReader"> /// Text reader for the source string contaninig the ini data /// </param> /// <returns> /// An <see cref="IniData"/> instance containing the data readed /// from the source /// </returns> /// <exception cref="ParsingException"> /// Thrown if the data could not be parsed /// </exception> public void Parse(TextReader textReader, ref IniData iniData) { iniData.Clear(); iniData.Scheme = Scheme.DeepClone(); _errorExceptions.Clear(); if (Configuration.ParseComments) { CurrentCommentListTemp.Clear(); } _currentSectionNameTemp = null; _mBuffer.Reset(textReader); _currentLineNumber = 0; while (_mBuffer.ReadLine()) { _currentLineNumber++; try { ProcessLine(_mBuffer, iniData); } catch (Exception ex) { _errorExceptions.Add(ex); if (Configuration.ThrowExceptionsOnError) { throw; } } } // TODO: is this try necessary? try { // Orphan comments, assing to last section/key value if (Configuration.ParseComments && CurrentCommentListTemp.Count > 0) { if (iniData.Sections.Count > 0) { // Check if there are actually sections in the file var sections = iniData.Sections; var section = sections.FindByName(_currentSectionNameTemp); section.Comments.AddRange(CurrentCommentListTemp); } else if (iniData.Global.Count > 0) { // No sections, put the comment in the last key value pair // but only if the ini file contains at least one key-value pair iniData.Global.GetLast().Comments.AddRange(CurrentCommentListTemp); } CurrentCommentListTemp.Clear(); } } catch (Exception ex) { _errorExceptions.Add(ex); if (Configuration.ThrowExceptionsOnError) { throw; } } if (HasError) { iniData.Clear(); } }