]> git.saurik.com Git - wxWidgets.git/blob - src/common/fmapbase.cpp
check the week day for consistency in ParseFormat() (replaces patch 788052)
[wxWidgets.git] / src / common / fmapbase.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: common/fmapbase.cpp
3 // Purpose: wxFontMapperBase class implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 21.06.2003 (extracted from common/fontmap.cpp)
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999-2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_FONTMAP
28
29 #ifndef WX_PRECOMP
30 #include "wx/app.h"
31 #include "wx/log.h"
32 #include "wx/intl.h"
33 #endif //WX_PRECOMP
34
35 #if defined(__WXMSW__)
36 #include "wx/msw/private.h" // includes windows.h for LOGFONT
37 #include "wx/msw/winundef.h"
38 #endif
39
40 #include "wx/fontmap.h"
41 #include "wx/fmappriv.h"
42
43 #include "wx/apptrait.h"
44 #include "wx/module.h"
45
46 // wxMemoryConfig uses wxFileConfig
47 #if wxUSE_CONFIG && wxUSE_FILECONFIG
48 #include "wx/config.h"
49 #include "wx/memconf.h"
50 #endif
51
52 // ----------------------------------------------------------------------------
53 // constants
54 // ----------------------------------------------------------------------------
55
56 // encodings supported by GetEncodingDescription
57 static wxFontEncoding gs_encodings[] =
58 {
59 wxFONTENCODING_ISO8859_1,
60 wxFONTENCODING_ISO8859_2,
61 wxFONTENCODING_ISO8859_3,
62 wxFONTENCODING_ISO8859_4,
63 wxFONTENCODING_ISO8859_5,
64 wxFONTENCODING_ISO8859_6,
65 wxFONTENCODING_ISO8859_7,
66 wxFONTENCODING_ISO8859_8,
67 wxFONTENCODING_ISO8859_9,
68 wxFONTENCODING_ISO8859_10,
69 wxFONTENCODING_ISO8859_11,
70 wxFONTENCODING_ISO8859_12,
71 wxFONTENCODING_ISO8859_13,
72 wxFONTENCODING_ISO8859_14,
73 wxFONTENCODING_ISO8859_15,
74 wxFONTENCODING_KOI8,
75 wxFONTENCODING_CP932,
76 wxFONTENCODING_CP936,
77 wxFONTENCODING_CP949,
78 wxFONTENCODING_CP950,
79 wxFONTENCODING_CP1250,
80 wxFONTENCODING_CP1251,
81 wxFONTENCODING_CP1252,
82 wxFONTENCODING_CP1253,
83 wxFONTENCODING_CP1254,
84 wxFONTENCODING_CP1255,
85 wxFONTENCODING_CP1256,
86 wxFONTENCODING_CP1257,
87 wxFONTENCODING_CP437,
88 wxFONTENCODING_UTF7,
89 wxFONTENCODING_UTF8,
90 wxFONTENCODING_EUC_JP,
91 };
92
93 // the descriptions for them
94 static const wxChar* gs_encodingDescs[] =
95 {
96 wxTRANSLATE( "Western European (ISO-8859-1)" ),
97 wxTRANSLATE( "Central European (ISO-8859-2)" ),
98 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
99 wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
100 wxTRANSLATE( "Cyrillic (ISO-8859-5)" ),
101 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
102 wxTRANSLATE( "Greek (ISO-8859-7)" ),
103 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
104 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
105 wxTRANSLATE( "Nordic (ISO-8859-10)" ),
106 wxTRANSLATE( "Thai (ISO-8859-11)" ),
107 wxTRANSLATE( "Indian (ISO-8859-12)" ),
108 wxTRANSLATE( "Baltic (ISO-8859-13)" ),
109 wxTRANSLATE( "Celtic (ISO-8859-14)" ),
110 wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ),
111 wxTRANSLATE( "KOI8-R" ),
112 wxTRANSLATE( "Windows Japanese (CP 932)" ),
113 wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ),
114 wxTRANSLATE( "Windows Korean (CP 949)" ),
115 wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ),
116 wxTRANSLATE( "Windows Central European (CP 1250)" ),
117 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
118 wxTRANSLATE( "Windows Western European (CP 1252)" ),
119 wxTRANSLATE( "Windows Greek (CP 1253)" ),
120 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
121 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
122 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
123 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
124 wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
125 wxTRANSLATE( "Unicode 7 bit (UTF-7)" ),
126 wxTRANSLATE( "Unicode 8 bit (UTF-8)" ),
127 wxTRANSLATE( "Extended Unix Codepage for Japanese (EUC-JP)" ),
128 };
129
130 // and the internal names (these are not translated on purpose!)
131 static const wxChar* gs_encodingNames[] =
132 {
133 wxT( "iso-8859-1" ),
134 wxT( "iso-8859-2" ),
135 wxT( "iso-8859-3" ),
136 wxT( "iso-8859-4" ),
137 wxT( "iso-8859-5" ),
138 wxT( "iso-8859-6" ),
139 wxT( "iso-8859-7" ),
140 wxT( "iso-8859-8" ),
141 wxT( "iso-8859-9" ),
142 wxT( "iso-8859-10" ),
143 wxT( "iso-8859-11" ),
144 wxT( "iso-8859-12" ),
145 wxT( "iso-8859-13" ),
146 wxT( "iso-8859-14" ),
147 wxT( "iso-8859-15" ),
148 wxT( "koi8-r" ),
149 wxT( "windows-932" ),
150 wxT( "windows-936" ),
151 wxT( "windows-949" ),
152 wxT( "windows-950" ),
153 wxT( "windows-1250" ),
154 wxT( "windows-1251" ),
155 wxT( "windows-1252" ),
156 wxT( "windows-1253" ),
157 wxT( "windows-1254" ),
158 wxT( "windows-1255" ),
159 wxT( "windows-1256" ),
160 wxT( "windows-1257" ),
161 wxT( "windows-437" ),
162 wxT( "utf-7" ),
163 wxT( "utf-8" ),
164 wxT( "euc-jp" ),
165 };
166
167 wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingDescs) == WXSIZEOF(gs_encodings) &&
168 WXSIZEOF(gs_encodingNames) == WXSIZEOF(gs_encodings),
169 EncodingsArraysNotInSync );
170
171 // ----------------------------------------------------------------------------
172 // private classes
173 // ----------------------------------------------------------------------------
174
175 // clean up the font mapper object
176 class wxFontMapperModule : public wxModule
177 {
178 public:
179 wxFontMapperModule() : wxModule() { }
180 virtual bool OnInit() { return TRUE; }
181 virtual void OnExit() { delete wxFontMapper::Set(NULL); }
182
183 DECLARE_DYNAMIC_CLASS(wxFontMapperModule)
184 };
185
186 IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule)
187
188
189 // ============================================================================
190 // wxFontMapperBase implementation
191 // ============================================================================
192
193 wxFontMapper *wxFontMapperBase::sm_instance = NULL;
194
195 // ----------------------------------------------------------------------------
196 // ctor and dtor
197 // ----------------------------------------------------------------------------
198
199 wxFontMapperBase::wxFontMapperBase()
200 {
201 #if wxUSE_CONFIG && wxUSE_FILECONFIG
202 m_config = NULL;
203 m_configIsDummy = FALSE;
204 #endif // wxUSE_CONFIG
205 }
206
207 wxFontMapperBase::~wxFontMapperBase()
208 {
209 #if wxUSE_CONFIG && wxUSE_FILECONFIG
210 if ( m_configIsDummy )
211 delete m_config;
212 #endif // wxUSE_CONFIG
213 }
214
215 /* static */
216 wxFontMapper *wxFontMapperBase::Get()
217 {
218 if ( !sm_instance )
219 {
220 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
221 if ( traits )
222 {
223 sm_instance = traits->CreateFontMapper();
224
225 wxASSERT_MSG( sm_instance,
226 _T("wxAppTraits::CreateFontMapper() failed") );
227 }
228
229 if ( !sm_instance )
230 {
231 // last resort: we must create something because the existing code
232 // relies on always having a valid font mapper object
233 sm_instance = (wxFontMapper *)new wxFontMapperBase;
234 }
235 }
236
237 return sm_instance;
238 }
239
240 /* static */
241 wxFontMapper *wxFontMapperBase::Set(wxFontMapper *mapper)
242 {
243 wxFontMapper *old = sm_instance;
244 sm_instance = mapper;
245 return old;
246 }
247
248 #if wxUSE_CONFIG && wxUSE_FILECONFIG
249
250 // ----------------------------------------------------------------------------
251 // config usage customisation
252 // ----------------------------------------------------------------------------
253
254 /* static */
255 const wxChar *wxFontMapperBase::GetDefaultConfigPath()
256 {
257 return FONTMAPPER_ROOT_PATH;
258 }
259
260 void wxFontMapperBase::SetConfigPath(const wxString& prefix)
261 {
262 wxCHECK_RET( !prefix.IsEmpty() && prefix[0] == wxCONFIG_PATH_SEPARATOR,
263 wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
264
265 m_configRootPath = prefix;
266 }
267
268 // ----------------------------------------------------------------------------
269 // get config object and path for it
270 // ----------------------------------------------------------------------------
271
272 wxConfigBase *wxFontMapperBase::GetConfig()
273 {
274 if ( !m_config )
275 {
276 // try the default
277 m_config = wxConfig::Get(FALSE /*don't create on demand*/ );
278
279 if ( !m_config )
280 {
281 // we still want to have a config object because otherwise we would
282 // keep asking the user the same questions in the interactive mode,
283 // so create a dummy config which won't write to any files/registry
284 // but will allow us to remember the results of the questions at
285 // least during this run
286 m_config = new wxMemoryConfig;
287 m_configIsDummy = TRUE;
288 // VS: we can't call wxConfig::Set(m_config) here because that would
289 // disable automatic wxConfig instance creation if this code was
290 // called before wxApp::OnInit (this happens in wxGTK -- it sets
291 // default wxFont encoding in wxApp::Initialize())
292 }
293 }
294
295 if ( m_configIsDummy && wxConfig::Get(FALSE) != NULL )
296 {
297 // VS: in case we created dummy m_config (see above), we want to switch back
298 // to the real one as soon as one becomes available.
299 delete m_config;
300 m_config = wxConfig::Get(FALSE);
301 m_configIsDummy = FALSE;
302 // FIXME: ideally, we should add keys from dummy config to the real one now,
303 // but it is a low-priority task because typical wxWin application
304 // either doesn't use wxConfig at all or creates wxConfig object in
305 // wxApp::OnInit(), before any real interaction with the user takes
306 // place...
307 }
308
309 return m_config;
310 }
311
312 const wxString& wxFontMapperBase::GetConfigPath()
313 {
314 if ( !m_configRootPath )
315 {
316 // use the default
317 m_configRootPath = GetDefaultConfigPath();
318 }
319
320 return m_configRootPath;
321 }
322
323 // ----------------------------------------------------------------------------
324 // config helpers
325 // ----------------------------------------------------------------------------
326
327 bool wxFontMapperBase::ChangePath(const wxString& pathNew, wxString *pathOld)
328 {
329 wxConfigBase *config = GetConfig();
330 if ( !config )
331 return FALSE;
332
333 *pathOld = config->GetPath();
334
335 wxString path = GetConfigPath();
336 if ( path.IsEmpty() || path.Last() != wxCONFIG_PATH_SEPARATOR )
337 {
338 path += wxCONFIG_PATH_SEPARATOR;
339 }
340
341 wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR),
342 wxT("should be a relative path") );
343
344 path += pathNew;
345
346 config->SetPath(path);
347
348 return TRUE;
349 }
350
351 void wxFontMapperBase::RestorePath(const wxString& pathOld)
352 {
353 GetConfig()->SetPath(pathOld);
354 }
355
356 #endif
357
358 // ----------------------------------------------------------------------------
359 // charset/encoding correspondence
360 // ----------------------------------------------------------------------------
361
362 wxFontEncoding
363 wxFontMapperBase::CharsetToEncoding(const wxString& charset,
364 bool WXUNUSED(interactive))
365 {
366 int enc = NonInteractiveCharsetToEncoding(charset);
367 if ( enc == wxFONTENCODING_UNKNOWN )
368 {
369 // we should return wxFONTENCODING_SYSTEM from here for unknown
370 // encodings
371 enc = wxFONTENCODING_SYSTEM;
372 }
373
374 return (wxFontEncoding)enc;
375 }
376
377 int
378 wxFontMapperBase::NonInteractiveCharsetToEncoding(const wxString& charset)
379 {
380 wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
381
382 // we're going to modify it, make a copy
383 wxString cs = charset;
384
385 #if wxUSE_CONFIG && wxUSE_FILECONFIG
386 // first try the user-defined settings
387 wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH);
388 if ( path.IsOk() )
389 {
390 wxConfigBase *config = GetConfig();
391
392 // do we have an encoding for this charset?
393 long value = config->Read(charset, -1l);
394 if ( value != -1 )
395 {
396 if ( value == wxFONTENCODING_UNKNOWN )
397 {
398 // don't try to find it, in particular don't ask the user
399 return value;
400 }
401
402 if ( value >= 0 && value <= wxFONTENCODING_MAX )
403 {
404 encoding = (wxFontEncoding)value;
405 }
406 else
407 {
408 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
409 value, charset.c_str());
410 }
411 }
412
413 if ( encoding == wxFONTENCODING_SYSTEM )
414 {
415 // may be we have an alias?
416 config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH);
417
418 wxString alias = config->Read(charset);
419 if ( !!alias )
420 {
421 // yes, we do - use it instead
422 cs = alias;
423 }
424 }
425 }
426 #endif // wxUSE_CONFIG
427
428 // if didn't find it there, try to recognize it ourselves
429 if ( encoding == wxFONTENCODING_SYSTEM )
430 {
431 // trim any spaces
432 cs.Trim(true);
433 cs.Trim(false);
434
435 // discard the optional quotes
436 if ( !cs.empty() )
437 {
438 if ( cs[0u] == _T('"') && cs.Last() == _T('"') )
439 {
440 cs = wxString(cs.c_str(), cs.length() - 1);
441 }
442 }
443
444 cs.MakeUpper();
445
446 if ( cs.empty() || cs == _T("US-ASCII") )
447 {
448 encoding = wxFONTENCODING_DEFAULT;
449 }
450 else if ( cs == wxT("UTF-7") )
451 {
452 encoding = wxFONTENCODING_UTF7;
453 }
454 else if ( cs == wxT("UTF-8") )
455 {
456 encoding = wxFONTENCODING_UTF8;
457 }
458 else if ( cs == wxT("GB2312") )
459 {
460 encoding = wxFONTENCODING_GB2312;
461 }
462 else if ( cs == wxT("BIG5") )
463 {
464 encoding = wxFONTENCODING_BIG5;
465 }
466 else if ( cs == wxT("SJIS") ||
467 cs == wxT("SHIFT_JIS") ||
468 cs == wxT("SHIFT-JIS") )
469 {
470 encoding = wxFONTENCODING_SHIFT_JIS;
471 }
472 else if ( cs == wxT("EUC-JP") ||
473 cs == wxT("EUC_JP") )
474 {
475 encoding = wxFONTENCODING_EUC_JP;
476 }
477 else if ( cs == wxT("KOI8-R") ||
478 cs == wxT("KOI8-U") ||
479 cs == wxT("KOI8-RU") )
480 {
481 // although koi8-ru is not strictly speaking the same as koi8-r,
482 // they are similar enough to make mapping it to koi8 better than
483 // not reckognizing it at all
484 encoding = wxFONTENCODING_KOI8;
485 }
486 else if ( cs.Left(3) == wxT("ISO") )
487 {
488 // the dash is optional (or, to be exact, it is not, but
489 // several brokenmails "forget" it)
490 const wxChar *p = cs.c_str() + 3;
491 if ( *p == wxT('-') )
492 p++;
493
494 // printf( "iso %s\n", (const char*) cs.ToAscii() );
495
496 unsigned int value;
497 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
498 {
499 // printf( "value %d\n", (int)value );
500
501 // make it 0 based and check that it is strictly positive in
502 // the process (no such thing as iso8859-0 encoding)
503 if ( (value-- > 0) &&
504 (value < wxFONTENCODING_ISO8859_MAX -
505 wxFONTENCODING_ISO8859_1) )
506 {
507 // it's a valid ISO8859 encoding
508 value += wxFONTENCODING_ISO8859_1;
509 encoding = (wxFontEncoding)value;
510 }
511 }
512 }
513 else if ( cs.Left(4) == wxT("8859") )
514 {
515 const wxChar *p = cs.c_str();
516
517 unsigned int value;
518 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
519 {
520 // printf( "value %d\n", (int)value );
521
522 // make it 0 based and check that it is strictly positive in
523 // the process (no such thing as iso8859-0 encoding)
524 if ( (value-- > 0) &&
525 (value < wxFONTENCODING_ISO8859_MAX -
526 wxFONTENCODING_ISO8859_1) )
527 {
528 // it's a valid ISO8859 encoding
529 value += wxFONTENCODING_ISO8859_1;
530 encoding = (wxFontEncoding)value;
531 }
532 }
533 }
534 else // check for Windows charsets
535 {
536 size_t len;
537 if ( cs.Left(7) == wxT("WINDOWS") )
538 {
539 len = 7;
540 }
541 else if ( cs.Left(2) == wxT("CP") )
542 {
543 len = 2;
544 }
545 else // not a Windows encoding
546 {
547 len = 0;
548 }
549
550 if ( len )
551 {
552 const wxChar *p = cs.c_str() + len;
553 if ( *p == wxT('-') )
554 p++;
555
556 int value;
557 if ( wxSscanf(p, wxT("%u"), &value) == 1 )
558 {
559 if ( value >= 1250 )
560 {
561 value -= 1250;
562 if ( value < wxFONTENCODING_CP12_MAX -
563 wxFONTENCODING_CP1250 )
564 {
565 // a valid Windows code page
566 value += wxFONTENCODING_CP1250;
567 encoding = (wxFontEncoding)value;
568 }
569 }
570
571 switch ( value )
572 {
573 case 932:
574 encoding = wxFONTENCODING_CP932;
575 break;
576
577 case 936:
578 encoding = wxFONTENCODING_CP936;
579 break;
580
581 case 949:
582 encoding = wxFONTENCODING_CP949;
583 break;
584
585 case 950:
586 encoding = wxFONTENCODING_CP950;
587 break;
588 }
589 }
590 }
591 }
592 //else: unknown
593 }
594
595 return encoding;
596 }
597
598 /* static */
599 size_t wxFontMapperBase::GetSupportedEncodingsCount()
600 {
601 return WXSIZEOF(gs_encodings);
602 }
603
604 /* static */
605 wxFontEncoding wxFontMapperBase::GetEncoding(size_t n)
606 {
607 wxCHECK_MSG( n < WXSIZEOF(gs_encodings), wxFONTENCODING_SYSTEM,
608 _T("wxFontMapper::GetEncoding(): invalid index") );
609
610 return gs_encodings[n];
611 }
612
613 /* static */
614 wxString wxFontMapperBase::GetEncodingDescription(wxFontEncoding encoding)
615 {
616 if ( encoding == wxFONTENCODING_DEFAULT )
617 {
618 return _("Default encoding");
619 }
620
621 const size_t count = WXSIZEOF(gs_encodingDescs);
622
623 for ( size_t i = 0; i < count; i++ )
624 {
625 if ( gs_encodings[i] == encoding )
626 {
627 return wxGetTranslation(gs_encodingDescs[i]);
628 }
629 }
630
631 wxString str;
632 str.Printf(_("Unknown encoding (%d)"), encoding);
633
634 return str;
635 }
636
637 /* static */
638 wxString wxFontMapperBase::GetEncodingName(wxFontEncoding encoding)
639 {
640 if ( encoding == wxFONTENCODING_DEFAULT )
641 {
642 return _("default");
643 }
644
645 const size_t count = WXSIZEOF(gs_encodingNames);
646
647 for ( size_t i = 0; i < count; i++ )
648 {
649 if ( gs_encodings[i] == encoding )
650 {
651 return gs_encodingNames[i];
652 }
653 }
654
655 wxString str;
656 str.Printf(_("unknown-%d"), encoding);
657
658 return str;
659 }
660
661 #endif // wxUSE_FONTMAP
662