home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / mimecmn.cpp < prev    next >
C/C++ Source or Header  |  2002-11-09  |  18KB  |  651 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        common/mimecmn.cpp
  3. // Purpose:     classes and functions to manage MIME types
  4. // Author:      Vadim Zeitlin
  5. // Modified by:
  6. //  Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32
  7. // Created:     23.09.98
  8. // RCS-ID:      $Id: mimecmn.cpp,v 1.22.2.1 2002/11/09 00:25:27 VS Exp $
  9. // Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
  10. // Licence:     wxWindows license (part of wxExtra library)
  11. /////////////////////////////////////////////////////////////////////////////
  12.  
  13. // ============================================================================
  14. // declarations
  15. // ============================================================================
  16.  
  17. // ----------------------------------------------------------------------------
  18. // headers
  19. // ----------------------------------------------------------------------------
  20.  
  21. #ifdef    __GNUG__
  22.     #pragma implementation "mimetypebase.h"
  23. #endif
  24.  
  25. // for compilers that support precompilation, includes "wx.h".
  26. #include "wx/wxprec.h"
  27.  
  28. #ifdef __BORLANDC__
  29.     #pragma hdrstop
  30. #endif
  31.  
  32. #if wxUSE_MIMETYPE
  33.  
  34. #ifndef WX_PRECOMP
  35.     #include "wx/module.h"
  36. #endif
  37. // this one is needed for MSVC5
  38. #include "wx/module.h"
  39.  
  40. #ifndef WX_PRECOMP
  41.   #include "wx/string.h"
  42.   #if wxUSE_GUI
  43.     #include "wx/icon.h"
  44.   #endif
  45. #endif //WX_PRECOMP
  46.  
  47. #include "wx/log.h"
  48. #include "wx/file.h"
  49. #include "wx/intl.h"
  50. #include "wx/dynarray.h"
  51. #include "wx/confbase.h"
  52.  
  53. #include "wx/mimetype.h"
  54.  
  55. // other standard headers
  56. #include <ctype.h>
  57.  
  58. // implementation classes:
  59. #if defined(__WXMSW__)
  60.     #include "wx/msw/mimetype.h"
  61. #elif defined(__WXMAC__)
  62.     #include "wx/mac/mimetype.h"
  63. #elif defined(__WXPM__)
  64.     #include "wx/os2/mimetype.h"
  65. #else // Unix
  66.     #include "wx/unix/mimetype.h"
  67. #endif
  68.  
  69. // ============================================================================
  70. // common classes
  71. // ============================================================================
  72.  
  73. // ----------------------------------------------------------------------------
  74. // wxFileTypeInfo
  75. // ----------------------------------------------------------------------------
  76.  
  77. wxFileTypeInfo::wxFileTypeInfo(const wxChar *mimeType,
  78.                                const wxChar *openCmd,
  79.                                const wxChar *printCmd,
  80.                                const wxChar *desc,
  81.                                ...)
  82.               : m_mimeType(mimeType),
  83.                 m_openCmd(openCmd),
  84.                 m_printCmd(printCmd),
  85.                 m_desc(desc)
  86. {
  87.     va_list argptr;
  88.     va_start(argptr, desc);
  89.  
  90.     for ( ;; )
  91.     {
  92.         const wxChar *ext = va_arg(argptr, const wxChar *);
  93.         if ( !ext )
  94.         {
  95.             // NULL terminates the list
  96.             break;
  97.         }
  98.  
  99.         m_exts.Add(ext);
  100.     }
  101.  
  102.     va_end(argptr);
  103. }
  104.  
  105.  
  106. wxFileTypeInfo::wxFileTypeInfo(const wxArrayString& sArray)
  107. {
  108.     m_mimeType = sArray [0u];
  109.     m_openCmd  = sArray [1u];
  110.     m_printCmd = sArray [2u];
  111.     m_desc     = sArray [3u];
  112.  
  113.     size_t count = sArray.GetCount();
  114.     for ( size_t i = 4; i < count; i++ )
  115.     {
  116.         m_exts.Add(sArray[i]);
  117.     }
  118. }
  119.  
  120. #include "wx/arrimpl.cpp"
  121. WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo);
  122.  
  123. // ============================================================================
  124. // implementation of the wrapper classes
  125. // ============================================================================
  126.  
  127. // ----------------------------------------------------------------------------
  128. // wxFileType
  129. // ----------------------------------------------------------------------------
  130.  
  131. /* static */
  132. wxString wxFileType::ExpandCommand(const wxString& command,
  133.                                    const wxFileType::MessageParameters& params)
  134. {
  135.     bool hasFilename = FALSE;
  136.  
  137.     wxString str;
  138.     for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) {
  139.         if ( *pc == wxT('%') ) {
  140.             switch ( *++pc ) {
  141.                 case wxT('s'):
  142.                     // '%s' expands into file name (quoted because it might
  143.                     // contain spaces) - except if there are already quotes
  144.                     // there because otherwise some programs may get confused
  145.                     // by double double quotes
  146. #if 0
  147.                     if ( *(pc - 2) == wxT('"') )
  148.                         str << params.GetFileName();
  149.                     else
  150.                         str << wxT('"') << params.GetFileName() << wxT('"');
  151. #endif
  152.                     str << params.GetFileName();
  153.                     hasFilename = TRUE;
  154.                     break;
  155.  
  156.                 case wxT('t'):
  157.                     // '%t' expands into MIME type (quote it too just to be
  158.                     // consistent)
  159.                     str << wxT('\'') << params.GetMimeType() << wxT('\'');
  160.                     break;
  161.  
  162.                 case wxT('{'):
  163.                     {
  164.                         const wxChar *pEnd = wxStrchr(pc, wxT('}'));
  165.                         if ( pEnd == NULL ) {
  166.                             wxString mimetype;
  167.                             wxLogWarning(_("Unmatched '{' in an entry for mime type %s."),
  168.                                          params.GetMimeType().c_str());
  169.                             str << wxT("%{");
  170.                         }
  171.                         else {
  172.                             wxString param(pc + 1, pEnd - pc - 1);
  173.                             str << wxT('\'') << params.GetParamValue(param) << wxT('\'');
  174.                             pc = pEnd;
  175.                         }
  176.                     }
  177.                     break;
  178.  
  179.                 case wxT('n'):
  180.                 case wxT('F'):
  181.                     // TODO %n is the number of parts, %F is an array containing
  182.                     //      the names of temp files these parts were written to
  183.                     //      and their mime types.
  184.                     break;
  185.  
  186.                 default:
  187.                     wxLogDebug(wxT("Unknown field %%%c in command '%s'."),
  188.                                *pc, command.c_str());
  189.                     str << *pc;
  190.             }
  191.         }
  192.         else {
  193.             str << *pc;
  194.         }
  195.     }
  196.  
  197.     // metamail(1) man page states that if the mailcap entry doesn't have '%s'
  198.     // the program will accept the data on stdin so normally we should append
  199.     // "< %s" to the end of the command in such case, but not all commands
  200.     // behave like this, in particular a common test is 'test -n "$DISPLAY"'
  201.     // and appending "< %s" to this command makes the test fail... I don't
  202.     // know of the correct solution, try to guess what we have to do.
  203.  
  204.     // test now carried out on reading file so test should never get here
  205.     if ( !hasFilename && !str.IsEmpty()
  206. #ifdef __UNIX__
  207.                       && !str.StartsWith(_T("test "))
  208. #endif // Unix
  209.        ) {
  210.         str << wxT(" < '") << params.GetFileName() << wxT('\'');
  211.     }
  212.  
  213.     return str;
  214. }
  215.  
  216. wxFileType::wxFileType(const wxFileTypeInfo& info)
  217. {
  218.     m_info = &info;
  219.     m_impl = NULL;
  220. }
  221.  
  222. wxFileType::wxFileType()
  223. {
  224.     m_info = NULL;
  225.     m_impl = new wxFileTypeImpl;
  226. }
  227.  
  228. wxFileType::~wxFileType()
  229. {
  230.     if ( m_impl )
  231.         delete m_impl;
  232. }
  233.  
  234. bool wxFileType::GetExtensions(wxArrayString& extensions)
  235. {
  236.     if ( m_info )
  237.     {
  238.         extensions = m_info->GetExtensions();
  239.         return TRUE;
  240.     }
  241.  
  242.     return m_impl->GetExtensions(extensions);
  243. }
  244.  
  245. bool wxFileType::GetMimeType(wxString *mimeType) const
  246. {
  247.     wxCHECK_MSG( mimeType, FALSE, _T("invalid parameter in GetMimeType") );
  248.  
  249.     if ( m_info )
  250.     {
  251.         *mimeType = m_info->GetMimeType();
  252.  
  253.         return TRUE;
  254.     }
  255.  
  256.     return m_impl->GetMimeType(mimeType);
  257. }
  258.  
  259. bool wxFileType::GetMimeTypes(wxArrayString& mimeTypes) const
  260. {
  261.     if ( m_info )
  262.     {
  263.         mimeTypes.Clear();
  264.         mimeTypes.Add(m_info->GetMimeType());
  265.  
  266.         return TRUE;
  267.     }
  268.  
  269.     return m_impl->GetMimeTypes(mimeTypes);
  270. }
  271.  
  272. bool wxFileType::GetIcon(wxIcon *icon,
  273.                          wxString *iconFile,
  274.                          int *iconIndex) const
  275. {
  276.     if ( m_info )
  277.     {
  278.         if ( iconFile )
  279.             *iconFile = m_info->GetIconFile();
  280.         if ( iconIndex )
  281.             *iconIndex = m_info->GetIconIndex();
  282.  
  283. #if wxUSE_GUI
  284.         if ( icon && !m_info->GetIconFile().empty() )
  285.         {
  286.             // FIXME: what about the index?
  287.             icon->LoadFile(m_info->GetIconFile());
  288.         }
  289. #endif // wxUSE_GUI
  290.  
  291.         return TRUE;
  292.     }
  293.  
  294. #if defined(__WXMSW__) || defined(__UNIX__)
  295.     return m_impl->GetIcon(icon, iconFile, iconIndex);
  296. #else
  297.     return m_impl->GetIcon(icon);
  298. #endif
  299. }
  300.  
  301. bool wxFileType::GetDescription(wxString *desc) const
  302. {
  303.     wxCHECK_MSG( desc, FALSE, _T("invalid parameter in GetDescription") );
  304.  
  305.     if ( m_info )
  306.     {
  307.         *desc = m_info->GetDescription();
  308.  
  309.         return TRUE;
  310.     }
  311.  
  312.     return m_impl->GetDescription(desc);
  313. }
  314.  
  315. bool
  316. wxFileType::GetOpenCommand(wxString *openCmd,
  317.                            const wxFileType::MessageParameters& params) const
  318. {
  319.     wxCHECK_MSG( openCmd, FALSE, _T("invalid parameter in GetOpenCommand") );
  320.  
  321.     if ( m_info )
  322.     {
  323.         *openCmd = ExpandCommand(m_info->GetOpenCommand(), params);
  324.  
  325.         return TRUE;
  326.     }
  327.  
  328.     return m_impl->GetOpenCommand(openCmd, params);
  329. }
  330.  
  331. wxString wxFileType::GetOpenCommand(const wxString& filename) const
  332. {
  333.     wxString cmd;
  334.     if ( !GetOpenCommand(&cmd, filename) )
  335.     {
  336.         // return empty string to indicate an error
  337.         cmd.clear();
  338.     }
  339.  
  340.     return cmd;
  341. }
  342.  
  343. bool
  344. wxFileType::GetPrintCommand(wxString *printCmd,
  345.                             const wxFileType::MessageParameters& params) const
  346. {
  347.     wxCHECK_MSG( printCmd, FALSE, _T("invalid parameter in GetPrintCommand") );
  348.  
  349.     if ( m_info )
  350.     {
  351.         *printCmd = ExpandCommand(m_info->GetPrintCommand(), params);
  352.  
  353.         return TRUE;
  354.     }
  355.  
  356.     return m_impl->GetPrintCommand(printCmd, params);
  357. }
  358.  
  359.  
  360. size_t wxFileType::GetAllCommands(wxArrayString *verbs,
  361.                                   wxArrayString *commands,
  362.                                   const wxFileType::MessageParameters& params) const
  363. {
  364.     if ( verbs )
  365.         verbs->Clear();
  366.     if ( commands )
  367.         commands->Clear();
  368.  
  369. #if defined (__WXMSW__)  || defined(__UNIX__)
  370.     return m_impl->GetAllCommands(verbs, commands, params);
  371. #else // !__WXMSW__ || Unix
  372.     // we don't know how to retrieve all commands, so just try the 2 we know
  373.     // about
  374.     size_t count = 0;
  375.     wxString cmd;
  376.     if ( GetOpenCommand(&cmd, params) )
  377.     {
  378.         if ( verbs )
  379.             verbs->Add(_T("Open"));
  380.         if ( commands )
  381.             commands->Add(cmd);
  382.         count++;
  383.     }
  384.  
  385.     if ( GetPrintCommand(&cmd, params) )
  386.     {
  387.         if ( verbs )
  388.             verbs->Add(_T("Print"));
  389.         if ( commands )
  390.             commands->Add(cmd);
  391.  
  392.         count++;
  393.     }
  394.  
  395.     return count;
  396. #endif // __WXMSW__/| __UNIX__
  397. }
  398.  
  399. bool wxFileType::Unassociate()
  400. {
  401. #if defined(__WXMSW__)
  402.     return m_impl->Unassociate();
  403. #elif defined(__UNIX__) && !defined(__WXPM__)
  404.     return m_impl->Unassociate(this);
  405. #else
  406.     wxFAIL_MSG( _T("not implemented") ); // TODO
  407.     return FALSE;
  408. #endif
  409. }
  410.  
  411. bool wxFileType::SetCommand(const wxString& cmd, const wxString& verb,
  412. bool overwriteprompt)
  413. {
  414. #if defined (__WXMSW__)  || defined(__UNIX__)
  415.     return m_impl->SetCommand(cmd, verb, overwriteprompt);
  416. #else
  417.     wxFAIL_MSG(_T("not implemented"));
  418.     return FALSE;
  419. #endif
  420. }
  421.  
  422. bool wxFileType::SetDefaultIcon(const wxString& cmd, int index)
  423. {
  424.     wxString sTmp = cmd;
  425. #ifdef __WXMSW__
  426.     // VZ: should we do this?
  427.     // chris elliott : only makes sense in MS windows
  428.     if ( sTmp.empty() )
  429.         GetOpenCommand(&sTmp, wxFileType::MessageParameters(wxT(""), wxT("")));
  430. #endif
  431.     wxCHECK_MSG( !sTmp.empty(), FALSE, _T("need the icon file") );
  432.  
  433. #if defined (__WXMSW__) || defined(__UNIX__)
  434.     return m_impl->SetDefaultIcon (cmd, index);
  435. #else
  436.     wxFAIL_MSG(_T("not implemented"));
  437.  
  438.     return FALSE;
  439. #endif
  440. }
  441.  
  442.  
  443. // ----------------------------------------------------------------------------
  444. // wxMimeTypesManager
  445. // ----------------------------------------------------------------------------
  446.  
  447. void wxMimeTypesManager::EnsureImpl()
  448. {
  449.     if ( !m_impl )
  450.         m_impl = new wxMimeTypesManagerImpl;
  451. }
  452.  
  453. bool wxMimeTypesManager::IsOfType(const wxString& mimeType,
  454.                                   const wxString& wildcard)
  455. {
  456.     wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND,
  457.                   wxT("first MIME type can't contain wildcards") );
  458.  
  459.     // all comparaisons are case insensitive (2nd arg of IsSameAs() is FALSE)
  460.     if ( wildcard.BeforeFirst(wxT('/')).
  461.             IsSameAs(mimeType.BeforeFirst(wxT('/')), FALSE) )
  462.     {
  463.         wxString strSubtype = wildcard.AfterFirst(wxT('/'));
  464.  
  465.         if ( strSubtype == wxT("*") ||
  466.              strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), FALSE) )
  467.         {
  468.             // matches (either exactly or it's a wildcard)
  469.             return TRUE;
  470.         }
  471.     }
  472.  
  473.     return FALSE;
  474. }
  475.  
  476. wxMimeTypesManager::wxMimeTypesManager()
  477. {
  478.     m_impl = NULL;
  479. }
  480.  
  481. wxMimeTypesManager::~wxMimeTypesManager()
  482. {
  483.     if ( m_impl )
  484.         delete m_impl;
  485. }
  486.  
  487. bool wxMimeTypesManager::Unassociate(wxFileType *ft)
  488. {
  489. #if defined(__UNIX__) && !defined(__WXPM__) && !defined(__CYGWIN__) && !defined(__WXWINE__)
  490.     return m_impl->Unassociate(ft);
  491. #else
  492.     return ft->Unassociate();
  493. #endif
  494. }
  495.  
  496.  
  497. wxFileType *
  498. wxMimeTypesManager::Associate(const wxFileTypeInfo& ftInfo)
  499. {
  500.     EnsureImpl();
  501.  
  502. #if defined(__WXMSW__) || (defined(__UNIX__) && !defined(__WXPM__))
  503.     return m_impl->Associate(ftInfo);
  504. #else // other platforms
  505.     wxFAIL_MSG( _T("not implemented") ); // TODO
  506.     return NULL;
  507. #endif // platforms
  508. }
  509.  
  510. wxFileType *
  511. wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext)
  512. {
  513.     EnsureImpl();
  514.     wxFileType *ft = m_impl->GetFileTypeFromExtension(ext);
  515.  
  516.     if ( !ft ) {
  517.         // check the fallbacks
  518.         //
  519.         // TODO linear search is potentially slow, perhaps we should use a
  520.         //       sorted array?
  521.         size_t count = m_fallbacks.GetCount();
  522.         for ( size_t n = 0; n < count; n++ ) {
  523.             if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) {
  524.                 ft = new wxFileType(m_fallbacks[n]);
  525.  
  526.                 break;
  527.             }
  528.         }
  529.     }
  530.  
  531.     return ft;
  532. }
  533.  
  534. wxFileType *
  535. wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType)
  536. {
  537.     EnsureImpl();
  538.     wxFileType *ft = m_impl->GetFileTypeFromMimeType(mimeType);
  539.  
  540.     if ( ft ) {
  541.         // check the fallbacks
  542.         //
  543.         // TODO linear search is potentially slow, perhaps we should use a sorted
  544.         //      array?
  545.         size_t count = m_fallbacks.GetCount();
  546.         for ( size_t n = 0; n < count; n++ ) {
  547.             if ( wxMimeTypesManager::IsOfType(mimeType,
  548.                                               m_fallbacks[n].GetMimeType()) ) {
  549.                 ft = new wxFileType(m_fallbacks[n]);
  550.  
  551.                 break;
  552.             }
  553.         }
  554.     }
  555.  
  556.     return ft;
  557. }
  558.  
  559. bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback)
  560. {
  561.     EnsureImpl();
  562.     return m_impl->ReadMailcap(filename, fallback);
  563. }
  564.  
  565. bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename)
  566. {
  567.     EnsureImpl();
  568.     return m_impl->ReadMimeTypes(filename);
  569. }
  570.  
  571. void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes)
  572. {
  573.     EnsureImpl();
  574.     for ( const wxFileTypeInfo *ft = filetypes; ft && ft->IsValid(); ft++ ) {
  575.         AddFallback(*ft);
  576.     }
  577. }
  578.  
  579. size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes)
  580. {
  581.     EnsureImpl();
  582.     size_t countAll = m_impl->EnumAllFileTypes(mimetypes);
  583.  
  584.     // add the fallback filetypes
  585.     size_t count = m_fallbacks.GetCount();
  586.     for ( size_t n = 0; n < count; n++ ) {
  587.         if ( mimetypes.Index(m_fallbacks[n].GetMimeType()) == wxNOT_FOUND ) {
  588.             mimetypes.Add(m_fallbacks[n].GetMimeType());
  589.             countAll++;
  590.         }
  591.     }
  592.  
  593.     return countAll;
  594. }
  595.  
  596. void wxMimeTypesManager::Initialize(int mcapStyle,
  597.                                     const wxString& sExtraDir)
  598. {
  599. #if defined(__UNIX__) && !defined(__WXPM__) && !defined(__CYGWIN__) && !defined(__WXWINE__)
  600.     EnsureImpl();
  601.  
  602.     m_impl->Initialize(mcapStyle, sExtraDir);
  603. #else
  604.     (void)mcapStyle;    
  605.     (void)sExtraDir;    
  606. #endif // Unix
  607. }
  608.  
  609. // and this function clears all the data from the manager
  610. void wxMimeTypesManager::ClearData()
  611. {
  612. #if defined(__UNIX__) && !defined(__WXPM__) && !defined(__CYGWIN__) && !defined(__WXWINE__)
  613.     EnsureImpl();
  614.  
  615.     m_impl->ClearData();
  616. #endif // Unix
  617. }
  618.  
  619. // ----------------------------------------------------------------------------
  620. // global data and wxMimeTypeCmnModule
  621. // ----------------------------------------------------------------------------
  622.  
  623. // private object
  624. static wxMimeTypesManager gs_mimeTypesManager;
  625.  
  626. // and public pointer
  627. wxMimeTypesManager *wxTheMimeTypesManager = &gs_mimeTypesManager;
  628.  
  629. class wxMimeTypeCmnModule: public wxModule
  630. {
  631. public:
  632.     wxMimeTypeCmnModule() : wxModule() { }
  633.     virtual bool OnInit() { return TRUE; }
  634.     virtual void OnExit()
  635.     {
  636.         // this avoids false memory leak allerts:
  637.         if ( gs_mimeTypesManager.m_impl != NULL )
  638.         {
  639.             delete gs_mimeTypesManager.m_impl;
  640.             gs_mimeTypesManager.m_impl = NULL;
  641.             gs_mimeTypesManager.m_fallbacks.Clear();
  642.         }
  643.     }
  644.  
  645.     DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule)
  646. };
  647.  
  648. IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule, wxModule)
  649.  
  650. #endif // wxUSE_MIMETYPE
  651.