1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "WebGLValidateStrings.h"
7
8 #include <regex>
9
10 #include "WebGLTypes.h"
11
12 namespace mozilla {
13
14 /* GLSL ES 3.00 p17:
15 - Comments are delimited by / * and * /, or by // and a newline.
16
17 - '//' style comments include the initial '//' marker and continue up to, but
18 not including, the terminating newline.
19
20 - '/ * ... * /' comments include both the start and end marker.
21
22 - The begin comment delimiters (/ * or //) are not recognized as comment
23 delimiters inside of a comment, hence comments cannot be nested.
24
25 - Comments are treated syntactically as a single space.
26 */
27
CommentsToSpaces(const std::string & src)28 std::string CommentsToSpaces(const std::string& src) {
29 constexpr auto flags =
30 std::regex::ECMAScript | std::regex::nosubs | std::regex::optimize;
31
32 static const auto RE_COMMENT_BEGIN = std::regex("/[*/]", flags);
33 static const auto RE_LINE_COMMENT_END = std::regex(R"([^\\]\n)", flags);
34 static const auto RE_BLOCK_COMMENT_END = std::regex(R"(\*/)", flags);
35
36 std::string ret;
37 ret.reserve(src.size());
38
39 // Replace all comments with block comments with the right number of newlines.
40 // Line positions may be off, but line numbers will be accurate, which is more
41 // important.
42
43 auto itr = src.begin();
44 const auto end = src.end();
45 std::smatch match;
46 while (std::regex_search(itr, end, match, RE_COMMENT_BEGIN)) {
47 MOZ_ASSERT(match.length() == 2);
48 const auto commentBegin = itr + match.position();
49 ret.append(itr, commentBegin);
50
51 itr = commentBegin + match.length();
52
53 const bool isBlockComment = (*(commentBegin + 1) == '*');
54 const auto* endRegex = &RE_LINE_COMMENT_END;
55 if (isBlockComment) {
56 endRegex = &RE_BLOCK_COMMENT_END;
57 }
58
59 if (isBlockComment) {
60 ret += "/*";
61 }
62
63 auto commentEnd = end;
64 if (!isBlockComment && itr != end && *itr == '\n') {
65 commentEnd = itr + 1; // '//\n'
66 } else if (std::regex_search(itr, end, match, *endRegex)) {
67 commentEnd = itr + match.position() + match.length();
68 } else {
69 return ret;
70 }
71
72 for (; itr != commentEnd; ++itr) {
73 const auto cur = *itr;
74 if (cur == '\n') {
75 ret += cur;
76 }
77 }
78 if (isBlockComment) {
79 ret += "*/";
80 }
81 }
82
83 ret.append(itr, end);
84 return ret;
85 }
86
87 ////////////////////////////////////////////////////////////////////////////////
88
IsValidGLSLChar(const char c)89 static bool IsValidGLSLChar(const char c) {
90 if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
91 ('0' <= c && c <= '9')) {
92 return true;
93 }
94
95 switch (c) {
96 case ' ':
97 case '\t':
98 case '\v':
99 case '\f':
100 case '\r':
101 case '\n':
102 case '_':
103 case '.':
104 case '+':
105 case '-':
106 case '/':
107 case '*':
108 case '%':
109 case '<':
110 case '>':
111 case '[':
112 case ']':
113 case '(':
114 case ')':
115 case '{':
116 case '}':
117 case '^':
118 case '|':
119 case '&':
120 case '~':
121 case '=':
122 case '!':
123 case ':':
124 case ';':
125 case ',':
126 case '?':
127 return true;
128
129 default:
130 return false;
131 }
132 }
133
134 ////
135
CheckGLSLPreprocString(const bool webgl2,const std::string & string)136 Maybe<char> CheckGLSLPreprocString(const bool webgl2,
137 const std::string& string) {
138 for (const auto c : string) {
139 if (IsValidGLSLChar(c)) continue;
140 if (c == '#') continue;
141 if (c == '\\' && webgl2) continue;
142
143 return Some(c);
144 }
145 return {};
146 }
147
CheckGLSLVariableName(const bool webgl2,const std::string & name)148 Maybe<webgl::ErrorInfo> CheckGLSLVariableName(const bool webgl2,
149 const std::string& name) {
150 if (name.empty()) return {};
151
152 const uint32_t maxSize = webgl2 ? 1024 : 256;
153 if (name.size() > maxSize) {
154 const auto info = nsPrintfCString(
155 "Identifier is %zu characters long, exceeds the"
156 " maximum allowed length of %u characters.",
157 name.size(), maxSize);
158 return Some(webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, info.BeginReading()});
159 }
160
161 for (const auto cur : name) {
162 if (!IsValidGLSLChar(cur)) {
163 const auto info =
164 nsPrintfCString("String contains the illegal character 0x%x'.", cur);
165 return Some(
166 webgl::ErrorInfo{LOCAL_GL_INVALID_VALUE, info.BeginReading()});
167 }
168 }
169
170 if (name.find("webgl_") == 0 || name.find("_webgl_") == 0) {
171 return Some(webgl::ErrorInfo{
172 LOCAL_GL_INVALID_OPERATION,
173 "String matches reserved GLSL prefix pattern /_?webgl_/."});
174 }
175
176 return {};
177 }
178
179 } // namespace mozilla
180