Line data Source code
1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 "WebGLContext.h"
9 :
10 : namespace mozilla {
11 :
12 : bool
13 0 : TruncateComments(const nsAString& src, nsAString* const out)
14 : {
15 0 : const size_t dstByteCount = src.Length() * sizeof(src[0]);
16 0 : const UniqueBuffer dst(malloc(dstByteCount));
17 0 : if (!dst)
18 0 : return false;
19 :
20 0 : auto srcItr = src.BeginReading();
21 0 : const auto srcEnd = src.EndReading();
22 0 : const auto dstBegin = (decltype(src[0])*)dst.get();
23 0 : auto dstItr = dstBegin;
24 :
25 0 : const auto fnEmitUntil = [&](const decltype(srcItr)& nextSrcItr) {
26 0 : while (srcItr != nextSrcItr) {
27 0 : *dstItr = *srcItr;
28 0 : ++srcItr;
29 0 : ++dstItr;
30 : }
31 0 : };
32 :
33 : const auto fnFindSoonestOf = [&](const nsString* needles, size_t needleCount,
34 0 : size_t* const out_foundId)
35 : {
36 0 : auto foundItr = srcItr;
37 0 : while (foundItr != srcEnd) {
38 0 : const auto haystack = Substring(foundItr, srcEnd);
39 0 : for (size_t i = 0; i < needleCount; i++) {
40 0 : if (StringBeginsWith(haystack, needles[i])) {
41 0 : *out_foundId = i;
42 0 : return foundItr;
43 : }
44 : }
45 0 : ++foundItr;
46 : }
47 0 : *out_foundId = needleCount;
48 0 : return foundItr;
49 0 : };
50 :
51 : ////
52 :
53 0 : const nsString commentBeginnings[] = { NS_LITERAL_STRING("//"),
54 0 : NS_LITERAL_STRING("/*"),
55 0 : nsString() }; // Final empty string for "found
56 : // nothing".
57 0 : const nsString lineCommentEndings[] = { NS_LITERAL_STRING("\\\n"),
58 0 : NS_LITERAL_STRING("\n"),
59 0 : nsString() };
60 0 : const nsString blockCommentEndings[] = { NS_LITERAL_STRING("\n"),
61 0 : NS_LITERAL_STRING("*/"),
62 0 : nsString() };
63 :
64 0 : while (srcItr != srcEnd) {
65 : size_t foundId;
66 0 : fnEmitUntil( fnFindSoonestOf(commentBeginnings, 2, &foundId) );
67 0 : fnEmitUntil(srcItr + commentBeginnings[foundId].Length()); // Final empty string
68 : // allows us to skip
69 : // forward here
70 : // unconditionally.
71 0 : switch (foundId) {
72 : case 0: // line comment
73 : while (true) {
74 : size_t endId;
75 0 : srcItr = fnFindSoonestOf(lineCommentEndings, 2, &endId);
76 0 : fnEmitUntil(srcItr + lineCommentEndings[endId].Length());
77 0 : if (endId == 0)
78 0 : continue;
79 0 : break;
80 0 : }
81 0 : break;
82 :
83 : case 1: // block comment
84 : while (true) {
85 : size_t endId;
86 0 : srcItr = fnFindSoonestOf(blockCommentEndings, 2, &endId);
87 0 : fnEmitUntil(srcItr + blockCommentEndings[endId].Length());
88 0 : if (endId == 0)
89 0 : continue;
90 0 : break;
91 0 : }
92 0 : break;
93 :
94 : default: // not found
95 0 : break;
96 : }
97 : }
98 :
99 : MOZ_ASSERT((dstBegin+1) - dstBegin == 1);
100 0 : const uint32_t dstCharLen = dstItr - dstBegin;
101 0 : if (!out->Assign(dstBegin, dstCharLen, mozilla::fallible))
102 0 : return false;
103 :
104 0 : return true;
105 : }
106 :
107 : ////////////////////////////////////////////////////////////////////////////////
108 :
109 : static bool
110 0 : IsValidGLSLChar(char16_t c)
111 : {
112 0 : if (('a' <= c && c <= 'z') ||
113 0 : ('A' <= c && c <= 'Z') ||
114 0 : ('0' <= c && c <= '9'))
115 : {
116 0 : return true;
117 : }
118 :
119 0 : switch (c) {
120 : case ' ':
121 : case '\t':
122 : case '\v':
123 : case '\f':
124 : case '\r':
125 : case '\n':
126 : case '_':
127 : case '.':
128 : case '+':
129 : case '-':
130 : case '/':
131 : case '*':
132 : case '%':
133 : case '<':
134 : case '>':
135 : case '[':
136 : case ']':
137 : case '(':
138 : case ')':
139 : case '{':
140 : case '}':
141 : case '^':
142 : case '|':
143 : case '&':
144 : case '~':
145 : case '=':
146 : case '!':
147 : case ':':
148 : case ';':
149 : case ',':
150 : case '?':
151 0 : return true;
152 :
153 : default:
154 0 : return false;
155 : }
156 : }
157 :
158 : static bool
159 0 : IsValidGLSLPreprocChar(char16_t c)
160 : {
161 0 : if (IsValidGLSLChar(c))
162 0 : return true;
163 :
164 0 : switch (c) {
165 : case '\\':
166 : case '#':
167 0 : return true;
168 :
169 : default:
170 0 : return false;
171 : }
172 : }
173 :
174 : ////
175 :
176 : bool
177 0 : ValidateGLSLPreprocString(WebGLContext* webgl, const char* funcName,
178 : const nsAString& string)
179 : {
180 0 : for (size_t i = 0; i < string.Length(); ++i) {
181 0 : const auto& cur = string[i];
182 :
183 0 : if (!IsValidGLSLPreprocChar(cur)) {
184 0 : webgl->ErrorInvalidValue("%s: String contains the illegal character 0x%x.",
185 0 : funcName, cur);
186 0 : return false;
187 : }
188 :
189 0 : if (cur == '\\' && !webgl->IsWebGL2()) {
190 : // Todo: Backslash is technically still invalid in WebGLSL 1 under even under
191 : // WebGL 2.
192 0 : webgl->ErrorInvalidValue("%s: Backslash is not valid in WebGL 1.", funcName);
193 0 : return false;
194 : }
195 : }
196 :
197 0 : return true;
198 : }
199 :
200 : bool
201 0 : ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl, const char* funcName)
202 : {
203 0 : if (name.IsEmpty())
204 0 : return false;
205 :
206 0 : const uint32_t maxSize = webgl->IsWebGL2() ? 1024 : 256;
207 0 : if (name.Length() > maxSize) {
208 0 : webgl->ErrorInvalidValue("%s: Identifier is %u characters long, exceeds the"
209 : " maximum allowed length of %u characters.",
210 0 : funcName, name.Length(), maxSize);
211 0 : return false;
212 : }
213 :
214 0 : for (size_t i = 0; i < name.Length(); ++i) {
215 0 : const auto& cur = name[i];
216 0 : if (!IsValidGLSLChar(cur)) {
217 0 : webgl->ErrorInvalidValue("%s: String contains the illegal character 0x%x'.",
218 0 : funcName, cur);
219 0 : return false;
220 : }
221 : }
222 :
223 0 : nsString prefix1 = NS_LITERAL_STRING("webgl_");
224 0 : nsString prefix2 = NS_LITERAL_STRING("_webgl_");
225 :
226 0 : if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
227 0 : Substring(name, 0, prefix2.Length()).Equals(prefix2))
228 : {
229 : webgl->ErrorInvalidOperation("%s: String contains a reserved GLSL prefix.",
230 0 : funcName);
231 0 : return false;
232 : }
233 :
234 0 : return true;
235 : }
236 :
237 : } // namespace mozilla
|