Cutelyst  2.5.0
utils.cpp
1 /*
2  * Copyright (C) 2015-2018 Daniel Nicoletti <dantti12@gmail.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 #include "utils.h"
19 
20 #include <QTextStream>
21 #include <QVector>
22 
23 using namespace Cutelyst;
24 
25 QByteArray buildTableDivision(const QVector<int> &columnsSize)
26 {
27  QByteArray buffer;
28  QTextStream out(&buffer, QIODevice::WriteOnly);
29  for (int i = 0; i < columnsSize.size(); ++i) {
30  if (i) {
31  out << '+';
32  } else {
33  out << '.';
34  }
35  out << QByteArray().fill('-', columnsSize[i] + 2).data();
36  }
37  out << '.';
38 
39  return buffer;
40 }
41 
42 QByteArray Utils::buildTable(const QVector<QStringList> &table, const QStringList &headers, const QString &title)
43 {
44  QByteArray buffer;
45  QVector<int> columnsSize;
46 
47  if (!headers.isEmpty()) {
48  for (const QString &header : headers) {
49  columnsSize.push_back(header.size());
50  }
51  } else {
52  for (const QStringList &rows : table) {
53  if (columnsSize.empty()) {
54  for (const QString &row : rows) {
55  columnsSize.push_back(row.size());
56  }
57  } else if (rows.size() != columnsSize.size()) {
58  qFatal("Incomplete table");
59  }
60  }
61  }
62 
63  for (const QStringList &row : table) {
64  if (row.size() > columnsSize.size()) {
65  qFatal("Incomplete table");
66  break;
67  }
68 
69  for (int i = 0; i < row.size(); ++i) {
70  columnsSize[i] = qMax(columnsSize[i], row[i].size());
71  }
72  }
73 
74  // printing
75  QTextStream out(&buffer, QIODevice::WriteOnly);
76  out.setFieldAlignment(QTextStream::AlignLeft);
77  QByteArray div = buildTableDivision(columnsSize);
78 
79  if (!title.isEmpty()) {
80  out << title << endl;
81  }
82 
83  // Top line
84  out << div << endl;
85 
86  if (!headers.isEmpty()) {
87  // header titles
88  for (int i = 0; i < headers.size(); ++i) {
89  out << "| ";
90 
91  out.setFieldWidth(columnsSize[i]);
92  out << headers[i];
93 
94  out.setFieldWidth(0);
95  out << ' ';
96  }
97  out << '|' << endl;
98 
99  // header bottom line
100  out << div << endl;
101  }
102 
103  for (const QStringList &row : table) {
104  // content table
105  for (int i = 0; i < row.size(); ++i) {
106  out << "| ";
107 
108  out.setFieldWidth(columnsSize[i]);
109  out << row[i];
110 
111  out.setFieldWidth(0);
112  out << ' ';
113  }
114  out << '|' << endl;
115  }
116 
117  // table bottom line
118  out << div;
119 
120  return buffer;
121 }
122 
123 QString Utils::decodePercentEncoding(QString *s)
124 {
125  if (s->isEmpty()) {
126  return *s;
127  }
128 
129  QByteArray ba = s->toLatin1();
130 
131  char *data = ba.data();
132  const char *inputPtr = data;
133 
134  const int len = ba.count();
135  bool skipUtf8 = true;
136  int outlen = 0;
137  for (int i = 0 ; i < len; ++i, ++outlen) {
138  const char c = inputPtr[i];
139  if (c == '%' && i + 2 < len) {
140  int a = inputPtr[++i];
141  int b = inputPtr[++i];
142 
143  if (a >= '0' && a <= '9') a -= '0';
144  else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
145  else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;
146 
147  if (b >= '0' && b <= '9') b -= '0';
148  else if (b >= 'a' && b <= 'f') b = b - 'a' + 10;
149  else if (b >= 'A' && b <= 'F') b = b - 'A' + 10;
150 
151  *data++ = (char)((a << 4) | b);
152  skipUtf8 = false;
153  } else if (c == '+') {
154  *data++ = ' ';
155  } else {
156  *data++ = c;
157  }
158  }
159 
160  if (skipUtf8) {
161  return *s;
162  }
163 
164  return QString::fromUtf8(ba.data(), outlen);
165 }
166 
167 QString Utils::decodePercentEncoding(QByteArray *ba)
168 {
169  if (ba->isEmpty())
170  return QString();
171 
172  char *data = ba->data();
173  const char *inputPtr = data;
174 
175  int len = ba->count();
176  bool skipUtf8 = true;
177  int outlen = 0;
178  for (int i = 0; i < len; ++i, ++outlen) {
179  const char c = inputPtr[i];
180  if (c == '%' && i + 2 < len) {
181  int a = inputPtr[++i];
182  int b = inputPtr[++i];
183 
184  if (a >= '0' && a <= '9') a -= '0';
185  else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
186  else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;
187 
188  if (b >= '0' && b <= '9') b -= '0';
189  else if (b >= 'a' && b <= 'f') b = b - 'a' + 10;
190  else if (b >= 'A' && b <= 'F') b = b - 'A' + 10;
191 
192  *data++ = (char)((a << 4) | b);
193  skipUtf8 = false;
194  } else if (c == '+') {
195  *data++ = ' ';
196  } else {
197  *data++ = c;
198  }
199  }
200 
201  if (skipUtf8) {
202  return QString::fromLatin1(ba->data(), outlen);
203  } else {
204  return QString::fromUtf8(ba->data(), outlen);
205  }
206 }
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7