зеркало из https://github.com/mozilla/gecko-dev.git
216 строки
5.8 KiB
C++
216 строки
5.8 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 "WebGLContext.h"
|
|
|
|
namespace mozilla {
|
|
|
|
bool TruncateComments(const nsAString& src, nsAString* const out) {
|
|
const size_t dstByteCount = src.Length() * sizeof(src[0]);
|
|
const UniqueBuffer dst(malloc(dstByteCount));
|
|
if (!dst) return false;
|
|
|
|
auto srcItr = src.BeginReading();
|
|
const auto srcEnd = src.EndReading();
|
|
const auto dstBegin = (decltype(src[0])*)dst.get();
|
|
auto dstItr = dstBegin;
|
|
|
|
const auto fnEmitUntil = [&](const decltype(srcItr)& nextSrcItr) {
|
|
while (srcItr != nextSrcItr) {
|
|
*dstItr = *srcItr;
|
|
++srcItr;
|
|
++dstItr;
|
|
}
|
|
};
|
|
|
|
const auto fnFindSoonestOf = [&](const nsString* needles, size_t needleCount,
|
|
size_t* const out_foundId) {
|
|
auto foundItr = srcItr;
|
|
while (foundItr != srcEnd) {
|
|
const auto haystack = Substring(foundItr, srcEnd);
|
|
for (size_t i = 0; i < needleCount; i++) {
|
|
if (StringBeginsWith(haystack, needles[i])) {
|
|
*out_foundId = i;
|
|
return foundItr;
|
|
}
|
|
}
|
|
++foundItr;
|
|
}
|
|
*out_foundId = needleCount;
|
|
return foundItr;
|
|
};
|
|
|
|
////
|
|
|
|
const nsString commentBeginnings[] = {NS_LITERAL_STRING("//"),
|
|
NS_LITERAL_STRING("/*"),
|
|
nsString()}; // Final empty string for
|
|
// "found nothing".
|
|
const nsString lineCommentEndings[] = {NS_LITERAL_STRING("\\\n"),
|
|
NS_LITERAL_STRING("\n"), nsString()};
|
|
const nsString blockCommentEndings[] = {NS_LITERAL_STRING("\n"),
|
|
NS_LITERAL_STRING("*/"), nsString()};
|
|
|
|
while (srcItr != srcEnd) {
|
|
size_t foundId;
|
|
fnEmitUntil(fnFindSoonestOf(commentBeginnings, 2, &foundId));
|
|
fnEmitUntil(srcItr +
|
|
commentBeginnings[foundId].Length()); // Final empty string
|
|
// allows us to skip
|
|
// forward here
|
|
// unconditionally.
|
|
switch (foundId) {
|
|
case 0: // line comment
|
|
while (true) {
|
|
size_t endId;
|
|
srcItr = fnFindSoonestOf(lineCommentEndings, 2, &endId);
|
|
fnEmitUntil(srcItr + lineCommentEndings[endId].Length());
|
|
if (endId == 0) continue;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 1: // block comment
|
|
while (true) {
|
|
size_t endId;
|
|
srcItr = fnFindSoonestOf(blockCommentEndings, 2, &endId);
|
|
fnEmitUntil(srcItr + blockCommentEndings[endId].Length());
|
|
if (endId == 0) continue;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default: // not found
|
|
break;
|
|
}
|
|
}
|
|
|
|
MOZ_ASSERT((dstBegin + 1) - dstBegin == 1);
|
|
const uint32_t dstCharLen = dstItr - dstBegin;
|
|
if (!out->Assign(dstBegin, dstCharLen, mozilla::fallible)) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static bool IsValidGLSLChar(char16_t 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 bool IsValidGLSLPreprocChar(char16_t c) {
|
|
if (IsValidGLSLChar(c)) return true;
|
|
|
|
switch (c) {
|
|
case '\\':
|
|
case '#':
|
|
return true;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
////
|
|
|
|
bool ValidateGLSLPreprocString(WebGLContext* webgl, const nsAString& string) {
|
|
for (size_t i = 0; i < string.Length(); ++i) {
|
|
const auto& cur = string[i];
|
|
|
|
if (!IsValidGLSLPreprocChar(cur)) {
|
|
webgl->ErrorInvalidValue("String contains the illegal character 0x%x.",
|
|
cur);
|
|
return false;
|
|
}
|
|
|
|
if (cur == '\\' && !webgl->IsWebGL2()) {
|
|
// Todo: Backslash is technically still invalid in WebGLSL 1 under even
|
|
// under WebGL 2.
|
|
webgl->ErrorInvalidValue("Backslash is not valid in WebGL 1.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl) {
|
|
if (name.IsEmpty()) return false;
|
|
|
|
const uint32_t maxSize = webgl->IsWebGL2() ? 1024 : 256;
|
|
if (name.Length() > maxSize) {
|
|
webgl->ErrorInvalidValue(
|
|
"Identifier is %u characters long, exceeds the"
|
|
" maximum allowed length of %u characters.",
|
|
name.Length(), maxSize);
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < name.Length(); ++i) {
|
|
const auto& cur = name[i];
|
|
if (!IsValidGLSLChar(cur)) {
|
|
webgl->ErrorInvalidValue("String contains the illegal character 0x%x'.",
|
|
cur);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
nsString prefix1 = NS_LITERAL_STRING("webgl_");
|
|
nsString prefix2 = NS_LITERAL_STRING("_webgl_");
|
|
|
|
if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
|
|
Substring(name, 0, prefix2.Length()).Equals(prefix2)) {
|
|
webgl->ErrorInvalidOperation("String contains a reserved GLSL prefix.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace mozilla
|