summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium-shim/sandbox/win/src/line_break_interception.cc
diff options
context:
space:
mode:
Diffstat (limited to 'security/sandbox/chromium-shim/sandbox/win/src/line_break_interception.cc')
-rw-r--r--security/sandbox/chromium-shim/sandbox/win/src/line_break_interception.cc108
1 files changed, 108 insertions, 0 deletions
diff --git a/security/sandbox/chromium-shim/sandbox/win/src/line_break_interception.cc b/security/sandbox/chromium-shim/sandbox/win/src/line_break_interception.cc
new file mode 100644
index 0000000000..f2dcda0dc9
--- /dev/null
+++ b/security/sandbox/chromium-shim/sandbox/win/src/line_break_interception.cc
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=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 "sandbox/win/src/line_break_interception.h"
+
+#include <winnls.h>
+
+#include "sandbox/win/src/crosscall_client.h"
+#include "sandbox/win/src/ipc_tags.h"
+#include "sandbox/win/src/line_break_common.h"
+#include "sandbox/win/src/sandbox_nt_util.h"
+#include "sandbox/win/src/sharedmem_ipc_client.h"
+
+namespace sandbox {
+
+static const int kBreakSearchRange = 32;
+
+ResultCode GetComplexLineBreaksProxy(const wchar_t* aText, uint32_t aLength,
+ uint8_t* aBreakBefore) {
+ // Make sure that a test length for kMaxBrokeredLen hasn't been set too small
+ // allowing for a surrogate pair at the end of a chunk as well.
+ DCHECK(kMaxBrokeredLen > kBreakSearchRange + 1);
+
+ void* memory = GetGlobalIPCMemory();
+ if (!memory) {
+ return SBOX_ERROR_NO_SPACE;
+ }
+
+ memset(aBreakBefore, false, aLength);
+
+ SharedMemIPCClient ipc(memory);
+
+ uint8_t* breakBeforeIter = aBreakBefore;
+ const wchar_t* textIterEnd = aText + aLength;
+ do {
+ // Next chunk is either the remaining text or kMaxBrokeredLen long.
+ const wchar_t* textIter = aText + (breakBeforeIter - aBreakBefore);
+ const wchar_t* chunkEnd = textIter + kMaxBrokeredLen;
+ if (chunkEnd < textIterEnd) {
+ // Make sure we don't split a surrogate pair.
+ if (IS_HIGH_SURROGATE(*(chunkEnd - 1))) {
+ --chunkEnd;
+ }
+ } else {
+ // This chunk handles all the (remaining) text.
+ chunkEnd = textIterEnd;
+ }
+
+ // Uniscribe seems to often (perhaps always) set the first element to a
+ // break, so we use chunk_start_reset to hold the known value of the first
+ // element of a chunk and reset it after Uniscribe processing. The only time
+ // we don't start from an already processed element is the first call, but
+ // resetting this to false is correct because whether we can break before
+ // the first character is decided by our caller.
+ uint8_t chunk_start_reset = *breakBeforeIter;
+
+ uint32_t len = chunkEnd - textIter;
+ // CountedBuffer takes a wchar_t* even though it doesn't change the buffer.
+ CountedBuffer textBuf(const_cast<wchar_t*>(textIter),
+ sizeof(wchar_t) * len);
+ InOutCountedBuffer breakBeforeBuf(breakBeforeIter, len);
+ CrossCallReturn answer = {0};
+ ResultCode code = CrossCall(ipc, IpcTag::GETCOMPLEXLINEBREAKS, textBuf, len,
+ breakBeforeBuf, &answer);
+ if (SBOX_ALL_OK != code) {
+ return code;
+ }
+
+ if (answer.win32_result) {
+ ::SetLastError(answer.win32_result);
+ return SBOX_ERROR_GENERIC;
+ }
+
+ *breakBeforeIter = chunk_start_reset;
+
+ if (chunkEnd == textIterEnd) {
+ break;
+ }
+
+ // We couldn't process all of the text in one go, so back up by 32 chars and
+ // look for a break, then continue from that position. We back up 32 chars
+ // to try to avoid any false breaks at the end of the buffer caused by us
+ // splitting it into chunks.
+ uint8_t* processedToEnd = breakBeforeIter + len;
+ breakBeforeIter = processedToEnd - kBreakSearchRange;
+ while (!*breakBeforeIter) {
+ if (++breakBeforeIter == processedToEnd) {
+ // We haven't found a break in the search range, so go back to the start
+ // of our search range to try and ensure we don't get any false breaks
+ // at the start of the new chunk.
+ breakBeforeIter = processedToEnd - kBreakSearchRange;
+ // Make sure we don't split a surrogate pair.
+ if (IS_LOW_SURROGATE(
+ *(aText + (breakBeforeIter - aBreakBefore)))) {
+ ++breakBeforeIter;
+ }
+ break;
+ }
+ }
+ } while (true);
+
+ return SBOX_ALL_OK;
+}
+
+} // namespace sandbox