/// <summary> /// Tries to automatically detect the format of the given file, and creates an instance of it /// </summary> /// <typeparam name="T">Base type of file (i.e. image, archive)</typeparam> /// <param name="fileStream">File stream with data to use</param> /// <param name="endianness">Endianness of the file data</param> /// <returns>Instance of file; null if no instance was created</returns> public static T FromFile <T>(FileStream fileStream, Endian endianness) where T : FileFormat { // TODO: rework identification system? List <IdentificationMatch> matchedTypes = new List <IdentificationMatch>(); EndianBinaryReader reader = new EndianBinaryReader(fileStream, endianness); { foreach (var assembly in AssemblyHelpers.GetNonSystemAssemblies()) { foreach (var type in assembly.GetExportedTypes().Where(x => x == typeof(T) || x.InheritsFrom(typeof(T)))) { IdentificationMatch magicMatch = null, patternMatch = null; var customAttribs = type.GetCustomAttributes(false); bool requireMagicAndPattern = customAttribs.Any(x => x is MagicNumberAttribute) && customAttribs.Any(x => x is FilenamePatternAttribute); var magicNumberAttrib = customAttribs.FirstOrDefault(x => x is MagicNumberAttribute); var verifyMethod = type.GetMethod("VerifyMagicNumber", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (verifyMethod == null) { throw new NullReferenceException("Reflection error on method fetch for file verification"); } VerifyResult verifyResult = ((VerifyResult)verifyMethod.Invoke(null, new object[] { reader, type })); if (verifyResult == VerifyResult.VerifyOkay) { uint weight = int.MaxValue; if (magicNumberAttrib != null) { weight += (uint)(magicNumberAttrib as MagicNumberAttribute).MagicNumber.Length; } magicMatch = new IdentificationMatch(type, weight); } else if (verifyResult == VerifyResult.WrongMagicNumber) { continue; } foreach (var fnPatternAttrib in type.GetCustomAttributes(typeof(FilenamePatternAttribute), false)) { string pattern = (fnPatternAttrib as FilenamePatternAttribute).Pattern; Regex regEx = new Regex(pattern, RegexOptions.IgnoreCase); if (regEx.IsMatch(fileStream.Name)) { patternMatch = new IdentificationMatch(type, (uint)pattern.Length); } } if (requireMagicAndPattern) { if (magicMatch != null && patternMatch != null) { matchedTypes.Add(magicMatch); matchedTypes.Add(patternMatch); } } else { if (magicMatch != null) { matchedTypes.Add(magicMatch); } if (patternMatch != null) { matchedTypes.Add(patternMatch); } } } if (matchedTypes.Count > 0) { T fileInstance = (T)Activator.CreateInstance(matchedTypes.OrderByDescending(x => x.Weight).FirstOrDefault().Type); fileInstance.Open(reader); return(fileInstance); } } } return(default(T)); }
protected abstract void OnOpen(EndianBinaryReader reader);