forked from mirrors/gecko-dev
		
	 cf16621f3a
			
		
	
	
		cf16621f3a
		
	
	
	
	
		
			
			Convert u16->u8 on client. Crush to GLSL-charset and replace non-GLSL chars with boring-but-still-invalid '$'. Differential Revision: https://phabricator.services.mozilla.com/D125756
		
			
				
	
	
		
			192 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			192 lines
		
	
	
	
		
			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
 |