2015-01-16 02:40:39 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
|
|
/* 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 {
|
|
|
|
|
2016-12-28 04:47:19 +03:00
|
|
|
bool
|
|
|
|
TruncateComments(const nsAString& src, nsAString* const out)
|
2015-01-16 02:40:39 +03:00
|
|
|
{
|
2016-12-28 04:47:19 +03:00
|
|
|
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;
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
2016-12-28 04:47:19 +03:00
|
|
|
};
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-12-28 04:47:19 +03:00
|
|
|
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;
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
2016-12-28 04:47:19 +03:00
|
|
|
*out_foundId = needleCount;
|
|
|
|
return foundItr;
|
|
|
|
};
|
|
|
|
|
|
|
|
////
|
|
|
|
|
|
|
|
const nsString commentBeginnings[] = { NS_LITERAL_STRING("//"),
|
|
|
|
NS_LITERAL_STRING("/*"),
|
2017-01-04 03:12:06 +03:00
|
|
|
nsString() }; // Final empty string for "found
|
|
|
|
// nothing".
|
2016-12-28 04:47:19 +03:00
|
|
|
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) );
|
2017-01-04 03:12:06 +03:00
|
|
|
fnEmitUntil(srcItr + commentBeginnings[foundId].Length()); // Final empty string
|
|
|
|
// allows us to skip
|
|
|
|
// forward here
|
|
|
|
// unconditionally.
|
2016-12-28 04:47:19 +03:00
|
|
|
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;
|
2015-01-16 02:40:39 +03:00
|
|
|
break;
|
|
|
|
}
|
2016-12-28 04:47:19 +03:00
|
|
|
break;
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-12-28 04:47:19 +03:00
|
|
|
case 1: // block comment
|
|
|
|
while (true) {
|
|
|
|
size_t endId;
|
|
|
|
srcItr = fnFindSoonestOf(blockCommentEndings, 2, &endId);
|
|
|
|
fnEmitUntil(srcItr + blockCommentEndings[endId].Length());
|
|
|
|
if (endId == 0)
|
|
|
|
continue;
|
2015-01-16 02:40:39 +03:00
|
|
|
break;
|
|
|
|
}
|
2016-12-28 04:47:19 +03:00
|
|
|
break;
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-12-28 04:47:19 +03:00
|
|
|
default: // not found
|
2015-01-16 02:40:39 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-28 04:47:19 +03:00
|
|
|
MOZ_ASSERT((dstBegin+1) - dstBegin == 1);
|
|
|
|
const uint32_t dstCharLen = dstItr - dstBegin;
|
|
|
|
if (!out->Assign(dstBegin, dstCharLen, mozilla::fallible))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
|
2016-12-30 05:48:04 +03:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////
|
|
|
|
|
2015-01-16 02:40:39 +03:00
|
|
|
bool
|
2016-12-30 05:48:04 +03:00
|
|
|
ValidateGLSLPreprocString(WebGLContext* webgl, const char* funcName,
|
|
|
|
const nsAString& string)
|
2015-01-16 02:40:39 +03:00
|
|
|
{
|
|
|
|
for (size_t i = 0; i < string.Length(); ++i) {
|
2016-12-30 05:48:04 +03:00
|
|
|
const auto& cur = string[i];
|
2017-01-03 13:05:43 +03:00
|
|
|
|
2016-12-30 05:48:04 +03:00
|
|
|
if (!IsValidGLSLPreprocChar(cur)) {
|
2017-01-03 13:05:43 +03:00
|
|
|
webgl->ErrorInvalidValue("%s: String contains the illegal character 0x%x.",
|
|
|
|
funcName, cur);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cur == '\\' && !webgl->IsWebGL2()) {
|
|
|
|
// Todo: Backslash is technically still invalid in WebGLSL 1 under even under
|
|
|
|
// WebGL 2.
|
|
|
|
webgl->ErrorInvalidValue("%s: Backslash is not valid in WebGL 1.", funcName);
|
|
|
|
return false;
|
2015-01-16 02:40:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl, const char* funcName)
|
|
|
|
{
|
|
|
|
if (name.IsEmpty())
|
|
|
|
return false;
|
|
|
|
|
2016-01-29 09:44:08 +03:00
|
|
|
const uint32_t maxSize = webgl->IsWebGL2() ? 1024 : 256;
|
2015-01-16 02:40:39 +03:00
|
|
|
if (name.Length() > maxSize) {
|
2016-12-30 05:48:04 +03:00
|
|
|
webgl->ErrorInvalidValue("%s: Identifier is %u characters long, exceeds the"
|
|
|
|
" maximum allowed length of %u characters.",
|
2015-01-16 02:40:39 +03:00
|
|
|
funcName, name.Length(), maxSize);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-12-30 05:48:04 +03:00
|
|
|
for (size_t i = 0; i < name.Length(); ++i) {
|
|
|
|
const auto& cur = name[i];
|
|
|
|
if (!IsValidGLSLChar(cur)) {
|
|
|
|
webgl->ErrorInvalidValue("%s: String contains the illegal character 0x%x'.",
|
|
|
|
funcName, cur);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2015-01-16 02:40:39 +03:00
|
|
|
|
|
|
|
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("%s: String contains a reserved GLSL prefix.",
|
|
|
|
funcName);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace mozilla
|