Necuima Posted October 17, 2018 Share Posted October 17, 2018 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 More sharing options...
Necuima Posted October 18, 2018 Author Share Posted October 18, 2018 Hi Larry, I have found a function 'FindMimeFromData' and will see if I can figure out how to use it. Will let you know how I get on. Cheers, Necuima Link to comment Share on other sites More sharing options...
Larry Posted October 20, 2018 Share Posted October 20, 2018 Awesome. I've never gone down this particular path (I don't think). Link to comment Share on other sites More sharing options...
Necuima Posted October 25, 2018 Author Share Posted October 25, 2018 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 More sharing options...
Necuima Posted November 1, 2018 Author Share Posted November 1, 2018 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 More sharing options...
Necuima Posted December 17, 2018 Author Share Posted December 17, 2018 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 More sharing options...
Larry Posted December 17, 2018 Share Posted December 17, 2018 Thanks for sharing that! Link to comment Share on other sites More sharing options...
Necuima Posted December 18, 2018 Author Share Posted December 18, 2018 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 More sharing options...
Necuima Posted January 9, 2019 Author Share Posted January 9, 2019 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 More sharing options...
Necuima Posted January 23, 2019 Author Share Posted January 23, 2019 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 More sharing options...
Recommended Posts