1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/os2/mimetype.cpp
3// Purpose:     classes and functions to manage MIME types
4// Author:      David Webster
5// Modified by:
6// Created:     01.21.00
7// RCS-ID:      $Id: mimetype.cpp 38920 2006-04-26 08:21:31Z ABX $
8// Copyright:   Adopted from msw port --(c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence:     wxWindows licence (part of wxExtra library)
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#if wxUSE_MIMETYPE
16
17#include "wx/os2/mimetype.h"
18
19#ifndef WX_PRECOMP
20    #include "wx/dynarray.h"
21    #include "wx/string.h"
22    #include "wx/intl.h"
23    #include "wx/log.h"
24    #if wxUSE_GUI
25        #include "wx/icon.h"
26    #endif
27#endif //WX_PRECOMP
28
29#define INCL_DOS
30#define INCL_GPI
31#define INCL_WIN
32#include <os2.h>
33
34#include "wx/file.h"
35#include "wx/iconloc.h"
36#include "wx/confbase.h"
37
38// other standard headers
39#include <ctype.h>
40
41// in case we're compiling in non-GUI mode
42class WXDLLEXPORT wxIcon;
43
44// These classes use Windows registry to retrieve the required information.
45//
46// Keys used (not all of them are documented, so it might actually stop working
47// in futur versions of Windows...):
48//  1. "HKCR\MIME\Database\Content Type" contains subkeys for all known MIME
49//     types, each key has a string value "Extension" which gives (dot preceded)
50//     extension for the files of this MIME type.
51//
52//  2. "HKCR\.ext" contains
53//   a) unnamed value containing the "filetype"
54//   b) value "Content Type" containing the MIME type
55//
56// 3. "HKCR\filetype" contains
57//   a) unnamed value containing the description
58//   b) subkey "DefaultIcon" with single unnamed value giving the icon index in
59//      an icon file
60//   c) shell\open\command and shell\open\print subkeys containing the commands
61//      to open/print the file (the positional parameters are introduced by %1,
62//      %2, ... in these strings, we change them to %s ourselves)
63
64// although I don't know of any official documentation which mentions this
65// location, uses it, so it isn't likely to change
66static const wxChar *MIME_DATABASE_KEY = wxT("MIME\\Database\\Content Type\\");
67
68wxString wxFileTypeImpl::GetCommand(const wxChar *WXUNUSED(verb)) const
69{
70// TODO: OS/2 doesn't have a registry but uses Prf
71/*
72    // suppress possible error messages
73    wxLogNull nolog;
74    wxString strKey;
75
76    if ( wxRegKey(wxRegKey::HKCR, m_ext + _T("\\shell")).Exists() )
77        strKey = m_ext;
78    if ( wxRegKey(wxRegKey::HKCR, m_strFileType + _T("\\shell")).Exists() )
79        strKey = m_strFileType;
80
81    if ( !strKey )
82    {
83        // no info
84        return wxEmptyString;
85    }
86
87    strKey << wxT("\\shell\\") << verb;
88    wxRegKey key(wxRegKey::HKCR, strKey + _T("\\command"));
89    wxString command;
90    if ( key.Open() ) {
91        // it's the default value of the key
92        if ( key.QueryValue(wxT(""), command) ) {
93            // transform it from '%1' to '%s' style format string (now also
94            // test for %L - apparently MS started using it as well for the
95            // same purpose)
96
97            // NB: we don't make any attempt to verify that the string is valid,
98            //     i.e. doesn't contain %2, or second %1 or .... But we do make
99            //     sure that we return a string with _exactly_ one '%s'!
100            bool foundFilename = false;
101            size_t len = command.Len();
102            for ( size_t n = 0; (n < len) && !foundFilename; n++ ) {
103                if ( command[n] == wxT('%') &&
104                     (n + 1 < len) &&
105                     (command[n + 1] == wxT('1') ||
106                      command[n + 1] == wxT('L')) ) {
107                    // replace it with '%s'
108                    command[n + 1] = wxT('s');
109
110                    foundFilename = true;
111                }
112            }
113
114#if wxUSE_DDE
115            // look whether we must issue some DDE requests to the application
116            // (and not just launch it)
117            strKey += _T("\\DDEExec");
118            wxRegKey keyDDE(wxRegKey::HKCR, strKey);
119            if ( keyDDE.Open() ) {
120                wxString ddeCommand, ddeServer, ddeTopic;
121                keyDDE.QueryValue(_T(""), ddeCommand);
122                ddeCommand.Replace(_T("%1"), _T("%s"));
123
124                wxRegKey(wxRegKey::HKCR, strKey + _T("\\Application")).
125                    QueryValue(_T(""), ddeServer);
126                wxRegKey(wxRegKey::HKCR, strKey + _T("\\Topic")).
127                    QueryValue(_T(""), ddeTopic);
128
129                // HACK: we use a special feature of wxExecute which exists
130                //       just because we need it here: it will establish DDE
131                //       conversation with the program it just launched
132                command.Prepend(_T("WX_DDE#"));
133                command << _T('#') << ddeServer
134                        << _T('#') << ddeTopic
135                        << _T('#') << ddeCommand;
136            }
137            else
138#endif // wxUSE_DDE
139                if ( !foundFilename ) {
140                // we didn't find any '%1' - the application doesn't know which
141                // file to open (note that we only do it if there is no DDEExec
142                // subkey)
143                //
144                // HACK: append the filename at the end, hope that it will do
145                command << wxT(" %s");
146            }
147        }
148    }
149    //else: no such file type or no value, will return empty string
150
151    return command;
152*/
153   return wxEmptyString;
154}
155
156bool
157wxFileTypeImpl::GetOpenCommand(wxString *openCmd,
158                               const wxFileType::MessageParameters& params)
159                               const
160{
161    wxString cmd;
162    if ( m_info ) {
163        cmd = m_info->GetOpenCommand();
164    }
165    else {
166        cmd = GetCommand(wxT("open"));
167    }
168
169    *openCmd = wxFileType::ExpandCommand(cmd, params);
170
171    return !openCmd->empty();
172}
173
174bool
175wxFileTypeImpl::GetPrintCommand(wxString *printCmd,
176                                const wxFileType::MessageParameters& params)
177                                const
178{
179    wxString cmd;
180    if ( m_info ) {
181        cmd = m_info->GetPrintCommand();
182    }
183    else {
184        cmd = GetCommand(wxT("print"));
185    }
186
187    *printCmd = wxFileType::ExpandCommand(cmd, params);
188
189    return !printCmd->empty();
190}
191
192// TODO this function is half implemented
193bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
194{
195    if ( m_info ) {
196        extensions = m_info->GetExtensions();
197
198        return true;
199    }
200    else if ( m_ext.empty() ) {
201        // the only way to get the list of extensions from the file type is to
202        // scan through all extensions in the registry - too slow...
203        return false;
204    }
205    else {
206        extensions.Empty();
207        extensions.Add(m_ext);
208
209        // it's a lie too, we don't return _all_ extensions...
210        return true;
211    }
212}
213
214bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const
215{
216    if ( m_info ) {
217        // we already have it
218        *mimeType = m_info->GetMimeType();
219
220        return true;
221    }
222
223    // suppress possible error messages
224    wxLogNull nolog;
225// TODO:  substitue reg key stuff (maybe make a Prf class for OS/2??)
226/*
227    wxRegKey key(wxRegKey::HKCR, wxT(".") + m_ext);
228    if ( key.Open() && key.QueryValue(wxT("Content Type"), *mimeType) ) {
229        return true;
230    }
231    else {
232        return false;
233    }
234*/
235    return false;
236}
237
238bool wxFileTypeImpl::GetMimeTypes(wxArrayString& mimeTypes) const
239{
240    wxString s;
241
242    if (GetMimeType(&s))
243    {
244        mimeTypes.Clear();
245        mimeTypes.Add(s);
246        return true;
247    }
248    else
249        return false;
250}
251
252bool wxFileTypeImpl::GetIcon(wxIconLocation *WXUNUSED(iconLoc)) const
253{
254    if ( m_info ) {
255        // we don't have icons in the fallback resources
256        return false;
257    }
258
259    wxString strIconKey;
260    strIconKey << m_strFileType << wxT("\\DefaultIcon");
261
262    // suppress possible error messages
263    wxLogNull nolog;
264//TODO:
265/*
266    wxRegKey key(wxRegKey::HKCR, strIconKey);
267
268    if ( key.Open() ) {
269        wxString strIcon;
270        // it's the default value of the key
271        if ( key.QueryValue(wxEmptyString, strIcon) ) {
272            // the format is the following: <full path to file>, <icon index>
273            // NB: icon index may be negative as well as positive and the full
274            //     path may contain the environment variables inside '%'
275            wxString strFullPath = strIcon.BeforeLast(wxT(',')),
276            strIndex = strIcon.AfterLast(wxT(','));
277
278            // index may be omitted, in which case BeforeLast(',') is empty and
279            // AfterLast(',') is the whole string
280            if ( strFullPath.empty() ) {
281                strFullPath = strIndex;
282                strIndex = wxT("0");
283            }
284
285            if ( iconLoc )
286            {
287                iconLoc->SetFileName(wxExpandEnvVars(strFullPath));
288
289                iconLoc->SetIndex(wxAtoi(strIndex));
290            }
291
292            return true;
293        }
294    }
295
296    // no such file type or no value or incorrect icon entry
297*/
298    return false;
299}
300
301bool wxFileTypeImpl::GetDescription(wxString *desc) const
302{
303    if ( m_info ) {
304        // we already have it
305        *desc = m_info->GetDescription();
306
307        return true;
308    }
309
310    // suppress possible error messages
311    wxLogNull nolog;
312// TODO:
313/*
314    wxRegKey key(wxRegKey::HKCR, m_strFileType);
315
316    if ( key.Open() ) {
317        // it's the default value of the key
318        if ( key.QueryValue(wxT(""), *desc) ) {
319            return true;
320        }
321    }
322*/
323    return false;
324}
325
326// extension -> file type
327wxFileType *
328wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
329{
330    // add the leading point if necessary
331    wxString str;
332    if ( ext[(size_t) 0] != wxT('.') ) {
333        str = wxT('.');
334    }
335    str << ext;
336
337    // suppress possible error messages
338    wxLogNull nolog;
339
340    bool knownExtension = false;
341
342    wxString strFileType;
343// TODO:
344/*
345    wxRegKey key(wxRegKey::HKCR, str);
346    if ( key.Open() ) {
347        // it's the default value of the key
348        if ( key.QueryValue(wxT(""), strFileType) ) {
349            // create the new wxFileType object
350            wxFileType *fileType = new wxFileType;
351            fileType->m_impl->Init(strFileType, ext);
352
353            return fileType;
354        }
355        else {
356            // this extension doesn't have a filetype, but it's known to the
357            // system and may be has some other useful keys (open command or
358            // content-type), so still return a file type object for it
359            knownExtension = true;
360        }
361    }
362*/
363    // check the fallbacks
364    // TODO linear search is potentially slow, perhaps we should use a sorted
365    //      array?
366    size_t count = m_fallbacks.GetCount();
367    for ( size_t n = 0; n < count; n++ ) {
368        if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) {
369            wxFileType *fileType = new wxFileType;
370            fileType->m_impl->Init(m_fallbacks[n]);
371
372            return fileType;
373        }
374    }
375
376    if ( knownExtension )
377    {
378        wxFileType *fileType = new wxFileType;
379        fileType->m_impl->Init(wxEmptyString, ext);
380
381        return fileType;
382    }
383    else
384    {
385        // unknown extension
386        return NULL;
387    }
388}
389
390// MIME type -> extension -> file type
391wxFileType *
392wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
393{
394    wxString strKey = MIME_DATABASE_KEY;
395    strKey << mimeType;
396
397    // suppress possible error messages
398    wxLogNull nolog;
399
400    wxString ext;
401// TODO:
402/*
403    wxRegKey key(wxRegKey::HKCR, strKey);
404    if ( key.Open() ) {
405        if ( key.QueryValue(wxT("Extension"), ext) ) {
406            return GetFileTypeFromExtension(ext);
407        }
408    }
409
410    // check the fallbacks
411    // TODO linear search is potentially slow, perhaps we should use a sorted
412    //      array?
413    size_t count = m_fallbacks.GetCount();
414    for ( size_t n = 0; n < count; n++ ) {
415        if ( wxMimeTypesManager::IsOfType(mimeType,
416                                          m_fallbacks[n].GetMimeType()) ) {
417            wxFileType *fileType = new wxFileType;
418            fileType->m_impl->Init(m_fallbacks[n]);
419
420            return fileType;
421        }
422    }
423*/
424    // unknown MIME type
425    return NULL;
426}
427
428size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& WXUNUSED(mimetypes))
429{
430    // enumerate all keys under MIME_DATABASE_KEY
431// TODO:
432/*
433    wxRegKey key(wxRegKey::HKCR, MIME_DATABASE_KEY);
434
435    wxString type;
436    long cookie;
437    bool cont = key.GetFirstKey(type, cookie);
438    while ( cont )
439    {
440        mimetypes.Add(type);
441
442        cont = key.GetNextKey(type, cookie);
443    }
444
445    return mimetypes.GetCount();
446*/
447  return 0;
448}
449
450#endif //wxUSE_MIMETYPE
451