4

Is there a built-in way to get the standard extension of a given MIME type in Delphi (XE7)?

I'm looking for the easiest and most general way to implement a function that would be called like this:

fileExt := GetExtension('text/xml');
Helmut D
  • 630
  • 6
  • 11
  • not that I know of, but a quick google finds this: https://www.thoughtco.com/file-extensions-and-mime-types-3469109 – Tuncay Göncüoğlu Jul 06 '17 at 11:46
  • Thank you for the link, but I hoped for a system function, as the set of MIME types changes over time. For example, in the table you linked, there's no entry for docx (application/vnd.openxmlformats-officedocument.wordprocessingml.document). – Helmut D Jul 06 '17 at 11:51

4 Answers4

5

It seems Indy has a built in function for that, on TIdThreadSafeMimeTable:

Uses
  IdCustomHTTPServer;


function GetMIMETypeDefaultExtension(const aMIMEType: String): String;
var
  mimetable: TIdThreadSafeMimeTable;
Begin
  if not(aMIMEType.Trim.IsEmpty) then
  Begin
    mimetable := TIdThreadSafeMimeTable.Create(true);
    try
      result := mimetable.GetDefaultFileExt(aMIMEType);
    finally
      mimetable.Free;
    end
  End
  else
      result := '';
End;

Edit: function fixed to use TIdThreadSafeMimeTable directly without custom http server.

Tuncay Göncüoğlu
  • 1,699
  • 17
  • 21
  • 1
    You may also use *TIdThreadSafeMimeTable* in the same unit directly (no need to create a server) – mjn42 Jul 06 '17 at 12:35
  • changed the anser to use that class instead, as you suggested. – Tuncay Göncüoğlu Jul 06 '17 at 13:42
  • 2
    `TIdThreadSafeMimeTable` is intended for use with `TIdHTTPServer`, since it is a multi-threaded server whose worker threads frequently require access to cached MIME info. There is a non-threadsafe `TIdMimeTable` in the `IdGlobalProtocols` unit, which also has standalone `GetMIMETypeFromFile()` and `GetMIMEDefaultFileExt()` functions (which use `TIdMimeTable` internally). In the example above, since it is creating and destroying the table every time it is called, using `TIdThreadSafeMimeTable` is overkill, just use `TIdMimeTable` or even `GetMIMEDefaultFileExt()` instead. – Remy Lebeau Jul 06 '17 at 16:52
  • true, but in the function above you'd have to create and destroy the instance anyway, calling buildcache anyway(directly or indirectly), so, you wouldn't gain anything by using the non-threadsafe version. and when thats the case, I'd much rather have a general purpose function that I wont have to worry about if its thread-safe or not. – Tuncay Göncüoğlu Jul 07 '17 at 10:25
5

Indy's IndyProtocols package has a TIdMimeTable class and standalone GetMIMETypeFromFile() and GetMIMEDefaultFileExt() wrapper functions in the IdGlobalProtocols unit, eg:

uses
  ..., IdGlobalProtocols;

function GetExtension(const AMIMEType: string);
begin
  Result := GetMIMEDefaultFileExt(AMIMEType);
end

Just know that internally, GetMIMEDefaultFileExt() creates and destroys a TIdMimeTable object, and that object re-builds its list of known extensions and MIME types every time it is created. If you are going to be querying MIME extensions frequently, it would be worth creating your own TIdMimeTable object (or TIdThreadSafeMimeTable if you need to share the table across multiple threads) and reuse it each time:

uses
  ..., IdGlobalProtocols;

var
  MimeTable: TIdMimeTable = nil;

function GetExtension(const AMIMEType: string);
begin
  if MimeTable = nil then
    MimeTable := TIdMimeTable.Create;
  Result := MimeTable.GetDefaultFileExt(AMIMEType);
end;

initialization
finalization
  MimeTable.Free;

uses
  ..., IdGlobalProtocols, IdCustomHTTPServer;

var
  MimeTable: TIdThreadSafeMimeTable = nil;

function GetExtension(const AMIMEType: string);
begin
  if MimeTable = nil then
    MimeTable := TIdThreadSafeMimeTable.Create;
  Result := MimeTable.GetDefaultFileExt(AMIMEType);
end;

initialization
finalization
  MimeTable.Free;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
3

HKEY_CLASSES_ROOT\MIME\Database\Content Type\text/html, value Extension.

Denis Anisimov
  • 3,297
  • 1
  • 10
  • 18
  • Surely there's an API or some standard way of encapsulating this. Without documentation saying this is stable it looks like fragile registry hacking. – David Heffernan Jul 06 '17 at 12:58
  • @DavidHeffernan Indy uses this registry key too so we can think this is "official" way. – Denis Anisimov Jul 06 '17 at 14:58
  • 2
    There is no Win32 API to query Window's MIME database, but its Registry key is documented in multiple places in MSDN, so its location is known to be valid and unlikely to change between Windows versions. Besides, Indy doesn't rely solely on the Registry anyway. It has a long list of defaults, and then uses the Registry to override/fill-in any missing gaps. – Remy Lebeau Jul 06 '17 at 17:05
1

For more current versions of Delphi, you can use the TMimeTypes class in the unit System.Net.Mime

There are two methods which you can use to seed the internal dictionary to perform the lookup. The first AddDefTypes will add the standard types, and the method AddOSTypes will add any defined by the host OS (for windows, it does a registry crawl). If you call TMimeTypes.GetDefault it will construct a TMimeTypes instance using both methods the first time it is called (singleton).

skamradt
  • 15,366
  • 2
  • 36
  • 53