Jump to content
Larry Ullman's Book Forums

Checking MIME Type


Recommended Posts

Hi, If anyone has some C++ code to check a file's MIME type, I'd really appreciate a copy or a URL to find it.  I am specifically trying to verify that if a file that I am reading (from a Windows file system) has a jpg file suffix, or variants thereof, that the file is indeed of MIME type image/jpeg. The development environment in this instance is Visual Studio 2017.  I have scoured Google and Stack Overflow but haven't come up with anything.

Many thanks in anticipation,

Cheers, Necuima

Link to comment
Share on other sites

I am going around and around in circles trying to create an LPWSTR (wchar_t*) variable in Visual Studio C++ 2017.  MS and Stack Overflow provide lots of examples but I can't get any of them to work!

I THINK that I have all the other variables/parameters set OK for the native C 'FindMimeFromData' function.

I'll keep experimenting! And if I find a solution I will post it.

Link to comment
Share on other sites

I finally found how to create the variable required which was LPWSTR* and now it compiles OK but won't link.  It is more trouble than it is worth but I found one already developed in C# which I might play around with in due course.  The solution in C# is from https://www.codeproject.com/Articles/849083/Determining-File-Type-A-Demonstration-of-Different

For anyone interested, here's the code to get the variables all in the correct format (Visual Studio 2017 C++17 Windows Form):

if (openFileDialog1->ShowDialog() != System::Windows::Forms::DialogResult::Yes)
		{	// weird!!  The negative case is the one that works??
			//save the file name in the text box
			this->txtFileName->Text = openFileDialog1->FileName;
			// see: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/ms775107(v=vs.85)
			// convert the file name to the form that the FindMimeFromData expects
			// fopen expects a C string
			char* InputFileName = (char*)Marshal::StringToHGlobalAnsi(txtFileName->Text).ToPointer();
			
			// now 'looking for'
			String^ managed_looking_for = L"image/jpeg";
			marshal::marshal_context context;	// sets the context - needed - see: https://msdn.microsoft.com/en-us/library/bb384865.aspx
			wchar_t const* c_looking_for = context.marshal_as<wchar_t const*>(managed_looking_for);

			// now 'out'
			String^ managed_out = gcnew String("                                  ");
			LPWSTR* c_out = (LPWSTR*)Marshal::StringToHGlobalUni(managed_out).ToPointer();
						
			char buff[256];
			
			FILE *in = fopen(InputFileName, "rb");
			fread(buff, 1, 256, in);

			FindMimeFromData(NULL, NULL, buff, 256, c_looking_for, FMFD_DEFAULT, c_out, 0);
			printf("%ls\n", c_out);
			
		}
	else
		MessageBox::Show("An error occurred during the file select process - please try again.");
}	// end file select button clicked

Just FYI the linker errors are:

unresolved token (0A000B0F) "extern "C" long __stdcall FindMimeFromData(struct IBindCtx *,wchar_t const *,void *,unsigned long,wchar_t const *,unsigned long,wchar_t * *,unsigned long)" (?FindMimeFromData@@$$J232YGJPAUIBindCtx@@PB_WPAXK1KPAPA_WK@Z) referenced in function "private: void __clrcall TestFileType::MyForm::btnSelectFile_Click(class System::Object ^,class System::EventArgs ^)" (?btnSelectFile_Click@MyForm@TestFileType@@$$FA$AAMXP$AAVObject@System@@P$AAVEventArgs@4@@Z)

I do not intend to spend any more time on this at the moment!

Cheers from Oz.

 

 

Link to comment
Share on other sites

  • 1 month later...

