cutelyst 3.9.1
A C++ Web Framework built on top of Qt, using the simple approach of Catalyst (Perl) framework.
utils.cpp
1/*
2 * SPDX-FileCopyrightText: (C) 2015-2022 Daniel Nicoletti <dantti12@gmail.com>
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5#include "utils.h"
6
7#include <QTextStream>
8#include <QVector>
9
10using namespace Cutelyst;
11
12QByteArray buildTableDivision(const QVector<int> &columnsSize)
13{
14 QByteArray buffer;
15#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
16 QTextStream out(&buffer, QTextStream::WriteOnly);
17#else
19#endif
20 for (int i = 0; i < columnsSize.size(); ++i) {
21 if (i) {
22 out << '+';
23 } else {
24 out << '.';
25 }
26 out << QByteArray().fill('-', columnsSize[i] + 2).data();
27 }
28 out << '.';
29
30 return buffer;
31}
32
33QByteArray Utils::buildTable(const QVector<QStringList> &table,
34 const QStringList &headers,
35 const QString &title)
36{
37 QByteArray buffer;
38 QVector<int> columnsSize;
39
40 if (!headers.isEmpty()) {
41 for (const QString &header : headers) {
42 columnsSize.push_back(header.size());
43 }
44 } else {
45 for (const QStringList &rows : table) {
46 if (columnsSize.empty()) {
47 for (const QString &row : rows) {
48 columnsSize.push_back(row.size());
49 }
50 } else if (rows.size() != columnsSize.size()) {
51 qFatal("Incomplete table");
52 }
53 }
54 }
55
56 for (const QStringList &row : table) {
57 if (row.size() > columnsSize.size()) {
58 qFatal("Incomplete table");
59 break;
60 }
61
62 for (int i = 0; i < row.size(); ++i) {
63 columnsSize[i] = qMax(columnsSize[i], row[i].size());
64 }
65 }
66
67 // printing
68#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
69 QTextStream out(&buffer, QTextStream::WriteOnly);
70#else
72#endif
73
74 out.setFieldAlignment(QTextStream::AlignLeft);
75 QByteArray div = buildTableDivision(columnsSize);
76
77 if (!title.isEmpty()) {
78 out << title << '\n';
79 }
80
81 // Top line
82 out << div << '\n';
83
84 if (!headers.isEmpty()) {
85 // header titles
86 for (int i = 0; i < headers.size(); ++i) {
87 out << "| ";
88
89 out.setFieldWidth(columnsSize[i]);
90 out << headers[i];
91
92 out.setFieldWidth(0);
93 out << ' ';
94 }
95 out << '|' << '\n';
96
97 // header bottom line
98 out << div << '\n';
99 }
100
101 for (const QStringList &row : table) {
102 // content table
103 for (int i = 0; i < row.size(); ++i) {
104 out << "| ";
105
106 out.setFieldWidth(columnsSize[i]);
107 out << row[i];
108
109 out.setFieldWidth(0);
110 out << ' ';
111 }
112 out << '|' << '\n';
113 }
114
115 // table bottom line
116 out << div;
117
118 return buffer;
119}
120
121QString Utils::decodePercentEncoding(QString *s)
122{
123 if (s->isEmpty()) {
124 return *s;
125 }
126
127 QByteArray ba = s->toLatin1();
128
129 char *data = ba.data();
130 const char *inputPtr = data;
131
132 const int len = ba.count();
133 bool skipUtf8 = true;
134 int outlen = 0;
135 for (int i = 0; i < len; ++i, ++outlen) {
136 const char c = inputPtr[i];
137 if (c == '%' && i + 2 < len) {
138 int a = inputPtr[++i];
139 int b = inputPtr[++i];
140
141 if (a >= '0' && a <= '9')
142 a -= '0';
143 else if (a >= 'a' && a <= 'f')
144 a = a - 'a' + 10;
145 else if (a >= 'A' && a <= 'F')
146 a = a - 'A' + 10;
147
148 if (b >= '0' && b <= '9')
149 b -= '0';
150 else if (b >= 'a' && b <= 'f')
151 b = b - 'a' + 10;
152 else if (b >= 'A' && b <= 'F')
153 b = b - 'A' + 10;
154
155 *data++ = (char) ((a << 4) | b);
156 skipUtf8 = false;
157 } else if (c == '+') {
158 *data++ = ' ';
159 } else {
160 *data++ = c;
161 }
162 }
163
164 if (skipUtf8) {
165 return *s;
166 }
167
168 return QString::fromUtf8(ba.data(), outlen);
169}
170
171ParamsMultiMap Utils::decodePercentEncoding(char *data, int len)
172{
173 ParamsMultiMap ret;
174 if (len <= 0) {
175 return ret;
176 }
177
178 QString key;
179
180 const char *inputPtr = data;
181
182 bool hasKey = false;
183 bool skipUtf8 = true;
184 char *from = data;
185 int outlen = 0;
186
187 auto processKeyPair = [&] {
188 if (hasKey) {
189 if ((data - from) == 0) {
190 if (!key.isEmpty()) {
191 ret.insertMulti(key, {});
192 }
193 } else {
194 ret.insertMulti(key,
195 skipUtf8 ? QString::fromLatin1(from, data - from)
196 : QString::fromUtf8(from, data - from));
197 }
198 } else if ((data - from) > 0) {
199 ret.insertMulti(skipUtf8 ? QString::fromLatin1(from, data - from)
200 : QString::fromUtf8(from, data - from),
201 {});
202 }
203 };
204
205 for (int i = 0; i < len; ++i, ++outlen) {
206 const char c = inputPtr[i];
207 if (c == '%' && i + 2 < len) {
208 int a = inputPtr[++i];
209 int b = inputPtr[++i];
210
211 if (a >= '0' && a <= '9')
212 a -= '0';
213 else if (a >= 'a' && a <= 'f')
214 a = a - 'a' + 10;
215 else if (a >= 'A' && a <= 'F')
216 a = a - 'A' + 10;
217
218 if (b >= '0' && b <= '9')
219 b -= '0';
220 else if (b >= 'a' && b <= 'f')
221 b = b - 'a' + 10;
222 else if (b >= 'A' && b <= 'F')
223 b = b - 'A' + 10;
224
225 *data++ = (char) ((a << 4) | b);
226 skipUtf8 = false;
227 } else if (c == '+') {
228 *data++ = ' ';
229 } else if (c == '=') {
230 key = skipUtf8 ? QString::fromLatin1(from, data - from)
231 : QString::fromUtf8(from, data - from);
232 from = data;
233 hasKey = true;
234 skipUtf8 = true; // reset
235 } else if (c == '&') {
236 processKeyPair();
237 key.clear();
238 hasKey = false;
239 from = data;
240 skipUtf8 = true; // reset
241 } else {
242 *data++ = c;
243 }
244 }
245
246 processKeyPair();
247
248 return ret;
249}
250
251QString Utils::decodePercentEncoding(QByteArray *ba)
252{
253 if (ba->isEmpty()) {
254 return {};
255 }
256
257 char *data = ba->data();
258 const char *inputPtr = data;
259
260 int len = ba->count();
261 bool skipUtf8 = true;
262 int outlen = 0;
263 for (int i = 0; i < len; ++i, ++outlen) {
264 const char c = inputPtr[i];
265 if (c == '%' && i + 2 < len) {
266 int a = inputPtr[++i];
267 int b = inputPtr[++i];
268
269 if (a >= '0' && a <= '9')
270 a -= '0';
271 else if (a >= 'a' && a <= 'f')
272 a = a - 'a' + 10;
273 else if (a >= 'A' && a <= 'F')
274 a = a - 'A' + 10;
275
276 if (b >= '0' && b <= '9')
277 b -= '0';
278 else if (b >= 'a' && b <= 'f')
279 b = b - 'a' + 10;
280 else if (b >= 'A' && b <= 'F')
281 b = b - 'A' + 10;
282
283 *data++ = (char) ((a << 4) | b);
284 skipUtf8 = false;
285 } else if (c == '+') {
286 *data++ = ' ';
287 } else {
288 *data++ = c;
289 }
290 }
291
292 if (skipUtf8) {
293 return QString::fromLatin1(ba->data(), outlen);
294 } else {
295 return QString::fromUtf8(ba->data(), outlen);
296 }
297}
The Cutelyst namespace holds all public Cutelyst API.
Definition Mainpage.dox:8
QMultiMap< QString, QString > ParamsMultiMap
int count(char ch) const const
char * data()
QByteArray & fill(char ch, int size)
bool isEmpty() const const
bool isEmpty() const const
void clear()
QString fromLatin1(const char *str, int size)
QString fromUtf8(const char *str, int size)
bool isEmpty() const const
QByteArray toLatin1() const const
bool empty() const const
void push_back(const T &value)
int size() const const