cutelyst  3.7.0
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, const QStringList &headers, const QString &title)
34 {
35  QByteArray buffer;
36  QVector<int> columnsSize;
37 
38  if (!headers.isEmpty()) {
39  for (const QString &header : headers) {
40  columnsSize.push_back(header.size());
41  }
42  } else {
43  for (const QStringList &rows : table) {
44  if (columnsSize.empty()) {
45  for (const QString &row : rows) {
46  columnsSize.push_back(row.size());
47  }
48  } else if (rows.size() != columnsSize.size()) {
49  qFatal("Incomplete table");
50  }
51  }
52  }
53 
54  for (const QStringList &row : table) {
55  if (row.size() > columnsSize.size()) {
56  qFatal("Incomplete table");
57  break;
58  }
59 
60  for (int i = 0; i < row.size(); ++i) {
61  columnsSize[i] = qMax(columnsSize[i], row[i].size());
62  }
63  }
64 
65  // printing
66 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
67  QTextStream out(&buffer, QTextStream::WriteOnly);
68 #else
69  QTextStream out(&buffer, QIODevice::WriteOnly);
70 #endif
71 
72  out.setFieldAlignment(QTextStream::AlignLeft);
73  QByteArray div = buildTableDivision(columnsSize);
74 
75  if (!title.isEmpty()) {
76  out << title << '\n';
77  }
78 
79  // Top line
80  out << div << '\n';
81 
82  if (!headers.isEmpty()) {
83  // header titles
84  for (int i = 0; i < headers.size(); ++i) {
85  out << "| ";
86 
87  out.setFieldWidth(columnsSize[i]);
88  out << headers[i];
89 
90  out.setFieldWidth(0);
91  out << ' ';
92  }
93  out << '|' << '\n';
94 
95  // header bottom line
96  out << div << '\n';
97  }
98 
99  for (const QStringList &row : table) {
100  // content table
101  for (int i = 0; i < row.size(); ++i) {
102  out << "| ";
103 
104  out.setFieldWidth(columnsSize[i]);
105  out << row[i];
106 
107  out.setFieldWidth(0);
108  out << ' ';
109  }
110  out << '|' << '\n';
111  }
112 
113  // table bottom line
114  out << div;
115 
116  return buffer;
117 }
118 
119 QString Utils::decodePercentEncoding(QString *s)
120 {
121  if (s->isEmpty()) {
122  return *s;
123  }
124 
125  QByteArray ba = s->toLatin1();
126 
127  char *data = ba.data();
128  const char *inputPtr = data;
129 
130  const int len = ba.count();
131  bool skipUtf8 = true;
132  int outlen = 0;
133  for (int i = 0 ; i < len; ++i, ++outlen) {
134  const char c = inputPtr[i];
135  if (c == '%' && i + 2 < len) {
136  int a = inputPtr[++i];
137  int b = inputPtr[++i];
138 
139  if (a >= '0' && a <= '9') a -= '0';
140  else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
141  else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;
142 
143  if (b >= '0' && b <= '9') b -= '0';
144  else if (b >= 'a' && b <= 'f') b = b - 'a' + 10;
145  else if (b >= 'A' && b <= 'F') b = b - 'A' + 10;
146 
147  *data++ = (char)((a << 4) | b);
148  skipUtf8 = false;
149  } else if (c == '+') {
150  *data++ = ' ';
151  } else {
152  *data++ = c;
153  }
154  }
155 
156  if (skipUtf8) {
157  return *s;
158  }
159 
160  return QString::fromUtf8(ba.data(), outlen);
161 }
162 
163 ParamsMultiMap Utils::decodePercentEncoding(char *data, int len)
164 {
165  ParamsMultiMap ret;
166  if (len <= 0) {
167  return ret;
168  }
169 
170  QString key;
171 
172  const char *inputPtr = data;
173 
174  bool hasKey = false;
175  bool skipUtf8 = true;
176  char *from = data;
177  int outlen = 0;
178 
179  auto processKeyPair = [&] {
180  if (hasKey) {
181  if ((data - from) == 0) {
182  if (!key.isEmpty()) {
183  ret.insertMulti(key, {});
184  }
185  } else {
186  ret.insertMulti(key, skipUtf8 ? QString::fromLatin1(from, data - from) : QString::fromUtf8(from, data - from));
187  }
188  } else if ((data - from) > 0) {
189  ret.insertMulti(skipUtf8 ? QString::fromLatin1(from, data - from) : QString::fromUtf8(from, data - from), {});
190  }
191  };
192 
193  for (int i = 0; i < len; ++i, ++outlen) {
194  const char c = inputPtr[i];
195  if (c == '%' && i + 2 < len) {
196  int a = inputPtr[++i];
197  int b = inputPtr[++i];
198 
199  if (a >= '0' && a <= '9') a -= '0';
200  else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
201  else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;
202 
203  if (b >= '0' && b <= '9') b -= '0';
204  else if (b >= 'a' && b <= 'f') b = b - 'a' + 10;
205  else if (b >= 'A' && b <= 'F') b = b - 'A' + 10;
206 
207  *data++ = (char)((a << 4) | b);
208  skipUtf8 = false;
209  } else if (c == '+') {
210  *data++ = ' ';
211  } else if (c == '=') {
212  key = skipUtf8 ? QString::fromLatin1(from, data - from) : QString::fromUtf8(from, data - from);
213  from = data;
214  hasKey = true;
215  skipUtf8 = true; // reset
216  } else if (c == '&') {
217  processKeyPair();
218  key.clear();
219  hasKey = false;
220  from = data;
221  skipUtf8 = true; // reset
222  } else {
223  *data++ = c;
224  }
225  }
226 
227  processKeyPair();
228 
229  return ret;
230 }
231 
232 QString Utils::decodePercentEncoding(QByteArray *ba)
233 {
234  if (ba->isEmpty()) {
235  return {};
236  }
237 
238  char *data = ba->data();
239  const char *inputPtr = data;
240 
241  int len = ba->count();
242  bool skipUtf8 = true;
243  int outlen = 0;
244  for (int i = 0; i < len; ++i, ++outlen) {
245  const char c = inputPtr[i];
246  if (c == '%' && i + 2 < len) {
247  int a = inputPtr[++i];
248  int b = inputPtr[++i];
249 
250  if (a >= '0' && a <= '9') a -= '0';
251  else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
252  else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;
253 
254  if (b >= '0' && b <= '9') b -= '0';
255  else if (b >= 'a' && b <= 'f') b = b - 'a' + 10;
256  else if (b >= 'A' && b <= 'F') b = b - 'A' + 10;
257 
258  *data++ = (char)((a << 4) | b);
259  skipUtf8 = false;
260  } else if (c == '+') {
261  *data++ = ' ';
262  } else {
263  *data++ = c;
264  }
265  }
266 
267  if (skipUtf8) {
268  return QString::fromLatin1(ba->data(), outlen);
269  } else {
270  return QString::fromUtf8(ba->data(), outlen);
271  }
272 }
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:8
QMultiMap< QString, QString > ParamsMultiMap