1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/unix/mimetype.cpp 
   3 // Purpose:     classes and functions to manage MIME types 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> 
   9 // Licence:     wxWindows licence (part of wxExtra library) 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // for compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  19 #if wxUSE_MIMETYPE && wxUSE_FILE 
  21 #include "wx/unix/mimetype.h" 
  24     #include "wx/dynarray.h" 
  25     #include "wx/string.h" 
  32 #include "wx/confbase.h" 
  36 #include "wx/tokenzr.h" 
  37 #include "wx/iconloc.h" 
  38 #include "wx/filename.h" 
  40 #include "wx/apptrait.h" 
  42 // other standard headers 
  52     wxMimeTextFile(const wxString
& fname
) 
  59        wxFFile 
file( m_fname 
); 
  63        size_t size 
= file
.Length(); 
  64        wxCharBuffer 
buffer( size 
); 
  65        file
.Read( (void*) (const char*) buffer
, size 
); 
  67        // Check for valid UTF-8 here? 
  68        wxString all 
= wxString::FromUTF8( buffer
, size 
); 
  70        wxStringTokenizer 
tok( all
, "\n" ); 
  71        while (tok
.HasMoreTokens()) 
  73           wxString t 
= tok
.GetNextToken(); 
  75           if ((!!t
) && (t
.Find( "comment" ) != 0) && (t
.Find( "#" ) != 0) && (t
.Find( "generic" ) != 0)) 
  81     unsigned int GetLineCount() const { return m_text
.GetCount(); } 
  82     wxString 
