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 }
QByteArray & fill(char ch, int size)
bool isEmpty() const const
QMap::iterator insertMulti(const Key &key, const T &value)
void clear()
QString fromUtf8(const char *str, int size)
bool isEmpty() const const
bool isEmpty() const const
int count(char ch) const const
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7
QByteArray toLatin1() const const
char * data()
void push_back(const T &value)
QString fromLatin1(const char *str, int size)
int size() const const
bool empty() const const