2 /////////////////////////////////////////////////////////////////////////////
3 // Name: unix/mimetype.cpp
4 // Purpose: classes and functions to manage MIME types
5 // Author: Vadim Zeitlin
9 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
10 // Licence: wxWindows license (part of wxExtra library)
11 /////////////////////////////////////////////////////////////////////////////
13 // known bugs; there may be others!! chris elliott, biol75@york.ac.uk 27 Mar 01
15 // 1) .mailcap and .mimetypes can be either in a netscape or metamail format
16 // and entries may get confused during writing (I've tried to fix this; please let me know
17 // any files that fail)
18 // 2) KDE and Gnome do not yet fully support international read/write
19 // 3) Gnome key lines like open.latex."LaTeX this file"=latex %f will have odd results
20 // 4) writing to files comments out the existing data; I hope this avoids losing
21 // any data which we could not read, and data which we did not store like test=
22 // 5) results from reading files with multiple entries (especially matches with type/* )
23 // may (or may not) work for getXXX commands
24 // 6) Loading the png icons in Gnome doesn't work for me...
25 // 7) In Gnome, if keys.mime exists but keys.users does not, there is
26 // an error message in debug mode, but the file is still written OK
27 // 8) Deleting entries is only allowed from the user file; sytem wide entries
28 // will be preserved during unassociate
29 // 9) KDE does not yet handle multiple actions; Netscape mode n??ever will
31 // ============================================================================
33 // ============================================================================
35 // ----------------------------------------------------------------------------
37 // ----------------------------------------------------------------------------
40 #pragma implementation "mimetype.h"
43 // for compilers that support precompilation, includes "wx.h".
44 #include "wx/wxprec.h"
54 #if wxUSE_FILE && wxUSE_TEXTFILE
57 #include "wx/string.h"
68 #include "wx/dynarray.h"
69 #include "wx/confbase.h"
72 #include "wx/textfile.h"
75 #include "wx/tokenzr.h"
77 #include "wx/unix/mimetype.h"
79 // other standard headers
82 // this is a class to extend wxArrayString...
83 class wxMimeArrayString
: public wxArrayString
91 size_t pIndexOf (const wxString
& verb
)
95 // avoid a problem with modifying const parameter
97 while ( (i
< GetCount()) && (! Item(i
).MakeLower().Contains(sTmp
)) )
101 if ( i
==GetCount() ) i
= (size_t)wxNOT_FOUND
;
105 bool ReplaceOrAddLineCmd (const wxString verb
, const wxString
& cmd
)
107 size_t nIndex
= pIndexOf (verb
);
108 if (nIndex
== (size_t)wxNOT_FOUND
)
109 Add(verb
+ wxT("=") + cmd
);
111 Item(nIndex
) = verb
+ wxT("=") + cmd
;
115 wxString
GetVerb (size_t i
)
117 if (i
< 0) return wxEmptyString
;
118 if (i
> GetCount() ) return wxEmptyString
;
119 wxString sTmp
= Item(i
).BeforeFirst(wxT('='));
123 wxString
GetCmd (size_t i
)
125 if (i
< 0) return wxEmptyString
;
126 if (i
> GetCount() ) return wxEmptyString
;
127 wxString sTmp
= Item(i
).AfterFirst(wxT('='));
132 //this class extends wxTextFile
133 class wxMimeTextFile
: public wxTextFile
137 wxMimeTextFile () : wxTextFile () {};
138 wxMimeTextFile (const wxString
& strFile
) : wxTextFile (strFile
) { };
140 int pIndexOf(const wxString
& sSearch
, bool bIncludeComments
= FALSE
, int iStart
= 0)
143 int nResult
= wxNOT_FOUND
;
144 if (i
>=GetLineCount()) return wxNOT_FOUND
;
146 wxString sTest
= sSearch
;
150 if (bIncludeComments
)
152 while ( (i
< GetLineCount()) )
156 if (sLine
.Contains(sTest
)) nResult
= (int) i
;
162 while ( (i
< GetLineCount()) )
166 if ( ! sLine
.StartsWith(wxT("#")))
168 if (sLine
.Contains(sTest
)) nResult
= (int) i
;
176 bool CommentLine(int nIndex
)
178 if (nIndex
<0) return FALSE
;
179 if (nIndex
>= (int)GetLineCount() ) return FALSE
;
180 GetLine(nIndex
) = GetLine(nIndex
).Prepend(wxT("#"));
184 bool CommentLine(const wxString
& sTest
)
186 int nIndex
= pIndexOf(sTest
);
187 if (nIndex
<0) return FALSE
;
188 if (nIndex
>= (int)GetLineCount() ) return FALSE
;
189 GetLine(nIndex
) = GetLine(nIndex
).Prepend(wxT("#"));
193 wxString
GetVerb (size_t i
)
195 if (i
< 0) return wxEmptyString
;
196 if (i
> GetLineCount() ) return wxEmptyString
;
197 wxString sTmp
= GetLine(i
).BeforeFirst(wxT('='));
201 wxString
GetCmd (size_t i
)
203 if (i
< 0) return wxEmptyString
;
204 if (i
> GetLineCount() ) return wxEmptyString
;
205 wxString sTmp
= GetLine(i
).AfterFirst(wxT('='));
210 // in case we're compiling in non-GUI mode
211 class WXDLLEXPORT wxIcon
;
213 // ----------------------------------------------------------------------------
215 // ----------------------------------------------------------------------------
217 // MIME code tracing mask
218 #define TRACE_MIME _T("mime")
220 // ----------------------------------------------------------------------------
222 // ----------------------------------------------------------------------------
224 // there are some fields which we don't understand but for which we don't give
225 // warnings as we know that they're not important - this function is used to
227 static bool IsKnownUnimportantField(const wxString
& field
);
229 // ----------------------------------------------------------------------------
231 // ----------------------------------------------------------------------------
235 // This class uses both mailcap and mime.types to gather information about file
238 // The information about mailcap file was extracted from metamail(1) sources
239 // and documentation and subsequently revised when I found the RFC 1524
242 // Format of mailcap file: spaces are ignored, each line is either a comment
243 // (starts with '#') or a line of the form <field1>;<field2>;...;<fieldN>.
244 // A backslash can be used to quote semicolons and newlines (and, in fact,
245 // anything else including itself).
247 // The first field is always the MIME type in the form of type/subtype (see RFC
248 // 822) where subtype may be '*' meaning "any". Following metamail, we accept
249 // "type" which means the same as "type/*", although I'm not sure whether this
252 // The second field is always the command to run. It is subject to
253 // parameter/filename expansion described below.
255 // All the following fields are optional and may not be present at all. If
256 // they're present they may appear in any order, although each of them should
257 // appear only once. The optional fields are the following:
258 // * notes=xxx is an uninterpreted string which is silently ignored
259 // * test=xxx is the command to be used to determine whether this mailcap line
260 // applies to our data or not. The RHS of this field goes through the
261 // parameter/filename expansion (as the 2nd field) and the resulting string
262 // is executed. The line applies only if the command succeeds, i.e. returns 0
264 // * print=xxx is the command to be used to print (and not view) the data of
265 // this type (parameter/filename expansion is done here too)
266 // * edit=xxx is the command to open/edit the data of this type
267 // * needsterminal means that a new interactive console must be created for
269 // * copiousoutput means that the viewer doesn't interact with the user but
270 // produces (possibly) a lof of lines of output on stdout (i.e. "cat" is a
271 // good example), thus it might be a good idea to use some kind of paging
273 // * textualnewlines means not to perform CR/LF translation (not honored)
274 // * compose and composetyped fields are used to determine the program to be
275 // called to create a new message pert in the specified format (unused).
277 // Parameter/filename expansion:
278 // * %s is replaced with the (full) file name
279 // * %t is replaced with MIME type/subtype of the entry
280 // * for multipart type only %n is replaced with the nnumber of parts and %F is
281 // replaced by an array of (content-type, temporary file name) pairs for all
282 // message parts (TODO)
283 // * %{parameter} is replaced with the value of parameter taken from
284 // Content-type header line of the message.
287 // There are 2 possible formats for mime.types file, one entry per line (used
288 // for global mime.types and called Mosaic format) and "expanded" format where
289 // an entry takes multiple lines (used for users mime.types and called
292 // For both formats spaces are ignored and lines starting with a '#' are
293 // comments. Each record has one of two following forms:
294 // a) for "brief" format:
295 // <mime type> <space separated list of extensions>
296 // b) for "expanded" format:
297 // type=<mime type> \
298 // desc="<description>" \
299 // exts="<comma separated list of extensions>"
301 // We try to autodetect the format of mime.types: if a non-comment line starts
302 // with "type=" we assume the second format, otherwise the first one.
304 // there may be more than one entry for one and the same mime type, to
305 // choose the right one we have to run the command specified in the test
306 // field on our data.
308 // ----------------------------------------------------------------------------
310 // ----------------------------------------------------------------------------
312 // GNOME stores the info we're interested in in several locations:
313 // 1. xxx.keys files under /usr/share/mime-info
314 // 2. xxx.keys files under ~/.gnome/mime-info
316 // The format of xxx.keys file is the following:
321 // with blank lines separating the entries and indented lines starting with
322 // TABs. We're interested in the field icon-filename whose value is the path
323 // containing the icon.
325 // Update (Chris Elliott): apparently there may be an optional "[lang]" prefix
326 // just before the field name.
329 bool wxMimeTypesManagerImpl::CheckGnomeDirsExist ()
332 wxGetHomeDir( &gnomedir
);
333 wxString sTmp
= gnomedir
;
334 sTmp
= sTmp
+ "/.gnome" ;
335 if (! wxDir::Exists ( sTmp
) )
337 if (!wxMkdir ( sTmp
))
339 wxFAIL_MSG (wxString ("Failed to create directory\n.gnome in \nCheckGnomeDirsExist") + sTmp
);
343 sTmp
= sTmp
+ "/mime-info";
344 if (! wxDir::Exists ( sTmp
) )
346 if (!wxMkdir ( sTmp
))
348 wxFAIL_MSG (wxString ("Failed to create directory\nmime-info in \nCheckGnomeDirsExist") + sTmp
);
358 bool wxMimeTypesManagerImpl::WriteGnomeKeyFile(int index
, bool delete_index
)
361 wxGetHomeDir( &gnomedir
);
363 wxMimeTextFile
outfile ( gnomedir
+ "/.gnome/mime-info/user.keys");
364 // if this fails probably Gnome is not installed ??
365 // create it anyway as a private mime store
367 if (! outfile
.Open () )
369 if (delete_index
) return FALSE
;
370 if (!CheckGnomeDirsExist() ) return FALSE
;
374 wxString sTmp
, strType
= m_aTypes
[index
];
375 int nIndex
= outfile
.pIndexOf(strType
);
376 if ( nIndex
== wxNOT_FOUND
)
378 outfile
.AddLine ( strType
+ wxT(':') );
379 // see file:/usr/doc/gnome-libs-devel-1.0.40/devel-docs/mime-type-handling.txt
380 // as this does not deal with internationalisation
381 // wxT( "\t[en_US]") + verb + wxT ('=') + cmd + wxT(" %f");
382 wxMimeArrayString
* entries
= m_aEntries
[index
];
384 for (i
=0; i
< entries
->GetCount(); i
++)
386 sTmp
= entries
->Item(i
);
387 sTmp
.Replace( wxT("%s"), wxT("%f") );
388 sTmp
= wxT ( "\t") + sTmp
;
389 outfile
.AddLine ( sTmp
);
391 //for international use do something like this
392 //outfile.AddLine ( wxString( "\t[en_US]icon-filename=") + cmd );
393 outfile
.AddLine ( wxT( "\ticon-filename=") + m_aIcons
[index
] );
397 if (delete_index
) outfile
.CommentLine(nIndex
);
398 wxMimeArrayString sOld
;
399 size_t nOld
= nIndex
+ 1;
400 bool oldEntryEnd
= FALSE
;
401 while ( (nOld
< outfile
.GetLineCount() )&& (oldEntryEnd
== FALSE
))
403 sTmp
= outfile
.GetLine(nOld
);
404 if ( (sTmp
[0u] == wxT('\t')) || (sTmp
[0u] == wxT('#')) )
406 // we have another line to deal with
407 outfile
.CommentLine(nOld
);
409 // add the line to our store
410 if ((!delete_index
) && (sTmp
[0u] == wxT('\t'))) sOld
.Add(sTmp
);
412 // next mimetpye ??or blank line
413 else oldEntryEnd
= TRUE
;
415 // list of entries in our data; these should all be in sOld,
416 // though sOld may also contain other entries , eg flags
419 wxMimeArrayString
* entries
= m_aEntries
[index
];
421 for (i
=0; i
< entries
->GetCount(); i
++)
423 // replace any entries in sold that match verbs we know
424 sOld
.ReplaceOrAddLineCmd ( entries
->GetVerb(i
), entries
->GetCmd (i
) );
426 //sOld should also contain the icon
427 if ( !m_aIcons
[index
].IsEmpty() )
428 sOld
.ReplaceOrAddLineCmd ( wxT( "icon-filename"), m_aIcons
[index
] );
430 for (i
=0; i
< sOld
.GetCount(); i
++)
433 sTmp
.Replace( wxT("%s"), wxT("%f") );
434 sTmp
= wxT ( "\t") + sTmp
;
436 outfile
.InsertLine ( sTmp
, nIndex
);
440 bool bTmp
= outfile
.Write ();
445 bool wxMimeTypesManagerImpl::WriteGnomeMimeFile(int index
, bool delete_index
)
448 wxGetHomeDir( &gnomedir
);
450 wxMimeTextFile
outfile ( gnomedir
+ "/.gnome/mime-info/user.mime");
451 // if this fails probably Gnome is not installed ??
452 // create it anyway as a private mime store
453 if (! outfile
.Open () )
455 if (delete_index
) return FALSE
;
456 if (!CheckGnomeDirsExist() ) return FALSE
;
459 wxString strType
= m_aTypes
[index
];
460 int nIndex
= outfile
.pIndexOf(strType
);
461 if ( nIndex
== wxNOT_FOUND
)
463 outfile
.AddLine ( strType
);
464 outfile
.AddLine ( wxT( "\text:") + m_aExtensions
.Item(index
) );
470 outfile
.CommentLine(nIndex
);
471 outfile
.CommentLine(nIndex
+1);
474 {// check for next line being the right one to replace ??
475 wxString sOld
= outfile
.GetLine(nIndex
+1);
476 if (sOld
.Contains(wxT("\text: ")))
478 outfile
.GetLine(nIndex
+1) = wxT( "\text: ") + m_aExtensions
.Item(index
);
482 outfile
.InsertLine(wxT( "\text: ") + m_aExtensions
.Item(index
), nIndex
+ 1 );
486 bool bTmp
= outfile
.Write ();
491 void wxMimeTypesManagerImpl::LoadGnomeDataFromKeyFile(const wxString
& filename
)
493 wxTextFile
textfile(filename
);
494 if ( !textfile
.Open() )
496 wxLogTrace(TRACE_MIME
, wxT("--- Opened Gnome file %s ---"),
499 // values for the entry being parsed
500 wxString curMimeType
, curIconFile
;
501 wxMimeArrayString
* entry
= new wxMimeArrayString
;
503 // these are always empty in this file
504 wxArrayString strExtensions
;
508 size_t nLineCount
= textfile
.GetLineCount();
510 while ( nLine
< nLineCount
)
512 pc
= textfile
[nLine
].c_str();
513 if ( *pc
!= _T('#') )
516 wxLogTrace(TRACE_MIME
, wxT("--- Reading from Gnome file %s '%s' ---"),
517 filename
.c_str(),pc
);
520 if (sTmp
.Contains(wxT("=")) )
522 if (sTmp
.Contains( wxT("icon-filename=") ) )
524 curIconFile
= sTmp
.AfterFirst(wxT('='));
526 else //: some other field,
528 //may contain lines like this (RH7)
529 // \t[lang]open.tex."TeX this file"=tex %f
530 // \tflags.tex.flags=needsterminal
531 // \topen.latex."LaTeX this file"=latex %f
532 // \tflags.latex.flags=needsterminal
536 // \topen.convert.Convert file to Postscript=dvips %f -o `basename %f .dvi`.ps
538 // for now ignore lines with flags in...FIX
539 sTmp
= sTmp
.AfterLast(wxT(']'));
540 sTmp
= sTmp
.AfterLast(wxT('\t'));
541 sTmp
.Trim(FALSE
).Trim();
542 if (0 == sTmp
.Replace ( wxT("%f"), wxT("%s") )) sTmp
= sTmp
+ wxT(" %s");
547 } // emd of has an equals sign
550 // not a comment and not an equals sign
551 if (sTmp
.Contains(wxT('/')))
553 // this is the start of the new mimetype
554 // overwrite any existing data
555 if (! curMimeType
.IsEmpty())
557 AddToMimeData ( curMimeType
, curIconFile
, entry
, strExtensions
, strDesc
);
559 // now get ready for next bit
560 entry
= new wxMimeArrayString
;
562 curMimeType
= sTmp
.BeforeFirst(wxT(':'));
565 } // end of not a comment
566 // ignore blank lines
568 } // end of while, save any data
569 if (! curMimeType
.IsEmpty())
571 AddToMimeData ( curMimeType
, curIconFile
, entry
, strExtensions
, strDesc
);
578 void wxMimeTypesManagerImpl::LoadGnomeMimeTypesFromMimeFile(const wxString
& filename
)
580 wxTextFile
textfile(filename
);
581 if ( !textfile
.Open() )
583 wxLogTrace(TRACE_MIME
, wxT("--- Opened Gnome file %s ---"),
586 // values for the entry being parsed
587 wxString curMimeType
, curExtList
;
590 size_t nLineCount
= textfile
.GetLineCount();
591 for ( size_t nLine
= 0; ; nLine
++ )
593 if ( nLine
< nLineCount
)
595 pc
= textfile
[nLine
].c_str();
596 if ( *pc
== _T('#') )
604 // so that we will fall into the "if" below
611 if ( !!curMimeType
&& !!curExtList
)
613 wxLogTrace(TRACE_MIME
, wxT("--- At end of Gnome file finding mimetype %s ---"),
614 curMimeType
.c_str());
616 AddMimeTypeInfo(curMimeType
, curExtList
, wxEmptyString
);
621 // the end - this can only happen if nLine == nLineCount
630 // what do we have here?
631 if ( *pc
== _T('\t') )
633 // this is a field=value ling
634 pc
++; // skip leading TAB
636 static const int lenField
= 4; // strlen("ext:")
637 if ( wxStrncmp(pc
, _T("ext:"), lenField
) == 0 )
639 // skip ' ' which follows and take everything left until the end
641 curExtList
= pc
+ lenField
+ 1;
643 //else: some other field, we don't care
647 // this is the start of the new section
648 wxLogTrace(TRACE_MIME
, wxT("--- In Gnome file finding mimetype %s ---"),
649 curMimeType
.c_str());
651 if (! curMimeType
.IsEmpty()) AddMimeTypeInfo(curMimeType
, curExtList
, wxEmptyString
);
655 while ( *pc
!= _T(':') && *pc
!= _T('\0') )
657 curMimeType
+= *pc
++;
664 void wxMimeTypesManagerImpl::LoadGnomeMimeFilesFromDir(const wxString
& dirbase
)
666 wxASSERT_MSG( !!dirbase
&& !wxEndsWithPathSeparator(dirbase
),
667 _T("base directory shouldn't end with a slash") );
669 wxString dirname
= dirbase
;
670 dirname
<< _T("/mime-info");
672 if ( !wxDir::Exists(dirname
) )
676 if ( !dir
.IsOpened() )
679 // we will concatenate it with filename to get the full path below
683 bool cont
= dir
.GetFirst(&filename
, _T("*.mime"), wxDIR_FILES
);
686 LoadGnomeMimeTypesFromMimeFile(dirname
+ filename
);
688 cont
= dir
.GetNext(&filename
);
691 cont
= dir
.GetFirst(&filename
, _T("*.keys"), wxDIR_FILES
);
694 LoadGnomeDataFromKeyFile(dirname
+ filename
);
696 cont
= dir
.GetNext(&filename
);
703 void wxMimeTypesManagerImpl::GetGnomeMimeInfo(const wxString
& sExtraDir
)
707 dirs
.Add(_T("/usr/share"));
708 dirs
.Add(_T("/usr/local/share"));
711 wxGetHomeDir( &gnomedir
);
712 gnomedir
+= _T("/.gnome");
713 dirs
.Add( gnomedir
);
714 if (!sExtraDir
.IsEmpty()) dirs
.Add( sExtraDir
);
716 size_t nDirs
= dirs
.GetCount();
717 for ( size_t nDir
= 0; nDir
< nDirs
; nDir
++ )
719 LoadGnomeMimeFilesFromDir(dirs
[nDir
]);
728 // ----------------------------------------------------------------------------
730 // ----------------------------------------------------------------------------
732 // KDE stores the icon info in its .kdelnk files. The file for mimetype/subtype
733 // may be found in either of the following locations
735 // 1. $KDEDIR/share/mimelnk/mimetype/subtype.kdelnk
736 // 2. ~/.kde/share/mimelnk/mimetype/subtype.kdelnk
738 // The format of a .kdelnk file is almost the same as the one used by
739 // wxFileConfig, i.e. there are groups, comments and entries. The icon is the
740 // value for the entry "Type"
742 // kde writing; see http://webcvs.kde.org/cgi-bin/cvsweb.cgi/~checkout~/kdelibs/kio/DESKTOP_ENTRY_STANDARD
743 // for now write to .kdelnk but should eventually do .desktop instead (in preference??)
745 bool wxMimeTypesManagerImpl::CheckKDEDirsExist ( const wxString
& sOK
, const wxString
& sTest
)
750 if (wxDir::Exists(sOK
)) return TRUE
;
755 wxString sStart
= sOK
+ wxT("/") + sTest
.BeforeFirst(wxT('/'));
756 if (!wxDir::Exists(sStart
)) wxMkdir(sStart
);
757 wxString sEnd
= sTest
.AfterFirst(wxT('/'));
758 return CheckKDEDirsExist(sStart
, sEnd
);
762 bool wxMimeTypesManagerImpl::WriteKDEMimeFile(int index
, bool delete_index
)
764 wxMimeTextFile appoutfile
, mimeoutfile
;
765 wxString sHome
= wxGetHomeDir();
766 wxString sTmp
= wxT(".kde/share/mimelnk/");
767 wxString sMime
= m_aTypes
[index
] ;
768 CheckKDEDirsExist (sHome
, sTmp
+ sMime
.BeforeFirst(wxT('/')) );
769 sTmp
= sHome
+ wxT('/') + sTmp
+ sMime
+ wxT(".kdelnk");
772 bool bMimeExists
= mimeoutfile
.Open (sTmp
);
775 bTemp
= mimeoutfile
.Create (sTmp
);
776 // some unknown error eg out of disk space
777 if (!bTemp
) return FALSE
;
780 sTmp
= wxT(".kde/share/applnk/");
781 CheckKDEDirsExist (sHome
, sTmp
+ sMime
.AfterFirst(wxT('/')) );
782 sTmp
= sHome
+ wxT('/') + sTmp
+ sMime
.AfterFirst(wxT('/')) + wxT(".kdelnk");
785 bAppExists
= appoutfile
.Open (sTmp
);
788 bTemp
= appoutfile
.Create (sTmp
);
789 // some unknown error eg out of disk space
790 if (!bTemp
) return FALSE
;
793 // fixed data; write if new file
796 mimeoutfile
.AddLine(wxT("#KDE Config File"));
797 mimeoutfile
.AddLine(wxT("[KDE Desktop Entry]"));
798 mimeoutfile
.AddLine(wxT("Version=1.0"));
799 mimeoutfile
.AddLine(wxT("Type=MimeType"));
800 mimeoutfile
.AddLine(wxT("MimeType=") + sMime
);
805 mimeoutfile
.AddLine(wxT("#KDE Config File"));
806 mimeoutfile
.AddLine(wxT("[KDE Desktop Entry]"));
807 appoutfile
.AddLine(wxT("Version=1.0"));
808 appoutfile
.AddLine(wxT("Type=Application"));
809 appoutfile
.AddLine(wxT("MimeType=") + sMime
+ wxT(';'));
814 mimeoutfile
.CommentLine(wxT("Comment="));
816 mimeoutfile
.AddLine(wxT("Comment=") + m_aDescriptions
[index
]);
817 appoutfile
.CommentLine(wxT("Name="));
819 appoutfile
.AddLine(wxT("Comment=") + m_aDescriptions
[index
]);
821 sTmp
= m_aIcons
[index
];
822 // we can either give the full path, or the shortfilename if its in
823 // one of the directories we search
824 mimeoutfile
.CommentLine(wxT("Icon=") );
825 if (!delete_index
) mimeoutfile
.AddLine(wxT("Icon=") + sTmp
);
826 appoutfile
.CommentLine(wxT("Icon=") );
827 if (!delete_index
) appoutfile
.AddLine(wxT("Icon=") + sTmp
);
829 sTmp
= wxT(" ") + m_aExtensions
[index
];
831 wxStringTokenizer
tokenizer(sTmp
, _T(" "));
832 sTmp
= wxT("Patterns=");
833 mimeoutfile
.CommentLine(sTmp
);
834 while ( tokenizer
.HasMoreTokens() )
836 // holds an extension; need to change it to *.ext;
837 wxString e
= wxT("*.") + tokenizer
.GetNextToken() + wxT(";");
840 if (!delete_index
) mimeoutfile
.AddLine(sTmp
);
842 wxMimeArrayString
* entries
= m_aEntries
[index
];
843 // if we don't find open just have an empty string ... FIX this
844 size_t iOpen
= entries
->pIndexOf(wxT("open"));
845 sTmp
= entries
->GetCmd(iOpen
);
846 sTmp
.Replace( wxT("%s"), wxT("%f") );
848 mimeoutfile
.CommentLine(wxT("DefaultApp=") );
849 if (!delete_index
) mimeoutfile
.AddLine(wxT("DefaultApp=") + sTmp
);
851 sTmp
.Replace( wxT("%f"), wxT("") );
852 appoutfile
.CommentLine(wxT("Exec="));
853 if (!delete_index
) appoutfile
.AddLine(wxT("Exec=") + sTmp
);
855 if (entries
->GetCount() > 1)
857 //other actions as well as open
861 if (mimeoutfile
.Write ()) bTemp
= TRUE
;
862 mimeoutfile
.Close ();
863 if (appoutfile
.Write ()) bTemp
= TRUE
;
871 void wxMimeTypesManagerImpl::LoadKDELinksForMimeSubtype(const wxString
& dirbase
,
872 const wxString
& subdir
,
873 const wxString
& filename
,
874 const wxArrayString
& icondirs
)
877 if ( !file
.Open(dirbase
+ filename
) ) return;
879 wxMimeArrayString
* entry
= new wxMimeArrayString
;
881 wxString mimetype
, mime_desc
, strIcon
;
883 int nIndex
= file
.pIndexOf ("MimeType=");
884 if (nIndex
== wxNOT_FOUND
)
886 // construct mimetype from the directory name and the basename of the
887 // file (it always has .kdelnk extension)
888 mimetype
<< subdir
<< _T('/') << filename
.BeforeLast(_T('.'));
890 else mimetype
= file
.GetCmd (nIndex
);
892 // first find the description string: it is the value in either "Comment="
893 // line or "Comment[<locale_name>]=" one
894 nIndex
= wxNOT_FOUND
;
898 wxLocale
*locale
= wxGetLocale();
901 // try "Comment[locale name]" first
902 comment
<< _T("Comment[") + locale
->GetName() + _T("]=");
903 nIndex
= file
.pIndexOf(comment
);
907 if ( nIndex
== wxNOT_FOUND
)
909 comment
= _T("Comment=");
910 nIndex
= file
.pIndexOf(comment
);
913 if ( nIndex
!= wxNOT_FOUND
) mime_desc
= file
.GetCmd(nIndex
);
914 //else: no description
916 // next find the extensions
917 wxString mime_extension
;
919 nIndex
= file
.pIndexOf(_T("Patterns="));
920 if ( nIndex
!= wxNOT_FOUND
)
922 wxString exts
= file
.GetCmd (nIndex
) ;;
924 wxStringTokenizer
tokenizer(exts
, _T(";"));
925 while ( tokenizer
.HasMoreTokens() )
927 wxString e
= tokenizer
.GetNextToken();
928 if ( e
.Left(2) != _T("*.") )
929 continue; // don't support too difficult patterns
931 if ( !mime_extension
.empty() )
933 // separate from the previous ext
934 mime_extension
<< _T(' ');
937 mime_extension
<< e
.Mid(2);
940 sExts
.Add(mime_extension
);
943 // ok, now we can take care of icon:
945 nIndex
= file
.pIndexOf(_T("Icon="));
946 if ( nIndex
!= wxNOT_FOUND
)
948 strIcon
= file
.GetCmd(nIndex
);
949 //it could be the real path, but more often a short name
950 if (!wxFileExists(strIcon
))
952 // icon is just the short name
953 if ( !strIcon
.IsEmpty() )
955 // we must check if the file exists because it may be stored
956 // in many locations, at least ~/.kde and $KDEDIR
957 size_t nDir
, nDirs
= icondirs
.GetCount();
958 for ( nDir
= 0; nDir
< nDirs
; nDir
++ )
959 if (wxFileExists(icondirs
[nDir
] + strIcon
))
961 strIcon
.Prepend(icondirs
[nDir
]);
967 // now look for lines which know about the application
968 // exec= or DefaultApp=
970 nIndex
= file
.pIndexOf(wxT("DefaultApp"));
972 if ( nIndex
== wxNOT_FOUND
)
975 nIndex
= file
.pIndexOf(wxT("Exec"));
978 if ( nIndex
!= wxNOT_FOUND
)
980 wxString sTmp
= file
.GetCmd(nIndex
);
981 // we expect %f; others including %F and %U and %u are possible
982 if (0 == sTmp
.Replace ( wxT("%f"), wxT("%s") )) sTmp
= sTmp
+ wxT(" %s");
983 entry
->ReplaceOrAddLineCmd (wxString(wxT("open")), sTmp
);
986 AddToMimeData (mimetype
, strIcon
, entry
, sExts
, mime_desc
);
991 void wxMimeTypesManagerImpl::LoadKDELinksForMimeType(const wxString
& dirbase
,
992 const wxString
& subdir
,
993 const wxArrayString
& icondirs
)
995 wxString dirname
= dirbase
;
998 if ( !dir
.IsOpened() )
1004 bool cont
= dir
.GetFirst(&filename
, _T("*.kdelnk"), wxDIR_FILES
);
1007 LoadKDELinksForMimeSubtype(dirname
, subdir
, filename
, icondirs
);
1009 cont
= dir
.GetNext(&filename
);
1011 // new standard for Gnome and KDE
1012 cont
= dir
.GetFirst(&filename
, _T("*.desktop"), wxDIR_FILES
);
1015 LoadKDELinksForMimeSubtype(dirname
, subdir
, filename
, icondirs
);
1017 cont
= dir
.GetNext(&filename
);
1021 void wxMimeTypesManagerImpl::LoadKDELinkFilesFromDir(const wxString
& dirbase
,
1022 const wxArrayString
& icondirs
)
1024 wxASSERT_MSG( !!dirbase
&& !wxEndsWithPathSeparator(dirbase
),
1025 _T("base directory shouldn't end with a slash") );
1027 wxString dirname
= dirbase
;
1028 dirname
<< _T("/mimelnk");
1030 if ( !wxDir::Exists(dirname
) )
1034 if ( !dir
.IsOpened() )
1037 // we will concatenate it with dir name to get the full path below
1041 bool cont
= dir
.GetFirst(&subdir
, wxEmptyString
, wxDIR_DIRS
);
1044 LoadKDELinksForMimeType(dirname
, subdir
, icondirs
);
1046 cont
= dir
.GetNext(&subdir
);
1050 void wxMimeTypesManagerImpl::GetKDEMimeInfo(const wxString
& sExtraDir
)
1053 wxArrayString icondirs
;
1055 // settings in ~/.kde have maximal priority
1056 dirs
.Add(wxGetHomeDir() + _T("/.kde/share"));
1057 icondirs
.Add(wxGetHomeDir() + _T("/.kde/share/icons/"));
1059 // the variable KDEDIR is set when KDE is running
1060 const char *kdedir
= getenv("KDEDIR");
1063 dirs
.Add(wxString(kdedir
) + _T("/share"));
1064 icondirs
.Add(wxString(kdedir
) + _T("/share/icons/"));
1068 // try to guess KDEDIR
1069 dirs
.Add(_T("/usr/share"));
1070 dirs
.Add(_T("/opt/kde/share"));
1071 icondirs
.Add(_T("/usr/share/icons/"));
1072 icondirs
.Add(_T("/usr/X11R6/share/icons/")); // Debian/Corel linux
1073 icondirs
.Add(_T("/opt/kde/share/icons/"));
1076 if (!sExtraDir
.IsEmpty()) dirs
.Add (sExtraDir
);
1077 icondirs
.Add(sExtraDir
+ wxT("/icons"));
1079 size_t nDirs
= dirs
.GetCount();
1080 for ( size_t nDir
= 0; nDir
< nDirs
; nDir
++ )
1082 LoadKDELinkFilesFromDir(dirs
[nDir
], icondirs
);
1090 // ----------------------------------------------------------------------------
1091 // wxFileTypeImpl (Unix)
1092 // ----------------------------------------------------------------------------
1095 wxString
wxFileTypeImpl::GetExpandedCommand(const wxString
& verb
, const wxFileType::MessageParameters
& params
) const
1099 while ( (i
< m_index
.GetCount() ) && sTmp
.IsEmpty() )
1101 sTmp
= m_manager
->GetCommand ( verb
, m_index
[i
] );
1105 return wxFileType::ExpandCommand(sTmp
, params
);
1108 bool wxFileTypeImpl::GetIcon(wxIcon
*icon
, wxString
*iconFile
/*= NULL */,
1109 int *iconIndex
/*= NULL*/) const
1114 while ( (i
< m_index
.GetCount() ) && sTmp
.IsEmpty() )
1116 sTmp
= m_manager
->m_aIcons
[m_index
[i
]];
1119 if ( sTmp
.IsEmpty () ) return FALSE
;
1123 if (sTmp
.Right(4).MakeUpper() == _T(".XPM"))
1126 icn
= wxIcon(sTmp
, wxBITMAP_TYPE_ANY
);
1131 if (iconFile
) *iconFile
= sTmp
;
1132 if (iconIndex
) *iconIndex
= 0;
1140 wxFileTypeImpl::GetMimeTypes(wxArrayString
& mimeTypes
) const
1143 for (size_t i
= 0; i
< m_index
.GetCount(); i
++)
1144 mimeTypes
.Add(m_manager
->m_aTypes
[m_index
[i
]]);
1149 size_t wxFileTypeImpl::GetAllCommands(wxArrayString
*verbs
,
1150 wxArrayString
*commands
,
1151 const wxFileType::MessageParameters
& params
) const
1154 wxString vrb
, cmd
, sTmp
;
1156 wxMimeArrayString
* sPairs
;
1158 // verbs and commands have been cleared already in mimecmn.cpp...
1159 // if we find no entries in the exact match, try the inexact match
1160 for (size_t n
= 0; ((count
==0) && (n
< m_index
.GetCount())); n
++)
1162 // list of verb = command pairs for this mimetype
1163 sPairs
= m_manager
->m_aEntries
[m_index
[n
]];
1165 for ( i
= 0; i
< sPairs
->GetCount () ; i
++ )
1167 vrb
= sPairs
->GetVerb(i
);
1168 // some gnome entries have . inside
1169 vrb
= vrb
.AfterLast(wxT('.'));
1170 cmd
= sPairs
->GetCmd (i
);
1171 if (! cmd
.IsEmpty() )
1173 cmd
= wxFileType::ExpandCommand(cmd
, params
);
1175 if ( vrb
.IsSameAs (wxT("open")))
1177 verbs
->Insert(vrb
,0u);
1178 commands
->Insert(cmd
,0u);
1183 commands
->Add (cmd
);
1194 bool wxFileTypeImpl::GetExtensions(wxArrayString
& extensions
)
1196 wxString strExtensions
= m_manager
->GetExtension(m_index
[0]);
1199 // one extension in the space or comma delimitid list
1201 for ( const wxChar
*p
= strExtensions
; ; p
++ ) {
1202 if ( *p
== wxT(' ') || *p
== wxT(',') || *p
== wxT('\0') ) {
1203 if ( !strExt
.IsEmpty() ) {
1204 extensions
.Add(strExt
);
1207 //else: repeated spaces (shouldn't happen, but it's not that
1208 // important if it does happen)
1210 if ( *p
== wxT('\0') )
1213 else if ( *p
== wxT('.') ) {
1214 // remove the dot from extension (but only if it's the first char)
1215 if ( !strExt
.IsEmpty() ) {
1218 //else: no, don't append it
1228 // set an arbitrary command,
1229 // could adjust the code to ask confirmation if it already exists and
1230 // overwriteprompt is TRUE, but this is currently ignored as *Associate* has
1231 // no overwrite prompt
1232 bool wxFileTypeImpl::SetCommand(const wxString
& cmd
, const wxString
& verb
, bool overwriteprompt
/*= TRUE*/)
1234 wxArrayString strExtensions
;
1235 wxString strDesc
, strIcon
;
1237 wxMimeArrayString
*entry
= new wxMimeArrayString ();
1238 entry
->Add(verb
+ wxT("=") + cmd
+ wxT(" %s "));
1240 wxArrayString strTypes
;
1241 GetMimeTypes (strTypes
);
1242 if (strTypes
.GetCount() < 1) return FALSE
;
1246 for (i
= 0; i
< strTypes
.GetCount(); i
++)
1248 if (!m_manager
->DoAssociation (strTypes
[i
], strIcon
, entry
, strExtensions
, strDesc
))
1255 // ignore index on the grouds that we only have one icon in a Unix file
1256 bool wxFileTypeImpl::SetDefaultIcon(const wxString
& strIcon
/*= wxEmptyString*/, int /*index = 0*/)
1258 if (strIcon
.IsEmpty()) return FALSE
;
1259 wxArrayString strExtensions
;
1262 wxMimeArrayString
*entry
= new wxMimeArrayString ();
1264 wxArrayString strTypes
;
1265 GetMimeTypes (strTypes
);
1266 if (strTypes
.GetCount() < 1) return FALSE
;
1270 for (i
= 0; i
< strTypes
.GetCount(); i
++)
1272 if (!m_manager
->DoAssociation (strTypes
[i
], strIcon
, entry
, strExtensions
, strDesc
))
1278 // ----------------------------------------------------------------------------
1279 // wxMimeTypesManagerImpl (Unix)
1280 // ----------------------------------------------------------------------------
1283 wxMimeTypesManagerImpl::wxMimeTypesManagerImpl()
1285 m_initialized
= FALSE
;
1286 m_mailcapStylesInited
= 0;
1289 // read system and user mailcaps and other files
1290 void wxMimeTypesManagerImpl::Initialize(int mailcapStyles
,
1291 const wxString
& sExtraDir
)
1293 // read mimecap amd mime.types
1294 if ( (mailcapStyles
& wxMAILCAP_NETSCAPE
) ||
1295 (mailcapStyles
& wxMAILCAP_STANDARD
) )
1296 GetMimeInfo(sExtraDir
);
1298 // read GNOME tables
1299 if ( mailcapStyles
& wxMAILCAP_GNOME
)
1300 GetGnomeMimeInfo(sExtraDir
);
1303 if ( mailcapStyles
& wxMAILCAP_KDE
)
1304 GetKDEMimeInfo(sExtraDir
);
1306 m_mailcapStylesInited
|= mailcapStyles
;
1309 // clear data so you can read another group of WM files
1310 void wxMimeTypesManagerImpl::ClearData()
1314 m_aExtensions
.Clear ();
1315 m_aDescriptions
.Clear ();
1317 size_t cnt
= m_aTypes
.GetCount();
1318 for (size_t i
= 0; i
< cnt
; i
++)
1320 m_aEntries
[i
]->Clear ();
1322 m_aEntries
.Clear ();
1323 m_mailcapStylesInited
= 0;
1326 wxMimeTypesManagerImpl::~wxMimeTypesManagerImpl()
1328 ClearData(); // do we need to delete the ArrayStrings too to avoid a leak
1330 // delete m_aEntries //fix a leak here ?;
1334 void wxMimeTypesManagerImpl::GetMimeInfo (const wxString
& sExtraDir
)
1336 // read this for netscape or Metamail formats
1338 // directories where we look for mailcap and mime.types by default
1339 // used by netscape and pine and other mailers, using 2 different formats!
1341 // (taken from metamail(1) sources)
1343 // although RFC 1524 specifies the search path of
1344 // /etc/:/usr/etc:/usr/local/etc only, it doesn't hurt to search in more
1345 // places - OTOH, the RFC also says that this path can be changed with
1346 // MAILCAPS environment variable (containing the colon separated full
1347 // filenames to try) which is not done yet (TODO?)
1349 wxString strHome
= wxGetenv(wxT("HOME"));
1352 dirs
.Add ( wxT("/etc/") );
1353 dirs
.Add ( wxT("/usr/etc/") );
1354 dirs
.Add ( wxT("/usr/local/etc/") );
1355 dirs
.Add ( wxT("/etc/mail/") );
1356 dirs
.Add ( wxT("/usr/public/lib/") );
1357 dirs
.Add ( strHome
+ wxT("/.") );
1358 if (!sExtraDir
.IsEmpty()) dirs
.Add ( sExtraDir
+ wxT("/") );
1360 size_t nDirs
= dirs
.GetCount();
1361 for ( size_t nDir
= 0; nDir
< nDirs
; nDir
++ )
1363 wxString file
= dirs
[nDir
] + wxT("mailcap");
1364 if ( wxFile::Exists(file
) ) {
1368 file
= dirs
[nDir
] + wxT("mime.types");
1369 if ( wxFile::Exists(file
) ) {
1370 ReadMimeTypes(file
);
1376 bool wxMimeTypesManagerImpl::WriteToMimeTypes (int index
, bool delete_index
)
1378 // check we have the right manager
1379 if (! ( m_mailcapStylesInited
& wxMAILCAP_STANDARD
) )
1383 wxString strHome
= wxGetenv(wxT("HOME"));
1385 // and now the users mailcap
1386 wxString strUserMailcap
= strHome
+ wxT("/.mime.types");
1388 wxMimeTextFile file
;
1389 if ( wxFile::Exists(strUserMailcap
) )
1391 bTemp
= file
.Open(strUserMailcap
);
1395 if (delete_index
) return FALSE
;
1396 bTemp
= file
.Create(strUserMailcap
);
1401 // test for netscape's header and return FALSE if its found
1402 nIndex
= file
.pIndexOf (wxT("#--Netscape"));
1403 if (nIndex
!= wxNOT_FOUND
)
1405 wxASSERT_MSG(FALSE
,wxT("Error in .mime.types \nTrying to mix Netscape and Metamail formats\nFile not modiifed"));
1408 // write it in alternative format
1409 // get rid of unwanted entries
1410 wxString strType
= m_aTypes
[index
];
1411 nIndex
= file
.pIndexOf (strType
);
1412 // get rid of all the unwanted entries...
1413 if (nIndex
!= wxNOT_FOUND
) file
.CommentLine (nIndex
);
1417 // add the new entries in
1418 wxString sTmp
= strType
.Append (wxT(' '), 40-strType
.Len() );
1419 sTmp
= sTmp
+ m_aExtensions
[index
];
1420 file
.AddLine (sTmp
);
1424 bTemp
= file
.Write ();
1430 bool wxMimeTypesManagerImpl::WriteToNSMimeTypes (int index
, bool delete_index
)
1432 //check we have the right managers
1433 if (! ( m_mailcapStylesInited
& wxMAILCAP_NETSCAPE
) )
1437 wxString strHome
= wxGetenv(wxT("HOME"));
1439 // and now the users mailcap
1440 wxString strUserMailcap
= strHome
+ wxT("/.mime.types");
1442 wxMimeTextFile file
;
1443 if ( wxFile::Exists(strUserMailcap
) )
1445 bTemp
= file
.Open(strUserMailcap
);
1449 if (delete_index
) return FALSE
;
1450 bTemp
= file
.Create(strUserMailcap
);
1455 // write it in the format that Netscape uses
1457 // test for netscape's header and insert if required...
1458 // this is a comment so use TRUE
1459 nIndex
= file
.pIndexOf (wxT("#--Netscape"), TRUE
);
1460 if (nIndex
== wxNOT_FOUND
)
1462 // either empty file or metamail format
1463 // at present we can't cope with mixed formats, so exit to preseve
1464 // metamail entreies
1465 if (file
.GetLineCount () > 0)
1467 wxASSERT_MSG(FALSE
, wxT(".mime.types File not in Netscape format\nNo entries written to\n.mime.types or to .mailcap"));
1470 file
.InsertLine (wxT( "#--Netscape Communications Corporation MIME Information" ), 0);
1474 wxString strType
= wxT("type=") + m_aTypes
[index
];
1475 nIndex
= file
.pIndexOf (strType
);
1476 // get rid of all the unwanted entries...
1477 if (nIndex
!= wxNOT_FOUND
)
1479 wxString sOld
= file
[nIndex
];
1480 while ( (sOld
.Contains(wxT("\\"))) && (nIndex
< (int) file
.GetLineCount()) )
1482 file
.CommentLine(nIndex
);
1483 sOld
= file
[nIndex
];
1484 wxLogTrace(TRACE_MIME
, wxT("--- Deleting from mime.types line '%d %s' ---"), nIndex
, sOld
.c_str());
1487 if (nIndex
< (int) file
.GetLineCount()) file
.CommentLine (nIndex
);
1489 else nIndex
= (int) file
.GetLineCount();
1491 wxString sTmp
= strType
+ wxT(" \\");
1492 if (!delete_index
) file
.InsertLine (sTmp
, nIndex
);
1493 if ( ! m_aDescriptions
.Item(index
).IsEmpty() )
1495 sTmp
= wxT("desc=\"") + m_aDescriptions
[index
]+ wxT("\" \\") ; //.trim ??
1499 file
.InsertLine (sTmp
, nIndex
);
1502 wxString sExts
= m_aExtensions
.Item(index
);
1503 sTmp
= wxT("exts=\"") + sExts
.Trim(FALSE
).Trim() + wxT("\"");
1507 file
.InsertLine (sTmp
, nIndex
);
1510 bTemp
= file
.Write ();
1517 bool wxMimeTypesManagerImpl::WriteToMailCap (int index
, bool delete_index
)
1519 //check we have the right managers
1520 if ( !( ( m_mailcapStylesInited
& wxMAILCAP_NETSCAPE
) ||
1521 ( m_mailcapStylesInited
& wxMAILCAP_STANDARD
) ) )
1525 wxString strHome
= wxGetenv(wxT("HOME"));
1527 // and now the users mailcap
1528 wxString strUserMailcap
= strHome
+ wxT("/.mailcap");
1530 wxMimeTextFile file
;
1531 if ( wxFile::Exists(strUserMailcap
) )
1533 bTemp
= file
.Open(strUserMailcap
);
1537 if (delete_index
) return FALSE
;
1538 bTemp
= file
.Create(strUserMailcap
);
1542 // now got a file we can write to ....
1543 wxMimeArrayString
* entries
= m_aEntries
[index
];
1544 size_t iOpen
= entries
->pIndexOf(wxT("open"));
1545 wxString sCmd
= entries
->GetCmd(iOpen
);
1548 sTmp
= m_aTypes
[index
];
1550 int nIndex
= file
.pIndexOf(sTmp
);
1551 // get rid of all the unwanted entries...
1552 if (nIndex
== wxNOT_FOUND
)
1554 nIndex
= (int) file
.GetLineCount();
1558 sOld
= file
[nIndex
];
1559 wxLogTrace(TRACE_MIME
, wxT("--- Deleting from mailcap line '%d' ---"), nIndex
);
1561 while ( (sOld
.Contains(wxT("\\"))) && (nIndex
< (int) file
.GetLineCount()) )
1563 file
.CommentLine(nIndex
);
1564 if (nIndex
< (int) file
.GetLineCount()) sOld
= sOld
+ file
[nIndex
];
1566 if (nIndex
< (int) file
.GetLineCount()) file
.CommentLine (nIndex
);
1569 sTmp
= sTmp
+ wxT(";") + sCmd
; //includes wxT(" %s ");
1571 // write it in the format that Netscape uses (default)
1572 if (! ( m_mailcapStylesInited
& wxMAILCAP_STANDARD
) )
1574 if (! delete_index
) file
.InsertLine (sTmp
, nIndex
);
1578 // write extended format
1581 // todo FIX this code;
1583 // sOld holds all the entries, but our data store only has some
1584 // eg test= is not stored
1586 // so far we have written the mimetype and command out
1587 wxStringTokenizer
sT (sOld
, wxT(";\\"));
1588 if (sT
.CountTokens () > 2)
1590 // first one mimetype; second one command, rest unknown...
1592 s
= sT
.GetNextToken();
1593 s
= sT
.GetNextToken();
1596 s
= sT
.GetNextToken();
1597 while ( ! s
.IsEmpty() )
1599 bool bKnownToken
= FALSE
;
1600 if (s
.Contains(wxT("description="))) bKnownToken
= TRUE
;
1601 if (s
.Contains(wxT("x11-bitmap="))) bKnownToken
= TRUE
;
1603 for (i
=0; i
< entries
->GetCount(); i
++)
1605 if (s
.Contains(entries
->GetVerb(i
))) bKnownToken
= TRUE
;
1609 sTmp
= sTmp
+ wxT("; \\");
1610 file
.InsertLine (sTmp
, nIndex
);
1613 s
= sT
.GetNextToken ();
1618 if (! m_aDescriptions
[index
].IsEmpty() )
1620 sTmp
= sTmp
+ wxT("; \\");
1621 file
.InsertLine (sTmp
, nIndex
);
1623 sTmp
= wxT(" description=\"") + m_aDescriptions
[index
] + wxT("\"");
1626 if (! m_aIcons
[index
].IsEmpty() )
1628 sTmp
= sTmp
+ wxT("; \\");
1629 file
.InsertLine (sTmp
, nIndex
);
1631 sTmp
= wxT(" x11-bitmap=\"") + m_aIcons
[index
] + wxT("\"");
1633 if ( entries
->GetCount() > 1 )
1637 for (i
=0; i
< entries
->GetCount(); i
++)
1640 sTmp
= sTmp
+ wxT("; \\");
1641 file
.InsertLine (sTmp
, nIndex
);
1643 sTmp
= wxT(" ") + entries
->Item(i
);
1647 file
.InsertLine (sTmp
, nIndex
);
1651 bTemp
= file
.Write ();
1658 wxMimeTypesManagerImpl::Associate(const wxFileTypeInfo
& ftInfo
)
1662 wxString strType
= ftInfo
.GetMimeType ();
1663 wxString strDesc
= ftInfo
.GetDescription ();
1664 wxString strIcon
= ftInfo
.GetIconFile ();
1666 wxMimeArrayString
*entry
= new wxMimeArrayString ();
1668 if ( ! ftInfo
.GetOpenCommand().IsEmpty())
1669 entry
->Add(wxT("open=") + ftInfo
.GetOpenCommand () + wxT(" %s "));
1670 if ( ! ftInfo
.GetPrintCommand ().IsEmpty())
1671 entry
->Add(wxT("print=") + ftInfo
.GetPrintCommand () + wxT(" %s "));
1673 // now find where these extensions are in the data store and remove them
1674 wxArrayString sA_Exts
= ftInfo
.GetExtensions ();
1675 wxString sExt
, sExtStore
;
1677 for (i
=0; i
< sA_Exts
.GetCount(); i
++)
1679 sExt
= sA_Exts
.Item(i
);
1680 //clean up to just a space before and after
1681 sExt
.Trim().Trim(FALSE
);
1682 sExt
= wxT(' ') + sExt
+ wxT(' ');
1683 for (nIndex
= 0; nIndex
< m_aExtensions
.GetCount(); nIndex
++)
1685 sExtStore
= m_aExtensions
.Item(nIndex
);
1686 if (sExtStore
.Replace(sExt
, wxT(" ") ) > 0) m_aExtensions
.Item(nIndex
) = sExtStore
;
1691 if ( !DoAssociation (strType
, strIcon
, entry
, sA_Exts
, strDesc
) )
1694 return GetFileTypeFromMimeType(strType
);
1698 bool wxMimeTypesManagerImpl::DoAssociation(const wxString
& strType
,
1699 const wxString
& strIcon
,
1700 wxMimeArrayString
*entry
,
1701 const wxArrayString
& strExtensions
,
1702 const wxString
& strDesc
)
1704 int nIndex
= AddToMimeData(strType
, strIcon
, entry
, strExtensions
, strDesc
, TRUE
);
1706 if ( nIndex
== wxNOT_FOUND
)
1709 return WriteMimeInfo (nIndex
, FALSE
);
1712 bool wxMimeTypesManagerImpl::WriteMimeInfo(int nIndex
, bool delete_mime
)
1716 if ( m_mailcapStylesInited
& wxMAILCAP_STANDARD
)
1718 // write in metamail format;
1719 if (WriteToMimeTypes (nIndex
, delete_mime
) )
1720 if ( WriteToMailCap (nIndex
, delete_mime
) )
1723 if ( m_mailcapStylesInited
& wxMAILCAP_NETSCAPE
)
1725 // write in netsacpe format;
1726 if (WriteToNSMimeTypes (nIndex
, delete_mime
) )
1727 if ( WriteToMailCap (nIndex
, delete_mime
) )
1730 if (m_mailcapStylesInited
& wxMAILCAP_GNOME
)
1732 // write in Gnome format;
1733 if (WriteGnomeMimeFile (nIndex
, delete_mime
) )
1734 if (WriteGnomeKeyFile (nIndex
, delete_mime
) )
1737 if (m_mailcapStylesInited
& wxMAILCAP_KDE
)
1739 // write in KDE format;
1740 if (WriteKDEMimeFile (nIndex
, delete_mime
) )
1747 int wxMimeTypesManagerImpl::AddToMimeData(const wxString
& strType
,
1748 const wxString
& strIcon
,
1749 wxMimeArrayString
*entry
,
1750 const wxArrayString
& strExtensions
,
1751 const wxString
& strDesc
,
1752 bool ReplaceExisting
)
1756 wxLogTrace(TRACE_MIME
, wxT("In Add to Mime data '%s' with %d entries and %d exts ---"),
1757 strType
.c_str(), entry
->GetCount(), strExtensions
.GetCount() );
1759 // ensure mimetype is always lower case
1760 wxString mimeType
= strType
;
1761 mimeType
.MakeLower();
1762 int nIndex
= m_aTypes
.Index(mimeType
);
1763 if ( nIndex
== wxNOT_FOUND
)
1766 m_aTypes
.Add(mimeType
);
1767 m_aIcons
.Add(strIcon
);
1768 m_aEntries
.Add(entry
);
1770 // change nIndex so we can add to the correct line
1771 nIndex
= m_aExtensions
.Add(wxT(' '));
1772 for (i
= 0; i
< strExtensions
.GetCount(); i
++)
1774 if (! m_aExtensions
.Item(nIndex
).Contains(wxT(' ') + strExtensions
.Item(i
) + wxT(' ')))
1775 m_aExtensions
.Item(nIndex
) += strExtensions
.Item(i
) + wxT(' ');
1777 m_aDescriptions
.Add(strDesc
);
1782 // nIndex has the existing data
1783 // always add the extensions to this mimetype
1785 for (i
= 0; i
< strExtensions
.GetCount(); i
++)
1787 if (! m_aExtensions
.Item(nIndex
).Contains(wxT(' ') + strExtensions
.Item(i
) + wxT(' ')))
1788 m_aExtensions
.Item(nIndex
) += strExtensions
.Item(i
) + wxT(' ');
1790 if (ReplaceExisting
)
1792 // if new description change it
1793 if ( ! strDesc
.IsEmpty())
1794 m_aDescriptions
[nIndex
] = strDesc
;
1796 // if new icon change it
1797 if ( ! strIcon
.IsEmpty())
1798 m_aIcons
[nIndex
] = strIcon
;
1800 wxMimeArrayString
*entryOld
= m_aEntries
[nIndex
];
1801 // replace any matching entries...
1802 for (i
=0; i
< entry
->GetCount(); i
++)
1803 entryOld
->ReplaceOrAddLineCmd (entry
->GetVerb(i
),
1804 entry
->GetCmd (i
) );
1808 // add data we don't already have ...
1809 // if new description add only if none
1810 if ( ! strDesc
.IsEmpty() && m_aDescriptions
.Item(i
).IsEmpty() )
1811 m_aDescriptions
[nIndex
] = strDesc
;
1813 // if new icon and no existing icon
1814 if ( ! strIcon
.IsEmpty() && m_aIcons
.Item(i
). IsEmpty () )
1815 m_aIcons
[nIndex
] = strIcon
;
1817 wxMimeArrayString
*entryOld
= m_aEntries
[nIndex
];
1818 // add any new entries...
1819 for (i
=0; i
< entry
->GetCount(); i
++)
1821 wxString sVerb
= entry
->GetVerb(i
);
1822 if ( entryOld
->pIndexOf ( sVerb
) == (size_t) wxNOT_FOUND
)
1823 entryOld
->Add (entry
->Item(i
));
1828 // check data integrity
1829 wxASSERT( m_aTypes
.Count() == m_aEntries
.Count() &&
1830 m_aTypes
.Count() == m_aExtensions
.Count() &&
1831 m_aTypes
.Count() == m_aIcons
.Count() &&
1832 m_aTypes
.Count() == m_aDescriptions
.Count() );
1839 wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString
& ext
)
1846 wxFileType
*fileType
= NULL
;
1847 size_t count
= m_aExtensions
.GetCount();
1848 for ( size_t n
= 0; n
< count
; n
++ )
1850 wxString extensions
= m_aExtensions
[n
];
1851 while ( !extensions
.IsEmpty() ) {
1852 wxString field
= extensions
.BeforeFirst(wxT(' '));
1853 extensions
= extensions
.AfterFirst(wxT(' '));
1855 // consider extensions as not being case-sensitive
1856 if ( field
.IsSameAs(ext
, FALSE
/* no case */) )
1859 if (fileType
== NULL
) fileType
= new wxFileType
;
1860 fileType
->m_impl
->Init(this, n
);
1861 // adds this mime type to _list_ of mime types with this extension
1870 wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString
& mimeType
)
1874 wxFileType
* fileType
= NULL
;
1875 // mime types are not case-sensitive
1876 wxString
mimetype(mimeType
);
1877 mimetype
.MakeLower();
1879 // first look for an exact match
1880 int index
= m_aTypes
.Index(mimetype
);
1881 if ( index
!= wxNOT_FOUND
)
1883 fileType
= new wxFileType
;
1884 fileType
->m_impl
->Init(this, index
);
1887 // then try to find "text/*" as match for "text/plain" (for example)
1888 // NB: if mimeType doesn't contain '/' at all, BeforeFirst() will return
1889 // the whole string - ok.
1891 index
= wxNOT_FOUND
;
1892 wxString strCategory
= mimetype
.BeforeFirst(wxT('/'));
1894 size_t nCount
= m_aTypes
.Count();
1895 for ( size_t n
= 0; n
< nCount
; n
++ ) {
1896 if ( (m_aTypes
[n
].BeforeFirst(wxT('/')) == strCategory
) &&
1897 m_aTypes
[n
].AfterFirst(wxT('/')) == wxT("*") ) {
1904 if ( index
!= wxNOT_FOUND
)
1906 fileType
= new wxFileType
;
1907 fileType
->m_impl
->Init(this, index
);
1913 wxString
wxMimeTypesManagerImpl::GetCommand(const wxString
& verb
, size_t nIndex
) const
1915 wxString command
, testcmd
, sV
, sTmp
;
1916 sV
= verb
+ wxT("=");
1917 // list of verb = command pairs for this mimetype
1918 wxMimeArrayString
* sPairs
= m_aEntries
[nIndex
];
1921 for ( i
= 0; i
< sPairs
->GetCount () ; i
++ )
1923 sTmp
= sPairs
->Item (i
);
1924 if ( sTmp
.Contains(sV
) ) command
= sTmp
.AfterFirst(wxT('='));
1929 void wxMimeTypesManagerImpl::AddFallback(const wxFileTypeInfo
& filetype
)
1933 wxString extensions
;
1934 const wxArrayString
& exts
= filetype
.GetExtensions();
1935 size_t nExts
= exts
.GetCount();
1936 for ( size_t nExt
= 0; nExt
< nExts
; nExt
++ ) {
1938 extensions
+= wxT(' ');
1940 extensions
+= exts
[nExt
];
1943 AddMimeTypeInfo(filetype
.GetMimeType(),
1945 filetype
.GetDescription());
1947 AddMailcapInfo(filetype
.GetMimeType(),
1948 filetype
.GetOpenCommand(),
1949 filetype
.GetPrintCommand(),
1951 filetype
.GetDescription());
1954 void wxMimeTypesManagerImpl::AddMimeTypeInfo(const wxString
& strMimeType
,
1955 const wxString
& strExtensions
,
1956 const wxString
& strDesc
)
1958 // reading mailcap may find image/* , while
1959 // reading mime.types finds image/gif and no match is made
1960 // this means all the get functions don't work fix this
1962 wxString sTmp
= strExtensions
;
1963 wxMimeArrayString
* entry
= new wxMimeArrayString () ;
1965 wxArrayString sExts
;
1966 sTmp
.Trim().Trim(FALSE
);
1968 while (!sTmp
.IsEmpty())
1970 sExts
.Add (sTmp
.AfterLast(wxT(' ')));
1971 sTmp
= sTmp
.BeforeLast(wxT(' '));
1974 AddToMimeData (strMimeType
, strIcon
, entry
, sExts
, strDesc
, (bool)TRUE
);
1977 void wxMimeTypesManagerImpl::AddMailcapInfo(const wxString
& strType
,
1978 const wxString
& strOpenCmd
,
1979 const wxString
& strPrintCmd
,
1980 const wxString
& strTest
,
1981 const wxString
& strDesc
)
1985 wxMimeArrayString
*entry
= new wxMimeArrayString
;
1986 entry
->Add(wxT("open=") + strOpenCmd
);
1987 entry
->Add(wxT("print=") + strPrintCmd
);
1988 entry
->Add(wxT("test=") + strTest
);
1991 wxArrayString strExtensions
;
1993 AddToMimeData (strType
, strIcon
, entry
, strExtensions
, strDesc
, TRUE
);
1997 bool wxMimeTypesManagerImpl::ReadMimeTypes(const wxString
& strFileName
)
1999 wxLogTrace(TRACE_MIME
, wxT("--- Parsing mime.types file '%s' ---"),
2000 strFileName
.c_str());
2002 wxTextFile
file(strFileName
);
2006 // the information we extract
2007 wxString strMimeType
, strDesc
, strExtensions
;
2009 size_t nLineCount
= file
.GetLineCount();
2010 const wxChar
*pc
= NULL
;
2011 for ( size_t nLine
= 0; nLine
< nLineCount
; nLine
++ ) {
2013 // now we're at the start of the line
2014 pc
= file
[nLine
].c_str();
2017 // we didn't finish with the previous line yet
2022 while ( wxIsspace(*pc
) )
2025 // comment or blank line?
2026 if ( *pc
== wxT('#') || !*pc
) {
2027 // skip the whole line
2032 // detect file format
2033 const wxChar
*pEqualSign
= wxStrchr(pc
, wxT('='));
2034 if ( pEqualSign
== NULL
) {
2038 // first field is mime type
2039 for ( strMimeType
.Empty(); !wxIsspace(*pc
) && *pc
!= wxT('\0'); pc
++ ) {
2044 while ( wxIsspace(*pc
) )
2047 // take all the rest of the string
2050 // no description...
2057 // the string on the left of '=' is the field name
2058 wxString
strLHS(pc
, pEqualSign
- pc
);
2061 for ( pc
= pEqualSign
+ 1; wxIsspace(*pc
); pc
++ )
2065 if ( *pc
== wxT('"') ) {
2066 // the string is quoted and ends at the matching quote
2067 pEnd
= wxStrchr(++pc
, wxT('"'));
2068 if ( pEnd
== NULL
) {
2069 wxLogWarning(_("Mime.types file %s, line %d: unterminated "
2071 strFileName
.c_str(), nLine
+ 1);
2075 // unquoted string ends at the first space or at the end of
2077 for ( pEnd
= pc
; *pEnd
&& !wxIsspace(*pEnd
); pEnd
++ )
2081 // now we have the RHS (field value)
2082 wxString
strRHS(pc
, pEnd
- pc
);
2084 // check what follows this entry
2085 if ( *pEnd
== wxT('"') ) {
2090 for ( pc
= pEnd
; wxIsspace(*pc
); pc
++ )
2093 // if there is something left, it may be either a '\\' to continue
2094 // the line or the next field of the same entry
2095 bool entryEnded
= *pc
== wxT('\0'),
2096 nextFieldOnSameLine
= FALSE
;
2097 if ( !entryEnded
) {
2098 nextFieldOnSameLine
= ((*pc
!= wxT('\\')) || (pc
[1] != wxT('\0')));
2101 // now see what we got
2102 if ( strLHS
== wxT("type") ) {
2103 strMimeType
= strRHS
;
2105 else if ( strLHS
== wxT("desc") ) {
2108 else if ( strLHS
== wxT("exts") ) {
2109 strExtensions
= strRHS
;
2112 wxLogWarning(_("Unknown field in file %s, line %d: '%s'."),
2113 strFileName
.c_str(), nLine
+ 1, strLHS
.c_str());
2116 if ( !entryEnded
) {
2117 if ( !nextFieldOnSameLine
)
2119 //else: don't reset it
2121 // as we don't reset strMimeType, the next field in this entry
2122 // will be interpreted correctly.
2128 // depending on the format (Mosaic or Netscape) either space or comma
2129 // is used to separate the extensions
2130 strExtensions
.Replace(wxT(","), wxT(" "));
2132 // also deal with the leading dot
2133 if ( !strExtensions
.IsEmpty() && strExtensions
[0u] == wxT('.') )
2135 strExtensions
.erase(0, 1);
2138 wxLogTrace(TRACE_MIME
, wxT("--- Found Mimetype '%s' ---"),
2139 strMimeType
.c_str());
2141 AddMimeTypeInfo(strMimeType
, strExtensions
, strDesc
);
2143 // finished with this line
2150 bool wxMimeTypesManagerImpl::ReadMailcap(const wxString
& strFileName
,
2153 // wxLog::AddTraceMask (TRACE_MIME);
2154 wxLogTrace(TRACE_MIME
, wxT("--- Parsing mailcap file '%s' ---"),
2155 strFileName
.c_str());
2157 wxTextFile
file(strFileName
);
2161 // see the comments near the end of function for the reason we need these
2162 // variables (search for the next occurence of them)
2163 // indices of MIME types (in m_aTypes) we already found in this file
2164 wxArrayInt aEntryIndices
;
2165 // aLastIndices[n] is the index of last element in
2166 // m_aEntries[aEntryIndices[n]] from this file
2167 // wxArrayInt aLastIndices;
2169 size_t nLineCount
= file
.GetLineCount();
2170 for ( size_t nLine
= 0; nLine
< nLineCount
; nLine
++ ) {
2171 // now we're at the start of the line
2172 const wxChar
*pc
= file
[nLine
].c_str();
2175 while ( wxIsspace(*pc
) )
2178 // comment or empty string?
2179 if ( *pc
== wxT('#') || *pc
== wxT('\0') )
2184 // what field are we currently in? The first 2 are fixed and there may
2185 // be an arbitrary number of other fields -- currently, we are not
2186 // interested in any of them, but we should parse them as well...
2192 } currentToken
= Field_Type
;
2194 // the flags and field values on the current line
2195 bool needsterminal
= FALSE
,
2196 copiousoutput
= FALSE
;
2197 wxMimeArrayString
*entry
;
2204 curField
; // accumulator
2206 bool test_passed
= TRUE
;
2210 // interpret the next character literally (notice that
2211 // backslash can be used for line continuation)
2212 if ( *++pc
== wxT('\0') ) {
2213 // fetch the next line if there is one
2214 if ( nLine
== nLineCount
- 1 ) {
2215 // something is wrong, bail out
2218 wxLogDebug(wxT("Mailcap file %s, line %d: "
2219 "'\\' on the end of the last line "
2221 strFileName
.c_str(),
2225 // pass to the beginning of the next line
2226 pc
= file
[++nLine
].c_str();
2228 // skip pc++ at the end of the loop
2233 // just a normal character
2239 cont
= FALSE
; // end of line reached, exit the loop
2244 // store this field and start looking for the next one
2246 // trim whitespaces from both sides
2247 curField
.Trim(TRUE
).Trim(FALSE
);
2249 switch ( currentToken
) {
2252 if ( strType
.empty() ) {
2253 // I don't think that this is a valid mailcap
2254 // entry, but try to interpret it somehow
2258 if ( strType
.Find(wxT('/')) == wxNOT_FOUND
) {
2259 // we interpret "type" as "type/*"
2260 strType
+= wxT("/*");
2263 currentToken
= Field_OpenCmd
;
2267 strOpenCmd
= curField
;
2268 entry
= new wxMimeArrayString ();
2269 entry
->Add(wxT("open=") + strOpenCmd
);
2271 currentToken
= Field_Other
;
2275 if ( !curField
.empty() ) {
2276 // "good" mailcap entry?
2279 if ( IsKnownUnimportantField(curField
) ) ok
= FALSE
;
2281 // is this something of the form foo=bar?
2282 const wxChar
*pEq
= wxStrchr(curField
, wxT('='));
2287 wxString lhs
= curField
.BeforeFirst(wxT('=')),
2288 rhs
= curField
.AfterFirst(wxT('='));
2290 lhs
.Trim(TRUE
); // from right
2291 rhs
.Trim(FALSE
); // from left
2293 // it might be quoted
2294 if ( rhs
[0u] == wxT('"') && rhs
.Last() == wxT('"') )
2296 wxString sTmp
= wxString(rhs
.c_str() + 1, rhs
.Len() - 2);
2299 bool verbfound
= TRUE
;
2300 if ( lhs
.Contains (wxT("test")))
2302 if ( ! rhs
.IsEmpty() )
2304 if ( wxSystem(rhs
) == 0 ) {
2307 wxLogTrace(TRACE_MIME
,
2308 wxT("Test '%s' for mime type '%s' succeeded."),
2309 rhs
.c_str(), strType
.c_str());
2313 test_passed
= FALSE
;
2314 wxLogTrace(TRACE_MIME
,
2315 wxT("Test '%s' for mime type '%s' failed."),
2316 rhs
.c_str(), strType
.c_str());
2321 if ( lhs
.Contains (wxT("desc")))
2326 if ( lhs
.Contains (wxT("x11-bitmap")))
2331 if ( lhs
.Contains (wxT("notes")))
2336 if (verbfound
) entry
->Add ( lhs
+ wxT('=') + rhs
);
2341 // no, it's a simple flag
2342 if ( curField
== wxT("needsterminal") ) {
2343 needsterminal
= TRUE
;
2346 if ( curField
== wxT("copiousoutput")) {
2347 // copiousoutput impies that the
2348 // viewer is a console program
2355 // don't flood the user with error
2356 // messages if we don't understand
2357 // something in his mailcap, but give
2358 // them in debug mode because this might
2359 // be useful for the programmer
2362 wxT("Mailcap file %s, line %d: "
2363 "unknown field '%s' for the "
2364 "MIME type '%s' ignored."),
2365 strFileName
.c_str(),
2382 // it already has this value
2383 //currentToken = Field_Other;
2387 wxFAIL_MSG(wxT("unknown field type in mailcap"));
2390 // next token starts immediately after ';'
2398 // continue in the same line
2402 // check that we really read something reasonable
2403 if ( currentToken
== Field_Type
|| currentToken
== Field_OpenCmd
) {
2404 wxLogWarning(_("Mailcap file %s, line %d: incomplete entry "
2406 strFileName
.c_str(), nLine
+ 1);
2409 // support for flags:
2410 // 1. create an xterm for 'needsterminal'
2411 // 2. append "| $PAGER" for 'copiousoutput'
2413 // Note that the RFC says that having both needsterminal and
2414 // copiousoutput is probably a mistake, so it seems that running
2415 // programs with copiousoutput inside an xterm as it is done now
2416 // is a bad idea (FIXME)
2417 if ( copiousoutput
)
2419 const wxChar
*p
= wxGetenv(_T("PAGER"));
2420 strOpenCmd
<< _T(" | ") << (p
? p
: _T("more"));
2421 wxLogTrace(TRACE_MIME
, wxT("Replacing .(for pager)...") + entry
->Item(0u) + wxT("with") + strOpenCmd
);
2423 entry
->ReplaceOrAddLineCmd (wxString(wxT("open")), strOpenCmd
);
2426 if ( needsterminal
)
2428 strOpenCmd
.Printf(_T("xterm -e sh -c '%s'"), strOpenCmd
.c_str());
2429 wxLogTrace(TRACE_MIME
, wxT("Replacing .(for needs term)...") + entry
->Item(0u) + wxT("with") + strOpenCmd
);
2431 entry
->ReplaceOrAddLineCmd (wxString(wxT("open")), strOpenCmd
);
2434 // NB: because of complications below (we must get entries priority
2435 // right), we can't use AddMailcapInfo() here, unfortunately.
2438 strType
.MakeLower();
2439 bool overwrite
= TRUE
;
2445 int nIndex
= m_aTypes
.Index(strType
);
2446 entryIndex
= aEntryIndices
.Index(nIndex
);
2447 if ( entryIndex
== wxNOT_FOUND
)
2450 // first time in this file, so replace the icons, entries
2451 // and description (no extensions to replace so ignore these
2453 aEntryIndices
.Add(nIndex
);
2454 //aLastIndices.Add(0);
2457 // not the first time in _this_ file
2458 // so we don't want to overwrite
2459 // existing entries,but want to add to them
2460 // so we don't alter the mimetype
2461 // the indices were shifted by 1
2467 wxArrayString strExtensions
;
2468 AddToMimeData (strType
, strIcon
, entry
, strExtensions
, strDesc
, !overwrite
);
2478 size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString
& mimetypes
)
2485 size_t count
= m_aTypes
.GetCount();
2486 for ( size_t n
= 0; n
< count
; n
++ )
2488 // don't return template types from here (i.e. anything containg '*')
2490 if ( type
.Find(_T('*')) == wxNOT_FOUND
)
2492 mimetypes
.Add(type
);
2496 return mimetypes
.GetCount();
2499 // ----------------------------------------------------------------------------
2500 // writing to MIME type files
2501 // ----------------------------------------------------------------------------
2503 bool wxMimeTypesManagerImpl::Unassociate(wxFileType
*ft
)
2505 wxArrayString sMimeTypes
;
2506 ft
->GetMimeTypes (sMimeTypes
);
2510 for (i
= 0; i
< sMimeTypes
.GetCount(); i
++)
2512 sMime
= sMimeTypes
.Item(i
);
2513 int nIndex
= m_aTypes
.Index (sMime
);
2514 if ( nIndex
== wxNOT_FOUND
)
2516 // error if we get here ??
2521 WriteMimeInfo(nIndex
, TRUE
);
2522 m_aTypes
.Remove (nIndex
);
2523 m_aEntries
.Remove (nIndex
);
2524 m_aExtensions
.Remove (nIndex
);
2525 m_aDescriptions
.Remove (nIndex
);
2526 m_aIcons
.Remove (nIndex
);
2529 // check data integrity
2530 wxASSERT( m_aTypes
.Count() == m_aEntries
.Count() &&
2531 m_aTypes
.Count() == m_aExtensions
.Count() &&
2532 m_aTypes
.Count() == m_aIcons
.Count() &&
2533 m_aTypes
.Count() == m_aDescriptions
.Count() );
2538 // ----------------------------------------------------------------------------
2539 // private functions
2540 // ----------------------------------------------------------------------------
2542 static bool IsKnownUnimportantField(const wxString
& fieldAll
)
2544 static const wxChar
*knownFields
[] =
2546 _T("x-mozilla-flags"),
2548 _T("textualnewlines"),
2551 wxString field
= fieldAll
.BeforeFirst(_T('='));
2552 for ( size_t n
= 0; n
< WXSIZEOF(knownFields
); n
++ )
2554 if ( field
.CmpNoCase(knownFields
[n
]) == 0 )
2562 // wxUSE_FILE && wxUSE_TEXTFILE