summaryrefslogtreecommitdiffstats
path: root/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp')
-rw-r--r--extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp235
1 files changed, 235 insertions, 0 deletions
diff --git a/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp b/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp
new file mode 100644
index 0000000000..cd80fb989b
--- /dev/null
+++ b/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp
@@ -0,0 +1,235 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <limits>
+
+#include "mozHunspellRLBoxHost.h"
+#include "mozilla/DebugOnly.h"
+#include "nsContentUtils.h"
+#include "nsILoadInfo.h"
+#include "nsNetUtil.h"
+#include "nsUnicharUtils.h"
+
+#include "hunspell_csutil.hxx"
+
+using namespace mozilla;
+
+mozHunspellFileMgrHost::mozHunspellFileMgrHost(const nsCString& aFilename) {
+ nsCOMPtr<nsIChannel> channel;
+ DebugOnly<Result<Ok, nsresult>> result = Open(aFilename, channel, mStream);
+ NS_WARNING_ASSERTION(result.value.isOk(), "Failed to open Hunspell file");
+}
+
+/* static */
+Result<Ok, nsresult> mozHunspellFileMgrHost::Open(
+ const nsCString& aPath, nsCOMPtr<nsIChannel>& aChannel,
+ nsCOMPtr<nsIInputStream>& aStream) {
+ nsCOMPtr<nsIURI> uri;
+ MOZ_TRY(NS_NewURI(getter_AddRefs(uri), aPath));
+
+ MOZ_TRY(NS_NewChannel(
+ getter_AddRefs(aChannel), uri, nsContentUtils::GetSystemPrincipal(),
+ nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT,
+ nsIContentPolicy::TYPE_OTHER));
+
+ MOZ_TRY(aChannel->Open(getter_AddRefs(aStream)));
+ return Ok();
+}
+
+Result<Ok, nsresult> mozHunspellFileMgrHost::ReadLine(nsCString& aLine) {
+ if (!mStream) {
+ return Err(NS_ERROR_NOT_INITIALIZED);
+ }
+
+ bool ok;
+ MOZ_TRY(NS_ReadLine(mStream.get(), &mLineBuffer, aLine, &ok));
+ if (!ok) {
+ mStream = nullptr;
+ }
+
+ mLineNum++;
+ return Ok();
+}
+
+/* static */
+Result<int64_t, nsresult> mozHunspellFileMgrHost::GetSize(
+ const nsCString& aFilename) {
+ int64_t ret = -1;
+
+ nsCOMPtr<nsIChannel> channel;
+ nsCOMPtr<nsIInputStream> stream;
+ MOZ_TRY(Open(aFilename, channel, stream));
+
+ channel->GetContentLength(&ret);
+ return ret;
+}
+
+bool mozHunspellFileMgrHost::GetLine(std::string& aResult) {
+ nsAutoCString line;
+ auto res = ReadLine(line);
+ if (res.isErr()) {
+ return false;
+ }
+
+ aResult.assign(line.BeginReading(), line.Length());
+ return true;
+}
+
+/* static */
+uint32_t mozHunspellCallbacks::sCurrentFreshId = 0;
+/* static */
+mozilla::StaticRWLock mozHunspellCallbacks::sFileMgrMapLock;
+/* static */
+std::map<uint32_t, std::unique_ptr<mozHunspellFileMgrHost>>
+ mozHunspellCallbacks::sFileMgrMap;
+/* static */
+std::set<nsCString> mozHunspellCallbacks::sFileMgrAllowList;
+
+/* static */
+void mozHunspellCallbacks::AllowFile(const nsCString& aFilename) {
+ mozilla::StaticAutoWriteLock lock(sFileMgrMapLock);
+ sFileMgrAllowList.insert(aFilename);
+}
+
+/* static */
+void mozHunspellCallbacks::Clear() {
+ mozilla::StaticAutoWriteLock lock(sFileMgrMapLock);
+ sCurrentFreshId = 0;
+ sFileMgrMap.clear();
+ sFileMgrAllowList.clear();
+}
+
+/* static */
+tainted_hunspell<uint32_t> mozHunspellCallbacks::CreateFilemgr(
+ rlbox_sandbox_hunspell& aSandbox,
+ tainted_hunspell<const char*> t_aFilename) {
+ mozilla::StaticAutoWriteLock lock(sFileMgrMapLock);
+
+ return t_aFilename.copy_and_verify_string(
+ [&](std::unique_ptr<char[]> aFilename) {
+ nsCString cFilename = nsDependentCString(aFilename.get());
+
+ // Ensure that the filename is in the allowlist
+ auto it = sFileMgrAllowList.find(cFilename);
+ MOZ_RELEASE_ASSERT(it != sFileMgrAllowList.end());
+
+ // Get new id
+ uint32_t freshId = GetFreshId();
+ // Save mapping of id to file manager
+ sFileMgrMap[freshId] = std::unique_ptr<mozHunspellFileMgrHost>(
+ new mozHunspellFileMgrHost(cFilename));
+
+ return freshId;
+ });
+}
+
+/* static */
+uint32_t mozHunspellCallbacks::GetFreshId() {
+ // i is uint64_t to prevent overflow during loop increment which would cause
+ // an infinite loop
+ for (uint64_t i = sCurrentFreshId; i < std::numeric_limits<uint32_t>::max();
+ i++) {
+ auto it = sFileMgrMap.find(i);
+ if (it == sFileMgrMap.end()) {
+ // set sCurrentFreshId to the next (possibly) available id
+ sCurrentFreshId = i + 1;
+ return static_cast<uint32_t>(i);
+ }
+ }
+
+ MOZ_CRASH("Ran out of unique file ids for hunspell dictionaries");
+}
+
+/* static */
+mozHunspellFileMgrHost& mozHunspellCallbacks::GetMozHunspellFileMgrHost(
+ tainted_hunspell<uint32_t> t_aFd) {
+ mozilla::StaticAutoReadLock lock(sFileMgrMapLock);
+ uint32_t aFd = t_aFd.copy_and_verify([](uint32_t aFd) { return aFd; });
+ auto iter = sFileMgrMap.find(aFd);
+ MOZ_RELEASE_ASSERT(iter != sFileMgrMap.end());
+ return *(iter->second.get());
+}
+
+/* static */
+tainted_hunspell<bool> mozHunspellCallbacks::GetLine(
+ rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aFd,
+ tainted_hunspell<char**> t_aLinePtr) {
+ mozHunspellFileMgrHost& inst =
+ mozHunspellCallbacks::GetMozHunspellFileMgrHost(t_aFd);
+ std::string line;
+ bool ok = inst.GetLine(line);
+ // If the getline fails, return a null which is "graceful" failure
+ if (ok) {
+ // Copy the line into the sandbox. This memory is eventually freed by
+ // hunspell.
+ size_t size = line.size() + 1;
+ tainted_hunspell<char*> t_line = aSandbox.malloc_in_sandbox<char>(size);
+
+ if (t_line == nullptr) {
+ // If malloc fails, we should go to "graceful" failure path
+ ok = false;
+ } else {
+ rlbox::memcpy(aSandbox, t_line, line.c_str(), size);
+ }
+ *t_aLinePtr = t_line;
+ } else {
+ *t_aLinePtr = nullptr;
+ }
+ return ok;
+}
+
+/* static */
+tainted_hunspell<int> mozHunspellCallbacks::GetLineNum(
+ rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aFd) {
+ mozHunspellFileMgrHost& inst =
+ mozHunspellCallbacks::GetMozHunspellFileMgrHost(t_aFd);
+ int num = inst.GetLineNum();
+ return num;
+}
+
+/* static */
+void mozHunspellCallbacks::DestructFilemgr(rlbox_sandbox_hunspell& aSandbox,
+ tainted_hunspell<uint32_t> t_aFd) {
+ mozilla::StaticAutoWriteLock lock(sFileMgrMapLock);
+ uint32_t aFd = t_aFd.copy_and_verify([](uint32_t aFd) { return aFd; });
+
+ auto iter = sFileMgrMap.find(aFd);
+ if (iter != sFileMgrMap.end()) {
+ sFileMgrMap.erase(iter);
+ }
+}
+
+// Callbacks for using Firefox's encoding instead of hunspell's
+
+/* static */
+tainted_hunspell<uint32_t> mozHunspellCallbacks::ToUpperCase(
+ rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aChar) {
+ uint32_t aChar =
+ t_aChar.copy_and_verify([](uint32_t aChar) { return aChar; });
+ return ::ToUpperCase(aChar);
+}
+
+/* static */
+tainted_hunspell<uint32_t> mozHunspellCallbacks::ToLowerCase(
+ rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aChar) {
+ uint32_t aChar =
+ t_aChar.copy_and_verify([](uint32_t aChar) { return aChar; });
+ return ::ToLowerCase(aChar);
+}
+
+/* static */ tainted_hunspell<struct cs_info*>
+mozHunspellCallbacks::GetCurrentCS(rlbox_sandbox_hunspell& aSandbox,
+ tainted_hunspell<const char*> t_es) {
+ tainted_hunspell<struct cs_info*> t_ccs =
+ aSandbox.malloc_in_sandbox<struct cs_info>(256);
+ MOZ_RELEASE_ASSERT(t_ccs);
+ return t_es.copy_and_verify_string([&](std::unique_ptr<char[]> es) {
+ struct cs_info* ccs = hunspell_get_current_cs(es.get());
+ rlbox::memcpy(aSandbox, t_ccs, ccs, sizeof(struct cs_info) * 256);
+ delete[] ccs;
+ return t_ccs;
+ });
+}