Avoid potential negative array index access to cached text.
[LibreOffice.git] / include / svl / ondemand.hxx
blob4a0a91b18264496a708e8e5c79b693eeb4dd29b3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #pragma once
22 #include <com/sun/star/uno/Reference.hxx>
23 #include <i18nlangtag/lang.h>
24 #include <i18nutil/transliteration.hxx>
25 #include <unotools/syslocale.hxx>
26 #include <unotools/localedatawrapper.hxx>
27 #include <unotools/calendarwrapper.hxx>
28 #include <unotools/transliterationwrapper.hxx>
29 #include <unotools/nativenumberwrapper.hxx>
30 #include <unotools/charclass.hxx>
31 #include <optional>
34 On demand instantiation and initialization of several i18n wrappers,
35 helping the number formatter to not perform worse than it already does.
38 /** @short
39 Switch between LANGUAGE_SYSTEM and LANGUAGE_ENGLISH_US and any other
40 LocaleDataWrapper.
41 SvNumberformatter uses it upon switching locales.
43 @descr
44 Avoids reloading and analysing of locale data again and again.
46 @ATTENTION
47 If the default ctor is used the init() method MUST be called before
48 accessing any locale data. The passed parameters Locale and LanguageType
49 must match each other.
52 class OnDemandLocaleDataWrapper
54 css::uno::Reference<css::uno::XComponentContext> m_xContext;
55 SvtSysLocale aSysLocale;
56 LanguageType eCurrentLanguage;
57 LanguageType eLastAnyLanguage;
58 std::optional<LocaleDataWrapper> moEnglish;
59 std::optional<LocaleDataWrapper> moAny;
60 int nCurrent; // 0 == system, 1 == english, 2 == any
61 bool bInitialized;
63 public:
64 OnDemandLocaleDataWrapper()
65 : eLastAnyLanguage(LANGUAGE_DONTKNOW)
66 , nCurrent(0)
67 , bInitialized(false)
69 eCurrentLanguage = LANGUAGE_SYSTEM;
72 bool isInitialized() const { return bInitialized; }
74 void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext,
75 const LanguageTag& rLanguageTag)
77 m_xContext = rxContext;
78 changeLocale(rLanguageTag);
79 bInitialized = true;
82 void changeLocale(const LanguageTag& rLanguageTag)
84 LanguageType eLang = rLanguageTag.getLanguageType(false);
85 if (eLang == LANGUAGE_SYSTEM)
86 nCurrent = 0;
87 else if (eLang == LANGUAGE_ENGLISH_US)
89 if (!moEnglish)
90 moEnglish.emplace(m_xContext, rLanguageTag);
91 nCurrent = 1;
93 else
95 if (!moAny)
97 moAny.emplace(m_xContext, rLanguageTag);
98 eLastAnyLanguage = eLang;
100 else if (eLastAnyLanguage != eLang)
102 moAny.emplace(m_xContext, rLanguageTag);
103 eLastAnyLanguage = eLang;
105 nCurrent = 2;
107 eCurrentLanguage = eLang;
110 LanguageType getCurrentLanguage() const { return eCurrentLanguage; }
112 const LocaleDataWrapper* get() const
114 switch (nCurrent)
116 case 0:
117 return &aSysLocale.GetLocaleData();
118 case 1:
119 return &*moEnglish;
120 case 2:
121 return &*moAny;
122 default:
123 assert(false);
124 return nullptr;
127 const LocaleDataWrapper* operator->() const { return get(); }
128 const LocaleDataWrapper& operator*() const { return *get(); }
131 /** Load a calendar only if it's needed. Keep calendar for "en-US" locale
132 separately, as there can be alternation between locale dependent and
133 locale independent formats.
134 SvNumberformatter uses it upon switching locales.
136 @ATTENTION If the default ctor is used the init() method MUST be called
137 before accessing the calendar.
139 class OnDemandCalendarWrapper
141 css::uno::Reference<css::uno::XComponentContext> m_xContext;
142 css::lang::Locale aEnglishLocale;
143 css::lang::Locale aLocale;
144 mutable css::lang::Locale aLastAnyLocale;
145 mutable std::optional<CalendarWrapper> moEnglish;
146 mutable std::optional<CalendarWrapper> moAny;
148 public:
149 OnDemandCalendarWrapper()
151 LanguageTag aEnglishLanguageTag(LANGUAGE_ENGLISH_US);
152 aEnglishLocale = aEnglishLanguageTag.getLocale();
153 aLastAnyLocale = aEnglishLocale;
156 void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext,
157 const css::lang::Locale& rLocale)
159 m_xContext = rxContext;
160 changeLocale(rLocale);
161 moEnglish.reset();
162 moAny.reset();
165 void changeLocale(const css::lang::Locale& rLocale) { aLocale = rLocale; }
167 CalendarWrapper* get() const
169 CalendarWrapper* pPtr;
170 if (aLocale == aEnglishLocale)
172 if (!moEnglish)
174 moEnglish.emplace(m_xContext);
175 moEnglish->loadDefaultCalendar(aEnglishLocale);
177 pPtr = &*moEnglish;
179 else
181 if (!moAny)
183 moAny.emplace(m_xContext);
184 moAny->loadDefaultCalendar(aLocale);
185 aLastAnyLocale = aLocale;
187 else if (aLocale != aLastAnyLocale)
189 moAny->loadDefaultCalendar(aLocale);
190 aLastAnyLocale = aLocale;
192 pPtr = &*moAny;
194 return pPtr;
198 /** Load a transliteration only if it's needed.
199 SvNumberformatter uses it upon switching locales.
200 @ATTENTION If the default ctor is used the init() method MUST be called
201 before accessing the transliteration.
203 class OnDemandTransliterationWrapper
205 css::uno::Reference<css::uno::XComponentContext> m_xContext;
206 LanguageType eLanguage;
207 TransliterationFlags nType;
208 mutable std::optional<::utl::TransliterationWrapper> moTransliterate;
209 mutable bool bValid;
210 bool bInitialized;
212 public:
213 OnDemandTransliterationWrapper()
214 : eLanguage(LANGUAGE_SYSTEM)
215 , nType(TransliterationFlags::NONE)
216 , bValid(false)
217 , bInitialized(false)
221 bool isInitialized() const { return bInitialized; }
223 void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext, LanguageType eLang)
225 m_xContext = rxContext;
226 nType = TransliterationFlags::IGNORE_CASE;
227 changeLocale(eLang);
228 moTransliterate.reset();
229 bInitialized = true;
232 void changeLocale(LanguageType eLang)
234 bValid = false;
235 eLanguage = eLang;
238 const ::utl::TransliterationWrapper* get() const
240 if (!bValid)
242 if (!moTransliterate)
243 moTransliterate.emplace(m_xContext, nType);
244 moTransliterate->loadModuleIfNeeded(eLanguage);
245 bValid = true;
247 return &*moTransliterate;
250 const ::utl::TransliterationWrapper* operator->() const { return get(); }
253 /** Load a native number service wrapper only if it's needed.
254 SvNumberformatter uses it.
256 @ATTENTION
257 If the default ctor is used the init() method MUST be called
258 before accessing the native number supplier.
260 class OnDemandNativeNumberWrapper
262 css::uno::Reference<css::uno::XComponentContext> m_xContext;
263 mutable std::optional<NativeNumberWrapper> moNativeNumber;
265 public:
266 OnDemandNativeNumberWrapper() {}
268 void init(const css::uno::Reference<css::uno::XComponentContext>& rxContext)
270 m_xContext = rxContext;
271 moNativeNumber.reset();
274 NativeNumberWrapper* get() const
276 if (!moNativeNumber)
277 moNativeNumber.emplace(m_xContext);
278 return &*moNativeNumber;
282 /** @short
283 SvNumberformatter uses it upon switching locales.
285 @descr
286 Avoids reloading and analysing of locale data again and again.
288 @ATTENTION
289 If the default ctor is used the init() method MUST be called before
290 accessing any locale data.
293 class OnDemandCharClass
295 std::optional<CharClass> moCharClass1;
296 std::optional<CharClass> moCharClass2;
297 int nCurrent; // -1 == uninitialised, 0 == class1, 1 == class2
299 public:
300 OnDemandCharClass()
301 : nCurrent(-1)
305 void changeLocale(const css::uno::Reference<css::uno::XComponentContext>& xContext,
306 const LanguageTag& rLanguageTag)
308 // check for existing match
309 if (moCharClass1 && moCharClass1->getLanguageTag() == rLanguageTag)
311 nCurrent = 0;
312 return;
314 if (moCharClass2 && moCharClass2->getLanguageTag() == rLanguageTag)
316 nCurrent = 1;
317 return;
319 // no match - update one the current entries
320 if (nCurrent == -1 || nCurrent == 1)
322 moCharClass1.emplace(xContext, rLanguageTag);
323 nCurrent = 0;
325 else
327 moCharClass2.emplace(xContext, rLanguageTag);
328 nCurrent = 1;
332 const CharClass* get() const
334 switch (nCurrent)
336 case 0:
337 return &*moCharClass1;
338 case 1:
339 return &*moCharClass2;
340 default:
341 assert(false);
342 return nullptr;
345 const CharClass* operator->() const { return get(); }
346 const CharClass& operator*() const { return *get(); }
349 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */