File: Core\CSharp\System\Windows\DataFormats.cs
Project: wpf\src\PresentationCore.csproj (PresentationCore)
//---------------------------------------------------------------------------
//
// <copyright file=DataFormats.cs company=Microsoft>
// Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Description: Manage the data formats.
//
// See spec at http://avalon/uis/Data%20Transfer%20clipboard%20dragdrop/Avalon%20Data%20Transfer%20Object.htm
//
// History:
//  04/26/2002 : susiA      Created
//  06/04/2003 : sangilj    Moved to WCP
//
//---------------------------------------------------------------------------
 
using MS.Win32;
using System.Collections;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using MS.Internal.PresentationCore;
using SecurityHelper=MS.Internal.SecurityHelper;
 
namespace System.Windows
{
    #region DataFormats class
 
    /// <summary>
    /// Translates between Windows Design text-based formats and
    /// 32-bit signed integer-based clipboard formats.
    /// </summary>
    public static class DataFormats
    {
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------
 
        #region Public Methods
 
        /// <summary>
        /// Gets an object with the Windows Clipboard numeric
        /// ID and name for the specified ID.
        /// </summary>
        public static DataFormat GetDataFormat(int id)
        {
            return InternalGetDataFormat(id);
        }
 
        /// <summary>
        /// Gets the data format with the Windows Clipboard numeric ID and name for the specified data format.
        /// </summary>
        /// <remarks>
        ///     Callers must have UnmanagedCode permission to call this API.
        /// </remarks>
        ///<SecurityNote>
        ///  Critical:Calls UnsafeNativeMethods.RegisterClipboardFormat which uses [SuppressUnmanagedCodeSecurity]
        ///  PublicOK:So we demand unmanaged code before calling.
        ///</SecurityNote>
        [SecurityCritical]
        public static DataFormat GetDataFormat(string format)
        {
            
            if (format == null)
            {
                throw new ArgumentNullException("format");
            }
 
            if (format == string.Empty)
            {
                throw new ArgumentException(SR.Get(SRID.DataObject_EmptyFormatNotAllowed));
            }
 
            // Ensures the predefined Win32 data formats into our format list.
            EnsurePredefined();
 
            // Lock the data format list to obtains the mutual-exclusion.
            lock (_formatListlock)
            {
                int formatId;
                int index;
 
                // It is much faster to do a case sensitive search here.  So do
                // the case sensitive compare first, then the expensive one.
                //
                for (int n = 0; n < _formatList.Count; n++)
                {
                    DataFormat formatItem;
 
                    formatItem = (DataFormat)_formatList[n];
 
                    if (formatItem.Name.Equals(format))
                    {
                        return formatItem;
                    }
                }
 
                for (int n = 0; n < _formatList.Count; n++)
                {
                    DataFormat formatItem;
 
                    formatItem = (DataFormat)_formatList[n];
 
                    if (String.Compare(formatItem.Name, format, StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return formatItem;
                    }
                }
 
                // In the most cases the default formats return earlier. If we got here
                // then this is an attempt to register a new format which is not ok in partial trust.
                SecurityHelper.DemandUnmanagedCode();
                // Reigster the this format string.
                formatId = UnsafeNativeMethods.RegisterClipboardFormat(format);
 
                if (formatId == 0)
                {
                    throw new System.ComponentModel.Win32Exception();
                }
 
                index = _formatList.Add(new DataFormat(format, formatId));
 
                return (DataFormat)_formatList[index];
            }
        }
 
        #endregion Public Methods
 
        //------------------------------------------------------
        //
        //  Public Fields
        //
        //------------------------------------------------------
 
        #region Public Fields
 
        /// <summary>
        /// Specifies the standard ANSI text format. This field is read-only.
        /// </summary>
        public static readonly string Text = "Text";
 
        /// <summary>
        /// Specifies the standard Windows Unicode text format. This
        /// field is read-only.
        /// </summary>
        public static readonly string UnicodeText = "UnicodeText";
 
        /// <summary>
        /// Specifies the Windows Device Independent Bitmap (DIB)
        /// format. This field is read-only.
        /// </summary>
        public static readonly string Dib = "DeviceIndependentBitmap";
 
        /// <summary>
        /// Specifies a Windows bitmap format. This field is read-only.
        /// </summary>
        public static readonly string Bitmap = "Bitmap";
 
        /// <summary>
        /// Specifies the Windows enhanced metafile format. This
        /// field is read-only.
        /// </summary>
        public static readonly string EnhancedMetafile = "EnhancedMetafile";
 
        /// <summary>
        /// Specifies the Windows metafile format. This field is read-only.
        /// </summary>
        public static readonly string MetafilePicture = "MetaFilePict";
 
        /// <summary>
        /// Specifies the Windows symbolic link format. This
        /// field is read-only.
        /// </summary>
        public static readonly string SymbolicLink = "SymbolicLink";
 
        /// <summary>
        /// Specifies the Windows data interchange format. This
        /// field is read-only.
        /// </summary>
        public static readonly string Dif = "DataInterchangeFormat";
 
        /// <summary>
        /// Specifies the Tagged Image File Format (TIFF). This
        /// field is read-only.
        /// </summary>
        public static readonly string Tiff = "TaggedImageFileFormat";
 
        /// <summary>
        /// Specifies the standard Windows original equipment
        /// manufacturer (OEM) text format. This field is read-only.
        /// </summary>
        public static readonly string OemText = "OEMText";
 
        /// <summary>
        /// Specifies the Windows palette format. This
        /// field is read-only.
        /// </summary>
        public static readonly string Palette = "Palette";
 
        /// <summary>
        /// Specifies the Windows pen data format, which consists of
        /// pen strokes for handwriting software; This field is read-only.
        /// </summary>
        public static readonly string PenData = "PenData";
 
        /// <summary>
        /// Specifies the Resource Interchange File Format (RIFF)
        /// audio format. This field is read-only.
        /// </summary>
        public static readonly string Riff = "RiffAudio";
 
        /// <summary>
        /// Specifies the wave audio format, which Windows Design does not
        /// directly use. This field is read-only.
        /// </summary>
        public static readonly string WaveAudio = "WaveAudio";
 
        /// <summary>
        /// Specifies the Windows file drop format, which Windows Design
        /// does not directly use. This field is read-only.
        /// </summary>
        public static readonly string FileDrop = "FileDrop";
 
        /// <summary>
        /// Specifies the Windows culture format, which Windows Design does
        /// not directly use. This field is read-only.
        /// </summary>
        public static readonly string Locale = "Locale";
 
        /// <summary>
        /// Specifies text consisting of HTML data. This
        /// field is read-only.
        /// </summary>
        public static readonly string Html = "HTML Format";
 
        /// <summary>
        /// Specifies text consisting of Rich Text Format (RTF) data. This
        /// field is read-only.
        /// </summary>
        public static readonly string Rtf = "Rich Text Format";
 
        /// <summary>
        /// Specifies a comma-separated value (CSV) format, which is a
        /// common interchange format used by spreadsheets. This format is not used directly
        /// by Windows Design. This field is read-only.
        /// </summary>
        public static readonly string CommaSeparatedValue = "CSV";
 
        /// <summary>
        /// Specifies the Windows Design string class format, which Win
        /// Forms uses to store string objects. This
        /// field is read-only.
        /// </summary>
        public static readonly string StringFormat = typeof(string).FullName;
 
        /// <summary>
        /// Specifies a format that encapsulates any type of Windows Design
        /// object. This field is read-only.
        /// </summary>
        public static readonly string Serializable = "PersistentObject";
 
        // ToDo(sangilj):  Need application's version information on Serializable format string.
 
        /// <summary>
        /// Specifies a data format as Xaml. This field is read-only.
        /// </summary>
        public static readonly string Xaml = "Xaml";
 
        /// <summary>
        /// Specifies a data format as Xaml Package. This field is read-only.
        /// </summary>
        public static readonly string XamlPackage = "XamlPackage";
        #endregion Public Fields
 
        //------------------------------------------------------
        //
        //  Internal Fields
        //
        //------------------------------------------------------
 
        #region Internal Fields
        /// <summary>
        /// Specifies a data format as ApplicationTrust which is used to block
        /// paste from partial trust to full trust applications. The intent of this 
        /// format is to store the permission set of the source application where the content came from.
        /// This is then compared at paste time
        /// </summary>
        internal static readonly string ApplicationTrust = "ApplicationTrust";
 
        internal static readonly string FileName = "FileName";
        internal static readonly string FileNameW = "FileNameW";
        
        #endregion  Internal Fields
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        /// <summary>
        /// Convert TextDataFormat to Dataformats.
        /// </summary>
        internal static string ConvertToDataFormats(TextDataFormat textDataformat)
        {
            string dataFormat = DataFormats.UnicodeText;
 
            switch (textDataformat)
            {
                case TextDataFormat.Text:
                    dataFormat = DataFormats.Text;
                    break;
 
                case TextDataFormat.UnicodeText:
                    dataFormat = DataFormats.UnicodeText;
                    break;
 
                case TextDataFormat.Rtf:
                    dataFormat = DataFormats.Rtf;
                    break;
 
                case TextDataFormat.Html:
                    dataFormat = DataFormats.Html;
                    break;
 
                case TextDataFormat.CommaSeparatedValue:
                    dataFormat = DataFormats.CommaSeparatedValue;
                    break;
 
                case TextDataFormat.Xaml:
                    dataFormat = DataFormats.Xaml;
                    break;
            }
 
            return dataFormat;
        }
 
        /// <summary>
        /// Validate the text data format.
        /// </summary>
        internal static bool IsValidTextDataFormat(TextDataFormat textDataFormat)
        {
            if (textDataFormat == TextDataFormat.Text ||
                textDataFormat == TextDataFormat.UnicodeText ||
                textDataFormat == TextDataFormat.Rtf ||
                textDataFormat == TextDataFormat.Html ||
                textDataFormat == TextDataFormat.CommaSeparatedValue ||
                textDataFormat == TextDataFormat.Xaml)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
 
        #endregion Internal Methods
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        /// <summary>
        /// Allows a the new format name to be specified if the requested format is not
        /// in the list
        /// </summary>
        /// <SecurityNote>
        /// Critical - Calls UnsafeNativeMethods.GetClipboardFormatName() which is a P/Invoke method.
        /// Safe     - The StringBuilder object is constructed internally so we are not passing 
        ///            GetClipboardFormatName() a possibly malicious object.
        /// </SecurityNote>
        [SecuritySafeCritical]
        private static DataFormat InternalGetDataFormat(int id)
        {
            // Ensures the predefined Win32 data formats into our format list.
            EnsurePredefined();
 
            // Lock the data format list to obtains the mutual-exclusion.
            lock (_formatListlock)
            {
                DataFormat formatItem;
                StringBuilder sb;
                int index;
 
                for (int n = 0; n < _formatList.Count; n++)
                {
                    formatItem = (DataFormat)_formatList[n];
 
                    // OLE FORMATETC defined CLIPFORMAT as the unsigned short, so we should ignore
                    // high 2bytes to find the matched CLIPFORMAT ID. (Reference bug#1026539)
                    if ((formatItem.Id & 0x0000ffff) == (id & 0x0000ffff))
                    {
                        return formatItem;
                    }
                }
 
                sb = new StringBuilder(NativeMethods.MAX_PATH);
 
                // This can happen if windows adds a standard format that we don't know about,
                // so we should play it safe.
                if (UnsafeNativeMethods.GetClipboardFormatName(id, sb, sb.Capacity) == 0)
                {
                    sb.Length = 0;
                    sb.Append("Format").Append(id);
                }
 
                index = _formatList.Add(new DataFormat(sb.ToString(), id));
 
                return (DataFormat)_formatList[index];
            }
        }
 
        /// <summary>
        /// Ensures that the Win32 predefined formats are setup in our format list.  This
        /// is called anytime we need to search the list
        /// </summary>
        /// <SecurityNote>
        ///     Critical: Invokes UnsafeNativeMethods.RegisterClipboardFormat for the Ink Serialized Format
        ///     TreatAsSafe: This method will be invoked by the transparent callers. The method doesn't take 
        ///                  any user's input and won't be called from any arbitrary code externally either.
        ///                  It only builds up an internal format table which is safe all the time.                  
        /// </SecurityNote>
        [SecurityCritical, SecurityTreatAsSafe]
        private static void EnsurePredefined()
        {
            // Lock the data format list to obtains the mutual-exclusion.
            lock (_formatListlock)
            {
                if (_formatList == null)
                {
                    // Create format list for the default formats.
                    _formatList = new ArrayList(19);
 
                    _formatList.Add(new DataFormat(UnicodeText, NativeMethods.CF_UNICODETEXT));
                    _formatList.Add(new DataFormat(Text, NativeMethods.CF_TEXT));
                    _formatList.Add(new DataFormat(Bitmap, NativeMethods.CF_BITMAP));
                    _formatList.Add(new DataFormat(MetafilePicture, NativeMethods.CF_METAFILEPICT));
                    _formatList.Add(new DataFormat(EnhancedMetafile, NativeMethods.CF_ENHMETAFILE));
                    _formatList.Add(new DataFormat(Dif, NativeMethods.CF_DIF));
                    _formatList.Add(new DataFormat(Tiff, NativeMethods.CF_TIFF));
                    _formatList.Add(new DataFormat(OemText, NativeMethods.CF_OEMTEXT));
                    _formatList.Add(new DataFormat(Dib, NativeMethods.CF_DIB));
                    _formatList.Add(new DataFormat(Palette, NativeMethods.CF_PALETTE));
                    _formatList.Add(new DataFormat(PenData, NativeMethods.CF_PENDATA));
                    _formatList.Add(new DataFormat(Riff, NativeMethods.CF_RIFF));
                    _formatList.Add(new DataFormat(WaveAudio, NativeMethods.CF_WAVE));
                    _formatList.Add(new DataFormat(SymbolicLink, NativeMethods.CF_SYLK));
                    _formatList.Add(new DataFormat(FileDrop, NativeMethods.CF_HDROP));
                    _formatList.Add(new DataFormat(Locale, NativeMethods.CF_LOCALE));
                    int xamlFormatId = UnsafeNativeMethods.RegisterClipboardFormat(Xaml);
                    if (xamlFormatId != 0)
                    {
                        _formatList.Add(new DataFormat(Xaml,xamlFormatId));
                    }
 
                    // This is the format to store trust boundary information. Essentially this is accompalished by storing 
                    // the permission set of the source application where the content comes from. During paste we compare this to
                    // the permissio set of the target application.
                    int applicationTrustFormatId = UnsafeNativeMethods.RegisterClipboardFormat(DataFormats.ApplicationTrust);
                    if (applicationTrustFormatId != 0)
                    {
                        _formatList.Add(new DataFormat(ApplicationTrust, applicationTrustFormatId));
                    }
                    // RegisterClipboardFormat returns 0 on failure
                    int inkServicesFrameworkFormatId = UnsafeNativeMethods.RegisterClipboardFormat(System.Windows.Ink.StrokeCollection.InkSerializedFormat);
 
                    if (inkServicesFrameworkFormatId != 0)
                    {
                        _formatList.Add(new DataFormat(System.Windows.Ink.StrokeCollection.InkSerializedFormat,
                                                        inkServicesFrameworkFormatId));
                    }
 
                }
            }
        }
 
        #endregion Private Methods
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Fields
 
        // The registered data format list.
        private static ArrayList _formatList;
 
        // This object is for locking the _formatList to access safe in the multi-thread.
        private static Object _formatListlock = new Object();
 
        #endregion Private Fields
    }
 
    #endregion DataFormats class
}