Tuesday, May 4, 2010

How to validate video file

In my previous post I showed you how to validate an image/picture file. Today I will add a video support to this validation and I will refactor the class a bit. Just know that video validation use exactly the same logic.

    public enum FileType
{
Picture,
Audio,
Video,
Text,
Other,
}

public static class FileValidator
{
private static Dictionary<FileType, byte[][]> _definedHeaders = new Dictionary<FileType, byte[][]>( 2 );

// Defined video headers.
private static byte[][] _videoHeaders = new byte[][]
{
new byte[]{ 0x41, 0x56, 0x49, 0x20 }, // .avi
new byte[]{ 0x52, 0x49, 0x46, 0x46 }, // .avi
new byte[]{ 0x30, 0x26, 0xB2, 0x75, 0x8E, 0x66, 0xCF, 0x11, 0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62 }, // .asf, .wmv
new byte[]{ 0x00, 0x00, 0x01, 0xB3 }, // .mpg
new byte[]{ 0x00, 0x00, 0x01, 0xba}, // .mpg
new byte[]{ 0x00, 0x00, 0x00, 0x18}, // .mp4
new byte[]{ 0x46, 0x4C, 0x56 } // .flv
};

// Defined image headers.
private static byte[][] _imageHeaders = new byte[][]
{
new byte[]{ 0xFF, 0xD8 }, // .jpg, .jpeg, .jpe, .jfif, .jif
new byte[]{ 0x42, 0x4D}, // .bmp
new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, // .png
new byte[]{ 0x47, 0x49, 0x46 } // .gif
};

static FileValidator()
{
RegisterHeaders();
}

private static void RegisterHeaders()
{
_definedHeaders.Add( FileType.Picture, _imageHeaders );
_definedHeaders.Add( FileType.Video, _videoHeaders );
}

/// <summary>
/// Validate that the stream is of an expected type.
/// </summary>
/// <remarks>
/// IMPORTANT: The calling code is responsible for creating and disposing the stream.
/// </remarks>
/// <param name="theStream">The stream of a file.</param>
/// <exception cref="Exception">Throws if the stream is of invalid file.</exception>
/// <returns></returns>
public static bool IsValidFile( Stream theStream, FileType ofTFileype )
{
if( theStream.Length > 0 )
{
byte[] header = new byte[ 8 ]; // Change size if needed.
theStream.Read( header, 0, header.Length );

bool hasHeader = _definedHeaders[ ofTFileype ].Count( magic =>
{
int i = 0;
if( magic.Length > header.Length )
return false;
return magic.Count( b => { return b == header[ i++ ]; } ) == magic.Length;
} ) > 0;

return hasHeader;
}

return false;
}

public static bool IsValidFile( FileInfo fileInfo, FileType ofFileType )
{
bool result = fileInfo.Exists;

if( IsFileTypeRegistered( ofFileType ) )
{
using( Stream stream = fileInfo.OpenRead() )
{
result = result ? FileValidator.IsValidFile( stream, ofFileType ) : false;

if( !result )
throw new Exception( string.Format( "Invalid {0} file. {1}", ofFileType.NameToString(), fileInfo.FullName ) );
}
}

return result;
}

private static bool IsFileTypeRegistered( FileType fileType )
{
return _definedHeaders.ContainsKey( fileType );
}

public static bool IsValidFile( string file, FileType ofFileType )
{
return IsValidFile( new FileInfo( file ), ofFileType );
}
}

Thursday, April 29, 2010

Validate image

When we work with files we use stream. The problem is that you expect a stream of an image/picture but actually you get something else - probably a stream of a renamed 500GB iso file. So it is a good practice to validate and be sure that the file is actually an image/picture before reading the whole file. This is a simple task because each image/picture type has a header with unique value at the beginning if the file. So we will get the first few bytes from our file and compare them with statically defined headers for each image/picture type. These statically defined headers can be googled easily.

        //  Defined image headers.
private static byte[][] _imageHeaders = new byte[][]
{
new byte[]{ 0xFF, 0xD8 }, // .jpg, .jpeg, .jpe, .jfif, .jif
new byte[]{ 0x42, 0x4D}, // .bmp
new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, // .png
new byte[]{ 0x47, 0x49, 0x46 } // .gif
};

/// <summary>
/// Validate that the stream is of an image file.
/// </summary>
/// <remarks>
/// IMPORTANT: The calling code is responsible for creating and disposing the image stream.
/// Supported file types: .JPEG .BMP .GIF .PNG
/// </remarks>
/// <param name="imageStream">The stream of a picture file.</param>
/// <exception cref="Exception">Throws if the stream is of invalid image.</exception>
/// <returns></returns>
public static bool IsValidImage( Stream imageStream )
{
if( imageStream.Length > 0 )
{
byte[] header = new byte[ 8 ]; // Change size if needed.
imageStream.Read( header, 0, header.Length );

bool hasImageHeader = _imageHeaders.Count( magic =>
{
int i = 0;
if( magic.Length > header.Length )
return false;
return magic.Count( b => { return b == header[ i++ ]; } ) == magic.Length;
} ) > 0;

return hasImageHeader;
}

return false;
}

