| File: | root/firefox-clang/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" ")", "/root/firefox-clang/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__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" ")", "/root/firefox-clang/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__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); if (count == 0) { NS_CycleCollectableHasRefCntZero (); } 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", "/root/firefox-clang/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 ::kIID), (nsCycleCollectionISupports::kIID)) && (LowWordEquals (aIID, (nsXPCOMCycleCollectionParticipant::kIID)) || LowWordEquals (aIID, (nsCycleCollectionISupports::kIID)))) { if (LowWordEquals (aIID, (nsXPCOMCycleCollectionParticipant::kIID))) { *aInstancePtr = mozHunspell::cycleCollection::GetParticipant(); return NS_OK ; } if (LowWordEquals(aIID, (nsCycleCollectionISupports::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::kIID)))>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!aIID.Equals((nsISupports::kIID ))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure ("!aIID.Equals((nsISupports::kIID))", "/root/firefox-clang/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 92); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aIID.Equals((nsISupports::kIID))" ")"); do { MOZ_CrashSequence(__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", "/root/firefox-clang/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 109); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!hasRun" ")" ); do { MOZ_CrashSequence(__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()" , "/root/firefox-clang/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 137); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDictionaries.IsEmpty()" ")"); do { MOZ_CrashSequence(__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, "/root/firefox-clang/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, "/root/firefox-clang/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()" , "/root/firefox-clang/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 222); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aDictionaries.IsEmpty()" ")"); do { MOZ_CrashSequence(__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, "/root/firefox-clang/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", "/root/firefox-clang/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" , "/root/firefox-clang/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 386); AnnotateMozCrashReason("MOZ_ASSERT" "(" "result != kOutputFull" ")"); do { MOZ_CrashSequence(__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", "/root/firefox-clang/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()", "/root/firefox-clang/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()", "/root/firefox-clang/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()" , "/root/firefox-clang/extensions/spellcheck/hunspell/glue/mozHunspell.cpp" , 497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSuggestions.IsEmpty()" ")"); do { MOZ_CrashSequence(__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, "/root/firefox-clang/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, "/root/firefox-clang/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\")" , "/root/firefox-clang/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\")" , "/root/firefox-clang/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\")" , "/root/firefox-clang/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 , "/root/firefox-clang/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 , "/root/firefox-clang/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 | } |