But I did spend some more time on it!  I leveraged the class library kindly provided by Ed Gadziemski (https://www.codeproject.com/Articles/849083/Determining-File-Type-A-Demonstration-of-Different) and developed a small C# UI front-end in Visual Studio 2017.  I used C# as that is what Ed's class library is written in.

Here's part of the UI/front-end code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using FileTypesLib;

namespace ReadFile
{
    public partial class ReadFileCS : Form
    {
        FileTypes fileTypes = new FileTypes();

        public ReadFileCS()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void btnSelectFile_Click(object sender, EventArgs e)
        {
            var filePath = string.Empty;
            txtMIMETypeBox.Clear();
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.InitialDirectory = "e:\\pictures";
                openFileDialog.Filter = "image files (*.jpg)|*.jpg|All files (*.*)|*.*";
                openFileDialog.FilterIndex = 2;
                openFileDialog.RestoreDirectory = true;

                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    //Get the path of specified file
                    filePath = openFileDialog.FileName;
                    txtSelected_File.Text = filePath;
                    btnSelectFile.Focus();
                    // get the file's MIME type
                    txtMIMETypeBox.Text = fileTypes.GetMimeType(filePath);
                }   // end dialog box opened OK
            }   // end using (OpenFileDialog openFileDialog = new OpenFileDialog())

        }   // end private void btnSelectFile_Click(object sender, EventArgs e)

        private void btnExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

    }   // end public partial class ReadFileCS : Form
}   // end namespace ReadFile

It may be of interest to someone!

Season's Greetings from Oz.

Link to comment
Share on other sites

Hi Larry,

Now have it working with a Visual Studio 2017 C++ front-end using the same C sharp DLL.  It is very similar.

The changes are:

using namespace FileTypesLib; 

FileTypes^ fileTypes = gcnew FileTypes();

if (openFileDialog1->ShowDialog() != System::Windows::Forms::DialogResult::Yes)

{ // weird!! The negative case is the one that works??

String^ theFileName = openFileDialog1->FileName;

// save the file name in the text box

this->txtSelectedFile->Text = theFileName;

// get the MIME type and save it in the form text box

txtMIMEType->Text = fileTypes->GetMimeType(theFileName);

}

Again, it may be of interest to someone.

Cheers

Link to comment
Share on other sites

  • 3 weeks later...

Here's some C++ to check if a file is of MIME type 'image/jpeg'.

private: String^ GetMimeType(String^ FileName)
		{
			// MessageBox::Show("GetMimeType called with " + FileName);
			const unsigned short JPG_SIGNATURE_LENGTH = 3;
			char jpg_signature[JPG_SIGNATURE_LENGTH] = { 255, 216, 255 };	// an array of chars with the 'signature' for jpg files
			char buff[12];	// create a buffer for the first 12 bytes of the file
			// convert managed string FileName to a standard string
			// ifstream expects a pointer to a C string (array) of chars
			char* InputFileName = (char*)Marshal::StringToHGlobalAnsi(FileName).ToPointer();
			std::ifstream fileInput(InputFileName, std::ios::binary);	// opens the file as a binary file
			if (fileInput.is_open())
				{
					// MessageBox::Show("fileInput is open for " + FileName);
					fileInput.read(reinterpret_cast<char *>(&buff), sizeof(buff));	// read the first 12 bytes of the binary input file
					// now compare the first three bytes
					for (int i = 0; i < JPG_SIGNATURE_LENGTH; i++)
						{
							if (jpg_signature[i] != buff[i])
								{
									fileInput.close();
									return "Not jpeg";	// this will break the for loop and exit the method
								}
						}	// end for loop
					// the first 3 bytes matched the 'signature' for a jpeg file
					fileInput.close();
					return "image/jpeg";
				}
			else
				{
					MessageBox::Show("fileInput open failed for " + FileName);
				}
		
		}	// end GetMimeType

This is a combination of Visual Studio managed C++ and standard C++. The path of the file is passed to the method.  It may be of interest to someone.

Cheers from Oz.

Link to comment
Share on other sites

  • 2 weeks later...

To avoid compiler warnings change the following:

Change 'char jpg_signature' to 'unsigned char jpg_signature' and 'char buff[12]' to 'unsigned char buff[12]'.

Tested and still works correctly.

The method should probably be named 'checkMimeType'.

Cheers

Link to comment
Share on other sites

 Share

×
×
  • Create New...