Sunday, November 22, 2009

.NET C# Extension Methods - Reflection

Other extension methods:

---------------------------
I was wondering how to get the name of a property via reflection. So I searched the Internet and I found this on Google code. The code was not good enough though. I was not able to get a string name from level 3 (i.e: User.Name.First). I did a small modifications and ended with this class that works perfect.
    public static class MembersOf
    {
        public static string GetPath(System.Linq.Expressions.Expression> expr)
        {
            var node = expr.Body as System.Linq.Expressions.MemberExpression;
            if (ReferenceEquals(null, node))
                throw new System.InvalidOperationException("Expression must be of member access");

            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            string result = BuildName(node, sb).Remove(0, 1).ToString();
            sb.Clear();

            return result;
        }

        static System.Text.StringBuilder BuildName(System.Linq.Expressions.MemberExpression expr, System.Text.StringBuilder sb)
        {
            if (ReferenceEquals(null, expr) == false)
            {
                sb.Insert(0, expr.Member.Name);
                sb.Insert(0, ".");

                BuildName(expr.Expression as System.Linq.Expressions.MemberExpression, sb);
            }

            return sb;
        }
    }
Now the question is where this code can be handy? I use this when I want to build NHibernate Criteria or DetachedCriteria. When you create a Criteria you use a code like this one:
ICriteria crit = session.CreateCriteria(typeof(Customer));
crit.Add(Expression.Eq("Customer.Name.First", someValue));
Here the Name property is a NHibernate component. The problem is that if you change the property Name to FirstName you will not get a compile error but you will get runtime error when the query is executed against the database. Also you can use some refactoring tool like RefactorPro! and the changes in the component will be applied also in the criteria. Nice, ahh?!? And the code above will be:
ICriteria crit = session.CreateCriteria(typeof(Customer));
crit.Add(Expression.Eq(MembersOf<Customer>.GetPath(x=>x.Name.First), someValue));


Thursday, November 19, 2009

.NET C# Extension Methods - IDictionary

Other extension methods:

---------------------------

Extension method for IDictionary. Returns the values associated with the key specified by parameter key.

        /// <summary>
/// Gets the value of an element within a dictionary object.
/// </summary>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="bag">The actual dictionary.</param>
/// <param name="key">The key that will be searched for within the dictionary object.</param>
/// <param name="defaultValue">Returns default value if the specified key was not found.</param>
/// <returns>Specific value within dictionary object.</returns>
public static TValue GetValue<TValue>( this IDictionary bag, string key, TValue defaultValue )
{
object value = bag[ key ];

if( value == null )
{
value = defaultValue;
}

return defaultValue;
}

Extension method for IDictionary. Adds a key-value pair.

        /// <summary>
/// Adds a (key,value) pair in a dictionary object.
/// </summary>
/// <typeparam name="TKey">The type of keys in the dictionary.</typeparam>
/// <typeparam name="TValue">The type of values in the dictionary.</typeparam>
/// <param name="bag">The actual dictionary.</param>
/// <param name="key">The name of the key used for easy navigation in a dictionary object.</param>
/// <param name="value">The value assoiciated with the key.</param>
public static void SetValue<TKey, TValue>( this IDictionary<TKey,TValue> bag, TKey key, TValue value )
{
if( bag.ContainsKey( key ) )
{
bag[ key ] = value;
}
else
{
bag.Add( key, value );
}
}

.NET C# Extension Methods - DataGridView

Other extension methods:

---------------------------

Extension method for DataGridView. Returns IDictionary with values of all selected rows and columns that are specified by parameter columnName.

        /// <summary>
/// Gets values from selected rows and specified columns.
/// </summary>
/// <param name="grid">The grid.</param>
/// <param name="columnName">Name of the column/s.</param>
/// <returns></returns>
public static IList<IDictionary<string, object>> GetSelectedValuesFrom( this DataGridView grid, params string[] columnName )
{
IList<IDictionary<string,object>> results = new List<IDictionary<string, object>>( grid.SelectedRows.Count );

foreach( DataGridViewRow row in grid.SelectedRows )
{
IDictionary<string,object> rowResult = new Dictionary<string, object>( columnName.Length );

foreach( string column in columnName )
{
rowResult.Add( column, row.Cells[ column ] );
}

results.Add( rowResult );
}

return results;
}

Extension method for DataGridView. Returns a list with values of all selected rows in the columns specified by parameter columnName.

        public static IList<T> GetSelectedValuesFrom<T>( this DataGridView grid, string columnName )
{
IList<T> results = new List<T>( grid.SelectedRows.Count );

foreach( DataGridViewRow row in grid.SelectedRows )
results.Add( GetCurrentValueFrom<T>( grid, columnName ) );

return results;
}

Extension method for DataGridView. Returns a single value of selected row in the columns specified by parameter columnName.

        public static T GetCurrentValueFrom<T>( this DataGridView grid, string columnName )
{
if (grid.CurrentRow != null)
{
return (T)Convert.ChangeType(grid.CurrentRow.Cells[columnName].Value, typeof(T));
}
return (T) Convert.ChangeType(- 1,typeof(T));
}