// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace osu.Game.Beatmaps.Formats { public abstract class Decoder : Decoder where TOutput : new() { protected virtual TOutput CreateTemplateObject() => new TOutput(); public TOutput Decode(StreamReader primaryStream, params StreamReader[] otherStreams) { var output = CreateTemplateObject(); foreach (StreamReader stream in otherStreams.Prepend(primaryStream)) ParseStreamInto(stream, output); return output; } protected abstract void ParseStreamInto(StreamReader stream, TOutput output); } public abstract class Decoder { private static readonly Dictionary>> decoders = new Dictionary>>(); static Decoder() { LegacyBeatmapDecoder.Register(); JsonBeatmapDecoder.Register(); LegacyStoryboardDecoder.Register(); } /// /// Retrieves a to parse a . /// /// A stream pointing to the . public static Decoder GetDecoder(StreamReader stream) where T : new() { if (stream == null) throw new ArgumentNullException(nameof(stream)); if (!decoders.TryGetValue(typeof(T), out var typedDecoders)) throw new IOException(@"Unknown decoder type"); string line; do { line = stream.ReadLine()?.Trim(); } while (line != null && line.Length == 0); if (line == null) throw new IOException(@"Unknown file format (null)"); var decoder = typedDecoders.Select(d => line.StartsWith(d.Key, StringComparison.InvariantCulture) ? d.Value : null).FirstOrDefault(); if (decoder == null) throw new IOException($@"Unknown file format ({line})"); return (Decoder)decoder.Invoke(line); } /// /// Registers an instantiation function for a . /// /// A string in the file which triggers this decoder to be used. /// A function which constructs the given . protected static void AddDecoder(string magic, Func constructor) { if (!decoders.TryGetValue(typeof(T), out var typedDecoders)) decoders.Add(typeof(T), typedDecoders = new Dictionary>()); typedDecoders[magic] = constructor; } } }