Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/class/Managed.Windows.Forms/System.Windows.Forms/Mime.cs')
-rw-r--r--mcs/class/Managed.Windows.Forms/System.Windows.Forms/Mime.cs823
1 files changed, 823 insertions, 0 deletions
diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Mime.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Mime.cs
new file mode 100644
index 00000000000..d7ecc084726
--- /dev/null
+++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/Mime.cs
@@ -0,0 +1,823 @@
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
+//
+// Authors:
+//
+// Alexander Olk xenomorph2@onlinehome.de
+//
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Text.RegularExpressions;
+using System.Text;
+
+// Usage:
+// - for files:
+// string mimeType = Mime.GetMimeTypeForFile( string filename );
+// - for byte array:
+// string mimeType = Mime.GetMimeTypeForData( byte[] data );
+// - for string (maybe an email):
+// string mimeType = Mime.GetMimeTypeForString( string input );
+
+// - get alias for mime type:
+// string alias = Mime.GetMimeAlias( string mimeType );
+// - get subclass for mime type:
+// string subtype = Mime.GetMimeSubClass( string mimeType );
+// - get all available mime types:
+// string[] available = Mime.AvailableMimeTypes;
+
+// TODO:
+// - optimize
+// - little/big endian stuff for TypeHostXX
+// - async callback ?!?
+// - freedesktop org file extensions can have regular expressions also, resolve them too
+// - sort match collections by magic priority ( higher = first )
+// - MimeGenerated: use indexes to point to mime type name strings instead of repeating the name string each time (in match, subclass, etc.) !?!
+// - buffer is currently hard coded to size 8192, value should be determined by MimeGenerated
+
+namespace System.Windows.Forms
+{
+ internal class Mime
+ {
+ public static Mime Instance = new Mime();
+
+ private string current_file_name;
+ private string global_result = octet_stream;
+
+ private FileStream file_stream;
+
+ private byte[] buffer = new byte[ 8192 ];
+
+ private const string octet_stream = "application/octet-stream";
+ private const string text_plain = "text/plain";
+ private const string zero_file = "application/x-zerosize";
+
+ private StringDictionary mime_file_cache = new StringDictionary();
+
+ private const int mime_file_cache_max_size = 5000;
+
+ private string search_string;
+
+ private static object lock_object = new Object();
+
+ private int platform = (int) Environment.OSVersion.Platform;
+
+ private bool is_zero_file = false;
+
+ public Mime( )
+ {
+ MimeGenerated.Init( );
+
+// Console.WriteLine( "Mime Instance created..." );
+ }
+
+ public static string GetMimeTypeForFile( string filename )
+ {
+ lock ( lock_object )
+ {
+ Instance.StartByFileName( filename );
+ }
+
+ return Instance.global_result;
+ }
+
+ // not tested
+ public static string GetMimeTypeForData( byte[] data )
+ {
+ lock ( lock_object )
+ {
+ Instance.StartDataLookup( data );
+ }
+
+ return Instance.global_result;
+ }
+
+ public static string GetMimeTypeForString( string input )
+ {
+ lock ( lock_object )
+ {
+ Instance.StartStringLookup( input );
+ }
+
+ return Instance.global_result;
+ }
+
+ public static string GetMimeAlias( string mimetype )
+ {
+ return MimeGenerated.Aliases[ mimetype ];
+ }
+
+ public static string GetMimeSubClass( string mimetype )
+ {
+ return MimeGenerated.SubClasses[ mimetype ];
+ }
+
+ public static string[] AvailableMimeTypes
+ {
+ get {
+ string[] result = new string[ MimeGenerated.MimeTypes.Count ];
+
+ MimeGenerated.MimeTypes.Keys.CopyTo( result, 0 );
+
+ return result;
+ }
+ }
+
+ private void StartByFileName( string filename )
+ {
+ if ( mime_file_cache.ContainsKey( filename ) )
+ {
+ global_result = mime_file_cache[ filename ];
+ return;
+ }
+
+ current_file_name = filename;
+ is_zero_file = false;
+
+// if ( !CheckForInode( ) )
+// {
+ global_result = octet_stream;
+
+ GoByFileName( );
+// }
+
+ if ( !mime_file_cache.ContainsKey( current_file_name ) )
+ mime_file_cache.Add( current_file_name, global_result );
+
+ // not tested
+ if ( mime_file_cache.Count > mime_file_cache_max_size )
+ {
+ IEnumerator enumerator = mime_file_cache.GetEnumerator( );
+
+ for ( int i = 0; i < mime_file_cache_max_size - 1000; i++ )
+ {
+ mime_file_cache.Remove( enumerator.Current.ToString( ) );
+ }
+ }
+ }
+
+ private void StartDataLookup( byte[] data )
+ {
+ global_result = octet_stream;
+
+ System.Array.Clear( buffer, 0, buffer.Length );
+
+ if ( data.Length > buffer.Length )
+ {
+ System.Array.Copy( data, buffer, buffer.Length );
+ }
+ else
+ {
+ System.Array.Copy( data, buffer, data.Length );
+ }
+
+ if ( CheckMatch80Plus( ) )
+ return;
+
+ if ( CheckMatchBelow80( ) )
+ return;
+
+ CheckForBinaryOrText( );
+ }
+
+ private void StartStringLookup( string input )
+ {
+ global_result = text_plain;
+
+ search_string = input;
+
+ if ( CheckForContentTypeString( ) )
+ return;
+ }
+
+// private bool CheckForInode( )
+// {
+// if ( ( platform == 4 ) || ( platform == 128 ) )
+// {
+//#if __MonoCS__
+// try
+// {
+// // *nix platform
+// Mono.Unix.UnixFileInfo ufi = new Mono.Unix.UnixFileInfo( current_file_name );
+//
+// if ( ufi.IsFile )
+// {
+// return false;
+// }
+// else
+// if ( ufi.IsDirectory )
+// {
+// global_result = "inode/directory";
+// return true;
+// }
+// else
+// if ( ufi.IsBlockDevice )
+// {
+// global_result = "inode/blockdevice";
+// return true;
+// }
+// else
+// if ( ufi.IsSocket )
+// {
+// global_result = "inode/socket";
+// return true;
+// }
+// else
+// if ( ufi.IsSymbolicLink )
+// {
+// global_result = "inode/symlink";
+// return true;
+// }
+// else
+// if ( ufi.IsCharacterDevice )
+// {
+// global_result = "inode/chardevice";
+// return true;
+// }
+// else
+// if ( ufi.IsFIFO )
+// {
+// global_result = "inode/fifo";
+// return true;
+// }
+// } catch( Exception e )
+// {
+// return false;
+// }
+//#endif
+// }
+// else
+// {
+// // TODO!!!!
+// // windows platform
+// }
+//
+// return false;
+// }
+
+ private void GoByFileName( )
+ {
+ // check if we can open the file
+ if ( !OpenFile( ) )
+ {
+ // couldn't open the file, check globals only
+
+ CheckGlobalPatterns( );
+
+ return;
+ }
+
+ if ( !is_zero_file )
+ {
+ // check for matches with a priority >= 80
+ if ( CheckMatch80Plus( ) )
+ return;
+ }
+
+ // check global patterns, aka file extensions...
+ // this should be done for zero size files also,
+ // for example zero size file trash.ccc~ should return
+ // application/x-trash instead of application/x-zerosize
+ if ( CheckGlobalPatterns( ) )
+ return;
+
+ // if file size is zero, no other checks are needed
+ if ( is_zero_file )
+ return;
+
+ // ok, still nothing matches then try matches with a priority < 80
+ if ( CheckMatchBelow80( ) )
+ return;
+
+ // wow, still nothing... return application/octet-stream for binary data, or text/plain for textual data
+ CheckForBinaryOrText( );
+ }
+
+ private bool CheckMatch80Plus( )
+ {
+ foreach ( Match match in MimeGenerated.Matches80Plus )
+ {
+ if ( TestMatch( match ) )
+ {
+ global_result = match.MimeType;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void CheckGlobalResult( )
+ {
+ int comma_index = global_result.IndexOf( "," );
+
+ if ( comma_index != -1 )
+ {
+ global_result = global_result.Substring( 0, comma_index );
+ }
+ }
+
+ private bool CheckGlobalPatterns( )
+ {
+ string filename = Path.GetFileName( current_file_name );
+ string filename_lower = filename.ToLower( );
+
+ // first check for literals
+
+ for ( int i = 0; i < MimeGenerated.GlobalLiterals.Count; i++ )
+ {
+ string key = MimeGenerated.GlobalLiterals.GetKey( i );
+
+ // no regex char
+ if ( key.IndexOf( '[' ) == -1 )
+ {
+ if ( key.Equals( filename ) )
+ {
+ global_result = MimeGenerated.GlobalLiterals[ i ];
+ CheckGlobalResult( );
+ return true;
+ }
+ }
+ else // regex it ;)
+ {
+ if ( Regex.IsMatch( filename, key ) )
+ {
+ global_result = MimeGenerated.GlobalLiterals[ i ];
+ CheckGlobalResult( );
+ return true;
+ }
+ }
+ }
+
+ if ( filename.IndexOf( '.' ) != -1 )
+ {
+ // check for double extension like .tar.gz
+
+ for ( int i = 0; i < MimeGenerated.GlobalPatternsLong.Count; i++ )
+ {
+ string key = MimeGenerated.GlobalPatternsLong.GetKey( i );
+
+ if ( filename.EndsWith( key ) )
+ {
+ global_result = MimeGenerated.GlobalPatternsLong[ i ];
+ CheckGlobalResult( );
+ return true;
+ }
+ else
+ {
+ if ( filename_lower.EndsWith( key ) )
+ {
+ global_result = MimeGenerated.GlobalPatternsLong[ i ];
+ CheckGlobalResult( );
+ return true;
+ }
+ }
+ }
+
+ // check normal extensions...
+
+ string extension = Path.GetExtension( current_file_name );
+
+ if ( extension.Length != 0 )
+ {
+ global_result = MimeGenerated.GlobalPatternsShort[ extension ];
+
+ if ( global_result != null )
+ {
+ CheckGlobalResult( );
+ return true;
+ }
+
+ string extension_lower = extension.ToLower( );
+
+ global_result = MimeGenerated.GlobalPatternsShort[ extension_lower ];
+
+ if ( global_result != null )
+ {
+ CheckGlobalResult( );
+ return true;
+ }
+ }
+ }
+
+ // finally check if a prefix or suffix matches
+
+ for ( int i = 0; i < MimeGenerated.GlobalSufPref.Count; i++ )
+ {
+ string key = MimeGenerated.GlobalSufPref.GetKey( i );
+
+ if ( key.StartsWith( "*" ) )
+ {
+ if ( filename.EndsWith( key.Replace( "*", "" ) ) )
+ {
+ global_result = MimeGenerated.GlobalSufPref[ i ];
+ CheckGlobalResult( );
+ return true;
+ }
+ }
+ else
+ {
+ if ( filename.StartsWith( key.Replace( "*", "" ) ) )
+ {
+ global_result = MimeGenerated.GlobalSufPref[ i ];
+ CheckGlobalResult( );
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private bool CheckMatchBelow80( )
+ {
+ foreach ( Match match in MimeGenerated.MatchesBelow80 )
+ {
+ if ( TestMatch( match ) )
+ {
+ global_result = match.MimeType;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private void CheckForBinaryOrText( )
+ {
+ // check the first 32 bytes
+
+ for ( int i = 0; i < 32; i++ )
+ {
+ char c = System.Convert.ToChar( buffer[ i ] );
+
+ if ( c != '\t' && c != '\n' && c != '\r' && c != 12 && c < 32 )
+ {
+ global_result = octet_stream;
+ return;
+ }
+ }
+
+ global_result = text_plain;
+ }
+
+ private bool TestMatch( Match match )
+ {
+ bool found = false;
+
+ // using a simple brute force search algorithm
+ // compare each (masked) value from the buffer with the (masked) value from the match
+ // TODO:
+ // - to find some more speed, maybe we should use unsafe code
+ // - check if buffer[0] and buffer[lastmatchbyte] match ByteValue[0] and ByteValue[lastmatchbyte] in a match
+
+ for ( int offset_counter = 0; offset_counter < match.OffsetLength; offset_counter++ )
+ {
+ if ( match.Mask == null )
+ {
+ if ( buffer[ match.Offset + offset_counter ] == match.ByteValue[ 0 ] )
+ {
+ if ( match.ByteValue.Length == 1 )
+ {
+ if ( match.Matches.Count > 0 )
+ {
+ foreach ( Match sub_match in match.Matches )
+ {
+ if ( TestMatch( sub_match ) )
+ return true;
+ }
+ }
+ else
+ return true;
+ }
+
+ for ( int i = 1; i < match.ByteValue.Length; i++ )
+ {
+ if ( buffer[ match.Offset + offset_counter + i ] != match.ByteValue[ i ] )
+ {
+ found = false;
+ break;
+ }
+
+ found = true;
+ }
+
+ if ( found )
+ {
+ found = false;
+
+ if ( match.Matches.Count > 0 )
+ {
+ foreach ( Match sub_match in match.Matches )
+ {
+ if ( TestMatch( sub_match ) )
+ return true;
+ }
+ }
+ else
+ return true;
+ }
+ }
+ }
+ else // with mask ( it's the same as above, only AND the byte with the corresponding mask byte
+ {
+ if ( ( buffer[ match.Offset + offset_counter ] & match.Mask[ 0 ] ) ==
+ ( match.ByteValue[ 0 ] & match.Mask[ 0 ] ) )
+ {
+ if ( match.ByteValue.Length == 1 )
+ {
+ if ( match.Matches.Count > 0 )
+ {
+ foreach ( Match sub_match in match.Matches )
+ {
+ if ( TestMatch( sub_match ) )
+ return true;
+ }
+ }
+ else
+ return true;
+ }
+
+ for ( int i = 1; i < match.ByteValue.Length; i++ )
+ {
+ if ( ( buffer[ match.Offset + offset_counter + i ] & match.Mask[ i ] ) !=
+ ( match.ByteValue[ i ] & match.Mask[ i ] ) )
+ {
+ found = false;
+ break;
+ }
+
+ found = true;
+ }
+
+ if ( found )
+ {
+ found = false;
+
+ if ( match.Matches.Count > 0 )
+ {
+ foreach ( Match sub_match in match.Matches )
+ {
+ if ( TestMatch( sub_match ) )
+ return true;
+ }
+ }
+ else
+ return true;
+ }
+ }
+ }
+ }
+
+ return found;
+ }
+
+ private bool OpenFile( )
+ {
+ try
+ {
+ System.Array.Clear( buffer, 0, buffer.Length );
+
+ file_stream = new FileStream( current_file_name, FileMode.Open, FileAccess.Read ); // FileShare ??? use BinaryReader ???
+
+ if ( file_stream.Length == 0 )
+ {
+ global_result = zero_file;
+ is_zero_file = true;
+ }
+ else
+ {
+ file_stream.Read( buffer, 0, buffer.Length );
+ }
+
+ file_stream.Close( );
+ }
+ catch (Exception e)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ private bool CheckForContentTypeString( )
+ {
+ int index = search_string.IndexOf( "Content-type:" );
+
+ if ( index != -1 )
+ {
+ index += 13; // Length of string "Content-type:"
+
+ global_result = "";
+
+ while ( search_string[ index ] != ';' )
+ {
+ global_result += search_string[ index++ ];
+ }
+
+ global_result.Trim( );
+
+ return true;
+ }
+
+ // convert string to byte array
+ byte[] string_byte = ( new ASCIIEncoding( ) ).GetBytes( search_string );
+
+ System.Array.Clear( buffer, 0, buffer.Length );
+
+ if ( string_byte.Length > buffer.Length )
+ {
+ System.Array.Copy( string_byte, buffer, buffer.Length );
+ }
+ else
+ {
+ System.Array.Copy( string_byte, buffer, string_byte.Length );
+ }
+
+ if ( CheckMatch80Plus( ) )
+ return true;
+
+ if ( CheckMatchBelow80( ) )
+ return true;
+
+ return false;
+ }
+ }
+
+ internal class MimeType
+ {
+ private string comment;
+ private Hashtable commentsLanguage = new Hashtable();
+
+ public string Comment
+ {
+ get {
+ return comment;
+ }
+ set {
+ comment = value;
+ }
+ }
+
+ public Hashtable CommentsLanguage
+ {
+ get {
+ return commentsLanguage;
+ }
+ set {
+ commentsLanguage = value;
+ }
+ }
+ public string GetCommentForLanguage( string language )
+ {
+ return commentsLanguage[ language ] as string;
+ }
+ }
+
+ internal enum MatchTypes
+ {
+ TypeString,
+ TypeHost16,
+ TypeHost32,
+ TypeBig16,
+ TypeBig32,
+ TypeLittle16,
+ TypeLittle32,
+ TypeByte
+ }
+
+ internal class Match
+ {
+ string mimeType;
+ byte[] byteValue;
+ byte[] mask = null;
+ int priority;
+ int offset;
+ int offsetLength;
+ int wordSize = 1;
+ MatchTypes matchType;
+ ArrayList matches = new ArrayList();
+
+ public string MimeType
+ {
+ set {
+ mimeType = value;
+ }
+
+ get {
+ return mimeType;
+ }
+ }
+
+ public byte[] ByteValue
+ {
+ set {
+ byteValue = value;
+ }
+
+ get {
+ return byteValue;
+ }
+ }
+
+ public byte[] Mask
+ {
+ set {
+ mask = value;
+ }
+
+ get {
+ return mask;
+ }
+ }
+
+ public int Priority
+ {
+ set {
+ priority = value;
+ }
+
+ get {
+ return priority;
+ }
+ }
+
+ public ArrayList Matches
+ {
+ set {
+ matches = value;
+ }
+
+ get {
+ return matches;
+ }
+ }
+
+ public int Offset
+ {
+ set {
+ offset = value;
+ }
+
+ get {
+ return offset;
+ }
+ }
+
+ public int OffsetLength
+ {
+ set {
+ offsetLength = value;
+ }
+
+ get {
+ return offsetLength;
+ }
+ }
+
+ public int WordSize
+ {
+ set {
+ wordSize = value;
+ }
+
+ get {
+ return wordSize;
+ }
+ }
+
+ public MatchTypes MatchType
+ {
+ set {
+ matchType = value;
+ }
+
+ get {
+ return matchType;
+ }
+ }
+ }
+}
+