Platform-agnostic GContentType
This MR is my third attempt to push this through. The first one was in 2014, the second one was in 2017. Third time's a charm? :)
For those of you who just tuned in, a short recap:
-
GContentType
is a string. - The contents of this string are platform-dependent:
- On *nix it is a
MIME/type
, such astext/plain
- On Windows it is a file extension, such as
.txt
- On MacOS it is a Uniform Type Identifier, such as
com.apple.application
- On *nix it is a
- The idea was that these are the things that various platforms use to tie applications to files (i.e. what happens when the user doubleclicks a file, for example).
- The problem is that most applications are written with *nix (or, more specifically, Gnome) in mind, and tend to use
MIME/type
s. They might also wantMIME/type
s (GContentType
on *nix is said to beMIME/type
, but the API is written in such a way that there's a function to getMIME/type
fromGContentType
, which is implemented asg_strdup()
on *nix, but has other platforms do all kinds of contortions) and use the APIs to get it fromGContentType
, which are not trivial to implement. - Windows native support for
MIME/type
s is abysmal and is not worth mentioning. - I'm not sure what the situation with MacOS is, but there were issues in that area too (though they seem to be fixed).
- Luckily, the mechanism that handles
MIME/type
s on *nix, which isxdgmime
+shared-mime-info
, is not specific to *nix. It's just a bunch of xml files, some code to use them efficiently, and a convention as to where applications should install theirmime-info
additions. This can be made to work on Windows. - The problem with using it on Windows is that Windows continues to use file extensions for everything, and if Glib uses
MIME/type
s instead, we'll have incompatibilities and information loss (basically, you might not be able to create aGContentType-that-is-MIME/type
from file extension and then convert it back to the same file extension you started with, as the mapping is not straightforward). - The solution to that was to use a rare feature of
MIME/type
specs (RFC 2045 and 2046). I'm too lazy to read the spec again to figure out whether a technical term for this exists, i'm just calling it extended MIME/types. eM/ts have the form ofMIME/type; foo=bar baz="blue" zool=over
, i.e. it allows arbitrary parameters to be appended to the type itself. - We can use this to append
ext=.foo
to denote thatGContentType-that-is-MIME/type
was created for a file that has.foo
extension. This information will remain with theGContentType
for as long as it lives, and will be available in case it is later used to, for example, find the handler for that type (since on Windows that requires using a file extension, not aMIME/type
). - Additionally it was proposed to generate
application/x-extension-foo
MIME/type
dynamically for*.foo
files for which we've been unable to guess theMIME/type
.ext=foo
andapplication/x-extension-foo
are mostly orthogonal, although it seems prudent to avoid redundant cases likeapplication/x-extension-foo; ext=foo
. - Theoretically, this can be extended to store MacOS UTI strings, i.e. appending
uti=...
.
I implemented all of this, and adjusted the testsuite to make it pass (the new logic is, IMO, more correct than the old one, so the adjustments to the testsuite is less "made the tests fit the code bugs" and more "fixed the code and fixed broken tests").
To market this MR better, i developed it on my Debian machine, meaning that this is not a W32-specific code dump. Most changes will affect the *nix platform, and the testsuite passes there.
I'm open to suggestions for new tests could be added to cover the new functionality, and ideas on which of the APIs should be made public (for all platforms or for some of them).
This code should not break compliant Glib programs. Non-compliant Glib programs are those that exploited the knowledge of implementation details, i.e. interpreted GContentType
strings literally as file extensions or MIME/type
s, without going through any APIs. This also includes the programs that used strcmp()
to compare literal values of GContentType
s instead of using the appropriate APIs.
I didn't test anything on MacOS, and i'm not sure whether it compiles anymore after these changes (hopefully, it does).
This code is made to be as compatible as possible with Windows code in places where it is feasible. For example, it's easy to tell apart file extensions and MIME/type
strings, since the former start with a .
while the latter do not, so Windows part of the code won't try to pass extensions to xdgmime
as MIME/type
s.
This code includes a few changes to improve compatibility with MSVC (the result of a review by fanc some years ago), though i didn't verify that it still compiles with MSVC.