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 
10 using namespace Cutelyst;
11 
12 QByteArray 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 
33 QByteArray 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 
121 QString 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 
171 ParamsMultiMap 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 
251 QString 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 }
void push_back(parameter_type value)
QByteArray & fill(char ch, qsizetype size)
bool isEmpty() const const
QString fromUtf8(QByteArrayView str)
qsizetype size() const const
void clear()
bool empty() const const
bool isEmpty() const const
bool isEmpty() const const
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
qsizetype count() const const
QString fromLatin1(QByteArrayView str)
QByteArray toLatin1() const const
iterator insertMulti(const Key &key, const T &value)
char * data()