File: | var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp |
Warning: | line 246, column 7 Value stored to 'rv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /******* BEGIN LICENSE BLOCK ******* |
2 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
3 | * |
4 | * The contents of this file are subject to the Mozilla Public License Version |
5 | * 1.1 (the "License"); you may not use this file except in compliance with |
6 | * the License. You may obtain a copy of the License at |
7 | * http://www.mozilla.org/MPL/ |
8 | * |
9 | * Software distributed under the License is distributed on an "AS IS" basis, |
10 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
11 | * for the specific language governing rights and limitations under the |
12 | * License. |
13 | * |
14 | * The Initial Developers of the Original Code are Kevin Hendricks (MySpell) |
15 | * and László Németh (Hunspell). Portions created by the Initial Developers |
16 | * are Copyright (C) 2002-2005 the Initial Developers. All Rights Reserved. |
17 | * |
18 | * Contributor(s): Kevin Hendricks (kevin.hendricks@sympatico.ca) |
19 | * David Einstein (deinst@world.std.com) |
20 | * Michiel van Leeuwen (mvl@exedo.nl) |
21 | * Caolan McNamara (cmc@openoffice.org) |
22 | * László Németh (nemethl@gyorsposta.hu) |
23 | * Davide Prina |
24 | * Giuseppe Modugno |
25 | * Gianluca Turconi |
26 | * Simon Brouwer |
27 | * Noll Janos |
28 | * Biro Arpad |
29 | * Goldman Eleonora |
30 | * Sarlos Tamas |
31 | * Bencsath Boldizsar |
32 | * Halacsy Peter |
33 | * Dvornik Laszlo |
34 | * Gefferth Andras |
35 | * Nagy Viktor |
36 | * Varga Daniel |
37 | * Chris Halls |
38 | * Rene Engelhard |
39 | * Bram Moolenaar |
40 | * Dafydd Jones |
41 | * Harri Pitkanen |
42 | * Andras Timar |
43 | * Tor Lillqvist |
44 | * Jesper Kristensen (mail@jesperkristensen.dk) |
45 | * |
46 | * Alternatively, the contents of this file may be used under the terms of |
47 | * either the GNU General Public License Version 2 or later (the "GPL"), or |
48 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
49 | * in which case the provisions of the GPL or the LGPL are applicable instead |
50 | * of those above. If you wish to allow use of your version of this file only |
51 | * under the terms of either the GPL or the LGPL, and not to allow others to |
52 | * use your version of this file under the terms of the MPL, indicate your |
53 | * decision by deleting the provisions above and replace them with the notice |
54 | * and other provisions required by the GPL or the LGPL. If you do not delete |
55 | * the provisions above, a recipient may use your version of this file under |
56 | * the terms of any one of the MPL, the GPL or the LGPL. |
57 | * |
58 | ******* END LICENSE BLOCK *******/ |
59 | |
60 | #include "mozHunspell.h" |
61 | #include "nsReadableUtils.h" |
62 | #include "nsString.h" |
63 | #include "nsIObserverService.h" |
64 | #include "nsIDirectoryEnumerator.h" |
65 | #include "nsIFile.h" |
66 | #include "nsUnicharUtils.h" |
67 | #include "nsCRT.h" |
68 | #include "mozInlineSpellChecker.h" |
69 | #include "nsIPrefBranch.h" |
70 | #include "nsIPrefService.h" |
71 | #include "nsNetUtil.h" |
72 | #include "prenv.h" |
73 | #include "mozilla/Components.h" |
74 | #include "mozilla/Services.h" |
75 | #include "mozilla/dom/ContentParent_NotifyUpdatedDictionaries.h" |
76 | |
77 | #include <stdlib.h> |
78 | #include <tuple> |
79 | |
80 | using namespace mozilla; |
81 | |
82 | NS_IMPL_CYCLE_COLLECTING_ADDREF(mozHunspell)MozExternalRefCountType mozHunspell::AddRef(void) { static_assert (!std::is_destructible_v<mozHunspell>, "Reference-counted class " "mozHunspell" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 82; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); _mOwningThread.AssertOwnership("mozHunspell" " not thread-safe" ); nsISupports* base = mozHunspell::cycleCollection::Upcast(this ); nsrefcnt count = mRefCnt.incr(base); NS_LogAddRef((this), ( count), ("mozHunspell"), (uint32_t)(sizeof(*this))); return count ; } |
83 | NS_IMPL_CYCLE_COLLECTING_RELEASE(mozHunspell)MozExternalRefCountType mozHunspell::Release(void) { do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 83 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); _mOwningThread.AssertOwnership("mozHunspell" " not thread-safe" ); nsISupports* base = mozHunspell::cycleCollection::Upcast(this ); nsrefcnt count = mRefCnt.decr(base); NS_LogRelease((this), (count), ("mozHunspell")); return count; } void mozHunspell:: DeleteCycleCollectable(void) { delete (this); } |
84 | |
85 | NS_INTERFACE_MAP_BEGIN(mozHunspell)nsresult mozHunspell::QueryInterface(const nsIID& aIID, void ** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak( NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 85); MOZ_PretendNoReturn(); } } while (0); nsISupports* foundInterface ; |
86 | NS_INTERFACE_MAP_ENTRY(mozISpellCheckingEngine)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t <decltype(*this)>, mozISpellCheckingEngine>)) foundInterface = static_cast<mozISpellCheckingEngine*>(this); else |
87 | NS_INTERFACE_MAP_ENTRY(nsIObserver)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t <decltype(*this)>, nsIObserver>)) foundInterface = static_cast <nsIObserver*>(this); else |
88 | NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t <decltype(*this)>, nsISupportsWeakReference>)) foundInterface = static_cast<nsISupportsWeakReference*>(this); else |
89 | NS_INTERFACE_MAP_ENTRY(nsIMemoryReporter)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t <decltype(*this)>, nsIMemoryReporter>)) foundInterface = static_cast<nsIMemoryReporter*>(this); else |
90 | NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, mozISpellCheckingEngine)if (aIID.Equals(mozilla::detail::kImplementedIID<std::remove_reference_t <decltype(*this)>, nsISupports>)) foundInterface = static_cast <nsISupports*>(static_cast<mozISpellCheckingEngine*> (this)); else |
91 | NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozHunspell)if (TopThreeWordsEquals( aIID, (nsXPCOMCycleCollectionParticipant ::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>:: kIID), (nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports , void>::kIID)) && (LowWordEquals(aIID, (nsXPCOMCycleCollectionParticipant ::COMTypeInfo<nsXPCOMCycleCollectionParticipant, void>:: kIID)) || LowWordEquals(aIID, (nsCycleCollectionISupports::COMTypeInfo <nsCycleCollectionISupports, void>::kIID)))) { if (LowWordEquals (aIID, (nsXPCOMCycleCollectionParticipant::COMTypeInfo<nsXPCOMCycleCollectionParticipant , void>::kIID))) { *aInstancePtr = mozHunspell::cycleCollection ::GetParticipant(); return NS_OK; } if (LowWordEquals(aIID, ( nsCycleCollectionISupports::COMTypeInfo<nsCycleCollectionISupports , void>::kIID))) { *aInstancePtr = mozHunspell::cycleCollection ::Upcast(this); return NS_OK; } foundInterface = nullptr; } else |
92 | NS_INTERFACE_MAP_ENDfoundInterface = 0; nsresult status; if (!foundInterface) { do { static_assert( mozilla::detail::AssertionConditionType< decltype(!aIID.Equals((nsISupports::COMTypeInfo<nsISupports , void>::kIID)))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::COMTypeInfo <nsISupports, void>::kIID))))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))" , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 92); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::COMTypeInfo<nsISupports, void>::kIID))" ")"); do { *((volatile int*)__null) = 92; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); status = NS_NOINTERFACE ; } else { (foundInterface)->AddRef(); status = NS_OK; } * aInstancePtr = foundInterface; return status; } |
93 | |
94 | NS_IMPL_CYCLE_COLLECTION_WEAK(mozHunspell, mPersonalDictionary)mozHunspell::cycleCollection mozHunspell::_cycleCollectorGlobal ; void mozHunspell::cycleCollection::Unlink(void* p) { mozHunspell * tmp = DowncastCCParticipant<mozHunspell>(p); ImplCycleCollectionUnlink (tmp->mPersonalDictionary); tmp->ClearWeakReferences(); (void)tmp; } nsresult mozHunspell::cycleCollection::TraverseNative ( void* p, nsCycleCollectionTraversalCallback& cb) { mozHunspell * tmp = DowncastCCParticipant<mozHunspell>(p); cb.DescribeRefCountedNode (tmp->mRefCnt.get(), "mozHunspell"); ImplCycleCollectionTraverse (cb, tmp->mPersonalDictionary, "mPersonalDictionary", 0); ( void)tmp; return NS_OK; } |
95 | |
96 | NS_IMPL_COMPONENT_FACTORY(mozHunspell)template <> already_AddRefed<nsISupports> mozCreateComponent <mozHunspell>() { |
97 | auto hunspell = MakeRefPtr<mozHunspell>(); |
98 | if (NS_SUCCEEDED(hunspell->Init())((bool)(__builtin_expect(!!(!NS_FAILED_impl(hunspell->Init ())), 1)))) { |
99 | return hunspell.forget().downcast<mozISpellCheckingEngine>(); |
100 | } |
101 | return nullptr; |
102 | } |
103 | |
104 | mozHunspell::mozHunspell() { |
105 | #ifdef DEBUG1 |
106 | // There must be only one instance of this class: it reports memory based on |
107 | // a single static count in HunspellAllocator. |
108 | static bool hasRun = false; |
109 | MOZ_ASSERT(!hasRun)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!hasRun)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!hasRun))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!hasRun", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!hasRun" ")" ); do { *((volatile int*)__null) = 109; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
110 | hasRun = true; |
111 | #endif |
112 | } |
113 | |
114 | nsresult mozHunspell::Init() { |
115 | LoadDictionaryList(false); |
116 | |
117 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
118 | if (obs) { |
119 | obs->AddObserver(this, "profile-do-change", true); |
120 | obs->AddObserver(this, "profile-after-change", true); |
121 | } |
122 | |
123 | mozilla::RegisterWeakMemoryReporter(this); |
124 | |
125 | return NS_OK; |
126 | } |
127 | |
128 | mozHunspell::~mozHunspell() { |
129 | mozilla::UnregisterWeakMemoryReporter(this); |
130 | |
131 | mPersonalDictionary = nullptr; |
132 | mHunspells.Clear(); |
133 | } |
134 | |
135 | NS_IMETHODIMPnsresult |
136 | mozHunspell::GetDictionaries(nsTArray<nsCString>& aDictionaries) { |
137 | MOZ_ASSERT(aDictionaries.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDictionaries.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDictionaries.IsEmpty()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("aDictionaries.IsEmpty()" , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 137); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDictionaries.IsEmpty()" ")"); do { *((volatile int*)__null) = 137; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
138 | for (auto iter = mHunspells.ConstIter(); !iter.Done(); iter.Next()) { |
139 | if (iter.Data().mEnabled) { |
140 | aDictionaries.AppendElement(iter.Key()); |
141 | } |
142 | } |
143 | return NS_OK; |
144 | } |
145 | |
146 | /* Set the Dictionaries. |
147 | * This also Loads the dictionaries and initializes the converter using the |
148 | * dictionaries converter |
149 | */ |
150 | NS_IMETHODIMPnsresult |
151 | mozHunspell::SetDictionaries(const nsTArray<nsCString>& aDictionaries) { |
152 | if (aDictionaries.IsEmpty()) { |
153 | mHunspells.Clear(); |
154 | return NS_OK; |
155 | } |
156 | |
157 | // Disable any dictionaries we've already loaded that we're not |
158 | // going to use. |
159 | for (auto iter = mHunspells.Iter(); !iter.Done(); iter.Next()) { |
160 | if (!aDictionaries.Contains(iter.Key())) { |
161 | iter.Data().mEnabled = false; |
162 | } |
163 | } |
164 | |
165 | bool firstDictionary = true; |
166 | for (const auto& dictionary : aDictionaries) { |
167 | NS_ConvertUTF8toUTF16 dict(dictionary); |
168 | nsIURI* affFile = mDictionaries.GetWeak(dict); |
169 | if (!affFile) { |
170 | return NS_ERROR_FILE_NOT_FOUND; |
171 | } |
172 | |
173 | nsAutoCString affFileName; |
174 | nsresult rv = affFile->GetSpec(affFileName); |
175 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 175); return rv; } } while (false); |
176 | |
177 | if (auto entry = mHunspells.Lookup(dictionary)) { |
178 | if (entry.Data().mAffixFileName == affFileName) { |
179 | entry.Data().mEnabled = true; |
180 | continue; |
181 | } |
182 | } |
183 | |
184 | DictionaryData dictionaryData; |
185 | dictionaryData.mAffixFileName = affFileName; |
186 | |
187 | // Load the first dictionary now, we'll load the others lazily during |
188 | // checking. |
189 | if (firstDictionary) { |
190 | rv = dictionaryData.LoadIfNecessary(); |
191 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 191); return rv; } } while (false); |
192 | firstDictionary = false; |
193 | } |
194 | |
195 | mHunspells.InsertOrUpdate(dictionary, std::move(dictionaryData)); |
196 | } |
197 | |
198 | // If we have a large number of dictionaries loaded, try freeing any disabled |
199 | // dictionaries to limit memory use. |
200 | if (mHunspells.Count() > 10) { |
201 | mHunspells.RemoveIf([](const auto& iter) { return !iter.Data().mEnabled; }); |
202 | } |
203 | |
204 | return NS_OK; |
205 | } |
206 | |
207 | NS_IMETHODIMPnsresult mozHunspell::GetPersonalDictionary( |
208 | mozIPersonalDictionary** aPersonalDictionary) { |
209 | *aPersonalDictionary = mPersonalDictionary; |
210 | NS_IF_ADDREF(*aPersonalDictionary)ns_if_addref(*aPersonalDictionary); |
211 | return NS_OK; |
212 | } |
213 | |
214 | NS_IMETHODIMPnsresult mozHunspell::SetPersonalDictionary( |
215 | mozIPersonalDictionary* aPersonalDictionary) { |
216 | mPersonalDictionary = aPersonalDictionary; |
217 | return NS_OK; |
218 | } |
219 | |
220 | NS_IMETHODIMPnsresult mozHunspell::GetDictionaryList( |
221 | nsTArray<nsCString>& aDictionaries) { |
222 | MOZ_ASSERT(aDictionaries.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aDictionaries.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aDictionaries.IsEmpty()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("aDictionaries.IsEmpty()" , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 222); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDictionaries.IsEmpty()" ")"); do { *((volatile int*)__null) = 222; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
223 | for (const auto& key : mDictionaries.Keys()) { |
224 | aDictionaries.AppendElement(NS_ConvertUTF16toUTF8(key)); |
225 | } |
226 | |
227 | return NS_OK; |
228 | } |
229 | |
230 | void mozHunspell::LoadDictionaryList(bool aNotifyChildProcesses) { |
231 | mDictionaries.Clear(); |
232 | |
233 | nsresult rv; |
234 | |
235 | // find built in dictionaries, or dictionaries specified in |
236 | // spellchecker.dictionary_path in prefs |
237 | nsCOMPtr<nsIFile> dictDir; |
238 | |
239 | // check preferences first |
240 | nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1")); |
241 | if (prefs) { |
242 | nsAutoCString extDictPath; |
243 | rv = prefs->GetCharPref("spellchecker.dictionary_path", extDictPath); |
244 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
245 | // set the spellchecker.dictionary_path |
246 | rv = NS_NewNativeLocalFile(extDictPath, true, getter_AddRefs(dictDir)); |
Value stored to 'rv' is never read | |
247 | } |
248 | if (dictDir) { |
249 | LoadDictionariesFromDir(dictDir); |
250 | } |
251 | } |
252 | |
253 | // find dictionaries in DICPATH |
254 | char* dicEnv = PR_GetEnv("DICPATH"); |
255 | if (dicEnv) { |
256 | // do a two-pass dance so dictionaries are loaded right-to-left as |
257 | // preference |
258 | nsTArray<nsCOMPtr<nsIFile>> dirs; |
259 | nsAutoCString env(dicEnv); // assume dicEnv is UTF-8 |
260 | |
261 | char* currPath = nullptr; |
262 | char* nextPaths = env.BeginWriting(); |
263 | while ((currPath = NS_strtok(":", &nextPaths))) { |
264 | nsCOMPtr<nsIFile> dir; |
265 | rv = |
266 | NS_NewNativeLocalFile(nsCString(currPath), true, getter_AddRefs(dir)); |
267 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
268 | dirs.AppendElement(dir); |
269 | } |
270 | } |
271 | |
272 | // load them in reverse order so they override each other properly |
273 | for (int32_t i = dirs.Length() - 1; i >= 0; i--) { |
274 | LoadDictionariesFromDir(dirs[i]); |
275 | } |
276 | } |
277 | |
278 | // find dictionaries from restartless extensions |
279 | for (int32_t i = 0; i < mDynamicDirectories.Count(); i++) { |
280 | LoadDictionariesFromDir(mDynamicDirectories[i]); |
281 | } |
282 | |
283 | for (const auto& dictionaryEntry : mDynamicDictionaries) { |
284 | mDictionaries.InsertOrUpdate(dictionaryEntry.GetKey(), |
285 | dictionaryEntry.GetData()); |
286 | } |
287 | |
288 | DictionariesChanged(aNotifyChildProcesses); |
289 | } |
290 | |
291 | void mozHunspell::DictionariesChanged(bool aNotifyChildProcesses) { |
292 | // Now we have finished updating the list of dictionaries, update the current |
293 | // dictionary and any editors which may use it. |
294 | mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking(); |
295 | |
296 | if (aNotifyChildProcesses) { |
297 | mozilla::dom::ContentParent_NotifyUpdatedDictionaries(); |
298 | } |
299 | |
300 | // Check if the current dictionaries are still available. |
301 | // If not, try to replace it with other dictionaries of the same language. |
302 | if (!mHunspells.IsEmpty()) { |
303 | nsTArray<nsCString> dictionaries; |
304 | for (auto iter = mHunspells.ConstIter(); !iter.Done(); iter.Next()) { |
305 | if (iter.Data().mEnabled) { |
306 | dictionaries.AppendElement(iter.Key()); |
307 | } |
308 | } |
309 | nsresult rv = SetDictionaries(dictionaries); |
310 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) return; |
311 | } |
312 | |
313 | // If the current dictionaries are gone, and we don't have a good replacement, |
314 | // set no current dictionary. |
315 | if (!mHunspells.IsEmpty()) { |
316 | nsTArray<nsCString> empty; |
317 | SetDictionaries(empty); |
318 | } |
319 | } |
320 | |
321 | NS_IMETHODIMPnsresult |
322 | mozHunspell::LoadDictionariesFromDir(nsIFile* aDir) { |
323 | nsresult rv; |
324 | |
325 | bool check = false; |
326 | rv = aDir->Exists(&check); |
327 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !check) return NS_ERROR_UNEXPECTED; |
328 | |
329 | rv = aDir->IsDirectory(&check); |
330 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !check) return NS_ERROR_UNEXPECTED; |
331 | |
332 | nsCOMPtr<nsIDirectoryEnumerator> files; |
333 | rv = aDir->GetDirectoryEntries(getter_AddRefs(files)); |
334 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return NS_ERROR_UNEXPECTED; |
335 | |
336 | nsCOMPtr<nsIFile> file; |
337 | while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(files->GetNextFile (getter_AddRefs(file)))), 1))) && file) { |
338 | nsAutoString leafName; |
339 | file->GetLeafName(leafName); |
340 | if (!StringEndsWith(leafName, u".dic"_ns)) continue; |
341 | |
342 | nsAutoString dict(leafName); |
343 | dict.SetLength(dict.Length() - 4); // magic length of ".dic" |
344 | |
345 | // check for the presence of the .aff file |
346 | leafName = dict; |
347 | leafName.AppendLiteral(".aff"); |
348 | file->SetLeafName(leafName); |
349 | rv = file->Exists(&check); |
350 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !check) continue; |
351 | |
352 | // Replace '_' separator with '-' |
353 | dict.ReplaceChar('_', '-'); |
354 | |
355 | nsCOMPtr<nsIURI> uri; |
356 | rv = NS_NewFileURI(getter_AddRefs(uri), file); |
357 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 357); return rv; } } while (false); |
358 | |
359 | mDictionaries.InsertOrUpdate(dict, uri); |
360 | } |
361 | |
362 | return NS_OK; |
363 | } |
364 | |
365 | nsresult mozHunspell::DictionaryData::ConvertCharset(const nsAString& aStr, |
366 | std::string& aDst) { |
367 | if (NS_WARN_IF(!mEncoder)NS_warn_if_impl(!mEncoder, "!mEncoder", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 367)) { |
368 | return NS_ERROR_NOT_INITIALIZED; |
369 | } |
370 | |
371 | auto src = Span(aStr.BeginReading(), aStr.Length()); |
372 | CheckedInt<size_t> needed = |
373 | mEncoder->MaxBufferLengthFromUTF16WithoutReplacement(src.Length()); |
374 | if (!needed.isValid()) { |
375 | return NS_ERROR_OUT_OF_MEMORY; |
376 | } |
377 | |
378 | aDst.resize(needed.value()); |
379 | |
380 | char* dstPtr = &aDst[0]; |
381 | auto dst = Span(reinterpret_cast<uint8_t*>(dstPtr), needed.value()); |
382 | |
383 | uint32_t result; |
384 | size_t written; |
385 | std::tie(result, std::ignore, written) = |
386 | mEncoder->EncodeFromUTF16WithoutReplacement(src, dst, true); |
387 | MOZ_ASSERT(result != kOutputFull)do { static_assert( mozilla::detail::AssertionConditionType< decltype(result != kOutputFull)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(result != kOutputFull))), 0) )) { do { } while (false); MOZ_ReportAssertionFailure("result != kOutputFull" , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 387); AnnotateMozCrashReason("MOZ_ASSERT" "(" "result != kOutputFull" ")"); do { *((volatile int*)__null) = 387; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
388 | if (result != kInputEmpty) { |
389 | return NS_ERROR_UENC_NOMAPPING; |
390 | } |
391 | aDst.resize(written); |
392 | mEncoder->Encoding()->NewEncoderInto(*mEncoder); |
393 | return NS_OK; |
394 | } |
395 | |
396 | nsresult mozHunspell::DictionaryData::LoadIfNecessary() { |
397 | if (mHunspell && mEncoder && mDecoder) { |
398 | return NS_OK; |
399 | } |
400 | |
401 | if (mLoadFailed) { |
402 | return NS_ERROR_FAILURE; |
403 | } |
404 | |
405 | nsCString dictFileName = mAffixFileName; |
406 | int32_t dotPos = dictFileName.RFindChar('.'); |
407 | if (dotPos == -1) { |
408 | mLoadFailed = true; |
409 | return NS_ERROR_FAILURE; |
410 | } |
411 | dictFileName.SetLength(dotPos); |
412 | dictFileName.AppendLiteral(".dic"); |
413 | |
414 | UniquePtr<RLBoxHunspell> hunspell( |
415 | RLBoxHunspell::Create(mAffixFileName, dictFileName)); |
416 | if (!hunspell) { |
417 | mLoadFailed = true; |
418 | // TODO Bug 1788857: Verify error propagation in case of inaccessible file |
419 | return NS_ERROR_OUT_OF_MEMORY; |
420 | } |
421 | mHunspell = std::move(hunspell); |
422 | auto encoding = |
423 | Encoding::ForLabelNoReplacement(mHunspell->get_dict_encoding()); |
424 | if (!encoding) { |
425 | mLoadFailed = true; |
426 | return NS_ERROR_UCONV_NOCONV; |
427 | } |
428 | mEncoder = encoding->NewEncoder(); |
429 | mDecoder = encoding->NewDecoderWithoutBOMHandling(); |
430 | return NS_OK; |
431 | } |
432 | |
433 | NS_IMETHODIMPnsresult |
434 | mozHunspell::CollectReports(nsIHandleReportCallback* aHandleReport, |
435 | nsISupports* aData, bool aAnonymize) { |
436 | MOZ_COLLECT_REPORT("explicit/spell-check", KIND_HEAP, UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/spell-check" ), KIND_HEAP, UNITS_BYTES, HunspellAllocator::MemoryAllocated (), nsLiteralCString("Memory used by the spell-checking engine." ), aData) |
437 | HunspellAllocator::MemoryAllocated(),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/spell-check" ), KIND_HEAP, UNITS_BYTES, HunspellAllocator::MemoryAllocated (), nsLiteralCString("Memory used by the spell-checking engine." ), aData) |
438 | "Memory used by the spell-checking engine.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/spell-check" ), KIND_HEAP, UNITS_BYTES, HunspellAllocator::MemoryAllocated (), nsLiteralCString("Memory used by the spell-checking engine." ), aData); |
439 | |
440 | return NS_OK; |
441 | } |
442 | |
443 | NS_IMETHODIMPnsresult |
444 | mozHunspell::Check(const nsAString& aWord, bool* aResult) { |
445 | if (NS_WARN_IF(!aResult)NS_warn_if_impl(!aResult, "!aResult", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 445)) { |
446 | return NS_ERROR_INVALID_ARG; |
447 | } |
448 | |
449 | if (NS_WARN_IF(mHunspells.IsEmpty())NS_warn_if_impl(mHunspells.IsEmpty(), "mHunspells.IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 449)) { |
450 | return NS_ERROR_FAILURE; |
451 | } |
452 | |
453 | *aResult = true; |
454 | for (auto iter = mHunspells.Iter(); !iter.Done(); iter.Next()) { |
455 | if (!iter.Data().mEnabled) { |
456 | continue; |
457 | } |
458 | |
459 | nsresult rv = iter.Data().LoadIfNecessary(); |
460 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
461 | continue; |
462 | } |
463 | |
464 | std::string charsetWord; |
465 | rv = iter.Data().ConvertCharset(aWord, charsetWord); |
466 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
467 | continue; |
468 | } |
469 | |
470 | // Depending upon the encoding, we might end up with a string that begins |
471 | // with the null byte. Since the hunspell interface uses C-style strings, |
472 | // this appears like an empty string, and hunspell marks empty strings as |
473 | // spelled correctly. Skip these cases to allow another dictionary to have |
474 | // the chance to spellcheck them. |
475 | if (charsetWord.empty() || charsetWord[0] == 0) { |
476 | continue; |
477 | } |
478 | |
479 | *aResult = iter.Data().mHunspell->spell(charsetWord); |
480 | if (*aResult) { |
481 | break; |
482 | } |
483 | } |
484 | |
485 | if (!*aResult && mPersonalDictionary) { |
486 | return mPersonalDictionary->Check(aWord, aResult); |
487 | } |
488 | |
489 | return NS_OK; |
490 | } |
491 | |
492 | NS_IMETHODIMPnsresult |
493 | mozHunspell::Suggest(const nsAString& aWord, nsTArray<nsString>& aSuggestions) { |
494 | if (NS_WARN_IF(mHunspells.IsEmpty())NS_warn_if_impl(mHunspells.IsEmpty(), "mHunspells.IsEmpty()", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 494)) { |
495 | return NS_ERROR_FAILURE; |
496 | } |
497 | |
498 | MOZ_ASSERT(aSuggestions.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType< decltype(aSuggestions.IsEmpty())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aSuggestions.IsEmpty()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("aSuggestions.IsEmpty()" , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 498); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSuggestions.IsEmpty()" ")"); do { *((volatile int*)__null) = 498; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
499 | |
500 | for (auto iter = mHunspells.Iter(); !iter.Done(); iter.Next()) { |
501 | if (!iter.Data().mEnabled) { |
502 | continue; |
503 | } |
504 | |
505 | nsresult rv = iter.Data().LoadIfNecessary(); |
506 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
507 | continue; |
508 | } |
509 | |
510 | std::string charsetWord; |
511 | rv = iter.Data().ConvertCharset(aWord, charsetWord); |
512 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 512); return rv; } } while (false); |
513 | |
514 | std::vector<std::string> suggestions = |
515 | iter.Data().mHunspell->suggest(charsetWord); |
516 | if (!suggestions.empty()) { |
517 | aSuggestions.SetCapacity(aSuggestions.Length() + suggestions.size()); |
518 | for (Span<const char> charSrc : suggestions) { |
519 | // Convert the suggestion to utf16 |
520 | auto src = AsBytes(charSrc); |
521 | nsresult rv = |
522 | iter.Data().mDecoder->Encoding()->DecodeWithoutBOMHandling( |
523 | src, *aSuggestions.AppendElement()); |
524 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 524); return rv; } } while (false); |
525 | iter.Data().mDecoder->Encoding()->NewDecoderWithoutBOMHandlingInto( |
526 | *iter.Data().mDecoder); |
527 | } |
528 | } |
529 | } |
530 | |
531 | return NS_OK; |
532 | } |
533 | |
534 | NS_IMETHODIMPnsresult |
535 | mozHunspell::Observe(nsISupports* aSubj, const char* aTopic, |
536 | const char16_t* aData) { |
537 | NS_ASSERTION(!strcmp(aTopic, "profile-do-change") ||do { if (!(!strcmp(aTopic, "profile-do-change") || !strcmp(aTopic , "profile-after-change"))) { NS_DebugBreak(NS_DEBUG_ASSERTION , "Unexpected observer topic", "!strcmp(aTopic, \"profile-do-change\") || !strcmp(aTopic, \"profile-after-change\")" , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 539); MOZ_PretendNoReturn(); } } while (0) |
538 | !strcmp(aTopic, "profile-after-change"),do { if (!(!strcmp(aTopic, "profile-do-change") || !strcmp(aTopic , "profile-after-change"))) { NS_DebugBreak(NS_DEBUG_ASSERTION , "Unexpected observer topic", "!strcmp(aTopic, \"profile-do-change\") || !strcmp(aTopic, \"profile-after-change\")" , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 539); MOZ_PretendNoReturn(); } } while (0) |
539 | "Unexpected observer topic")do { if (!(!strcmp(aTopic, "profile-do-change") || !strcmp(aTopic , "profile-after-change"))) { NS_DebugBreak(NS_DEBUG_ASSERTION , "Unexpected observer topic", "!strcmp(aTopic, \"profile-do-change\") || !strcmp(aTopic, \"profile-after-change\")" , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 539); MOZ_PretendNoReturn(); } } while (0); |
540 | |
541 | LoadDictionaryList(false); |
542 | |
543 | return NS_OK; |
544 | } |
545 | |
546 | NS_IMETHODIMPnsresult mozHunspell::AddDirectory(nsIFile* aDir) { |
547 | mDynamicDirectories.AppendObject(aDir); |
548 | LoadDictionaryList(true); |
549 | return NS_OK; |
550 | } |
551 | |
552 | NS_IMETHODIMPnsresult mozHunspell::RemoveDirectory(nsIFile* aDir) { |
553 | mDynamicDirectories.RemoveObject(aDir); |
554 | LoadDictionaryList(true); |
555 | |
556 | #ifdef MOZ_THUNDERBIRD |
557 | /* |
558 | * This notification is needed for Thunderbird. Thunderbird derives the |
559 | * dictionary from the document's "lang" attribute. If a dictionary is |
560 | * removed, we need to change the "lang" attribute. |
561 | */ |
562 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
563 | if (obs) { |
564 | obs->NotifyObservers(nullptr, SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION"spellcheck-dictionary-remove", |
565 | nullptr); |
566 | } |
567 | #endif |
568 | return NS_OK; |
569 | } |
570 | |
571 | NS_IMETHODIMPnsresult mozHunspell::AddDictionary(const nsAString& aLang, |
572 | nsIURI* aFile) { |
573 | NS_ENSURE_TRUE(aFile, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 573); return NS_ERROR_INVALID_ARG; } } while (false); |
574 | |
575 | mDynamicDictionaries.InsertOrUpdate(aLang, aFile); |
576 | mDictionaries.InsertOrUpdate(aLang, aFile); |
577 | DictionariesChanged(true); |
578 | return NS_OK; |
579 | } |
580 | |
581 | NS_IMETHODIMPnsresult mozHunspell::RemoveDictionary(const nsAString& aLang, |
582 | nsIURI* aFile, bool* aRetVal) { |
583 | NS_ENSURE_TRUE(aFile, NS_ERROR_INVALID_ARG)do { if ((__builtin_expect(!!(!(aFile)), 0))) { NS_DebugBreak (NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "aFile" ") failed", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 583); return NS_ERROR_INVALID_ARG; } } while (false); |
584 | *aRetVal = false; |
585 | |
586 | nsCOMPtr<nsIURI> file = mDynamicDictionaries.Get(aLang); |
587 | bool equal; |
588 | if (file && NS_SUCCEEDED(file->Equals(aFile, &equal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(file->Equals(aFile , &equal))), 1))) && equal) { |
589 | mDynamicDictionaries.Remove(aLang); |
590 | LoadDictionaryList(true); |
591 | *aRetVal = true; |
592 | } |
593 | return NS_OK; |
594 | } |