/* -*- 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 { 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 char* funcName, const nsAString& string) { for (size_t i = 0; i < string.Length(); ++i) { const auto& cur = string[i]; if (!IsValidGLSLPreprocChar(cur)) { 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; } } return true; } bool ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl, const char* funcName) { if (name.IsEmpty()) return false; const uint32_t maxSize = webgl->IsWebGL2() ? 1024 : 256; if (name.Length() > maxSize) { webgl->ErrorInvalidValue("%s: Identifier is %u characters long, exceeds the" " maximum allowed length of %u characters.", funcName, name.Length(), maxSize); return false; } 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; } } 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