7

i have a workflow where user is allowed to upload any file and then that file will be read.

Now my question is if user have image file xyz.jpg and he renamed it to xyz only (extension removed) in this can we still get the type/extension of the file using/reading files data/metadata.

Thanks all

Anil Namde
  • 6,452
  • 11
  • 63
  • 100
  • 2
    don't let them upload files with no extension! :) – JohnIdol May 13 '10 at 12:50
  • 1
    possible duplicate of [Using .NET, how can you find the mime type of a file based on the file signature not the extension. ](http://stackoverflow.com/questions/58510/using-net-how-can-you-find-the-mime-type-of-a-file-based-on-the-file-signature) – Mark Byers May 13 '10 at 12:50
  • I agree - files without extensions are of questionable value to a user, what makes them think they would be of any more value to you? This is not expected behavior and should not generate extra complexity on your part. – Sky Sanders May 13 '10 at 13:02

5 Answers5

15

See PInvoke.net for more detail

   [DllImport("urlmon.dll", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = false)]
    static extern int FindMimeFromData(IntPtr pBC,
          [MarshalAs(UnmanagedType.LPWStr)] string pwzUrl,
         [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.I1, SizeParamIndex=3)] 
        byte[] pBuffer,
          int cbSize,
             [MarshalAs(UnmanagedType.LPWStr)]  string pwzMimeProposed,
          int dwMimeFlags,
          out IntPtr ppwzMimeOut,
          int dwReserved);

Sample usage:

  public string MimeTypeFrom(byte[] dataBytes, string mimeProposed) {
   if (dataBytes == null)
     throw new ArgumentNullException("dataBytes");
   string mimeRet = String.Empty;
   IntPtr suggestPtr = IntPtr.Zero, filePtr = IntPtr.Zero, outPtr = IntPtr.Zero;
   if (mimeProposed != null && mimeProposed.Length > 0) {
     //suggestPtr = Marshal.StringToCoTaskMemUni(mimeProposed); // for your experiments ;-)
     mimeRet = mimeProposed;
   }
   int ret = FindMimeFromData(IntPtr.Zero, null, dataBytes, dataBytes.Length, mimeProposed, 0, out outPtr, 0);
   if (ret == 0 && outPtr != IntPtr.Zero) {
    //todo: this leaks memory outPtr must be freed
     return Marshal.PtrToStringUni(outPtr);
   }
   return mimeRet;
}

// call it this way:
Trace.Write("MimeType is " + MimeTypeFrom(Encoding.ASCII.GetBytes("%PDF-"), "text/plain"));

Another example:

/// <summary>
/// Ensures that file exists and retrieves the content type 
/// </summary>
/// <param name="file"></param>
/// <returns>Returns for instance "images/jpeg" </returns>
public static string getMimeFromFile(string file)
{
    IntPtr mimeout;
    if (!System.IO.File.Exists(file))
    throw new FileNotFoundException(file + " not found");

    int MaxContent = (int)new FileInfo(file).Length;
    if (MaxContent > 4096) MaxContent = 4096;
    FileStream fs = File.OpenRead(file);


    byte[] buf = new byte[MaxContent];        
    fs.Read(buf, 0, MaxContent);
    fs.Close();
    int result = FindMimeFromData(IntPtr.Zero, file, buf, MaxContent, null, 0, out mimeout, 0);

    if (result != 0)
    throw Marshal.GetExceptionForHR(result);
    string mime = Marshal.PtrToStringUni(mimeout);
    Marshal.FreeCoTaskMem(mimeout);
    return mime;
}
Sky Sanders
  • 36,396
  • 8
  • 69
  • 90
3

You can use the unmanaged function FindMimeFromData in urlmon.dll.

using System.Runtime.InteropServices;

[DllImport(@"urlmon.dll", CharSet = CharSet.Auto)]
private extern static System.UInt32 FindMimeFromData(
    System.UInt32 pBC,
    [MarshalAs(UnmanagedType.LPStr)] System.String pwzUrl,
    [MarshalAs(UnmanagedType.LPArray)] byte[] pBuffer,
    System.UInt32 cbSize,
    [MarshalAs(UnmanagedType.LPStr)] System.String pwzMimeProposed,
    System.UInt32 dwMimeFlags,
    out System.UInt32 ppwzMimeOut,
    System.UInt32 dwReserverd
);

See here for an example usage.

Community
  • 1
  • 1
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • +1 - very cool, didn't know about that. Do you reckon the ContentType of HttpPostedFile is set by consulting this? Also - found another q with a code sample: http://stackoverflow.com/questions/58510/using-net-how-can-you-find-the-mime-type-of-a-file-based-on-the-file-signature – Andras Zoltan May 13 '10 at 12:54
  • @Andras The content type of the posted file is set arbitrarily by the poster (code, browser, flash etc) and is not to be depended on unless you have a tightly controlled environment. – Sky Sanders May 13 '10 at 12:57
  • I noticed that and promptly undeleted. ;-) and agreed on other point as well. – Sky Sanders May 13 '10 at 13:10
  • That's clever. Sorry for my bad answer! You learn something new every day! – spender May 13 '10 at 13:17
  • @code poet - in my answer (deleted because this and yours, +1 also btw, are superior) I mentioned to the OP that actually ContentType is unreliable. – Andras Zoltan May 13 '10 at 13:21
  • @Andras - you may want to check on that `Server Error in '/blog' Application.`. Looks like someone changed your default trust level. (sorry mark) – Sky Sanders May 13 '10 at 13:48
  • @code poet - thanks! It does this sometimes - then you hit F5 and it's fine. Been really lazy with that site; I develop the craziest stuff at work, and then my own blog is just a non-customized blogengine! – Andras Zoltan May 13 '10 at 20:00
2

Yes, probably for many file types this is possible, but it would require parsing of the binary contents of the file on a case by case basis.

spender
  • 117,338
  • 33
  • 229
  • 351
0

Are there specific file formats you need to detect? It makes the task a lot easier if you can narrow it down to a few formats that can be identified by the contents of the file.

If you need to detect a broad range of file types, there are third party toolkits you can use, but I'll warn you that they tend to be very expensive. The two I am familiar with are Stellent's (now Oracle's) Outside In, and Autonomy Keyview. Both provide programmer toolkits.

JohnFx
  • 34,542
  • 18
  • 104
  • 162
0

If you just need to see if the uploaded file is an Image, just parse it accordingly

try
{
Image image = Bitmap.FromStream(fileData);
}
catch(Exception e)
{
    // this isn't an image.
}
Kurru
  • 14,180
  • 18
  • 64
  • 84