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
9 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10 // Licence: wxWindows licence (part of wxExtra library)
11 /////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 // for compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
30 #include "wx/mimetype.h"
33 #include "wx/dynarray.h"
34 #include "wx/string.h"
37 #include "wx/module.h"
42 #include "wx/iconloc.h"
43 #include "wx/confbase.h"
45 // other standard headers
48 // implementation classes:
49 #if defined(__WXMSW__)
50 #include "wx/msw/mimetype.h"
51 #elif defined(__WXMAC__)
52 #include "wx/mac/mimetype.h"
53 #elif defined(__WXPM__) || defined (__EMX__)
54 #include "wx/os2/mimetype.h"
56 #elif defined(__DOS__)
57 #include "wx/msdos/mimetype.h"
59 #include "wx/unix/mimetype.h"
62 // ============================================================================
64 // ============================================================================
66 // ----------------------------------------------------------------------------
68 // ----------------------------------------------------------------------------
71 wxMimeTypeCommands::AddOrReplaceVerb(const wxString
& verb
, const wxString
& cmd
)
73 int n
= m_verbs
.Index(verb
, false /* ignore case */);
74 if ( n
== wxNOT_FOUND
)
86 wxMimeTypeCommands::GetCommandForVerb(const wxString
& verb
, size_t *idx
) const
90 int n
= m_verbs
.Index(verb
);
91 if ( n
!= wxNOT_FOUND
)
93 s
= m_commands
[(size_t)n
];
99 // different from any valid index
106 wxString
wxMimeTypeCommands::GetVerbCmd(size_t n
) const
108 return m_verbs
[n
] + wxT('=') + m_commands
[n
];
111 // ----------------------------------------------------------------------------
113 // ----------------------------------------------------------------------------
115 void wxFileTypeInfo::DoVarArgInit(const wxString
& mimeType
,
116 const wxString
& openCmd
,
117 const wxString
& printCmd
,
118 const wxString
& desc
,
121 m_mimeType
= mimeType
;
123 m_printCmd
= printCmd
;
128 // icc gives this warning in its own va_arg() macro, argh
130 #pragma warning(push)
131 #pragma warning(disable: 1684)
134 wxArgNormalizedString
ext(WX_VA_ARG_STRING(argptr
));
141 // NULL terminates the list
145 m_exts
.Add(ext
.GetString());
149 // NB: DoVarArgInit uses WX_VA_ARG_STRING macro to extract the string and this
150 // macro interprets the argument as char* or wchar_t* depending on build
151 // (and in UTF8 build, on the current locale). Because only one of the
152 // vararg forms below is called and the decision about which one gets
153 // called depends on the same conditions WX_VA_ARG_STRING uses, we can
154 // implement both of them in the exact same way:
156 #if !wxUSE_UTF8_LOCALE_ONLY
157 void wxFileTypeInfo::VarArgInitWchar(const wxChar
*mimeType
,
158 const wxChar
*openCmd
,
159 const wxChar
*printCmd
,
164 va_start(argptr
, desc
);
166 DoVarArgInit(mimeType
, openCmd
, printCmd
, desc
, argptr
);
170 #endif // !wxUSE_UTF8_LOCALE_ONLY
172 #if wxUSE_UNICODE_UTF8
173 void wxFileTypeInfo::VarArgInitUtf8(const char *mimeType
,
175 const char *printCmd
,
180 va_start(argptr
, desc
);
182 DoVarArgInit(mimeType
, openCmd
, printCmd
, desc
, argptr
);
186 #endif // wxUSE_UNICODE_UTF8
189 wxFileTypeInfo::wxFileTypeInfo(const wxArrayString
& sArray
)
191 m_mimeType
= sArray
[0u];
192 m_openCmd
= sArray
[1u];
193 m_printCmd
= sArray
[2u];
194 m_desc
= sArray
[3u];
196 size_t count
= sArray
.GetCount();
197 for ( size_t i
= 4; i
< count
; i
++ )
199 m_exts
.Add(sArray
[i
]);
203 #include "wx/arrimpl.cpp"
204 WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo
)
206 // ============================================================================
207 // implementation of the wrapper classes
208 // ============================================================================
210 // ----------------------------------------------------------------------------
212 // ----------------------------------------------------------------------------
215 wxString
wxFileType::ExpandCommand(const wxString
& command
,
216 const wxFileType::MessageParameters
& params
)
218 bool hasFilename
= false;
221 for ( const wxChar
*pc
= command
.c_str(); *pc
!= wxT('\0'); pc
++ ) {
222 if ( *pc
== wxT('%') ) {
225 // '%s' expands into file name (quoted because it might
226 // contain spaces) - except if there are already quotes
227 // there because otherwise some programs may get confused
228 // by double double quotes
230 if ( *(pc
- 2) == wxT('"') )
231 str
<< params
.GetFileName();
233 str
<< wxT('"') << params
.GetFileName() << wxT('"');
235 str
<< params
.GetFileName();
240 // '%t' expands into MIME type (quote it too just to be
242 str
<< wxT('\'') << params
.GetMimeType() << wxT('\'');
247 const wxChar
*pEnd
= wxStrchr(pc
, wxT('}'));
248 if ( pEnd
== NULL
) {
250 wxLogWarning(_("Unmatched '{' in an entry for mime type %s."),
251 params
.GetMimeType().c_str());
255 wxString
param(pc
+ 1, pEnd
- pc
- 1);
256 str
<< wxT('\'') << params
.GetParamValue(param
) << wxT('\'');
264 // TODO %n is the number of parts, %F is an array containing
265 // the names of temp files these parts were written to
266 // and their mime types.
270 wxLogDebug(wxT("Unknown field %%%c in command '%s'."),
271 *pc
, command
.c_str());
280 // metamail(1) man page states that if the mailcap entry doesn't have '%s'
281 // the program will accept the data on stdin so normally we should append
282 // "< %s" to the end of the command in such case, but not all commands
283 // behave like this, in particular a common test is 'test -n "$DISPLAY"'
284 // and appending "< %s" to this command makes the test fail... I don't
285 // know of the correct solution, try to guess what we have to do.
287 // test now carried out on reading file so test should never get here
288 if ( !hasFilename
&& !str
.empty()
290 && !str
.StartsWith(_T("test "))
293 str
<< wxT(" < '") << params
.GetFileName() << wxT('\'');
299 wxFileType::wxFileType(const wxFileTypeInfo
& info
)
305 wxFileType::wxFileType()
308 m_impl
= new wxFileTypeImpl
;
311 wxFileType::~wxFileType()
317 bool wxFileType::GetExtensions(wxArrayString
& extensions
)
321 extensions
= m_info
->GetExtensions();
325 return m_impl
->GetExtensions(extensions
);
328 bool wxFileType::GetMimeType(wxString
*mimeType
) const
330 wxCHECK_MSG( mimeType
, false, _T("invalid parameter in GetMimeType") );
334 *mimeType
= m_info
->GetMimeType();
339 return m_impl
->GetMimeType(mimeType
);
342 bool wxFileType::GetMimeTypes(wxArrayString
& mimeTypes
) const
347 mimeTypes
.Add(m_info
->GetMimeType());
352 return m_impl
->GetMimeTypes(mimeTypes
);
355 bool wxFileType::GetIcon(wxIconLocation
*iconLoc
) const
361 iconLoc
->SetFileName(m_info
->GetIconFile());
363 iconLoc
->SetIndex(m_info
->GetIconIndex());
370 return m_impl
->GetIcon(iconLoc
);
374 wxFileType::GetIcon(wxIconLocation
*iconloc
,
375 const MessageParameters
& params
) const
377 if ( !GetIcon(iconloc
) )
382 // we may have "%s" in the icon location string, at least under Windows, so
386 iconloc
->SetFileName(ExpandCommand(iconloc
->GetFileName(), params
));
392 bool wxFileType::GetDescription(wxString
*desc
) const
394 wxCHECK_MSG( desc
, false, _T("invalid parameter in GetDescription") );
398 *desc
= m_info
->GetDescription();
403 return m_impl
->GetDescription(desc
);
407 wxFileType::GetOpenCommand(wxString
*openCmd
,
408 const wxFileType::MessageParameters
& params
) const
410 wxCHECK_MSG( openCmd
, false, _T("invalid parameter in GetOpenCommand") );
414 *openCmd
= ExpandCommand(m_info
->GetOpenCommand(), params
);
419 return m_impl
->GetOpenCommand(openCmd
, params
);
422 wxString
wxFileType::GetOpenCommand(const wxString
& filename
) const
425 if ( !GetOpenCommand(&cmd
, filename
) )
427 // return empty string to indicate an error
435 wxFileType::GetPrintCommand(wxString
*printCmd
,
436 const wxFileType::MessageParameters
& params
) const
438 wxCHECK_MSG( printCmd
, false, _T("invalid parameter in GetPrintCommand") );
442 *printCmd
= ExpandCommand(m_info
->GetPrintCommand(), params
);
447 return m_impl
->GetPrintCommand(printCmd
, params
);
451 size_t wxFileType::GetAllCommands(wxArrayString
*verbs
,
452 wxArrayString
*commands
,
453 const wxFileType::MessageParameters
& params
) const
460 #if defined (__WXMSW__) || defined(__UNIX__)
461 return m_impl
->GetAllCommands(verbs
, commands
, params
);
462 #else // !__WXMSW__ || Unix
463 // we don't know how to retrieve all commands, so just try the 2 we know
467 if ( GetOpenCommand(&cmd
, params
) )
470 verbs
->Add(_T("Open"));
476 if ( GetPrintCommand(&cmd
, params
) )
479 verbs
->Add(_T("Print"));
487 #endif // __WXMSW__/| __UNIX__
490 bool wxFileType::Unassociate()
492 #if defined(__WXMSW__)
493 return m_impl
->Unassociate();
494 #elif defined(__UNIX__)
495 return m_impl
->Unassociate(this);
497 wxFAIL_MSG( _T("not implemented") ); // TODO
502 bool wxFileType::SetCommand(const wxString
& cmd
,
503 const wxString
& verb
,
504 bool overwriteprompt
)
506 #if defined (__WXMSW__) || defined(__UNIX__)
507 return m_impl
->SetCommand(cmd
, verb
, overwriteprompt
);
511 wxUnusedVar(overwriteprompt
);
512 wxFAIL_MSG(_T("not implemented"));
517 bool wxFileType::SetDefaultIcon(const wxString
& cmd
, int index
)
521 // VZ: should we do this?
522 // chris elliott : only makes sense in MS windows
524 GetOpenCommand(&sTmp
, wxFileType::MessageParameters(wxEmptyString
, wxEmptyString
));
526 wxCHECK_MSG( !sTmp
.empty(), false, _T("need the icon file") );
528 #if defined (__WXMSW__) || defined(__UNIX__)
529 return m_impl
->SetDefaultIcon (cmd
, index
);
532 wxFAIL_MSG(_T("not implemented"));
537 // ----------------------------------------------------------------------------
538 // wxMimeTypesManagerFactory
539 // ----------------------------------------------------------------------------
541 wxMimeTypesManagerFactory
*wxMimeTypesManagerFactory::m_factory
= NULL
;
544 void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory
*factory
)
552 wxMimeTypesManagerFactory
*wxMimeTypesManagerFactory::Get()
555 m_factory
= new wxMimeTypesManagerFactory
;
560 wxMimeTypesManagerImpl
*wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl()
562 return new wxMimeTypesManagerImpl
;
565 // ----------------------------------------------------------------------------
566 // wxMimeTypesManager
567 // ----------------------------------------------------------------------------
569 void wxMimeTypesManager::EnsureImpl()
572 m_impl
= wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl();
575 bool wxMimeTypesManager::IsOfType(const wxString
& mimeType
,
576 const wxString
& wildcard
)
578 wxASSERT_MSG( mimeType
.Find(wxT('*')) == wxNOT_FOUND
,
579 wxT("first MIME type can't contain wildcards") );
581 // all comparaisons are case insensitive (2nd arg of IsSameAs() is false)
582 if ( wildcard
.BeforeFirst(wxT('/')).
583 IsSameAs(mimeType
.BeforeFirst(wxT('/')), false) )
585 wxString strSubtype
= wildcard
.AfterFirst(wxT('/'));
587 if ( strSubtype
== wxT("*") ||
588 strSubtype
.IsSameAs(mimeType
.AfterFirst(wxT('/')), false) )
590 // matches (either exactly or it's a wildcard)
598 wxMimeTypesManager::wxMimeTypesManager()
603 wxMimeTypesManager::~wxMimeTypesManager()
609 bool wxMimeTypesManager::Unassociate(wxFileType
*ft
)
613 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
614 return m_impl
->Unassociate(ft
);
616 return ft
->Unassociate();
622 wxMimeTypesManager::Associate(const wxFileTypeInfo
& ftInfo
)
626 #if defined(__WXMSW__) || defined(__UNIX__)
627 return m_impl
->Associate(ftInfo
);
628 #else // other platforms
630 wxFAIL_MSG( _T("not implemented") ); // TODO
636 wxMimeTypesManager::GetFileTypeFromExtension(const wxString
& ext
)
640 wxString::const_iterator i
= ext
.begin();
641 const wxString::const_iterator end
= ext
.end();
642 wxString extWithoutDot
;
643 if ( i
!= end
&& *i
== '.' )
644 extWithoutDot
.assign(++i
, ext
.end());
648 wxCHECK_MSG( !ext
.empty(), NULL
, _T("extension can't be empty") );
650 wxFileType
*ft
= m_impl
->GetFileTypeFromExtension(extWithoutDot
);
653 // check the fallbacks
655 // TODO linear search is potentially slow, perhaps we should use a
657 size_t count
= m_fallbacks
.GetCount();
658 for ( size_t n
= 0; n
< count
; n
++ ) {
659 if ( m_fallbacks
[n
].GetExtensions().Index(ext
) != wxNOT_FOUND
) {
660 ft
= new wxFileType(m_fallbacks
[n
]);
671 wxMimeTypesManager::GetFileTypeFromMimeType(const wxString
& mimeType
)
674 wxFileType
*ft
= m_impl
->GetFileTypeFromMimeType(mimeType
);
677 // check the fallbacks
679 // TODO linear search is potentially slow, perhaps we should use a
681 size_t count
= m_fallbacks
.GetCount();
682 for ( size_t n
= 0; n
< count
; n
++ ) {
683 if ( wxMimeTypesManager::IsOfType(mimeType
,
684 m_fallbacks
[n
].GetMimeType()) ) {
685 ft
= new wxFileType(m_fallbacks
[n
]);
695 bool wxMimeTypesManager::ReadMailcap(const wxString
& filename
, bool fallback
)
698 return m_impl
->ReadMailcap(filename
, fallback
);
701 bool wxMimeTypesManager::ReadMimeTypes(const wxString
& filename
)
704 return m_impl
->ReadMimeTypes(filename
);
707 void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo
*filetypes
)
710 for ( const wxFileTypeInfo
*ft
= filetypes
; ft
&& ft
->IsValid(); ft
++ ) {
715 size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString
& mimetypes
)
718 size_t countAll
= m_impl
->EnumAllFileTypes(mimetypes
);
720 // add the fallback filetypes
721 size_t count
= m_fallbacks
.GetCount();
722 for ( size_t n
= 0; n
< count
; n
++ ) {
723 if ( mimetypes
.Index(m_fallbacks
[n
].GetMimeType()) == wxNOT_FOUND
) {
724 mimetypes
.Add(m_fallbacks
[n
].GetMimeType());
732 void wxMimeTypesManager::Initialize(int mcapStyle
,
733 const wxString
& sExtraDir
)
735 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
738 m_impl
->Initialize(mcapStyle
, sExtraDir
);
745 // and this function clears all the data from the manager
746 void wxMimeTypesManager::ClearData()
748 #if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__)
755 // ----------------------------------------------------------------------------
756 // global data and wxMimeTypeCmnModule
757 // ----------------------------------------------------------------------------
760 static wxMimeTypesManager gs_mimeTypesManager
;
762 // and public pointer
763 wxMimeTypesManager
*wxTheMimeTypesManager
= &gs_mimeTypesManager
;
765 class wxMimeTypeCmnModule
: public wxModule
768 wxMimeTypeCmnModule() : wxModule() { }
770 virtual bool OnInit() { return true; }
771 virtual void OnExit()
773 wxMimeTypesManagerFactory::Set(NULL
);
775 if ( gs_mimeTypesManager
.m_impl
!= NULL
)
777 delete gs_mimeTypesManager
.m_impl
;
778 gs_mimeTypesManager
.m_impl
= NULL
;
779 gs_mimeTypesManager
.m_fallbacks
.Clear();
783 DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule
)
786 IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule
, wxModule
)
788 #endif // wxUSE_MIMETYPE