зеркало из https://github.com/mozilla/gecko-dev.git
193 строки
4.7 KiB
C++
193 строки
4.7 KiB
C++
/* -*- 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
|