kwave  18.07.70
Parser.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  Parser.cpp - parser for Kwave's internal commands
3  -------------------
4  begin : Sat Feb 3 2001
5  copyright : (C) 2001 by Thomas Eschenbacher
6  email : Thomas Eschenbacher <thomas.eschenbacher@gmx.de>
7 
8  ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include "config.h"
20 
21 #include <QChar>
22 #include <QLatin1Char>
23 #include <QRegExp>
24 #include <QString>
25 
26 #include "libkwave/Parser.h"
27 #include "libkwave/String.h"
28 #include "libkwave/Utils.h"
29 
30 //***************************************************************************
31 Kwave::Parser::Parser (const QString &init)
32  :m_command(_("")), m_param(), m_current(0), m_commands()
33 {
34  QString line = init.trimmed();
35  unsigned int level = 0;
36  bool escaped = false;
37  int pos;
38 
39  m_commands = splitCommands(line);
40  line = m_commands.first();
41 
42  // --- parse the command ---
43  pos = line.indexOf(QLatin1Char('('));
44  if (pos >= 0) {
45  // command present
46  m_command = line.left(pos).simplified();
47  line.remove(0, pos+1);
48  } else {
49  m_command.clear();
50  }
51 
52  // --- parse the list of parameters ---
53  QString param;
54  while (line.length()) {
55  QChar c = line[0];
56  line.remove(0,1);
57 
58  // the next character is escaped
59  if (!escaped && (c.toLatin1() == '\\')) {
60  escaped = true;
61  param += c;
62  continue;
63  }
64 
65  // escaped character
66  if (escaped) {
67  escaped = false;
68  param += c;
69  continue;
70  }
71 
72  switch (c.toLatin1()) {
73  case ',':
74  if (!level) {
75  m_param.append(unescape(param.trimmed()));
76  param.clear();
77  } else param += c;
78  break;
79 
80  case '(':
81  level++;
82  param += c;
83  break;
84  case ')':
85  if (!level) {
86  param = unescape(param.trimmed());
87  if (param.length())
88  m_param.append(param);
89  // break, belongs to command, end of line
90  line.clear();
91  }
92  else
93  level--;
94  param += c;
95  break;
96  default:
97  param += c;
98  }
99  }
100 
101  line = line.trimmed();
102  if (line.length()) {
103  qWarning("Parser: trailing garbage after command: '%s'", DBG(line));
104  }
105 }
106 
107 //***************************************************************************
109 {
110 }
111 
112 //***************************************************************************
113 QStringList Kwave::Parser::splitCommands(QString &line)
114 {
115  // split a line into commands
116  unsigned int level = 0;
117  QString cmd = _("");
118  QStringList commands;
119  bool escaped = false;
120 
121  while (line.length()) {
122  QChar c = line[0];
123  line.remove(0,1);
124 
125  // the next character is escaped
126  if (!escaped && (c.toLatin1() == '\\')) {
127  escaped = true;
128  cmd += c;
129  continue;
130  }
131 
132  // escaped character
133  if (escaped) {
134  escaped = false;
135  cmd += c;
136  continue;
137  }
138 
139  switch (c.toLatin1()) {
140  case ';':
141  if (!level) {
142  // next command in the list
143  commands.append(cmd.trimmed());
144  cmd = _("");
145  } else cmd += c;
146  break;
147  case '(':
148  level++;
149  cmd += c;
150  break;
151  case ')':
152  level--;
153  cmd += c;
154  break;
155  default:
156  cmd += c;
157  }
158  }
159 
160  if (cmd.length()) {
161  commands.append(cmd.trimmed());
162  }
163 
164  return commands;
165 }
166 
167 //***************************************************************************
169 {
170  m_current = 0;
171  return nextParam();
172 }
173 
174 //***************************************************************************
175 const QString &Kwave::Parser::nextParam()
176 {
177  static const QString empty = _("");
178  if (m_current >= count()) return empty;
179  return m_param[m_current++];
180 }
181 
182 //***************************************************************************
184 {
185  nextParam();
186 }
187 
188 //***************************************************************************
190 {
191  QStringList list;
192  while (!isDone())
193  list.append(nextParam());
194  return list;
195 }
196 
197 //***************************************************************************
199 {
200  const QString &p = nextParam();
201 
202  // first test for "true" and "false"
203  if (p.toLower() == _("true")) return true;
204  if (p.toLower() == _("false")) return false;
205 
206  // maybe numeric ?
207  bool ok;
208  int value = p.toInt(&ok);
209  if (ok) return (value != 0);
210 
211  qWarning("Parser: invalid bool format: '%s'", DBG(p));
212  return false;
213 }
214 
215 //***************************************************************************
217 {
218  const QString &p = nextParam();
219  bool ok;
220  int value = p.toInt(&ok);
221 
222  if (!ok) {
223  qWarning("Parser: unable to parse int from '%s'", DBG(p));
224  value = 0;
225  }
226 
227  return value;
228 }
229 
230 //***************************************************************************
231 unsigned int Kwave::Parser::toUInt()
232 {
233  const QString &p = nextParam();
234  bool ok;
235  unsigned int value = p.toUInt(&ok);
236 
237  if (!ok) {
238  qWarning("Parser: unable to parse unsigned int from '%s'", DBG(p));
239  value = 0;
240  }
241 
242  return value;
243 }
244 
245 //***************************************************************************
247 {
248  const QString &p = nextParam();
249  bool ok;
250  sample_index_t value = p.toULongLong(&ok);
251 
252  if (!ok) {
253  qWarning("Parser: unable to parse unsigned int from '%s'", DBG(p));
254  value = 0;
255  }
256 
257  return value;
258 }
259 
260 
261 //***************************************************************************
263 {
264  const QString &p = nextParam();
265  bool ok;
266  double value = p.toDouble(&ok);
267 
268  if (!ok) {
269  qWarning("Parser: unable to parse double from '%s'", DBG(p));
270  value = 0.0;
271  }
272 
273  return value;
274 }
275 
276 //***************************************************************************
277 QString Kwave::Parser::escape(const QString &text)
278 {
279  static const QString special = _(":;<=>?[\\]^`");
280  QString escaped;
281 
282  for (QString::ConstIterator it = text.begin(); it != text.end(); ++it) {
283  const QChar c(*it);
284 
285  if ((c.toLatin1() < '.') || (c.toLatin1() > 'z') || special.contains(c))
286  escaped += _("\\");
287 
288  escaped += c;
289  }
290 
291  return escaped;
292 }
293 
294 //***************************************************************************
295 QString Kwave::Parser::escapeForFileName(const QString &text)
296 {
297  QString result = text;
298 
299  // convert all kinds of (multiple) whitespaces, including tabs
300  // and newlines into single spaces
301  QRegExp rx(_("[\\s\\\t\\\r\\\n]+"));
302  result.replace(rx, QChar(0x0020));
303 
304  // NOTE: this escapes any kind of special chars, but not a slash "/"
305  result = escape(result);
306 
307  // special handling for slashes "/" -> replace with unicode FRACTION SLASH
308  result.replace(QChar(0x002F), QChar(0x2044));
309 
310  return result;
311 }
312 
313 //***************************************************************************
314 QString Kwave::Parser::unescape(const QString &text)
315 {
316  QString unescaped;
317 
318  bool esc = false;
319  for (QString::ConstIterator it = text.begin(); it != text.end(); ++it) {
320  const QChar c(*it);
321 
322  if (!esc && (c.toLatin1() == '\\')) {
323  // this is the leading escape character -> skip it
324  esc = true;
325  continue;
326  }
327 
328  esc = false;
329  unescaped += c;
330  }
331 
332  return unescaped;
333 }
334 
335 //***************************************************************************
336 QUrl Kwave::Parser::toUrl(const QString &command)
337 {
338  QUrl url;
339 
340  url.setScheme(Kwave::urlScheme());
341  Parser parser(command);
342 
343  // encode the command as "path"
344  url.setPath(QString::fromLatin1(QUrl::toPercentEncoding(parser.command())));
345 
346  // encode the parameter list into a comma separated string
347  unsigned int count = parser.count();
348  QByteArray params;
349  for (unsigned int i = 0; i < count; ++i) {
350  QString param = parser.nextParam();
351  if (params.length()) params += ',';
352  params += QUrl::toPercentEncoding(param);
353  }
354  url.setQuery(QString::fromLatin1(params));
355 
356  return url;
357 }
358 
359 //***************************************************************************
360 QString Kwave::Parser::fromUrl(const QUrl &url)
361 {
362  if (url.scheme().toLower() != Kwave::urlScheme()) return QString();
363 
364  // get the command name (path)
365  QString command = QUrl::fromPercentEncoding(url.path().toLatin1());
366 
367  // get the parameter list
368  command += _("(");
369  QStringList params = url.query().split(_(","));
370  if (!params.isEmpty()) {
371  bool first = true;
372  foreach (const QString &param, params) {
373  if (!first) command += _(",");
374  command += QUrl::fromPercentEncoding(param.toLatin1());
375  first = false;
376  }
377  }
378  command += _(")");
379 
380  return command;
381 }
382 
383 //***************************************************************************
384 //***************************************************************************
sample_index_t toSampleIndex()
Definition: Parser.cpp:246
virtual ~Parser()
Definition: Parser.cpp:108
static QString fromUrl(const QUrl &url)
Definition: Parser.cpp:360
QStringList m_commands
Definition: Parser.h:196
unsigned int m_current
Definition: Parser.h:193
Parser(const QString &init)
Definition: Parser.cpp:31
quint64 sample_index_t
Definition: Sample.h:28
int toInt()
Definition: Parser.cpp:216
static QString unescape(const QString &text)
Definition: Parser.cpp:314
static QString escapeForFileName(const QString &text)
Definition: Parser.cpp:295
QStringList splitCommands(QString &line)
Definition: Parser.cpp:113
unsigned int toUInt()
Definition: Parser.cpp:231
double toDouble()
Definition: Parser.cpp:262
QStringList m_param
Definition: Parser.h:190
static QUrl toUrl(const QString &command)
Definition: Parser.cpp:336
const QString & firstParam()
Definition: Parser.cpp:168
#define _(m)
Definition: memcpy.c:66
bool isDone() const
Definition: Parser.h:70
#define DBG(qs)
Definition: String.h:55
const QStringList & params()
Definition: Parser.h:52
QString Q_DECL_EXPORT urlScheme()
Definition: Utils.cpp:177
QStringList remainingParams()
Definition: Parser.cpp:189
unsigned int count() const
Definition: Parser.h:75
static QString escape(const QString &text)
Definition: Parser.cpp:277
QString command()
Definition: Parser.h:47
void skipParam()
Definition: Parser.cpp:183
QString m_command
Definition: Parser.h:187
const QString & nextParam()
Definition: Parser.cpp:175
bool toBool()
Definition: Parser.cpp:198