Summary

Class:ProjectX.PublicApi.MagicBytes.Wizard
Assembly:ProjectX.PublicApi
File(s):C:\private\projects\projectx\backend\src\ProjectX.PublicApi\MagicBytes\Wizard.cs
Covered lines:0
Uncovered lines:51
Coverable lines:51
Total lines:161
Line coverage:0%
Branch coverage:0%

History

Metrics

MethodCyclomatic complexity  NPath complexity  Sequence coverage  Branch coverage  
.cctor()1000
Identify(...)3200
Identify(...)2000
DoesPatternMatchData(...)2200

File(s)

C:\private\projects\projectx\backend\src\ProjectX.PublicApi\MagicBytes\Wizard.cs

#LineLine coverage
 1using System.Collections.Generic;
 2using System.IO;
 3using System.Linq;
 4
 5namespace ProjectX.PublicApi.MagicBytes
 6{
 7    /// <summary>
 8    /// Represents a assistent used for identifying files by parsing the magic
 9    /// bytes.
 10    /// </summary>
 11    public static class Wizard
 12    {
 13        #region Private Static Fields
 14
 15        /// <summary>
 16        /// Saves all patterns used for identifying file types.
 17        /// </summary>
 18        private static List<Pattern> _patterns;
 19
 20        #endregion
 21
 22        #region Constructors
 23
 24        /// <summary>
 25        /// Initializes the wizard by setting up the default patterns.
 26        /// </summary>
 27        static Wizard()
 28        {
 029            Wizard._patterns = new Pattern[]
 030            {
 031                new Pattern(
 032                    new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A },
 033                    0,
 034                    "image/png",
 035                    "png",
 036                    "Portable Network Graphics"),
 037
 038                new Pattern(
 039                    new byte[] { 0xFF, 0xD8, 0xFF },
 040                    0,
 041                    "image/jpeg",
 042                    "jpg",
 043                    "Joint Photographic Experts Group"),
 044
 045                new Pattern(
 046                    new byte[] { 0x47, 0x49, 0x46, 0x38 },
 047                    0,
 048                    "image/gif",
 049                    "gif",
 050                    "Graphics Interchange Format"),
 051
 052                new Pattern(
 053                    new byte[] { 0x49, 0x49, 0x2A, 0x00 },
 054                    0,
 055                    "image/tiff",
 056                    "tiff",
 057                    "Tagged Image File Format")
 058
 059                // FIXME: add like 5 million more.
 060            }.OrderByDescending(x => x.Signature.Length).ToList();
 061        }
 62
 63        #endregion
 64
 65        #region Public Static Methods
 66
 67        /// <summary>
 68        /// Tries to identify the type of the file in the passed stream.
 69        /// Returns either the matched pattern or null if the file couldnt be
 70        /// identified.
 71        /// </summary>
 72        /// <remarks>
 73        /// THE STREAM HAS TO BE SEEKABLE!
 74        /// </remarks>
 75        /// <param name="stream">
 76        /// The stream from which the file should be identified.
 77        /// </param>
 78        /// <returns>
 79        /// Either the matched pattern instance or null.
 80        /// </returns>
 81        public static Pattern Identify(Stream stream)
 82        {
 083            var pos = stream.Position;
 84
 085            foreach (Pattern pattern in Wizard._patterns)
 86            {
 87                try
 88                {
 089                     if (Wizard.DoesPatternMatchData(pattern, stream))
 90                    {
 091                        return pattern;
 92                    }
 093                }
 94                finally
 95                {
 096                    stream.Position = pos;
 097                }
 98            }
 99
 0100            return null;
 0101        }
 102
 103        /// <summary>
 104        /// Tries to identify the type of the file in the passed buffer.
 105        /// Returns either the matched pattern or null if the file couldnt be
 106        /// identified.
 107        /// </summary>
 108        /// <remarks>
 109        /// THE STREAM HAS TO BE SEEKABLE!
 110        /// </remarks>
 111        /// <param name="buf">
 112        /// The buffer from which the file should be identified.
 113        /// </param>
 114        /// <returns>
 115        /// Either the matched pattern instance or null.
 116        /// </returns>
 117        public static Pattern Identify(byte[] buf)
 118        {
 0119            using (Stream stream = new MemoryStream(buf))
 120            {
 0121                return Wizard.Identify(stream);
 122            }
 0123        }
 124
 125        #endregion
 126
 127        #region Private Static Methods
 128
 129        /// <summary>
 130        /// Checks whether the passed pattern matches the file in the passed
 131        /// stream.
 132        /// </summary>
 133        /// <param name="pattern">
 134        /// The pattern which should be checked for matching the file in the
 135        /// passed stream.
 136        /// </param>
 137        /// <param name="stream">
 138        /// The stream containing the file to be identified.
 139        /// </param>
 140        /// <returns>
 141        /// A flag indicating whether the passed pattern matches the data in
 142        /// the passed stream.
 143        /// </returns>
 144        private static bool DoesPatternMatchData(
 145            Pattern pattern, Stream stream)
 146        {
 0147             if (stream.Length < pattern.Signature.Length + pattern.Offset)
 148            {
 0149                return false;
 150            }
 151
 0152            stream.Seek(pattern.Offset, SeekOrigin.Current);
 0153            var buf = new byte[pattern.Signature.Length];
 0154            stream.Read(buf, 0, buf.Length);
 155
 0156            return pattern.Signature.SequenceEqual(buf);
 157        }
 158
 159        #endregion
 160    }
 161}