Revision control

Copy as Markdown

// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qshaderrewriter_p.h"
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace QShaderRewriter {
struct Tokenizer {
enum Token {
Token_Void,
Token_OpenBrace,
Token_CloseBrace,
Token_SemiColon,
Token_Identifier,
Token_Unspecified,
Token_EOF
};
static const char *NAMES[];
void initialize(const QByteArray &input);
Token next();
const char *pos;
const char *identifier;
};
const char *Tokenizer::NAMES[] = {
"Void",
"OpenBrace",
"CloseBrace",
"SemiColon",
"Identifier",
"Unspecified",
"EOF"
};
void Tokenizer::initialize(const QByteArray &input)
{
pos = input.constData();
identifier = pos;
}
Tokenizer::Token Tokenizer::next()
{
while (*pos != 0) {
char c = *pos++;
switch (c) {
case 0:
return Token_EOF;
case '/':
if (*pos == '/') {
// '//' comment
++pos;
while (*pos != 0 && *pos != '\n') ++pos;
if (*pos != 0) ++pos; // skip the newline
} else if (*pos == '*') {
// /* */ comment
++pos;
while (*pos != 0 && *pos != '*' && pos[1] != '/') ++pos;
if (*pos != 0) pos += 2;
}
break;
case '#': {
while (*pos != 0) {
if (*pos == '\n') {
++pos;
break;
} else if (*pos == '\\') {
++pos;
while (*pos != 0 && (*pos == ' ' || *pos == '\t'))
++pos;
if (*pos != 0 && (*pos == '\n' || (*pos == '\r' && pos[1] == '\n')))
pos+=2;
} else {
++pos;
}
}
break;
}
case ';': return Token_SemiColon;
case '{': return Token_OpenBrace;
case '}': return Token_CloseBrace;
case ' ':
case '\n':
case '\r': break;
case 'v': {
if (*pos == 'o' && pos[1] == 'i' && pos[2] == 'd') {
pos += 3;
return Token_Void;
}
Q_FALLTHROUGH();
}
default:
// Identifier...
if ((c >= 'a' && c <= 'z' ) || (c >= 'A' && c <= 'Z' ) || c == '_') {
identifier = pos - 1;
while (*pos != 0 && ((*pos >= 'a' && *pos <= 'z')
|| (*pos >= 'A' && *pos <= 'Z')
|| *pos == '_'
|| (*pos >= '0' && *pos <= '9'))) {
++pos;
}
return Token_Identifier;
} else {
return Token_Unspecified;
}
}
}
return Token_EOF;
}
void debugTokenizer(const QByteArray &input)
{
Tokenizer tok;
tok.initialize(input);
Tokenizer::Token t = tok.next();
while (t != Tokenizer::Token_EOF) {
if (t == Tokenizer::Token_Identifier)
qDebug() << Tokenizer::NAMES[t] << QByteArray::fromRawData(tok.identifier, tok.pos - tok.identifier);
else
qDebug() << Tokenizer::NAMES[t];
t = tok.next();
}
}
QByteArray addZAdjustment(const QByteArray &input, int vertexInputLocation)
{
Tokenizer tok;
tok.initialize(input);
Tokenizer::Token lt = tok.next();
Tokenizer::Token t = tok.next();
// First find "void main() { ... "
const char* voidPos = input.constData();
while (t != Tokenizer::Token_EOF) {
if (lt == Tokenizer::Token_Void && t == Tokenizer::Token_Identifier) {
if (qstrncmp("main", tok.identifier, 4) == 0)
break;
}
voidPos = tok.pos - 4;
lt = t;
t = tok.next();
}
QByteArray result;
result.reserve(1024);
result += QByteArray::fromRawData(input.constData(), voidPos - input.constData());
result += QByteArrayLiteral("layout(location = ");
result += QByteArray::number(vertexInputLocation);
result += QByteArrayLiteral(") in float _qt_order;\n");
// Find first brace '{'
while (t != Tokenizer::Token_EOF && t != Tokenizer::Token_OpenBrace) t = tok.next();
int braceDepth = 1;
t = tok.next();
// Find matching brace and insert our code there...
while (t != Tokenizer::Token_EOF) {
switch (t) {
case Tokenizer::Token_CloseBrace:
braceDepth--;
if (braceDepth == 0) {
result += QByteArray::fromRawData(voidPos, tok.pos - 1 - voidPos);
result += QByteArrayLiteral(" gl_Position.z = _qt_order * gl_Position.w;\n");
result += QByteArray(tok.pos - 1);
return result;
}
break;
case Tokenizer::Token_OpenBrace:
++braceDepth;
break;
default:
break;
}
t = tok.next();
}
return QByteArray();
}
} // namespace
QT_END_NAMESPACE