Cutelyst  1.11.0
utils.cpp
1 /*
2  * Copyright (C) 2015-2017 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  QChar *data = s->data();
130  int len = s->size();
131  int outlen = 0;
132  for (int i = 0 ; i < len ; ++i, ++outlen) {
133  QChar c = (*s)[i];
134  if (c == QLatin1Char('%') && i + 2 < len) {
135  int a = (*s)[++i].unicode();
136  int b = (*s)[++i].unicode();
137 
138  if (a >= '0' && a <= '9') a -= '0';
139  else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
140  else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;
141 
142  if (b >= '0' && b <= '9') b -= '0';
143  else if (b >= 'a' && b <= 'f') b = b - 'a' + 10;
144  else if (b >= 'A' && b <= 'F') b = b - 'A' + 10;
145 
146  *data++ = (ushort)((a << 4) | b);
147  } else {
148  *data++ = c;
149  }
150  }
151 
152  if (outlen != len)
153  s->truncate(outlen);
154 
155  return *s;
156 }
157 
158 QString Utils::decodePercentEncoding(QByteArray *ba)
159 {
160  if (ba->isEmpty())
161  return QString::fromLatin1(*ba);
162 
163  char *data = ba->data();
164  const char *inputPtr = data;
165 
166  int i = 0;
167  int len = ba->count();
168  int outlen = 0;
169  int a, b;
170  char c;
171  while (i < len) {
172  c = inputPtr[i];
173  if (c == '%' && i + 2 < len) {
174  a = inputPtr[++i];
175  b = inputPtr[++i];
176 
177  if (a >= '0' && a <= '9') a -= '0';
178  else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
179  else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;
180 
181  if (b >= '0' && b <= '9') b -= '0';
182  else if (b >= 'a' && b <= 'f') b = b - 'a' + 10;
183  else if (b >= 'A' && b <= 'F') b = b - 'A' + 10;
184 
185  *data++ = (char)((a << 4) | b);
186  } else if (c == '+') {
187  *data++ = ' ';
188  } else {
189  *data++ = c;
190  }
191 
192  ++i;
193  ++outlen;
194  }
195 
196  if (outlen != len)
197  ba->truncate(outlen);
198 
199  return QString::fromUtf8(*ba);
200 }
The Cutelyst namespace holds all public Cutelyst API.
Definition: Mainpage.dox:7