5 #include <QJsonDocument>
7 #include <QRegularExpression>
34 QStringList parts =
path.split(
'/',Qt::SkipEmptyParts);
35 return parts.join(
'/');
55 if (resource.at(0) !=
':')
57 VFS::WARN(
"rutils::resourceContents() can only access qrc resources." );
63 if (r.open(QIODevice::ReadOnly))
68 return r.readAll().replace(
'#',
"%23");
73 VFS::WARN( QString(
"Bad resourceContents path: %1").arg(resource) );
99 QJsonDocument d = QJsonDocument::fromJson( r, &err );
101 if (err.error == QJsonParseError::NoError)
107 VFS::ERROR( resource+
": "+err.errorString() );
111 return QJsonObject();
134 QRegularExpression seqrx(
"^(.*)\\.?\\[([-,x\\d]+)#(\\d+)\\]\\.(\\w{2,5})$");
135 QRegularExpressionMatch match = seqrx.match(p);
137 if (match.hasMatch())
141 o[
"prefix"] = match.captured(1);
142 o[
"range"] = match.captured(2);
143 o[
"padding"] = match.captured(3).toInt();
144 o[
"extension"] = match.captured(4);
151 return QJsonValue::Null;
194 QString
name,nameEsc,t,t2;
199 QRegExp digrx(
"(-?\\d+)");
200 QString digrxs(
"(-?\\d{%1})");
201 QRegExp digrxrx( QRegExp::escape(digrxs.arg(
'#')).replace(
'#',
"(-?\\d+)") );
202 QRegExp typerx(
"^.*\\.?("+types.join(
'|')+
")$" );
203 typerx.setCaseSensitivity(Qt::CaseInsensitive);
206 QRegExp unescaperx(
"\\\\(\\$|\\(|\\)|\\*|\\+|\\.|\\?|\\[|\\]|\\^|\\{|\\||\\})" );
208 QHash<QRegExp,int> signatures;
209 QHash<QRegExp, QList<int> > signatureFrames;
214 for( QJsonObject::const_iterator it = l.begin(); it != l.end(); ++it)
217 container = it.value().toBool();
219 if (!container && typerx.exactMatch(
name))
221 nameEsc = QRegExp::escape(
name);
223 for (c=d=o=0; c<100; c++)
227 o = digrx.indexIn(t,o);
231 capLen = digrx.cap(1).length();
232 t.replace(o,capLen,digrxs.arg(capLen));
233 t2.replace(o,capLen,digrx.pattern());
238 signatures[QRegExp(t)]++;
239 signatures[QRegExp(t2)]++;
246 {
VFS::ERROR(
"Too many loops when trying to do sequence listing for '"+nameEsc+
"'");
260 QHash<QRegExp, int>::iterator pit = signatures.begin();
261 while (pit != signatures.end())
263 if (pit.value() == 1) pit = signatures.erase(pit);
273 QRegExp bestSignature,s;
274 int bestSignatureCount,frame;
275 for( QJsonObject::const_iterator it = l.begin(); it != l.end(); ++it)
278 container = it.value().toBool();
280 if (!container && typerx.exactMatch(
name))
282 bestSignatureCount = 0;
283 for ( QHash<QRegExp,int>::const_iterator pit = signatures.begin(); pit != signatures.end(); ++pit )
288 if (s.exactMatch(
name))
290 if (c == bestSignatureCount)
291 if (s.pattern().length() < bestSignature.pattern().length())
293 frame = s.cap(1).toInt();
296 if (c > bestSignatureCount)
297 { bestSignatureCount = c;
299 frame = s.cap(1).toInt();
304 if (bestSignatureCount == 0)
307 { signatureFrames[bestSignature].append(frame);
331 for ( QHash<QRegExp,QList<int> >::const_iterator fit = signatureFrames.begin(); fit != signatureFrames.end(); ++fit )
333 QString sr = fit.key().pattern();
334 QList<int> fl = fit.value();
335 std::sort(fl.begin(),fl.end());
344 for (
int i=0;i<fl.length()-1;i++)
345 deltas.append(fl[i+1]-fl[i]);
355 for (
int i=1;i<=deltas.length();i++)
360 while(i<deltas.length() && deltas[i] == delta) i++,c++;
363 if (b==e) chunks << QString(
"%1").arg(b);
364 else if (c==1) chunks << QString(
"%1,%2").arg(b).arg(e);
365 else if (delta > 1) chunks << QString(
"%1-%2x%3").arg(b).arg(e).arg(delta);
366 else chunks << QString(
"%1-%2").arg(b).arg(e);
371 int p = digrxrx.indexIn(sr);
376 int d = digrxrx.cap(1).toInt();
377 sr.replace( digrxrx, QString(
"[%1#%2]").arg(chunks.join(
',')).arg(d) );
378 sr.replace( unescaperx,
"\\1" );
382 else if (sr.indexOf(digrx.pattern()) > -1)
384 sr.replace( digrx.pattern(), QString(
"[%1@]").arg(chunks.join(
',')) );
385 sr.replace( unescaperx,
"\\1" );
390 {
VFS::ERROR(
"Unexplained regex error... reverting to non-sequence view: "+sr );
410 return QStringList();
412 QRegularExpression seqrx(
"^([-,x\\d]+)([@#]?)(\\d*)$");
414 QRegularExpressionMatch match = seqrx.match(sequence);
415 if (match.hasMatch())
420 QString seq = match.captured(1);
421 QString hash = match.captured(2);
422 int pad = match.captured(3).toInt(&ok);
425 if (hash==
"" || hash==
"@") pad = 0;
429 QStringList n = seq.split(
",",Qt::SkipEmptyParts);
431 QRegularExpression digrx(
"^(-?\\d+)$");
432 QRegularExpression rangerx(
"^(-?\\d+)-(-?\\d+)$");
433 QRegularExpression steprx(
"^(-?\\d+)-(-?\\d+)x(\\d+)$");
434 QRegularExpressionMatch m;
440 QString c = n.takeFirst();
447 { b = m.captured(1).toInt();
448 e = m.captured(2).toInt();
449 s = m.captured(3).toInt();
456 m = rangerx.match(c);
458 { b = m.captured(1).toInt();
459 e = m.captured(2).toInt();
469 { b = e = m.captured(1).toInt();
477 return QStringList();
480 for (
int i=b;i<=e;i+=s)
482 l << QString(
"%1").arg(i,pad,10,QChar(
'0'));
490 return QStringList();
501 QRegularExpression seqrx(
"^(.*)\\.\\[([-,x\\d]+)#(\\d+)\\]\\.(\\w{2,5})$");
503 QRegularExpressionMatch match = seqrx.match(sequence);
504 if (match.hasMatch())
508 QString prefix = match.captured(1);
509 QString seq = match.captured(2);
510 QString pad = match.captured(3);
511 QString ext = match.captured(4);
515 QStringList n = seq.split(
",",Qt::SkipEmptyParts);
517 QRegularExpression digrx(
"^(-?\\d+)$");
518 QRegularExpression rangerx(
"^(-?\\d+)-(-?\\d+)$");
519 QRegularExpression steprx(
"^(-?\\d+)-(-?\\d+)x(\\d+)$");
520 QRegularExpressionMatch m;
526 QString c = n.takeFirst();
533 { b = m.captured(1).toInt();
534 e = m.captured(2).toInt();
535 s = m.captured(3).toInt();
542 m = rangerx.match(c);
544 { b = m.captured(1).toInt();
545 e = m.captured(2).toInt();
555 { b = e = m.captured(1).toInt();
563 return QStringList();
566 for (
int i=b;i<=e;i+=s)
568 l << QString(
"%1.%2.%3").arg(prefix).arg(i,pad.toInt(),10,QChar(
'0')).arg(ext);
578 return QStringList();
595 QByteArray r = d.toJson().toBase64();
596 QByteArray b = r.replace(
'/',
'_');
615 QByteArray r = p.replace(
'_',
'/');
616 QByteArray b = QByteArray::fromBase64(r);
619 QJsonDocument d = QJsonDocument::fromJson(b,&e);
621 if (!d.isNull() && e.error == QJsonParseError::NoError)
627 return QJsonObject();
642 attribute = attribute.replace(
"<",
"<");
643 attribute = attribute.replace(
">",
">");
663 FILE* pipe = popen(qUtf8Printable(command),
"r");
667 return QStringList();
675 if (fgets(buffer, 128, pipe) !=
nullptr)
682 return result.split(
"\n",Qt::SkipEmptyParts);
static void ERROR(QString message, int level=0, QString user="server")
Send a message to the VFS::_errors VFS_stream.
static void WARN(QString message, int level=0, QString user="server")
Send a message to the VFS::_warnings VFS_stream.
setter name
a setter DOCME
getter path
a getter DOCME
QStringList expandSequence(QString sequence)
Expand a sequence-notated list into a list of numbers.
QString cleanPath(QString path)
Clean and normalize a VFS path.
QStringList expandSequenceListing(QString sequence)
Expand a sequence-notated string into a list of names.
QStringList sequenceTypes
A list of regular expressions which can represent image or file sequences.
QJsonObject decodeBase64Path(QByteArray p, bool *ok)
Decode a base64 string as a JSON object.
QStringList exec(QString command, bool *ok=nullptr)
execute a command in a shell, and return the resulting output as a QStringList
QJsonObject jsonResource(QString resource, bool *ok=nullptr)
Fetch the contents of a Qt resource as a QJsonObject.
QJsonValue parseSequenceSyntax(QString path)
Check if a path or string matches our syntax for file sequences.
QJsonObject sequenceListing(QJsonObject l, QStringList types=sequenceTypes)
Given a list of filenames and a regex list, collapse the listing to sequences when possible.
QString unescapeXMLAttribute(QString attribute)
Un-escape an XML attribute.
QByteArray encodeBase64Path(QJsonObject p)
Encode a JSON object as a base64 string.
QByteArray resourceContents(QString resource, bool *ok=nullptr, bool squashHash=false)
Fetch the contents of a Qt resource file.