&GetLine( unsigned int line 
) { return m_text
[line
]; } 
  84     int pIndexOf(const wxString
& sSearch
, 
  85                  bool bIncludeComments 
= false, 
  88         wxString sTest 
= sSearch
; 
  90         for(size_t i 
= iStart
; i 
< GetLineCount(); i
++) 
  92             wxString sLine 
= GetLine(i
); 
  93             if(bIncludeComments 
|| ! sLine
.StartsWith(wxT("#"))) 
  95                 if(sLine
.StartsWith(sTest
)) 
 102     wxString 
GetVerb(size_t i
) 
 104         if (i 
> GetLineCount() ) 
 105             return wxEmptyString
; 
 107         wxString sTmp 
= GetLine(i
).BeforeFirst(wxT('=')); 
 111     wxString 
GetCmd(size_t i
) 
 113         if (i 
> GetLineCount() ) 
 114             return wxEmptyString
; 
 116         wxString sTmp 
= GetLine(i
).AfterFirst(wxT('=')); 
 121     wxArrayString m_text
; 
 125 // ---------------------------------------------------------------------------- 
 127 // ---------------------------------------------------------------------------- 
 129 // MIME code tracing mask 
 130 #define TRACE_MIME wxT("mime") 
 133 // Read a XDG *.desktop file of type 'Application' 
 134 void wxMimeTypesManagerImpl::LoadXDGApp(const wxString
& filename
) 
 136     wxLogTrace(TRACE_MIME
, wxT("loading XDG file %s"), filename
.c_str()); 
 138     wxMimeTextFile 
file(filename
); 
 142     // Here, only type 'Application' should be considered. 
 143     int nIndex 
= file
.pIndexOf( "Type=" ); 
 144     if (nIndex 
!= wxNOT_FOUND 
&& file
.GetCmd(nIndex
) != "application") 
 147     // The hidden entry specifies a file to be ignored. 
 148     nIndex 
= file
.pIndexOf( "Hidden=" ); 
 149     if (nIndex 
!= wxNOT_FOUND 
&& file
.GetCmd(nIndex
) == "true") 
 152     // Semicolon separated list of mime types handled by the application. 
 153     nIndex 
= file
.pIndexOf( wxT("MimeType=") ); 
 154     if (nIndex 
== wxNOT_FOUND
) 
 156     wxString mimetypes 
= file
.GetCmd (nIndex
); 
 158     // Name of the application 
 160     nIndex 
= wxNOT_FOUND
; 
 161 #if wxUSE_INTL // try "Name[locale name]" first 
 162     wxLocale 
*locale 
= wxGetLocale(); 
 164         nIndex 
= file
.pIndexOf(wxT("Name[")+locale
->GetName()+wxT("]=")); 
 166     if(nIndex 
== wxNOT_FOUND
) 
 167         nIndex 
= file
.pIndexOf( wxT("Name=") ); 
 168     if(nIndex 
!= wxNOT_FOUND
) 
 169         nameapp 
= file
.GetCmd(nIndex
); 
 171     // Icon of the application. 
 172     wxString nameicon
, namemini
; 
 173     nIndex 
= wxNOT_FOUND
; 
 174 #if wxUSE_INTL // try "Icon[locale name]" first 
 176         nIndex 
= file
.pIndexOf(wxT("Icon[")+locale
->GetName()+wxT("]=")); 
 178     if(nIndex 
== wxNOT_FOUND
) 
 179         nIndex 
= file
.pIndexOf( wxT("Icon=") ); 
 180     if(nIndex 
!= wxNOT_FOUND
) { 
 181         nameicon 
= wxString(wxT("--icon ")) + file
.GetCmd(nIndex
); 
 182         namemini 
= wxString(wxT("--miniicon ")) + file
.GetCmd(nIndex
); 
 185     // Replace some of the field code in the 'Exec' entry. 
 186     // TODO: deal with %d, %D, %n, %N, %k and %v (but last one is deprecated) 
 187     nIndex 
= file
.pIndexOf( wxT("Exec=") ); 
 188     if (nIndex 
== wxNOT_FOUND
) 
 190     wxString sCmd 
= file
.GetCmd(nIndex
); 
 191     // we expect %f; others including  %F and %U and %u are possible 
 192     sCmd
.Replace(wxT("%F"), wxT("%f")); 
 193     sCmd
.Replace(wxT("%U"), wxT("%f")); 
 194     sCmd
.Replace(wxT("%u"), wxT("%f")); 
 195     if (0 == sCmd
.Replace ( wxT("%f"), wxT("%s") )) 
 196         sCmd 
= sCmd 
+ wxT(" %s"); 
 197     sCmd
.Replace(wxT("%c"), nameapp
); 
 198     sCmd
.Replace(wxT("%i"), nameicon
); 
 199     sCmd
.Replace(wxT("%m"), namemini
); 
 201     wxStringTokenizer 
tokenizer(mimetypes
, wxT(";")); 
 202     while(tokenizer
.HasMoreTokens()) { 
 203         wxString mimetype 
= tokenizer
.GetNextToken().Lower(); 
 204         nIndex 
= m_aTypes
.Index(mimetype
); 
 205         if(nIndex 
!= wxNOT_FOUND
) { // is this a known MIME type? 
 206             wxMimeTypeCommands
* entry 
= m_aEntries
[nIndex
]; 
 207             entry
->AddOrReplaceVerb(wxT("open"), sCmd
); 
 212 void wxMimeTypesManagerImpl::LoadXDGAppsFilesFromDir(const wxString
& dirname
) 
 214     // Don't complain if we don't have permissions to read - it confuses users 
 217     if(! wxDir::Exists(dirname
)) 
 220     if ( !dir
.IsOpened() ) 
 224     // Look into .desktop files 
 225     bool cont 
= dir
.GetFirst(&filename
, wxT("*.desktop"), wxDIR_FILES
); 
 228         wxFileName 
p(dirname
, filename
); 
 229         LoadXDGApp( p
.GetFullPath() ); 
 230         cont 
= dir
.GetNext(&filename
); 
 234     // RR: I'm not sure this makes any sense. On my system we'll just 
 235     //     scan the YAST2 and other useless directories 
 237     // Look recursively into subdirs 
 238     cont 
= dir
.GetFirst(&filename
, wxEmptyString
, wxDIR_DIRS
); 
 241         wxFileName 
p(dirname
, wxEmptyString
); 
 242         p
.AppendDir(filename
); 
 243         LoadXDGAppsFilesFromDir( p
.GetPath() ); 
 244         cont 
= dir
.GetNext(&filename
); 
 250 void wxMimeTypesManagerImpl::LoadXDGGlobs(const wxString
& filename
) 
 252     if ( !wxFileName::FileExists(filename
) ) 
 255     wxLogTrace(TRACE_MIME
, wxT("loading XDG globs file from %s"), filename
.c_str()); 
 257     wxMimeTextFile 
file(filename
); 
 262     for (i 
= 0; i 
< file
.GetLineCount(); i
++) 
 264        wxStringTokenizer 
tok( file
.GetLine(i
), ":" ); 
 265        wxString mime 
= tok
.GetNextToken(); 
 266        wxString ext 
= tok
.GetNextToken(); 
 271        AddToMimeData(mime
, wxEmptyString
, NULL
, exts
, wxEmptyString
, true ); 
 275 // ---------------------------------------------------------------------------- 
 276 // wxFileTypeImpl (Unix) 
 277 // ---------------------------------------------------------------------------- 
 279 wxString 
wxFileTypeImpl::GetExpandedCommand(const wxString 
& verb
, const wxFileType::MessageParameters
& params
) const 
 283     while ( (i 
< m_index
.GetCount() ) && sTmp
.empty() ) 
 285         sTmp 
= m_manager
->GetCommand( verb
, m_index
[i
] ); 
 289     return wxFileType::ExpandCommand(sTmp
, params
); 
 292 bool wxFileTypeImpl::GetIcon(wxIconLocation 
*iconLoc
) const 
 296     while ( (i 
< m_index
.GetCount() ) && sTmp
.empty() ) 
 298         sTmp 
= m_manager
->m_aIcons
[m_index
[i
]]; 
 307         iconLoc
->SetFileName(sTmp
); 
 313 bool wxFileTypeImpl::GetMimeTypes(wxArrayString
& mimeTypes
) const 
 316     size_t nCount 
= m_index
.GetCount(); 
 317     for (size_t i 
= 0; i 
< nCount
; i
++) 
 318         mimeTypes
.Add(m_manager
->m_aTypes
[m_index
[i
]]); 
 323 size_t wxFileTypeImpl::GetAllCommands(wxArrayString 
*verbs
, 
 324                                   wxArrayString 
*commands
, 
 325                                   const wxFileType::MessageParameters
& params
) const 
 327     wxString vrb
, cmd
, sTmp
; 
 329     wxMimeTypeCommands 
* sPairs
; 
 331     // verbs and commands have been cleared already in mimecmn.cpp... 
 332     // if we find no entries in the exact match, try the inexact match 
 333     for (size_t n 
= 0; ((count 
== 0) && (n 
< m_index
.GetCount())); n
++) 
 335         // list of verb = command pairs for this mimetype 
 336         sPairs 
= m_manager
->m_aEntries 
[m_index
[n
]]; 
 338         for ( i 
= 0; i 
< sPairs
->GetCount(); i
++ ) 
 340             vrb 
= sPairs
->GetVerb(i
); 
 341             // some gnome entries have "." inside 
 342             vrb 
= vrb
.AfterLast(wxT('.')); 
 343             cmd 
= sPairs
->GetCmd(i
); 
 346                  cmd 
= wxFileType::ExpandCommand(cmd
, params
); 
 348                  if ( vrb
.IsSameAs(wxT("open"))) 
 351                         verbs
->Insert(vrb
, 0u); 
 353                         commands 
->Insert(cmd
, 0u); 
 369 bool wxFileTypeImpl::GetExtensions(wxArrayString
& extensions
) 
 371     const wxString strExtensions 
= m_manager
->GetExtension(m_index
[0]); 
 374     // one extension in the space or comma-delimited list 
 376     wxString::const_iterator end 
= strExtensions
.end(); 
 377     for ( wxString::const_iterator p 
= strExtensions
.begin(); /* nothing */; ++p 
) 
 379         if ( p 
== end 
|| *p 
== wxT(' ') || *p 
== wxT(',') ) 
 381             if ( !strExt
.empty() ) 
 383                 extensions
.Add(strExt
); 
 386             //else: repeated spaces 
 387             // (shouldn't happen, but it's not that important if it does happen) 
 392         else if ( *p 
== wxT('.') ) 
 394             // remove the dot from extension (but only if it's the first char) 
 395             if ( !strExt
.empty() ) 
 399             //else: no, don't append it 
 410 // set an arbitrary command: 
 411 // could adjust the code to ask confirmation if it already exists and 
 412 // overwriteprompt is true, but this is currently ignored as *Associate* has 
 413 // no overwrite prompt 
 415 wxFileTypeImpl::SetCommand(const wxString
& cmd
, 
 416                            const wxString
& verb
, 
 417                            bool WXUNUSED(overwriteprompt
)) 
 419     wxArrayString strExtensions
; 
 420     wxString strDesc
, strIcon
; 
 422     wxArrayString strTypes
; 
 423     GetMimeTypes(strTypes
); 
 424     if ( strTypes
.IsEmpty() ) 
 427     wxMimeTypeCommands 
*entry 
= new wxMimeTypeCommands(); 
 428     entry
->Add(verb 
+ wxT("=")  + cmd 
+ wxT(" %s ")); 
 431     size_t nCount 
= strTypes
.GetCount(); 
 432     for ( size_t i 
= 0; i 
< nCount
; i
++ ) 
 434         if ( m_manager
->DoAssociation
 
 443             // DoAssociation() took ownership of entry, don't delete it below 
 454 // ignore index on the grounds that we only have one icon in a Unix file 
 455 bool wxFileTypeImpl::SetDefaultIcon(const wxString
& strIcon
, int WXUNUSED(index
)) 
 460     wxArrayString strExtensions
; 
 463     wxArrayString strTypes
; 
 464     GetMimeTypes(strTypes
); 
 465     if ( strTypes
.IsEmpty() ) 
 468     wxMimeTypeCommands 
*entry 
= new wxMimeTypeCommands(); 
 470     size_t nCount 
= strTypes
.GetCount(); 
 471     for ( size_t i 
= 0; i 
< nCount
; i
++ ) 
 473         if ( m_manager
->DoAssociation
 
 482             // we don't need to free entry now, DoAssociation() took ownership 
 494 // ---------------------------------------------------------------------------- 
 495 // wxMimeTypesManagerImpl (Unix) 
 496 // ---------------------------------------------------------------------------- 
 498 wxMimeTypesManagerImpl::wxMimeTypesManagerImpl() 
 500     m_initialized 
= false; 
 503 void wxMimeTypesManagerImpl::InitIfNeeded() 
 505     if ( !m_initialized 
) 
 507         // set the flag first to prevent recursion 
 508         m_initialized 
= true; 
 510         int mailcapStyles 
= wxMAILCAP_ALL
; 
 511         if ( wxAppTraits 
* const traits 
= wxApp::GetTraitsIfExists() ) 
 513             wxString wm 
= traits
->GetDesktopEnvironment(); 
 516                 mailcapStyles 
= wxMAILCAP_KDE
; 
 517             else if ( wm 
== "GNOME" ) 
 518                 mailcapStyles 
= wxMAILCAP_GNOME
; 
 519             //else: unknown, use the default 
 522         Initialize(mailcapStyles
); 
 528 // read system and user mailcaps and other files 
 529 void wxMimeTypesManagerImpl::Initialize(int mailcapStyles
, 
 530                                         const wxString
& sExtraDir
) 
 533     // XDG tables are never installed on OpenVMS 
 537     // Read MIME type - extension associations 
 538     LoadXDGGlobs( "/usr/share/mime/globs" ); 
 539     LoadXDGGlobs( "/usr/local/share/mime/globs" ); 
 541     // Load desktop files for XDG, and then override them with the defaults. 
 542     // We will override them one desktop file at a time, rather 
 543     // than one mime type at a time, but it should be a reasonable 
 546         wxString xdgDataHome 
= wxGetenv("XDG_DATA_HOME"); 
 547         if ( xdgDataHome
.empty() ) 
 548             xdgDataHome 
= wxGetHomeDir() + "/.local/share"; 
 549         wxString xdgDataDirs 
= wxGetenv("XDG_DATA_DIRS"); 
 550         if ( xdgDataDirs
.empty() ) 
 552             xdgDataDirs 
= "/usr/local/share:/usr/share"; 
 553             if (mailcapStyles 
& wxMAILCAP_GNOME
) 
 554                 xdgDataDirs 
+= ":/usr/share/gnome:/opt/gnome/share"; 
 555             if (mailcapStyles 
& wxMAILCAP_KDE
) 
 556                 xdgDataDirs 
+= ":/usr/share/kde3:/opt/kde3/share"; 
 558         if ( !sExtraDir
.empty() ) 
 561            xdgDataDirs 
+= sExtraDir
; 
 565         wxStringTokenizer 
tokenizer(xdgDataDirs
, ":"); 
 566         while ( tokenizer
.HasMoreTokens() ) 
 568             wxString p 
= tokenizer
.GetNextToken(); 
 571         dirs
.insert(dirs
.begin(), xdgDataHome
); 
 573         wxString defaultsList
; 
 575         for (i 
= 0; i 
< dirs
.GetCount(); i
++) 
 577             wxString f 
= dirs
[i
]; 
 578             if (f
.Last() != '/') f 
+= '/'; 
 579             f 
+= "applications/defaults.list"; 
 587         // Load application files and associate them to corresponding mime types. 
 588         size_t nDirs 
= dirs
.GetCount(); 
 589         for (size_t nDir 
= 0; nDir 
< nDirs
; nDir
++) 
 591             wxString dirStr 
= dirs
[nDir
]; 
 592             if (dirStr
.Last() != '/') dirStr 
+= '/'; 
 593             dirStr 
+= "applications"; 
 594             LoadXDGAppsFilesFromDir(dirStr
); 
 597         if (!defaultsList
.IsEmpty()) 
 599             wxArrayString deskTopFilesSeen
; 
 601             wxMimeTextFile 
textfile(defaultsList
); 
 602             if ( textfile
.Open() ) 
 604                 int nIndex 
= textfile
.pIndexOf( wxT("[Default Applications]") ); 
 605                 if (nIndex 
!= wxNOT_FOUND
) 
 607                     for (i 
= nIndex
+1; i 
< textfile
.GetLineCount(); i
++) 
 609                         if (textfile
.GetLine(i
).Find(wxT("=")) != wxNOT_FOUND
) 
 611                             wxString desktopFile 
= textfile
.GetCmd(i
); 
 613                             if (deskTopFilesSeen
.Index(desktopFile
) == wxNOT_FOUND
) 
 615                                 deskTopFilesSeen
.Add(desktopFile
); 
 617                                 for (j 
= 0; j 
< dirs
.GetCount(); j
++) 
 619                                     wxString desktopPath 
= dirs
[j
]; 
 620                                     if (desktopPath
.Last() != '/') desktopPath 
+= '/'; 
 621                                     desktopPath 
+= "applications/"; 
 622                                     desktopPath 
+= desktopFile
; 
 624                                     if (wxFileExists(desktopPath
)) 
 625                                         LoadXDGApp(desktopPath
); 
 637 // clear data so you can read another group of WM files 
 638 void wxMimeTypesManagerImpl::ClearData() 
 642     m_aExtensions
.Clear(); 
 643     m_aDescriptions
.Clear(); 
 645     WX_CLEAR_ARRAY(m_aEntries
); 
 649 wxMimeTypesManagerImpl::~wxMimeTypesManagerImpl() 
 654 wxFileType 
* wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo
& ftInfo
) 
 658     wxString strType 
= ftInfo
.GetMimeType(); 
 659     wxString strDesc 
= ftInfo
.GetDescription(); 
 660     wxString strIcon 
= ftInfo
.GetIconFile(); 
 662     wxMimeTypeCommands 
*entry 
= new wxMimeTypeCommands(); 
 664     if ( ! ftInfo
.GetOpenCommand().empty()) 
 665         entry
->Add(wxT("open=")  + ftInfo
.GetOpenCommand() + wxT(" %s ")); 
 666     if ( ! ftInfo
.GetPrintCommand().empty()) 
 667         entry
->Add(wxT("print=") + ftInfo
.GetPrintCommand() + wxT(" %s ")); 
 669     // now find where these extensions are in the data store and remove them 
 670     wxArrayString sA_Exts 
= ftInfo
.GetExtensions(); 
 671     wxString sExt
, sExtStore
; 
 673     size_t nExtCount 
= sA_Exts
.GetCount(); 
 674     for (i
=0; i 
< nExtCount
; i
++) 
 676         sExt 
= sA_Exts
.Item(i
); 
 678         // clean up to just a space before and after 
 679         sExt
.Trim().Trim(false); 
 680         sExt 
= wxT(' ') + sExt 
+ wxT(' '); 
 681         size_t nCount 
= m_aExtensions
.GetCount(); 
 682         for (nIndex 
= 0; nIndex 
< nCount
; nIndex
++) 
 684             sExtStore 
= m_aExtensions
.Item(nIndex
); 
 685             if (sExtStore
.Replace(sExt
, wxT(" ") ) > 0) 
 686                 m_aExtensions
.Item(nIndex
) = sExtStore
; 
 690     if ( !DoAssociation(strType
, strIcon
, entry
, sA_Exts
, strDesc
) ) 
 693     return GetFileTypeFromMimeType(strType
); 
 696 bool wxMimeTypesManagerImpl::DoAssociation(const wxString
& strType
, 
 697                                            const wxString
& strIcon
, 
 698                                            wxMimeTypeCommands 
*entry
, 
 699                                            const wxArrayString
& strExtensions
, 
 700                                            const wxString
& strDesc
) 
 702     int nIndex 
= AddToMimeData(strType
, strIcon
, entry
, strExtensions
, strDesc
, true); 
 704     if ( nIndex 
== wxNOT_FOUND 
) 
 710 int wxMimeTypesManagerImpl::AddToMimeData(const wxString
& strType
, 
 711                                           const wxString
& strIcon
, 
 712                                           wxMimeTypeCommands 
*entry
, 
 713                                           const wxArrayString
& strExtensions
, 
 714                                           const wxString
& strDesc
, 
 715                                           bool replaceExisting
) 
 719     // ensure mimetype is always lower case 
 720     wxString mimeType 
= strType
.Lower(); 
 722     // is this a known MIME type? 
 723     int nIndex 
= m_aTypes
.Index(mimeType
); 
 724     if ( nIndex 
== wxNOT_FOUND 
) 
 726         // We put MIME types containing  "application" at the end, so that 
 727         // if the MIME type for the extention "htm" is searched for, it will 
 728         // rather find "text/html" than "application/x-mozilla-bookmarks". 
 729         if (mimeType
.Find( "application" ) == 0) 
 732            m_aTypes
.Add(mimeType
); 
 733            m_aIcons
.Add(strIcon
); 
 734            m_aEntries
.Add(entry 
? entry 
: new wxMimeTypeCommands
); 
 736            // change nIndex so we can use it below to add the extensions 
 737            m_aExtensions
.Add(wxEmptyString
); 
 738            nIndex 
= m_aExtensions
.size() - 1; 
 740            m_aDescriptions
.Add(strDesc
); 
 745            m_aTypes
.Insert(mimeType
,0); 
 746            m_aIcons
.Insert(strIcon
,0); 
 747            m_aEntries
.Insert(entry 
? entry 
: new wxMimeTypeCommands
,0); 
 749            // change nIndex so we can use it below to add the extensions 
 750            m_aExtensions
.Insert(wxEmptyString
,0); 
 753            m_aDescriptions
.Insert(strDesc
,0); 
 756     else // yes, we already have it 
 758         if ( replaceExisting 
) 
 760             // if new description change it 
 761             if ( !strDesc
.empty()) 
 762                 m_aDescriptions
[nIndex
] = strDesc
; 
 764             // if new icon change it 
 765             if ( !strIcon
.empty()) 
 766                 m_aIcons
[nIndex
] = strIcon
; 
 770                 delete m_aEntries
[nIndex
]; 
 771                 m_aEntries
[nIndex
] = entry
; 
 774         else // add data we don't already have ... 
 776             // if new description add only if none 
 777             if ( m_aDescriptions
[nIndex
].empty() ) 
 778                 m_aDescriptions
[nIndex
] = strDesc
; 
 780             // if new icon and no existing icon 
 781             if ( m_aIcons
[nIndex
].empty() ) 
 782                 m_aIcons
[nIndex
] = strIcon
; 
 784             // add any new entries... 
 787                 wxMimeTypeCommands 
*entryOld 
= m_aEntries
[nIndex
]; 
 789                 size_t count 
= entry
->GetCount(); 
 790                 for ( size_t i 
= 0; i 
< count
; i
++ ) 
 792                     const wxString
& verb 
= entry
->GetVerb(i
); 
 793                     if ( !entryOld
->HasVerb(verb
) ) 
 795                         entryOld
->AddOrReplaceVerb(verb
, entry
->GetCmd(i
)); 
 799                 // as we don't store it anywhere, it won't be deleted later as 
 800                 // usual -- do it immediately instead 
 806     // always add the extensions to this mimetype 
 807     wxString
& exts 
= m_aExtensions
[nIndex
]; 
 809     // add all extensions we don't have yet 
 811     size_t count 
= strExtensions
.GetCount(); 
 812     for ( size_t i 
= 0; i 
< count
; i
++ ) 
 814         ext 
= strExtensions
[i
]; 
 817         if ( exts
.Find(ext
) == wxNOT_FOUND 
) 
 823     // check data integrity 
 824     wxASSERT( m_aTypes
.GetCount() == m_aEntries
.GetCount() && 
 825               m_aTypes
.GetCount() == m_aExtensions
.GetCount() && 
 826               m_aTypes
.GetCount() == m_aIcons
.GetCount() && 
 827               m_aTypes
.GetCount() == m_aDescriptions
.GetCount() ); 
 832 wxFileType 
* wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString
& ext
) 
 839     size_t count 
= m_aExtensions
.GetCount(); 
 840     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 842         wxStringTokenizer 
tk(m_aExtensions
[n
], wxT(' ')); 
 844         while ( tk
.HasMoreTokens() ) 
 846             // consider extensions as not being case-sensitive 
 847             if ( tk
.GetNextToken().IsSameAs(ext
, false /* no case */) ) 
 850                 wxFileType 
*fileType 
= new wxFileType
; 
 851                 fileType
->m_impl
->Init(this, n
); 
 861 wxFileType 
* wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString
& mimeType
) 
 865     wxFileType 
* fileType 
= NULL
; 
 866     // mime types are not case-sensitive 
 867     wxString 
mimetype(mimeType
); 
 868     mimetype
.MakeLower(); 
 870     // first look for an exact match 
 871     int index 
= m_aTypes
.Index(mimetype
); 
 873     if ( index 
!= wxNOT_FOUND 
) 
 875         fileType 
= new wxFileType
; 
 876         fileType
->m_impl
->Init(this, index
); 
 879     // then try to find "text/*" as match for "text/plain" (for example) 
 880     // NB: if mimeType doesn't contain '/' at all, BeforeFirst() will return 
 881     //     the whole string - ok. 
 884     wxString strCategory 
= mimetype
.BeforeFirst(wxT('/')); 
 886     size_t nCount 
= m_aTypes
.GetCount(); 
 887     for ( size_t n 
= 0; n 
< nCount
; n
++ ) 
 889         if ( (m_aTypes
[n
].BeforeFirst(wxT('/')) == strCategory 
) && 
 890                 m_aTypes
[n
].AfterFirst(wxT('/')) == wxT("*") ) 
 897     if ( index 
!= wxNOT_FOUND 
) 
 899        // don't throw away fileType that was already found 
 901             fileType 
= new wxFileType
; 
 902         fileType
->m_impl
->Init(this, index
); 
 908 wxString 
wxMimeTypesManagerImpl::GetCommand(const wxString 
& verb
, size_t nIndex
) const 
 910     wxString command
, testcmd
, sV
, sTmp
; 
 911     sV 
= verb 
+ wxT("="); 
 913     // list of verb = command pairs for this mimetype 
 914     wxMimeTypeCommands 
* sPairs 
= m_aEntries 
[nIndex
]; 
 917     size_t nCount 
= sPairs
->GetCount(); 
 918     for ( i 
= 0; i 
< nCount
; i
++ ) 
 920         sTmp 
= sPairs
->GetVerbCmd (i
); 
 921         if ( sTmp
.Contains(sV
) ) 
 922             command 
= sTmp
.AfterFirst(wxT('=')); 
 928 void wxMimeTypesManagerImpl::AddFallback(const wxFileTypeInfo
& filetype
) 
 933     const wxArrayString
& exts 
= filetype
.GetExtensions(); 
 934     size_t nExts 
= exts
.GetCount(); 
 935     for ( size_t nExt 
= 0; nExt 
< nExts
; nExt
++ ) 
 938             extensions 
+= wxT(' '); 
 940         extensions 
+= exts
[nExt
]; 
 943     AddMimeTypeInfo(filetype
.GetMimeType(), 
 945                     filetype
.GetDescription()); 
 948 void wxMimeTypesManagerImpl::AddMimeTypeInfo(const wxString
& strMimeType
, 
 949                                              const wxString
& strExtensions
, 
 950                                              const wxString
& strDesc
) 
 952     // reading mailcap may find image/* , while 
 953     // reading mime.types finds image/gif and no match is made 
 954     // this means all the get functions don't work  fix this 
 956     wxString sTmp 
= strExtensions
; 
 959     sTmp
.Trim().Trim(false); 
 961     while (!sTmp
.empty()) 
 963         sExts
.Add(sTmp
.AfterLast(wxT(' '))); 
 964         sTmp 
= sTmp
.BeforeLast(wxT(' ')); 
 967     AddToMimeData(strMimeType
, strIcon
, NULL
, sExts
, strDesc
, true); 
 970 size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString
& mimetypes
) 
 976     size_t count 
= m_aTypes
.GetCount(); 
 977     for ( size_t n 
= 0; n 
< count
; n
++ ) 
 979         // don't return template types from here (i.e. anything containg '*') 
 980         const wxString 
&type 
= m_aTypes
[n
]; 
 981         if ( type
.Find(wxT('*')) == wxNOT_FOUND 
) 
 987     return mimetypes
.GetCount(); 
 990 // ---------------------------------------------------------------------------- 
 991 // writing to MIME type files 
 992 // ---------------------------------------------------------------------------- 
 994 bool wxMimeTypesManagerImpl::Unassociate(wxFileType 
*ft
) 
 998     wxArrayString sMimeTypes
; 
 999     ft
->GetMimeTypes(sMimeTypes
); 
1002     size_t nCount 
= sMimeTypes
.GetCount(); 
1003     for (i 
= 0; i 
< nCount
; i 
++) 
1005         const wxString 
&sMime 
= sMimeTypes
.Item(i
); 
1006         int nIndex 
= m_aTypes
.Index(sMime
); 
1007         if ( nIndex 
== wxNOT_FOUND
) 
1009             // error if we get here ?? 
1014             m_aTypes
.RemoveAt(nIndex
); 
1015             m_aEntries
.RemoveAt(nIndex
); 
1016             m_aExtensions
.RemoveAt(nIndex
); 
1017             m_aDescriptions
.RemoveAt(nIndex
); 
1018             m_aIcons
.RemoveAt(nIndex
); 
1021     // check data integrity 
1022     wxASSERT( m_aTypes
.GetCount() == m_aEntries
.GetCount() && 
1023             m_aTypes
.GetCount() == m_aExtensions
.GetCount() && 
1024             m_aTypes
.GetCount() == m_aIcons
.GetCount() && 
1025             m_aTypes
.GetCount() == m_aDescriptions
.GetCount() ); 
1031   // wxUSE_MIMETYPE && wxUSE_FILE