13 #include <QCoreApplication>
211 bool bIsArray =
false;
214 if (sTypeName.isEmpty())
215 return Error(pRequest, QString(
"XSD request on empty name" ));
222 if (sTypeName.startsWith(
"ArrayOf" ))
225 sTypeName = sTypeName.mid( 7 );
228 if (sTypeName.startsWith(
"MapOfString" ))
231 sTypeName = sTypeName.mid( 11 );
238 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
244 if (
id == QMetaType::UnknownType)
246 QString sFQN = sTypeName +
"*";
255 if (
id == QMetaType::UnknownType)
257 QString sFQN =
"V2" + sTypeName;
260 if (
id == QMetaType::UnknownType)
262 QString sFQN =
"V2" + sTypeName +
"*";
268 QMetaType metaType = QMetaType::fromName( sTypeName.toUtf8() );
269 if (metaType.id() == QMetaType::UnknownType)
270 metaType = QMetaType::fromName( sTypeName.toUtf8() +
"*" );
271 if (metaType.id() == QMetaType::UnknownType)
272 metaType = QMetaType::fromName(
"V2" + sTypeName.toUtf8() +
"*" );
276 int id = metaType.id();
283 if (!(bIsArray || bIsMap) && (
id < QMetaType::User))
284 return Error(pRequest,QString(
"XSD request on unsupported type %1").arg(sTypeName));
294 if (!pRequest->m_queries.contains(
"raw" ))
296 appendChild( createProcessingInstruction(
"xml-stylesheet",
297 R
"(type="text/xsl" href="/xslt/class.xslt")" ));
308 id >= QMetaType::User );
312 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
313 const QMetaObject *pMetaObject = QMetaType::metaObjectForType(
id);
315 const QMetaObject *pMetaObject = metaType.metaObject();
319 QObject* pClass = pMetaObject->newInstance();
320 if (pClass !=
nullptr)
359 const QMetaObject *pMetaObject = pClass->metaObject();
364 QMap<QString, TypeInfo> typesToInclude;
370 QDomElement oTypeNode = createElement(
"xs:complexType" );
371 QDomElement oSeqNode = createElement(
"xs:sequence" );
373 oTypeNode.setAttribute(
"name", sClassName );
375 oTypeNode.appendChild( oSeqNode );
387 int nCount = pMetaObject->propertyCount();
389 for (
int nIdx=0; nIdx < nCount; ++nIdx )
391 QMetaProperty metaProperty = pMetaObject->property( nIdx );
393 if (metaProperty.isDesignable())
395 const char *pszPropName = metaProperty.name();
396 QString sPropName( pszPropName );
398 if ( sPropName.compare(
"objectName" ) == 0)
405 QDomElement oNode = createElement(
"xs:element" );
406 QString sType = metaProperty.typeName();
407 bool bCustomType =
false;
408 QString sCustomAttr =
"type";
409 QString sContentName = QString();
410 QString sContentType = QString();
412 LOG(VB_UPNP, LOG_DEBUG, QString(
"Type: %1").arg( sType ));
418 if (sType ==
"QObject*")
420 QVariant val = metaProperty.read( pClass );
421 const QObject *pObject = val.value< QObject* >();
423 sType = pObject->metaObject()->className();
426 else if ((sType ==
"QVariantList" ) || (sType ==
"QVariantMap"))
432 if (sContentType.startsWith(
'Q'))
433 sContentType = sContentType.mid( 1 );
435 if (sContentType.startsWith(
"V2"))
436 sContentType.remove(0,2);
437 sContentType.remove( QChar(
'*'));
439 if (sType ==
"QVariantMap")
445 if (sContentName.isEmpty())
446 sContentName = sContentType;
448 sType =
"MapOfString" + sContentName;
451 sType =
"ArrayOf" + sContentType;
456 else if (sType ==
"QStringList")
458 sType =
"ArrayOfString";
461 else if (
IsEnum( metaProperty, sType ))
477 QString sNewPropName( metaProperty.name() );
480 oNode.setAttribute(
"nillable" ,
static_cast<int>(
true) );
484 TypeInfo info = { sCustomAttr, sContentType };
485 typesToInclude.insert( sType, info );
488 oNode.setAttribute(
"type" , (bCustomType ?
"tns:" :
"xs:") +
491 oNode.setAttribute(
"name" , sNewPropName );
492 oNode.setAttribute(
"minOccurs", 0 );
494 oSeqNode.appendChild( oNode );
504 QDomElement oElementNode = createElement(
"xs:element" );
506 oElementNode.setAttribute(
"type" ,
"tns:" + sClassName );
507 oElementNode.setAttribute(
"nillable",
"true" );
508 oElementNode.setAttribute(
"name" , sClassName );
514 appendChild( oRoot );
516 if (typesToInclude.count() > 0)
526 QString sBaseUri(
"http://" +
527 pRequest->m_headers->value(
"host") +
528 pRequest->m_path +
"xsd");
529 QMap<QString, TypeInfo >::const_iterator it = typesToInclude.constBegin();
530 while( it != typesToInclude.constEnd())
532 QDomElement oIncNode = createElement(
"xs:include" );
533 QString sType = it.key();
535 if (sType.startsWith(
"V2"))
540 QString sValue = QString(
"%1?%2=%3" ).arg( sBaseUri,
547 oIncNode.setAttribute(
"schemaLocation", sValue );
549 oRoot.appendChild( oIncNode );
554 oRoot.appendChild( oTypeNode );
555 oRoot.appendChild( oElementNode );
572 return (metaProperty.isEnumType() || metaProperty.isFlagType() );
597 const QString &sClassName,
600 QString sArrayName =
"ArrayOf" + sClassName;
604 sType =
"tns:" + sClassName;
614 QDomElement oTypeNode = createElement(
"xs:complexType" );
615 QDomElement oSeqNode = createElement(
"xs:sequence" );
619 oTypeNode.setAttribute(
"name", sArrayName );
620 oTypeNode.appendChild( oSeqNode );
622 QDomElement oNode = createElement(
"xs:element" );
624 oNode.setAttribute(
"type" , sType );
625 oNode.setAttribute(
"nillable" ,
"true" );
626 oNode.setAttribute(
"name" , sClassName );
627 oNode.setAttribute(
"maxOccurs" ,
"unbounded" );
628 oNode.setAttribute(
"minOccurs" ,
"0" );
630 oSeqNode.appendChild( oNode );
636 QDomElement oElementNode = createElement(
"xs:element" );
638 oElementNode.setAttribute(
"type" ,
"tns:" + sArrayName );
639 oElementNode.setAttribute(
"nillable",
"true" );
640 oElementNode.setAttribute(
"name" , sArrayName );
646 appendChild( oRoot );
650 QDomElement oIncNode = createElement(
"xs:include" );
654 QString sBaseUri(
"http://" +
655 pRequest->m_headers->value(
"host") +
656 pRequest->m_path +
"xsd" +
"?type=");
658 oIncNode.setAttribute(
"schemaLocation", sBaseUri + sClassName );
660 oRoot.appendChild( oIncNode );
663 oRoot.appendChild( oTypeNode );
664 oRoot.appendChild( oElementNode );
711 const QString &sClassName,
714 QString sArrayName =
"MapOfString" + sClassName;
716 QString sMapItemName = pRequest->m_queries.value(
"name");
720 if (sMapItemName.isEmpty())
721 sMapItemName = sClassName;
724 sType =
"tns:" + sMapItemName;
734 QDomElement oTypeNode = createElement(
"xs:complexType" );
735 QDomElement oSeqNode = createElement(
"xs:sequence" );
736 QDomElement oAnno = createElement(
"xs:annotation" );
737 QDomElement oAppInfo = createElement(
"xs:appinfo" );
739 QDomElement oNode = createElement(
"IsDictionary" );
740 oNode.setAttribute(
"xmlns",
"http://schemas.microsoft.com/2003/10/Serialization/" );
741 oNode.appendChild( createTextNode(
"true" ));
743 oTypeNode.appendChild( oAnno );
744 oAnno .appendChild( oAppInfo );
745 oAppInfo .appendChild( oNode );
753 oTypeNode.setAttribute(
"name", sArrayName );
754 oTypeNode.appendChild( oSeqNode );
760 QDomElement oInnerNode = createElement(
"xs:element" );
762 oInnerNode.setAttribute(
"name" , sClassName );
763 oInnerNode.setAttribute(
"maxOccurs" ,
"unbounded" );
764 oInnerNode.setAttribute(
"minOccurs" ,
"0" );
766 oSeqNode.appendChild( oInnerNode );
771 oNode = createElement(
"xs:complexType" );
773 oInnerNode.appendChild( oNode );
779 QDomElement oInnerSeq = createElement(
"xs:sequence" );
781 oNode.appendChild( oInnerSeq );
787 oNode = createElement(
"xs:element" );
789 oNode.setAttribute(
"type" ,
"xs:string" );
790 oNode.setAttribute(
"nillable" ,
"true" );
791 oNode.setAttribute(
"name" ,
"Key" );
793 oInnerSeq.appendChild( oNode );
799 oNode = createElement(
"xs:element" );
801 oNode.setAttribute(
"type" , sType );
802 oNode.setAttribute(
"nillable" ,
"true" );
803 oNode.setAttribute(
"name" ,
"Value" );
805 oInnerSeq.appendChild( oNode );
811 QDomElement oElementNode = createElement(
"xs:element" );
813 oElementNode.setAttribute(
"type" ,
"tns:" + sArrayName );
814 oElementNode.setAttribute(
"nillable",
"true" );
815 oElementNode.setAttribute(
"name" , sArrayName );
821 appendChild( oRoot );
825 QDomElement oIncNode = createElement(
"xs:include" );
828 QString sBaseUri(
"http://" +
829 pRequest->m_headers->value(
"host") +
830 pRequest->m_path +
"xsd" +
"?type=");
832 oIncNode.setAttribute(
"schemaLocation", sBaseUri + sClassName );
834 oRoot.appendChild( oIncNode );
837 oRoot.appendChild( oTypeNode );
838 oRoot.appendChild( oElementNode );
860 QString sTargetNamespace =
"http://mythtv.org";
862 QDomElement oRoot = createElement(
"xs:schema" );
864 oRoot.setAttribute(
"xmlns:xs" ,
"http://www.w3.org/2001/XMLSchema");
865 oRoot.setAttribute(
"xmlns:tns" , sTargetNamespace );
866 oRoot.setAttribute(
"targetNamespace" , sTargetNamespace );
867 oRoot.setAttribute(
"elementFormDefault" ,
"qualified" );
868 oRoot.setAttribute(
"attributeFormDefault",
"unqualified" );
878 if (sType.startsWith(
"V2"))
881 if (sType ==
"QDateTime")
884 if (sType ==
"QDate")
887 if (sType ==
"QTime")
899 if (bCustomType || sType.startsWith(
"V2"))
901 QString sTypeName( sType );
903 if (sTypeName.startsWith(
"V2"))
904 sTypeName.remove(0,2);
905 sTypeName.remove( QChar(
'*') );
907 if (sType ==
"QStringList" )
908 return "ArrayOfString";
913 if (sType ==
"QDateTime")
916 if (sType ==
"QDate")
919 if (sType ==
"QTime")
926 return "unsignedInt";
928 if (sType ==
"qlonglong" )
931 if (sType ==
"std::chrono::seconds" )
934 if (sType ==
"qulonglong" )
935 return "unsignedLong";
937 if (sType ==
"QJsonObject" )
940 if (sType ==
"long long" )
943 if (sType ==
"QFileInfo" )
946 if (sType.startsWith(
'Q'))
947 return sType.mid( 1 ).toLower();
949 return sType.toLower();
958 const QMetaObject *pMeta = pObject->metaObject();
963 nIdx = pMeta->indexOfClassInfo( sPropName.toUtf8() );
967 QString sMetadata = pMeta->classInfo( nIdx ).value();
968 QStringList sOptions = sMetadata.split(
';' );
970 QString sFullKey = sKey +
"=";
972 auto hasKey = [&sFullKey](
const QString& o) {
return o.startsWith( sFullKey ); };
973 auto it = std::find_if(sOptions.cbegin(), sOptions.cend(), hasKey);
974 if (it != sOptions.cend())
975 return (*it).mid( sFullKey.length() );
983 LOG(VB_GENERAL, LOG_ERR,
"MythCSD Exception: " + msg);