1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/mimecmn.cpp
3 // Purpose: classes and functions to manage MIME types
4 // Author: Vadim Zeitlin
6 // Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence (part of wxExtra library)
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
29 #include "wx/mimetype.h"
32 #include "wx/dynarray.h"
33 #include "wx/string.h"
36 #include "wx/module.h"
41 #include "wx/iconloc.h"
42 #include "wx/confbase.h"
44 // other standard headers
47 // implementation classes:
48 #if defined(__WINDOWS__)
49 #include "wx/msw/mimetype.h"
50 #elif ( defined(__DARWIN__) )
51 #include "wx/osx/mimetype.h"
52 #elif defined(__WXPM__) || defined (__EMX__)
53 #include "wx/os2/mimetype.h"
55 #elif defined(__DOS__)
56 #include "wx/msdos/mimetype.h"
58 #include "wx/unix/mimetype.h"
61 // ============================================================================
63 // ============================================================================
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
70 wxMimeTypeCommands::AddOrReplaceVerb(const wxString
& verb
, const wxString
& cmd
)
72 int n
= m_verbs
.Index(verb
, false /* ignore case */);
73 if ( n
== wxNOT_FOUND
)
85 wxMimeTypeCommands::GetCommandForVerb(const wxString
& verb
, size_t *idx
) const
89 int n
= m_verbs
.Index(verb
);
90 if ( n
!= wxNOT_FOUND
)
92 s
= m_commands
[(size_t)n
];
98 // different from any valid index
105 wxString
wxMimeTypeCommands::GetVerbCmd(size_t n
) const
107 return m_verbs
[n
] + wxT('=') + m_commands
[n
];
110 // ----------------------------------------------------------------------------
112 // ----------------------------------------------------------------------------
114 void wxFileTypeInfo::DoVarArgInit(const wxString
& mimeType
,
115 const wxString
& openCmd
,
116 const wxString
& printCmd
,
117 const wxString
& desc
,
120 m_mimeType
= mimeType
;
122 m_printCmd
= printCmd
;
127 // icc gives this warning in its own va_arg() macro, argh
129 #pragma warning(push)
130 #pragma warning(disable: 1684)
133 wxArgNormalizedString
ext(WX_VA_ARG_STRING(argptr
));
140 // NULL terminates the list
144 m_exts
.Add(ext
.GetString());
148 void wxFileTypeInfo::VarArgInit(const wxString
*mimeType
,
149 const wxString
*openCmd
,
150 const wxString
*printCmd
,
151 const wxString
*desc
,
155 va_start(argptr
, desc
);
157 DoVarArgInit(*mimeType
, *openCmd
, *printCmd
, *desc
, argptr
);
163 wxFileTypeInfo::wxFileTypeInfo(const wxArrayString
& sArray
)
165 m_mimeType
= sArray
[0u];
166 m_openCmd
= sArray
[1u];
167 m_printCmd
= sArray
[2u];
168 m_desc
= sArray
[3u];
170 size_t count
= sArray
.GetCount();
171 for ( size_t i
= 4; i
< count
; i
++ )
173 m_exts
.Add(sArray
[i
]);
177 #include "wx/arrimpl.cpp"
178 WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo
)
180 // ============================================================================
181 // implementation of the wrapper classes
182 // ============================================================================
184 // ----------------------------------------------------------------------------
186 // ----------------------------------------------------------------------------
189 wxString
wxFileType::ExpandCommand(const wxString
& command
,
190 const wxFileType::MessageParameters
& params
)
192 bool hasFilename
= false;
194 // We consider that only the file names with spaces in them need to be
195 // handled specially. This is not perfect, but this can be done easily
196 // under all platforms while handling the file names with quotes in them,
197 // for example, needs to be done differently.
198 const bool needToQuoteFilename
= params
.GetFileName().find_first_of(" \t")
202 for ( const wxChar
*pc
= command
.c_str(); *pc
!= wxT('\0'); pc
++ ) {
203 if ( *pc
== wxT('%') ) {
206 // don't quote the file name if it's already quoted: notice
207 // that we check for a quote following it and not preceding
208 // it as at least under Windows we can have commands
209 // containing "file://%s" (with quotes) in them so the
210 // argument may be quoted even if there is no quote
211 // directly before "%s" itself
212 if ( needToQuoteFilename
&& pc
[1] != '"' )
213 str
<< wxT('"') << params
.GetFileName() << wxT('"');
215 str
<< params
.GetFileName();
220 // '%t' expands into MIME type (quote it too just to be
222 str
<< wxT('\'') << params
.GetMimeType() << wxT('\'');
227 const wxChar
*pEnd
= wxStrchr(pc
, wxT('}'));
228 if ( pEnd
== NULL
) {
230 wxLogWarning(_("Unmatched '{' in an entry for mime type %s."),
231 params
.GetMimeType().c_str());
235 wxString
param(pc
+ 1, pEnd
- pc
- 1);
236 str
<< wxT('\'') << params
.GetParamValue(param
) << wxT('\'');
244 // TODO %n is the number of parts, %F is an array containing
245 // the names of temp files these parts were written to
246 // and their mime types.
250 wxLogDebug(wxT("Unknown field %%%c in command '%s'."),
251 *pc
, command
.c_str());
260 // metamail(1) man page states that if the mailcap entry doesn't have '%s'
261 // the program will accept the data on stdin so normally we should append
262 // "< %s" to the end of the command in such case, but not all commands
263 // behave like this, in particular a common test is 'test -n "$DISPLAY"'
264 // and appending "< %s" to this command makes the test fail... I don't
265 // know of the correct solution, try to guess what we have to do.
267 // test now carried out on reading file so test should never get here
268 if ( !hasFilename
&& !str
.empty()
270 && !str
.StartsWith(wxT("test "))
275 if ( needToQuoteFilename
)
277 str
<< params
.GetFileName();
278 if ( needToQuoteFilename
)
285 wxFileType::wxFileType(const wxFileTypeInfo
& info
)
291 wxFileType::wxFileType()
294 m_impl
= new wxFileTypeImpl
;
297 wxFileType::~wxFileType()
303 bool wxFileType::GetExtensions(wxArrayString
& extensions
)
307 extensions
= m_info
->GetExtensions();
311 return m_impl
->GetExtensions(extensions
);
314 bool wxFileType::GetMimeType(wxString
*mimeType
) const
316 wxCHECK_MSG( mimeType
, false, wxT("invalid parameter in GetMimeType") );
320 *mimeType
= m_info
->GetMimeType();
325 return m_impl
->GetMimeType(mimeType
);
328 bool wxFileType::GetMimeTypes(wxArrayString
& mimeTypes
) const
333 mimeTypes
.Add(m_info
->GetMimeType());
338 return m_impl
->GetMimeTypes(mimeTypes
);
341 bool wxFileType::GetIcon(wxIconLocation
*iconLoc
) const
347 iconLoc
->SetFileName(m_info
->GetIconFile());
349 iconLoc
->SetIndex(m_info
->GetIconIndex());
350 #endif // __WINDOWS__
356 return m_impl
->GetIcon(iconLoc
);
360 wxFileType::GetIcon(wxIconLocation
*iconloc
,
361 const MessageParameters
& params
) const
363 if ( !GetIcon(iconloc
) )
368 // we may have "%s" in the icon location string, at least under Windows, so
372 iconloc
->SetFileName(ExpandCommand(iconloc
->GetFileName(), params
));
378 bool wxFileType::GetDescription(wxString
*desc
) const
380 wxCHECK_MSG( desc
, false, wxT("invalid parameter in GetDescription") );
384 *desc
= m_info
->GetDescription();
389 return m_impl
->GetDescription(desc
);
393 wxFileType::GetOpenCommand(wxString
*openCmd
,
394 const wxFileType::MessageParameters
& params
) const
396 wxCHECK_MSG( openCmd
, false, wxT("invalid parameter in GetOpenCommand") );
400 *openCmd
= ExpandCommand(m_info
->GetOpenCommand(), params
);
405 return m_impl
->GetOpenCommand(openCmd
, params
);
408 wxString
wxFileType::GetOpenCommand(const wxString
& filename
) const
411 if ( !GetOpenCommand(&cmd
, filename
) )
413 // return empty string to indicate an error
421 wxFileType::GetPrintCommand(wxString
*printCmd
,
422 const wxFileType::MessageParameters
& params
) const
424 wxCHECK_MSG( printCmd
, false, wxT("invalid parameter in GetPrintCommand") );
428 *printCmd
= ExpandCommand(m_info
->GetPrintCommand(), params
);
433 return m_impl
->GetPrintCommand(printCmd
, params
);
437 size_t wxFileType::GetAllCommands(wxArrayString
*verbs
,
438 wxArrayString
*commands
,
439 const wxFileType::MessageParameters
& params
) const
446 #if defined (__WINDOWS__) || defined(__UNIX__)
447 return m_impl
->GetAllCommands(verbs
, commands
, params
);
448 #else // !__WINDOWS__ || __UNIX__
449 // we don't know how to retrieve all commands, so just try the 2 we know
453 if ( GetOpenCommand(&cmd
, params
) )
456 verbs
->Add(wxT("Open"));
462 if ( GetPrintCommand(&cmd
, params
) )
465 verbs
->Add(wxT("Print"));
473 #endif // __WINDOWS__/| __UNIX__
476 bool wxFileType::Unassociate()
478 #if defined(__WINDOWS__)
479 return m_impl
->Unassociate();
480 #elif defined(__UNIX__)
481 return m_impl
->Unassociate(this);
483 wxFAIL_MSG( wxT("not implemented") ); // TODO
488 bool wxFileType::SetCommand(const wxString
& cmd
,
489 const wxString
& verb
,
490 bool overwriteprompt
)
492 #if defined (__WINDOWS__) || defined(__UNIX__)
493 return m_impl
->SetCommand(cmd
, verb
, overwriteprompt
);
497 wxUnusedVar(overwriteprompt
);
498 wxFAIL_MSG(wxT("not implemented"));
503 bool wxFileType::SetDefaultIcon(const wxString
& cmd
, int index
)
507 // VZ: should we do this?
508 // chris elliott : only makes sense in MS windows
510 GetOpenCommand(&sTmp
, wxFileType::MessageParameters(wxEmptyString
, wxEmptyString
));
512 wxCHECK_MSG( !sTmp
.empty(), false, wxT("need the icon file") );
514 #if defined (__WINDOWS__) || defined(__UNIX__)
515 return m_impl
->SetDefaultIcon (cmd
, index
);
518 wxFAIL_MSG(wxT("not implemented"));
523 // ----------------------------------------------------------------------------
524 // wxMimeTypesManagerFactory
525 // ----------------------------------------------------------------------------
527 wxMimeTypesManagerFactory
*wxMimeTypesManagerFactory::m_factory
= NULL
;
530 void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory
*factory
)
538 wxMimeTypesManagerFactory
*wxMimeTypesManagerFactory::Get()
541 m_factory
= new wxMimeTypesManagerFactory
;
546 wxMimeTypesManagerImpl
*wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl()
548 return new wxMimeTypesManagerImpl
;
551 // ----------------------------------------------------------------------------
552 // wxMimeTypesManager
553 // ----------------------------------------------------------------------------
555 void wxMimeTypesManager::EnsureImpl()
558 m_impl
= wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl();
561 bool wxMimeTypesManager::IsOfType(const wxString
& mimeType
,
562 const wxString
& wildcard
)
564 wxASSERT_MSG( mimeType
.Find(wxT('*')) == wxNOT_FOUND
,
565 wxT("first MIME type can't contain wildcards") );
567 // all comparaisons are case insensitive (2nd arg of IsSameAs() is false)
568 if ( wildcard
.BeforeFirst(wxT('/')).
569 IsSameAs(mimeType
.BeforeFirst(wxT('/')), false) )
571 wxString strSubtype
= wildcard
.AfterFirst(wxT('/'));
573 if ( strSubtype
== wxT("*") ||
574 strSubtype
.IsSameAs(mimeType
.AfterFirst(wxT('/')), false) )
576 // matches (either exactly or it's a wildcard)
584 wxMimeTypesManager::wxMimeTypesManager()
589 wxMimeTypesManager::~wxMimeTypesManager()
595 bool wxMimeTypesManager::Unassociate(wxFileType
*ft
)
599 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
600 return m_impl
->Unassociate(ft
);
602 return ft
->Unassociate();
608 wxMimeTypesManager::Associate(const wxFileTypeInfo
& ftInfo
)
612 #if defined(__WINDOWS__) || defined(__UNIX__)
613 return m_impl
->Associate(ftInfo
);
614 #else // other platforms
616 wxFAIL_MSG( wxT("not implemented") ); // TODO
622 wxMimeTypesManager::GetFileTypeFromExtension(const wxString
& ext
)
626 wxString::const_iterator i
= ext
.begin();
627 const wxString::const_iterator end
= ext
.end();
628 wxString extWithoutDot
;
629 if ( i
!= end
&& *i
== '.' )
630 extWithoutDot
.assign(++i
, ext
.end());
634 wxCHECK_MSG( !ext
.empty(), NULL
, wxT("extension can't be empty") );
636 wxFileType
*ft
= m_impl
->GetFileTypeFromExtension(extWithoutDot
);
639 // check the fallbacks
641 // TODO linear search is potentially slow, perhaps we should use a
643 size_t count
= m_fallbacks
.GetCount();
644 for ( size_t n
= 0; n
< count
; n
++ ) {
645 if ( m_fallbacks
[n
].GetExtensions().Index(ext
) != wxNOT_FOUND
) {
646 ft
= new wxFileType(m_fallbacks
[n
]);
657 wxMimeTypesManager::GetFileTypeFromMimeType(const wxString
& mimeType
)
660 wxFileType
*ft
= m_impl
->GetFileTypeFromMimeType(mimeType
);
663 // check the fallbacks
665 // TODO linear search is potentially slow, perhaps we should use a
667 size_t count
= m_fallbacks
.GetCount();
668 for ( size_t n
= 0; n
< count
; n
++ ) {
669 if ( wxMimeTypesManager::IsOfType(mimeType
,
670 m_fallbacks
[n
].GetMimeType()) ) {
671 ft
= new wxFileType(m_fallbacks
[n
]);
681 void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo
*filetypes
)
684 for ( const wxFileTypeInfo
*ft
= filetypes
; ft
&& ft
->IsValid(); ft
++ ) {
689 size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString
& mimetypes
)
692 size_t countAll
= m_impl
->EnumAllFileTypes(mimetypes
);
694 // add the fallback filetypes
695 size_t count
= m_fallbacks
.GetCount();
696 for ( size_t n
= 0; n
< count
; n
++ ) {
697 if ( mimetypes
.Index(m_fallbacks
[n
].GetMimeType()) == wxNOT_FOUND
) {
698 mimetypes
.Add(m_fallbacks
[n
].GetMimeType());
706 void wxMimeTypesManager::Initialize(int mcapStyle
,
707 const wxString
& sExtraDir
)
709 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
712 m_impl
->Initialize(mcapStyle
, sExtraDir
);
719 // and this function clears all the data from the manager
720 void wxMimeTypesManager::ClearData()
722 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
729 // ----------------------------------------------------------------------------
730 // global data and wxMimeTypeCmnModule
731 // ----------------------------------------------------------------------------
734 static wxMimeTypesManager gs_mimeTypesManager
;
736 // and public pointer
737 wxMimeTypesManager
*wxTheMimeTypesManager
= &gs_mimeTypesManager
;
739 class wxMimeTypeCmnModule
: public wxModule
742 wxMimeTypeCmnModule() : wxModule() { }
744 virtual bool OnInit() { return true; }
745 virtual void OnExit()
747 wxMimeTypesManagerFactory::Set(NULL
);
749 if ( gs_mimeTypesManager
.m_impl
!= NULL
)
751 wxDELETE(gs_mimeTypesManager
.m_impl
);
752 gs_mimeTypesManager
.m_fallbacks
.Clear();
756 DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule
)
759 IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule
, wxModule
)
761 #endif // wxUSE_MIMETYPE