/// <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); }
protected virtual bool ProcessProperty(StringBuffer currentLine, IniData iniData) { if (currentLine.Count <= 0) { return(false); } var propertyAssigmentIdx = currentLine.FindSubstring(Scheme.PropertyAssigmentString); if (propertyAssigmentIdx.IsEmpty) { return(false); } var keyRange = Range.WithIndexes(0, propertyAssigmentIdx.start - 1); var valueStartIdx = propertyAssigmentIdx.end + 1; var valueSize = currentLine.Count - propertyAssigmentIdx.end - 1; var valueRange = Range.FromIndexWithSize(valueStartIdx, valueSize); var key = currentLine.Substring(keyRange); var value = currentLine.Substring(valueRange); if (Configuration.TrimProperties) { key.Trim(); value.Trim(); } if (key.IsEmpty) { if (Configuration.SkipInvalidLines) { return(false); } var errorFormat = "Found property without key. 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()); } // Check if we haven't read any section yet if (string.IsNullOrEmpty(_currentSectionNameTemp)) { if (!Configuration.AllowKeysWithoutSection) { var errorFormat = "Properties must be contained inside a section. Please see configuration option {0}.{1} to ignore this error."; var errorMsg = string.Format(errorFormat, nameof(Configuration), nameof(Configuration.AllowKeysWithoutSection)); throw new ParsingException(errorMsg, _currentLineNumber, currentLine.DiscardChanges().ToString()); } AddKeyToKeyValueCollection(key.ToString(), value.ToString(), iniData.Global, "global"); } else { var currentSection = iniData.Sections.FindByName(_currentSectionNameTemp); AddKeyToKeyValueCollection(key.ToString(), value.ToString(), currentSection.Properties, _currentSectionNameTemp); } 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(); } }