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