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