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
18 QTextStream out(&buffer, QIODevice::WriteOnly);
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
71 QTextStream out(&buffer, QIODevice::WriteOnly);
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
186 auto processKeyPair = [&] {
187 if (hasKey) {
188 if ((data - from) == 0) {
189 if (!key.isEmpty()) {
190 ret.insertMulti(key, {});
191 }
192 } else {
193 ret.insertMulti(key,
194 skipUtf8 ? QString::fromLatin1(from, data - from)
195 : QString::fromUtf8(from, data - from));
196 }
197 } else if ((data - from) > 0) {
198 ret.insertMulti(skipUtf8 ? QString::fromLatin1(from, data - from)
199 : QString::fromUtf8(from, data - from),
200 {});
201 }
202 };
203
204 for (int i = 0; i < len; ++i) {
205 const char c = inputPtr[i];
206 if (c == '%' && i + 2 < len) {
207 int a = inputPtr[++i];
208 int b = inputPtr[++i];
209
210 if (a >= '0' && a <= '9')
211 a -= '0';
212 else if (a >= 'a' && a <= 'f')
213 a = a - 'a' + 10;
214 else if (a >= 'A' && a <= 'F')
215 a = a - 'A' + 10;
216
217 if (b >= '0' && b <= '9')
218 b -= '0';
219 else if (b >= 'a' && b <= 'f')
220 b = b - 'a' + 10;
221 else if (b >= 'A' && b <= 'F')
222 b = b - 'A' + 10;
223
224 *data++ = (char) ((a << 4) | b);
225 skipUtf8 = false;
226 } else if (c == '+') {
227 *data++ = ' ';
228 } else if (c == '=') {
229 key = skipUtf8 ? QString::fromLatin1(from, data - from)
230 : QString::fromUtf8(from, data - from);
231 from = data;
232 hasKey = true;
233 skipUtf8 = true; // reset
234 } else if (c == '&') {
235 processKeyPair();
236 key.clear();
237 hasKey = false;
238 from = data;
239 skipUtf8 = true; // reset
240 } else {
241 *data++ = c;
242 }
243 }
244
245 processKeyPair();
246
247 return ret;
248}
249
250QString Utils::decodePercentEncoding(QByteArray *ba)
251{
252 if (ba->isEmpty()) {
253 return {};
254 }
255
256 char *data = ba->data();
257 const char *inputPtr = data;
258
259 int len = ba->count();
260 bool skipUtf8 = true;
261 int outlen = 0;
262 for (int i = 0; i < len; ++i, ++outlen) {
263 const char c = inputPtr[i];
264 if (c == '%' && i + 2 < len) {
265 int a = inputPtr[++i];
266 int b = inputPtr[++i];
267
268 if (a >= '0' && a <= '9')
269 a -= '0';
270 else if (a >= 'a' && a <= 'f')
271 a = a - 'a' + 10;
272 else if (a >= 'A' && a <= 'F')
273 a = a - 'A' + 10;
274
275 if (b >= '0' && b <= '9')
276 b -= '0';
277 else if (b >= 'a' && b <= 'f')
278 b = b - 'a' + 10;
279 else if (b >= 'A' && b <= 'F')
280 b = b - 'A' + 10;
281
282 *data++ = (char) ((a << 4) | b);
283 skipUtf8 = false;
284 } else if (c == '+') {
285 *data++ = ' ';
286 } else {
287 *data++ = c;
288 }
289 }
290
291 if (skipUtf8) {
292 return QString::fromLatin1(ba->data(), outlen);
293 } else {
294 return QString::fromUtf8(ba->data(), outlen);
295 }
296}
The Cutelyst namespace holds all public Cutelyst API.
Definition Mainpage.dox:8
QMultiMap< QString, QString > ParamsMultiMap