diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/canvas/WebGLValidateStrings.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/WebGLValidateStrings.cpp')
-rw-r--r-- | dom/canvas/WebGLValidateStrings.cpp | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/dom/canvas/WebGLValidateStrings.cpp b/dom/canvas/WebGLValidateStrings.cpp new file mode 100644 index 0000000000..43b814e835 --- /dev/null +++ b/dom/canvas/WebGLValidateStrings.cpp @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "WebGLValidateStrings.h" + +#include <regex> + +#include "WebGLTypes.h" +#include "nsPrintfCString.h" + +namespace mozilla { + +/* GLSL ES 3.00 p17: + - Comments are delimited by / * and * /, or by // and a newline. + + - '//' style comments include the initial '//' marker and continue up to, but +not including, the terminating newline. + + - '/ * ... * /' comments include both the start and end marker. + + - The begin comment delimiters (/ * or //) are not recognized as comment +delimiters inside of a comment, hence comments cannot be nested. + + - Comments are treated syntactically as a single space. +*/ + +std::string CommentsToSpaces(const std::string& src) { + constexpr auto flags = + std::regex::ECMAScript | std::regex::nosubs | std::regex::optimize; + + static const auto RE_COMMENT_BEGIN = std::regex("/[*/]", flags); + static const auto RE_LINE_COMMENT_END = std::regex(R"([^\\]\n)", flags); + static const auto RE_BLOCK_COMMENT_END = std::regex(R"(\*/)", flags); + + std::string ret; + ret.reserve(src.size()); + + // Replace all comments with block comments with the right number of newlines. + // Line positions may be off, but line numbers will be accurate, which is more + // important. + + auto itr = src.begin(); + const auto end = src.end(); + std::smatch match; + while (std::regex_search(itr, end, match, RE_COMMENT_BEGIN)) { + MOZ_ASSERT(match.length() == 2); + const auto commentBegin = itr + match.position(); + ret.append(itr, commentBegin); + + itr = commentBegin + match.length(); + + const bool isBlockComment = (*(commentBegin + 1) == '*'); + const auto* endRegex = &RE_LINE_COMMENT_END; + if (isBlockComment) { + endRegex = &RE_BLOCK_COMMENT_END; + } + + if (isBlockComment) { + ret += "/*"; + } + + auto commentEnd = end; + if (!isBlockComment && itr != end && *itr == '\n') { + commentEnd = itr + 1; // '//\n' + } else if (std::regex_search(itr, end, match, *endRegex)) { + commentEnd = itr + match.position() + match.length(); + } else { + return ret; + } + + for (; itr != commentEnd; ++itr) { + const auto cur = *itr; + if (cur == '\n') { + ret += cur; + } + } + if (isBlockComment) { + ret += "*/"; + } + } + + ret.append(itr, end); + return ret; +} + +//////////////////////////////////////////////////////////////////////////////// + +static constexpr bool IsValidGLSLChar(const char c) { + if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || + ('0' <= c && c <= '9')) { + return true; + } + + switch (c) { + case ' ': + case '\t': + case '\v': + case '\f': + case '\r': + case '\n': + case '_': + case '.': + case '+': + case '-': + case '/': + case '*': + case '%': + case '<': + case '>': + case '[': + case ']': + case '(': + case ')': + case '{': + case '}': + case '^': + case '|': + case '&': + case '~': + case '=': + case '!': + case ':': + case ';': + case ',': + case '?': + return true; + + default: + return false; + } +} + +static constexpr bool IsValidForPreprocOrGlsl(const char c) { + switch (c) { + case '#': + case '\\': + return true; + + default: + return IsValidGLSLChar(c); + } +} + +//// + +static constexpr char INVALID_GLSL_CHAR = '$'; + +std::string CrushGlslToAscii(const std::string& u8) { + static_assert(!IsValidForPreprocOrGlsl(INVALID_GLSL_CHAR)); + auto ascii = u8; + for (auto& c : ascii) { + if (MOZ_UNLIKELY(!IsValidForPreprocOrGlsl(c))) { + c = INVALID_GLSL_CHAR; + } + } + return ascii; +} + +Maybe<webgl::ErrorInfo> CheckGLSLVariableName(const bool webgl2, + const std::string& name) { + if (name.empty()) return {}; + + const uint32_t maxSize = webgl2 ? 1024 : 256; + if (name.size() > maxSize) { + const auto info = nsPrintfCString( + "Identifier is %zu characters long, exceeds the" + " maximum allowed length of %u characters.", + name.size(), maxSize); + return Some(webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, info.BeginReading()}); + } + + for (const auto cur : name) { + if (!IsValidGLSLChar(cur)) { + const auto info = + nsPrintfCString("String contains the illegal character 0x%x'.", cur); + return Some( + webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, info.BeginReading()}); + } + } + + if (name.find("webgl_") == 0 || name.find("_webgl_") == 0) { + return Some(webgl::ErrorInfo{ + LOCAL_GL_INVALID_OPERATION, + "String matches reserved GLSL prefix pattern /_?webgl_/."}); + } + + return {}; +} + +} // namespace mozilla |