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, 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 = NS_NewNativeLocalFile(nsCString(currPath), getter_AddRefs(dir)); |
266 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) { |
267 | dirs.AppendElement(dir); |
268 | } |
269 | } |
270 | |
271 | // load them in reverse order so they override each other properly |
272 | for (int32_t i = dirs.Length() - 1; i >= 0; i--) { |
273 | LoadDictionariesFromDir(dirs[i]); |
274 | } |
275 | } |
276 | |
277 | // find dictionaries from restartless extensions |
278 | for (int32_t i = 0; i < mDynamicDirectories.Count(); i++) { |
279 | LoadDictionariesFromDir(mDynamicDirectories[i]); |
280 | } |
281 | |
282 | for (const auto& dictionaryEntry : mDynamicDictionaries) { |
283 | mDictionaries.InsertOrUpdate(dictionaryEntry.GetKey(), |
284 | dictionaryEntry.GetData()); |
285 | } |
286 | |
287 | DictionariesChanged(aNotifyChildProcesses); |
288 | } |
289 | |
290 | void mozHunspell::DictionariesChanged(bool aNotifyChildProcesses) { |
291 | // Now we have finished updating the list of dictionaries, update the current |
292 | // dictionary and any editors which may use it. |
293 | mozInlineSpellChecker::UpdateCanEnableInlineSpellChecking(); |
294 | |
295 | if (aNotifyChildProcesses) { |
296 | mozilla::dom::ContentParent_NotifyUpdatedDictionaries(); |
297 | } |
298 | |
299 | // Check if the current dictionaries are still available. |
300 | // If not, try to replace it with other dictionaries of the same language. |
301 | if (!mHunspells.IsEmpty()) { |
302 | nsTArray<nsCString> dictionaries; |
303 | for (auto iter = mHunspells.ConstIter(); !iter.Done(); iter.Next()) { |
304 | if (iter.Data().mEnabled) { |
305 | dictionaries.AppendElement(iter.Key()); |
306 | } |
307 | } |
308 | nsresult rv = SetDictionaries(dictionaries); |
309 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) return; |
310 | } |
311 | |
312 | // If the current dictionaries are gone, and we don't have a good replacement, |
313 | // set no current dictionary. |
314 | if (!mHunspells.IsEmpty()) { |
315 | nsTArray<nsCString> empty; |
316 | SetDictionaries(empty); |
317 | } |
318 | } |
319 | |
320 | NS_IMETHODIMPnsresult |
321 | mozHunspell::LoadDictionariesFromDir(nsIFile* aDir) { |
322 | nsresult rv; |
323 | |
324 | bool check = false; |
325 | rv = aDir->Exists(&check); |
326 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !check) return NS_ERROR_UNEXPECTED; |
327 | |
328 | rv = aDir->IsDirectory(&check); |
329 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !check) return NS_ERROR_UNEXPECTED; |
330 | |
331 | nsCOMPtr<nsIDirectoryEnumerator> files; |
332 | rv = aDir->GetDirectoryEntries(getter_AddRefs(files)); |
333 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return NS_ERROR_UNEXPECTED; |
334 | |
335 | nsCOMPtr<nsIFile> file; |
336 | while (NS_SUCCEEDED(files->GetNextFile(getter_AddRefs(file)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(files->GetNextFile (getter_AddRefs(file)))), 1))) && file) { |
337 | nsAutoString leafName; |
338 | file->GetLeafName(leafName); |
339 | if (!StringEndsWith(leafName, u".dic"_ns)) continue; |
340 | |
341 | nsAutoString dict(leafName); |
342 | dict.SetLength(dict.Length() - 4); // magic length of ".dic" |
343 | |
344 | // check for the presence of the .aff file |
345 | leafName = dict; |
346 | leafName.AppendLiteral(".aff"); |
347 | file->SetLeafName(leafName); |
348 | rv = file->Exists(&check); |
349 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !check) continue; |
350 | |
351 | // Replace '_' separator with '-' |
352 | dict.ReplaceChar('_', '-'); |
353 | |
354 | nsCOMPtr<nsIURI> uri; |
355 | rv = NS_NewFileURI(getter_AddRefs(uri), file); |
356 | 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" , 356); return rv; } } while (false); |
357 | |
358 | mDictionaries.InsertOrUpdate(dict, uri); |
359 | } |
360 | |
361 | return NS_OK; |
362 | } |
363 | |
364 | nsresult mozHunspell::DictionaryData::ConvertCharset(const nsAString& aStr, |
365 | std::string& aDst) { |
366 | if (NS_WARN_IF(!mEncoder)NS_warn_if_impl(!mEncoder, "!mEncoder", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 366)) { |
367 | return NS_ERROR_NOT_INITIALIZED; |
368 | } |
369 | |
370 | auto src = Span(aStr.BeginReading(), aStr.Length()); |
371 | CheckedInt<size_t> needed = |
372 | mEncoder->MaxBufferLengthFromUTF16WithoutReplacement(src.Length()); |
373 | if (!needed.isValid()) { |
374 | return NS_ERROR_OUT_OF_MEMORY; |
375 | } |
376 | |
377 | aDst.resize(needed.value()); |
378 | |
379 | char* dstPtr = &aDst[0]; |
380 | auto dst = Span(reinterpret_cast<uint8_t*>(dstPtr), needed.value()); |
381 | |
382 | uint32_t result; |
383 | size_t written; |
384 | std::tie(result, std::ignore, written) = |
385 | mEncoder->EncodeFromUTF16WithoutReplacement(src, dst, true); |
386 | 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" , 386); AnnotateMozCrashReason("MOZ_ASSERT" "(" "result != kOutputFull" ")"); do { *((volatile int*)__null) = 386; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
387 | if (result != kInputEmpty) { |
388 | return NS_ERROR_UENC_NOMAPPING; |
389 | } |
390 | aDst.resize(written); |
391 | mEncoder->Encoding()->NewEncoderInto(*mEncoder); |
392 | return NS_OK; |
393 | } |
394 | |
395 | nsresult mozHunspell::DictionaryData::LoadIfNecessary() { |
396 | if (mHunspell && mEncoder && mDecoder) { |
397 | return NS_OK; |
398 | } |
399 | |
400 | if (mLoadFailed) { |
401 | return NS_ERROR_FAILURE; |
402 | } |
403 | |
404 | nsCString dictFileName = mAffixFileName; |
405 | int32_t dotPos = dictFileName.RFindChar('.'); |
406 | if (dotPos == -1) { |
407 | mLoadFailed = true; |
408 | return NS_ERROR_FAILURE; |
409 | } |
410 | dictFileName.SetLength(dotPos); |
411 | dictFileName.AppendLiteral(".dic"); |
412 | |
413 | UniquePtr<RLBoxHunspell> hunspell( |
414 | RLBoxHunspell::Create(mAffixFileName, dictFileName)); |
415 | if (!hunspell) { |
416 | mLoadFailed = true; |
417 | // TODO Bug 1788857: Verify error propagation in case of inaccessible file |
418 | return NS_ERROR_OUT_OF_MEMORY; |
419 | } |
420 | mHunspell = std::move(hunspell); |
421 | auto encoding = |
422 | Encoding::ForLabelNoReplacement(mHunspell->get_dict_encoding()); |
423 | if (!encoding) { |
424 | mLoadFailed = true; |
425 | return NS_ERROR_UCONV_NOCONV; |
426 | } |
427 | mEncoder = encoding->NewEncoder(); |
428 | mDecoder = encoding->NewDecoderWithoutBOMHandling(); |
429 | return NS_OK; |
430 | } |
431 | |
432 | NS_IMETHODIMPnsresult |
433 | mozHunspell::CollectReports(nsIHandleReportCallback* aHandleReport, |
434 | nsISupports* aData, bool aAnonymize) { |
435 | 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) |
436 | 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) |
437 | "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); |
438 | |
439 | return NS_OK; |
440 | } |
441 | |
442 | NS_IMETHODIMPnsresult |
443 | mozHunspell::Check(const nsAString& aWord, bool* aResult) { |
444 | if (NS_WARN_IF(!aResult)NS_warn_if_impl(!aResult, "!aResult", "/var/lib/jenkins/workspace/firefox-scan-build/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 444)) { |
445 | return NS_ERROR_INVALID_ARG; |
446 | } |
447 | |
448 | 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" , 448)) { |
449 | return NS_ERROR_FAILURE; |
450 | } |
451 | |
452 | *aResult = true; |
453 | for (auto iter = mHunspells.Iter(); !iter.Done(); iter.Next()) { |
454 | if (!iter.Data().mEnabled) { |
455 | continue; |
456 | } |
457 | |
458 | nsresult rv = iter.Data().LoadIfNecessary(); |
459 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
460 | continue; |
461 | } |
462 | |
463 | std::string charsetWord; |
464 | rv = iter.Data().ConvertCharset(aWord, charsetWord); |
465 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
466 | continue; |
467 | } |
468 | |
469 | // Depending upon the encoding, we might end up with a string that begins |
470 | // with the null byte. Since the hunspell interface uses C-style strings, |
471 | // this appears like an empty string, and hunspell marks empty strings as |
472 | // spelled correctly. Skip these cases to allow another dictionary to have |
473 | // the chance to spellcheck them. |
474 | if (charsetWord.empty() || charsetWord[0] == 0) { |
475 | continue; |
476 | } |
477 | |
478 | *aResult = iter.Data().mHunspell->spell(charsetWord); |
479 | if (*aResult) { |
480 | break; |
481 | } |
482 | } |
483 | |
484 | if (!*aResult && mPersonalDictionary) { |
485 | return mPersonalDictionary->Check(aWord, aResult); |
486 | } |
487 | |
488 | return NS_OK; |
489 | } |
490 | |
491 | NS_IMETHODIMPnsresult |
492 | mozHunspell::Suggest(const nsAString& aWord, nsTArray<nsString>& aSuggestions) { |
493 | 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" , 493)) { |
494 | return NS_ERROR_FAILURE; |
495 | } |
496 | |
497 | 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" , 497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSuggestions.IsEmpty()" ")"); do { *((volatile int*)__null) = 497; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
498 | |
499 | for (auto iter = mHunspells.Iter(); !iter.Done(); iter.Next()) { |
500 | if (!iter.Data().mEnabled) { |
501 | continue; |
502 | } |
503 | |
504 | nsresult rv = iter.Data().LoadIfNecessary(); |
505 | if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) { |
506 | continue; |
507 | } |
508 | |
509 | std::string charsetWord; |
510 | rv = iter.Data().ConvertCharset(aWord, charsetWord); |
511 | 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" , 511); return rv; } } while (false); |
512 | |
513 | std::vector<std::string> suggestions = |
514 | iter.Data().mHunspell->suggest(charsetWord); |
515 | if (!suggestions.empty()) { |
516 | aSuggestions.SetCapacity(aSuggestions.Length() + suggestions.size()); |
517 | for (Span<const char> charSrc : suggestions) { |
518 | // Convert the suggestion to utf16 |
519 | auto src = AsBytes(charSrc); |
520 | nsresult rv = |
521 | iter.Data().mDecoder->Encoding()->DecodeWithoutBOMHandling( |
522 | src, *aSuggestions.AppendElement()); |
523 | 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" , 523); return rv; } } while (false); |
524 | iter.Data().mDecoder->Encoding()->NewDecoderWithoutBOMHandlingInto( |
525 | *iter.Data().mDecoder); |
526 | } |
527 | } |
528 | } |
529 | |
530 | return NS_OK; |
531 | } |
532 | |
533 | NS_IMETHODIMPnsresult |
534 | mozHunspell::Observe(nsISupports* aSubj, const char* aTopic, |
535 | const char16_t* aData) { |
536 | 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" , 538); MOZ_PretendNoReturn(); } } while (0) |
537 | !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" , 538); MOZ_PretendNoReturn(); } } while (0) |
538 | "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" , 538); MOZ_PretendNoReturn(); } } while (0); |
539 | |
540 | LoadDictionaryList(false); |
541 | |
542 | return NS_OK; |
543 | } |
544 | |
545 | NS_IMETHODIMPnsresult mozHunspell::AddDirectory(nsIFile* aDir) { |
546 | mDynamicDirectories.AppendObject(aDir); |
547 | LoadDictionaryList(true); |
548 | return NS_OK; |
549 | } |
550 | |
551 | NS_IMETHODIMPnsresult mozHunspell::RemoveDirectory(nsIFile* aDir) { |
552 | mDynamicDirectories.RemoveObject(aDir); |
553 | LoadDictionaryList(true); |
554 | |
555 | #ifdef MOZ_THUNDERBIRD |
556 | /* |
557 | * This notification is needed for Thunderbird. Thunderbird derives the |
558 | * dictionary from the document's "lang" attribute. If a dictionary is |
559 | * removed, we need to change the "lang" attribute. |
560 | */ |
561 | nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService(); |
562 | if (obs) { |
563 | obs->NotifyObservers(nullptr, SPELLCHECK_DICTIONARY_REMOVE_NOTIFICATION"spellcheck-dictionary-remove", |
564 | nullptr); |
565 | } |
566 | #endif |
567 | return NS_OK; |
568 | } |
569 | |
570 | NS_IMETHODIMPnsresult mozHunspell::AddDictionary(const nsAString& aLang, |
571 | nsIURI* aFile) { |
572 | 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" , 572); return NS_ERROR_INVALID_ARG; } } while (false); |
573 | |
574 | mDynamicDictionaries.InsertOrUpdate(aLang, aFile); |
575 | mDictionaries.InsertOrUpdate(aLang, aFile); |
576 | DictionariesChanged(true); |
577 | return NS_OK; |
578 | } |
579 | |
580 | NS_IMETHODIMPnsresult mozHunspell::RemoveDictionary(const nsAString& aLang, |
581 | nsIURI* aFile, bool* aRetVal) { |
582 | 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" , 582); return NS_ERROR_INVALID_ARG; } } while (false); |
583 | *aRetVal = false; |
584 | |
585 | nsCOMPtr<nsIURI> file = mDynamicDictionaries.Get(aLang); |
586 | bool equal; |
587 | if (file && NS_SUCCEEDED(file->Equals(aFile, &equal))((bool)(__builtin_expect(!!(!NS_FAILED_impl(file->Equals(aFile , &equal))), 1))) && equal) { |
588 | mDynamicDictionaries.Remove(aLang); |
589 | LoadDictionaryList(true); |
590 | *aRetVal = true; |
591 | } |
592 | return NS_OK; |
593 | } |