/// <summary> /// /// </summary> /// <param name="bindings"></param> /// <param name="path"></param> public static void LoadFromStream ( IEnumerable<GameModule.ModuleBinding> bindings, Stream stream ) { try { var iniData = new IniData(); var parser = new StreamIniDataParser(); parser.Parser.Configuration.CommentString = "# "; using ( var sw = new StreamReader(stream) ) { iniData = parser.ReadData( sw ); } // read data : foreach ( var section in iniData.Sections ) { var bind = bindings .Where( b => b.NiceName == section.SectionName ) .SingleOrDefault(); if (bind==null) { Log.Warning("Module {0} does not exist. Section ignored.", section.SectionName ); } bind.Module.SetConfiguration( section.Keys ); } } catch (IniParser.Exceptions.ParsingException e) { Log.Warning("INI parser error: {0}", e.Message); } }
/// <summary> /// Writes the ini data to a stream. /// </summary> /// <param name="writer">A write stream where the ini data will be stored</param> /// <param name="iniData">An <see cref="IniData"/> instance.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="writer"/> is <c>null</c>. /// </exception> public void WriteData(StreamWriter writer, IniData iniData) { if (iniData == null) throw new ArgumentNullException("iniData"); if (writer == null) throw new ArgumentNullException("writer"); writer.Write(iniData.ToString()); }
/// <summary> /// /// </summary> /// <param name="options"></param> public BuildContext ( BuildOptions options, IniData iniData ) { this.Options = options; Log.Message("Source directories:"); contentPaths = new List<string>(); contentPaths.Add( options.FullInputDirectory ); contentPaths.AddRange( GetAllKeysFromSection( iniData, "ContentDirectories" ).Select( p => ResolveDirectory( p )).Where( p1 => p1!=null ) ); foreach ( var dir in contentPaths ) { Log.Message(" {0}", dir ); } Log.Message(""); Log.Message("Binary directories:"); binaryPaths = new List<string>(); binaryPaths.AddRange( GetAllKeysFromSection( iniData, "BinaryDirectories" ).Select( p => ResolveDirectory( p )).Where( p1 => p1!=null ) ); foreach ( var dir in binaryPaths ) { Log.Message(" {0}", dir ); } Log.Message(""); Log.Message("Target directory:"); Log.Message(" {0}", options.FullOutputDirectory ); Log.Message(""); Log.Message("Temp directory:"); Log.Message(" {0}", options.FullTempDirectory ); Log.Message(""); }
public static void SaveToStream ( IEnumerable<GameModule.ModuleBinding> bindings, Stream stream ) { try { // prepare ini data : IniData iniData = new IniData(); iniData.Configuration.CommentString = "# "; foreach ( var bind in bindings ) { var sectionName = bind.NiceName; var config = bind.Module.GetConfiguration(); iniData.Sections.AddSection( sectionName ); var sectionData = iniData.Sections.GetSectionData( sectionName ); foreach ( var key in config ) { if (sectionData.Keys.ContainsKey(key.KeyName)) { sectionData.Keys.RemoveKey(key.KeyName); } sectionData.Keys.AddKey( key ); } } // write file : var parser = new StreamIniDataParser(); using ( var sw = new StreamWriter(stream) ) { parser.WriteData( sw, iniData ); } } catch (IniParser.Exceptions.ParsingException e) { Log.Warning("INI parser error: {0}", e.Message); } }
/// <summary> /// Processes one line and parses the data found in that line /// (section or key/value pair who may or may not have comments) /// </summary> /// <param name="currentLine">The string with the line to process</param> protected virtual void ProcessLine(string currentLine, IniData currentIniData) { currentLine = currentLine.Trim(); // Extract comments from current line and store them in a tmp field if (LineContainsAComment(currentLine)) { currentLine = ExtractComment(currentLine); } // By default comments must span a complete line (i.e. the comment character // must be located at the beginning of a line, so it seems that the following // check is not needed. // But, if the comment parsing behaviour is changed in a derived class e.g. to // to allow parsing comment characters in the middle of a line, the implementor // will be forced to rewrite this complete method. // That was actually the behaviour for parsing comments // in earlier versions of the library, so checking if the current line is empty // (meaning the complete line was a comment) is future-proof. // If the entire line was a comment now should be empty, // so no further processing is needed. if (currentLine == String.Empty) return; //Process sections if (LineMatchesASection(currentLine)) { ProcessSection(currentLine, currentIniData); return; } //Process keys if (LineMatchesAKeyValuePair(currentLine)) { ProcessKeyValuePair(currentLine, currentIniData); return; } if (Configuration.AllowKeysWithoutValues) { if (LineMatchesAKeyOnly(currentLine)) { ProcessKeyOnly(currentLine, currentIniData); return; } } if (Configuration.SkipInvalidLines) return; throw new ParsingException( "Unknown file format. Couldn't parse the line: '" + currentLine + "'."); }
/// <summary> /// /// </summary> /// <param name="iniData"></param> /// <param name="sectionName"></param> /// <returns></returns> string[] GetAllKeysFromSection ( IniData iniData, string sectionName ) { if (!iniData.Sections.ContainsSection(sectionName)) { return new string[0]; } return iniData.Sections[ sectionName ] .Select( key => key.KeyName ) .ToArray(); }
/// <summary> /// Copies an instance of the <see cref="Fusion.Core.IniParser.Model.IniDataCaseInsensitive"/> class /// </summary> /// <param name="ori">Original </param> public IniDataCaseInsensitive(IniData ori) : this(new SectionDataCollection(ori.Sections, StringComparer.OrdinalIgnoreCase)) { Global = (KeyDataCollection)ori.Global.Clone(); Configuration = ori.Configuration.Clone(); }
/// <summary> /// /// </summary> /// <param name="sourceFolder"></param> /// <returns></returns> List<AssetSource> GatherAssetFiles ( string[] ignorePatterns, IniData iniData, BuildContext context, ref BuildResult result ) { var assetSources = new List<AssetSource>(); // key contain key path // value containt full path var files = new List<LocalFile>(); // gather files from all directories // and then distinct them by key path. foreach ( var contentDir in context.ContentDirectories ) { var localFiles = Directory.EnumerateFiles( contentDir, "*", SearchOption.AllDirectories ) .Where( f1 => Path.GetFileName(f1).ToLowerInvariant() != ".content" ); files.AddRange( localFiles.Select( fullpath => new LocalFile( contentDir, fullpath ) ) ); } files = files.DistinctBy( file => file.KeyPath ).ToList(); result.Total = files.Count; // ignore files by ignore pattern // and count ignored files : result.Ignored = files.RemoveAll( file => { foreach ( var pattern in ignorePatterns ) { if (Wildcard.Match( file.KeyPath, pattern )) { return true; } } return false; }); foreach ( var section in iniData.Sections ) { // 'Ingore' is a special section. if (section.SectionName=="Ignore") { continue; } if (section.SectionName=="ContentDirectories") { continue; } if (section.SectionName=="BinaryDirectories") { continue; } if (section.SectionName=="Download") { continue; } // get processor : if (!processors.ContainsKey(section.SectionName)) { Log.Warning("Asset processor '{0}' not found. Files will be skipped.", section.SectionName ); Log.Message(""); continue; } var procBind = processors[section.SectionName]; // get mask and arguments : var maskArgs = section.Keys .Reverse() .Select( key => new { Mask = key.KeyName.Split(' ', '\t').FirstOrDefault(), Args = CommandLineParser.SplitCommandLine( key.KeyName ).Skip(1).ToArray() }) .ToList(); foreach ( var file in files ) { if (file.Handled) { continue; } foreach ( var maskArg in maskArgs ) { if ( Wildcard.Match( file.KeyPath, maskArg.Mask, true ) ) { file.Handled = true; assetSources.Add( new AssetSource( file.KeyPath, file.BaseDir, procBind.Type, maskArg.Args, context ) ); break; } } } // count unhandled files : result.Skipped = files.Count( f => !f.Handled ); } return assetSources; }
/// <summary> /// Writes INI data to a text file. /// </summary> /// <param name="filePath"> /// Path to the file. /// </param> /// <param name="parsedData"> /// IniData to be saved as an INI file. /// </param> /// <param name="fileEncoding"> /// Specifies the encoding used to create the file. /// </param> public void WriteFile(string filePath, IniData parsedData, Encoding fileEncoding = null) { // The default value can't be assigned as a default parameter value because it is not // a constant expression. if (fileEncoding == null) fileEncoding = Encoding.ASCII; if (string.IsNullOrEmpty(filePath)) throw new ArgumentException("Bad filename."); if (parsedData == null) throw new ArgumentNullException("parsedData"); using (FileStream fs = File.Open(filePath, FileMode.Create, FileAccess.Write)) { using (StreamWriter sr = new StreamWriter(fs, fileEncoding)) { WriteData(sr, parsedData); } } }
public IniData(IniData ori) : this((SectionDataCollection)ori.Sections) { Global = (KeyDataCollection)ori.Global.Clone(); Configuration = ori.Configuration.Clone(); }
public IniData(IniData ori): this((SectionDataCollection) ori.Sections) { Global = (KeyDataCollection) ori.Global.Clone(); Configuration = ori.Configuration.Clone(); }
/// <summary> /// Merges the other iniData into this one by overwriting existing values. /// Comments get appended. /// </summary> /// <param name="toMergeIniData"> /// IniData instance to merge into this. /// If it is null this operation does nothing. /// </param> public void Merge(IniData toMergeIniData) { if (toMergeIniData == null) return; Global.Merge(toMergeIniData.Global); Sections.Merge(toMergeIniData.Sections); }
/// <summary> /// Copies an instance of the <see cref="Fusion.Core.IniParser.Model.IniDataCaseInsensitive"/> class /// </summary> /// <param name="ori">Original </param> public IniDataCaseInsensitive(IniData ori) : this(new SectionDataCollection(ori.Sections, StringComparer.OrdinalIgnoreCase)) { Global = (KeyDataCollection) ori.Global.Clone(); Configuration = ori.Configuration.Clone(); }
/// <summary> /// Creates a string from the INI data. /// </summary> /// <param name="iniData">An <see cref="IniData"/> instance.</param> /// <returns> /// A formatted string with the contents of the /// <see cref="IniData"/> instance object. /// </returns> public string WriteString(IniData iniData) { return iniData.ToString(); }
/// <summary> /// Proccess a string which contains an ini section. /// </summary> /// <param name="line"> /// The string to be processed /// </param> protected virtual void ProcessSection(string line, IniData currentIniData) { // Get section name with delimiters from line... string sectionName = Configuration.SectionRegex.Match(line).Value.Trim(); // ... and remove section's delimiters to get just the name sectionName = sectionName.Substring(1, sectionName.Length - 2).Trim(); // Check that the section's name is not empty if (sectionName == string.Empty) { throw new ParsingException("Section name is empty"); } // Temporally save section name. _currentSectionNameTemp = sectionName; //Checks if the section already exists if (currentIniData.Sections.ContainsSection(sectionName)) { if (Configuration.AllowDuplicateSections) { return; } throw new ParsingException(string.Format("Duplicate section with name '{0}' on line '{1}'", sectionName, line)); } // If the section does not exists, add it to the ini data currentIniData.Sections.AddSection(sectionName); // Save comments read until now and assign them to this section currentIniData.Sections.GetSectionData(sectionName).LeadingComments = _currentCommentListTemp; _currentCommentListTemp.Clear(); }
/// <summary> /// /// </summary> /// <param name="sourceFolder"></param> /// <param name="targetFolder"></param> /// <param name="force"></param> public BuildResult Build ( BuildOptions options, IniData iniData ) { BuildResult result = new BuildResult(); context = new BuildContext( options, iniData ); var ignorePatterns = new string[0]; if ( iniData.Sections.ContainsSection("Ignore") ) { ignorePatterns = iniData.Sections["Ignore"] .Select( element => element.KeyName ) .Select( key => ContentUtils.BackslashesToSlashes( key ) ) .ToArray(); } if ( iniData.Sections.ContainsSection("Download") ) { Download( context, iniData.Sections["Download"], result ); } // // gather files on source folder ignoring // files that match ignore pattern : // Log.Message("Gathering files..."); var assetSources = GatherAssetFiles( ignorePatterns, iniData, context, ref result ); Log.Message(""); // // Check hash collisions : // var collisions = assetSources .GroupBy( file0 => file0.TargetName ) .Where( fileGroup1 => fileGroup1.Count() > 1 ) .Distinct() .ToArray(); if (collisions.Any()) { Log.Error("Hash collisions detected:"); int collisionCount = 0; foreach ( var collision in collisions ) { Log.Error(" [{0}] {1}", collisionCount++, collision.Key); foreach ( var collisionEntry in collision ) { Log.Error( " {0}", collisionEntry.FullSourcePath ); } } throw new BuildException("Hash collisions detected"); } // // remove stale built content : // Log.Message("Cleaning stale content up..."); CleanStaleContent( options.FullOutputDirectory, assetSources ); Log.Message(""); // // Build everything : // foreach ( var assetSource in assetSources ) { var proc = assetSource.CreateProcessor(); BuildAsset( proc, assetSource.BuildArguments, assetSource, ref result ); } return result; }
/// <summary> /// Processes a string containing an ini key/value pair. /// </summary> /// <param name="line"> /// The string to be processed /// </param> protected virtual void ProcessKeyOnly(string line, IniData currentIniData) { // get key and value data string key = line; string value = ""; // Check if we haven't read any section yet if (string.IsNullOrEmpty(_currentSectionNameTemp)) { if (!Configuration.AllowKeysWithoutSection) { throw new ParsingException("key value pairs must be enclosed in a section"); } AddKeyToKeyValueCollection(key, value, currentIniData.Global, "global"); } else { var currentSection = currentIniData.Sections.GetSectionData(_currentSectionNameTemp); AddKeyToKeyValueCollection(key, value, currentSection.Keys, _currentSectionNameTemp); } }
public void SaveFile(string filePath, IniData parsedData) { WriteFile(filePath, parsedData, Encoding.ASCII); }