static int rtCrPkcs7ContentInfo_DecodeExtra(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTCRPKCS7CONTENTINFO pThis,
                                            const char *pszErrorTag)
{
    pThis->u.pCore = NULL;

    /*
     * Figure the type.
     */
    RTCRPKCS7CONTENTINFOCHOICE  enmChoice;
    size_t                      cbContent = 0;
    if (RTAsn1ObjId_CompareWithString(&pThis->ContentType, RTCRPKCS7SIGNEDDATA_OID) == 0)
    {
        enmChoice = RTCRPKCS7CONTENTINFOCHOICE_SIGNED_DATA;
        cbContent = sizeof(*pThis->u.pSignedData);
    }
    else if (RTAsn1ObjId_CompareWithString(&pThis->ContentType, RTCRSPCINDIRECTDATACONTENT_OID) == 0)
    {
        enmChoice = RTCRPKCS7CONTENTINFOCHOICE_SPC_INDIRECT_DATA_CONTENT;
        cbContent = sizeof(*pThis->u.pIndirectDataContent);
    }
    else if (RTAsn1ObjId_CompareWithString(&pThis->ContentType, RTCRTSPTSTINFO_OID) == 0)
    {
        enmChoice = RTCRPKCS7CONTENTINFOCHOICE_TSP_TST_INFO;
        cbContent = sizeof(*pThis->u.pTstInfo);
    }
    else
    {
        enmChoice = RTCRPKCS7CONTENTINFOCHOICE_UNKNOWN;
        cbContent = 0;
    }

    int rc = VINF_SUCCESS;
    if (enmChoice != RTCRPKCS7CONTENTINFOCHOICE_UNKNOWN)
    {
        /*
         * Detect CMS octet string and open the content cursor.
         * Current we don't have work with any contet which is octet string,
         * they're all sequences, which make detection so much simpler.
         */
        PRTASN1OCTETSTRING  pOctetString = &pThis->Content;
        RTASN1CURSOR        ContentCursor;
        rc = RTAsn1CursorInitSubFromCore(pCursor, &pThis->Content.Asn1Core, &ContentCursor, "Content");
        if (   RT_SUCCESS(rc)
            && RTAsn1CursorIsNextEx(&ContentCursor, ASN1_TAG_OCTET_STRING, ASN1_TAGFLAG_PRIMITIVE | ASN1_TAGCLASS_UNIVERSAL))
        {
            rc = RTAsn1MemAllocZ(&pThis->Content.EncapsulatedAllocation, (void **)&pThis->Content.pEncapsulated,
                                 sizeof(*pOctetString));
            if (RT_SUCCESS(rc))
            {
                pThis->pCmsContent = pOctetString = (PRTASN1OCTETSTRING)pThis->Content.pEncapsulated;
                rc = RTAsn1OctetString_DecodeAsn1(&ContentCursor, 0, pOctetString, "CmsContent");
                if (RT_SUCCESS(rc))
                    rc = RTAsn1CursorCheckEnd(&ContentCursor);
                if (RT_SUCCESS(rc))
                    rc = RTAsn1CursorInitSubFromCore(pCursor, &pOctetString->Asn1Core, &ContentCursor, "CmsContent");
            }
        }
        if (RT_SUCCESS(rc))
        {
            /*
             * Allocate memory for the decoded content.
             */
            rc = RTAsn1MemAllocZ(&pOctetString->EncapsulatedAllocation, (void **)&pOctetString->pEncapsulated, cbContent);
            if (RT_SUCCESS(rc))
            {
                pThis->u.pCore = pOctetString->pEncapsulated;

                /*
                 * Decode it.
                 */
                switch (enmChoice)
                {
                    case RTCRPKCS7CONTENTINFOCHOICE_SIGNED_DATA:
                        rc = RTCrPkcs7SignedData_DecodeAsn1(&ContentCursor, 0, pThis->u.pSignedData, "SignedData");
                        break;
                    case RTCRPKCS7CONTENTINFOCHOICE_SPC_INDIRECT_DATA_CONTENT:
                        rc = RTCrSpcIndirectDataContent_DecodeAsn1(&ContentCursor, 0, pThis->u.pIndirectDataContent,
                                                                   "IndirectDataContent");
                        break;
                    case RTCRPKCS7CONTENTINFOCHOICE_TSP_TST_INFO:
                        rc = RTCrTspTstInfo_DecodeAsn1(&ContentCursor, 0, pThis->u.pTstInfo, "TstInfo");
                        break;
                    default:
                        AssertFailed();
                        rc = VERR_IPE_NOT_REACHED_DEFAULT_CASE;
                        break;
                }
                if (RT_SUCCESS(rc))
                    rc = RTAsn1CursorCheckEnd(&ContentCursor);
                if (RT_SUCCESS(rc))
                    return VINF_SUCCESS;

                RTAsn1MemFree(&pOctetString->EncapsulatedAllocation, pOctetString->pEncapsulated);
                pOctetString->pEncapsulated = NULL;
                pThis->u.pCore = NULL;
            }
        }
    }
    return rc;
}
RTDECL(int) RTAsn1DynType_DecodeAsn1(PRTASN1CURSOR pCursor, uint32_t fFlags, PRTASN1DYNTYPE pDynType, const char *pszErrorTag)
{
    RT_ZERO(*pDynType);

    Assert(!(fFlags & RTASN1CURSOR_GET_F_IMPLICIT)); RT_NOREF_PV(fFlags);
    uint32_t        cbSavedLeft = pCursor->cbLeft;
    uint8_t const  *pbSavedCur  = pCursor->pbCur;

    int rc = RTAsn1CursorReadHdr(pCursor, &pDynType->u.Core, pszErrorTag);
    if (RT_SUCCESS(rc))
    {
        pDynType->enmType = RTASN1TYPE_CORE;

        if (pDynType->u.Core.fClass == (ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_PRIMITIVE))
        {
            switch (pDynType->u.Core.uTag)
            {
                case ASN1_TAG_BOOLEAN:
                    pDynType->enmType = RTASN1TYPE_BOOLEAN;
                    break;
                case ASN1_TAG_INTEGER:
                    pDynType->enmType = RTASN1TYPE_INTEGER;
                    break;
                //case ASN1_TAG_ENUMERATED:
                //    pDynType->enmType = RTASN1TYPE_ENUMERATED;
                //    break;
                //case ASN1_TAG_REAL:
                //    pDynType->enmType = RTASN1TYPE_REAL;
                //    break;
                case ASN1_TAG_BIT_STRING:
                    pDynType->enmType = RTASN1TYPE_BIT_STRING;
                    break;
                case ASN1_TAG_OCTET_STRING:
                    pDynType->enmType = RTASN1TYPE_OCTET_STRING;
                    break;
                case ASN1_TAG_NULL:
                    pDynType->enmType = RTASN1TYPE_NULL;
                    break;
                case ASN1_TAG_SEQUENCE:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_BAD_TAG, "ASN.1 SEQUENCE shall be constructed.");
                case ASN1_TAG_SET:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_BAD_TAG, "ASN.1 SET shall be constructed.");
                case ASN1_TAG_OID:
                    pDynType->enmType = RTASN1TYPE_OBJID;
                    break;
                //case ASN1_TAG_RELATIVE_OID:
                //    pDynType->enmType = RTASN1TYPE_RELATIVE_OBJID;
                //    break;
                case ASN1_TAG_UTC_TIME:
                case ASN1_TAG_GENERALIZED_TIME:
                    pDynType->enmType = RTASN1TYPE_TIME;
                    break;
                case ASN1_TAG_UTF8_STRING:
                case ASN1_TAG_NUMERIC_STRING:
                case ASN1_TAG_PRINTABLE_STRING:
                case ASN1_TAG_T61_STRING:
                case ASN1_TAG_VIDEOTEX_STRING:
                case ASN1_TAG_IA5_STRING:
                case ASN1_TAG_GRAPHIC_STRING:
                case ASN1_TAG_VISIBLE_STRING:
                case ASN1_TAG_UNIVERSAL_STRING:
                case ASN1_TAG_GENERAL_STRING:
                case ASN1_TAG_BMP_STRING:
                    pDynType->enmType = RTASN1TYPE_STRING;
                    break;
                //case ASN1_TAG_CHARACTER_STRING:
                //    pDynType->enmType = RTASN1TYPE_CHARACTER_STRING;
                //    break;

                default:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_TAG_NOT_IMPL,
                                               "Primitive tag %u (%#x) not implemented.",
                                               pDynType->u.Core.uTag, pDynType->u.Core.uTag);
            }
        }
        else if (pDynType->u.Core.fClass == (ASN1_TAGCLASS_UNIVERSAL | ASN1_TAGFLAG_CONSTRUCTED))
            switch (pDynType->u.Core.uTag)
            {
                case ASN1_TAG_BOOLEAN:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_BAD_TAG, "ASN.1 BOOLEAN shall be primitive.");
                case ASN1_TAG_INTEGER:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_BAD_TAG, "ASN.1 BOOLEAN shall be primitive.");
                case ASN1_TAG_ENUMERATED:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_BAD_TAG, "ASN.1 ENUMERATED shall be primitive.");
                case ASN1_TAG_REAL:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_BAD_TAG, "ASN.1 REAL shall be primitive.");
                case ASN1_TAG_BIT_STRING:
                    pDynType->enmType = RTASN1TYPE_BIT_STRING;
                    break;
                case ASN1_TAG_OCTET_STRING:
                    pDynType->enmType = RTASN1TYPE_OCTET_STRING;
                    break;
                case ASN1_TAG_NULL:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_BAD_TAG, "ASN.1 NULL shall be primitive.");
                case ASN1_TAG_SEQUENCE:
#if 0
                    pDynType->enmType = RTASN1TYPE_SEQUENCE_CORE;
                    pDynType->u.SeqCore.Asn1Core.fFlags |= RTASN1CORE_F_PRIMITE_TAG_STRUCT;
                    RTAsn1CursorSkip(pCursor, pDynType->u.Core.cb);
                    return VINF_SUCCESS;
#else
                    pDynType->enmType = RTASN1TYPE_CORE;
#endif
                    break;
                case ASN1_TAG_SET:
#if 0
                    pDynType->enmType = RTASN1TYPE_SET_CORE;
                    pDynType->u.SeqCore.Asn1Core.fFlags |= RTASN1CORE_F_PRIMITE_TAG_STRUCT;
                    RTAsn1CursorSkip(pCursor, pDynType->u.Core.cb);
                    return VINF_SUCCESS;
#else
                    pDynType->enmType = RTASN1TYPE_CORE;
#endif
                    break;
                case ASN1_TAG_OID:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_BAD_TAG, "ASN.1 OBJECT ID shall be primitive.");
                case ASN1_TAG_RELATIVE_OID:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_BAD_TAG, "ASN.1 RELATIVE OID shall be primitive.");

                case ASN1_TAG_UTF8_STRING:
                case ASN1_TAG_NUMERIC_STRING:
                case ASN1_TAG_PRINTABLE_STRING:
                case ASN1_TAG_T61_STRING:
                case ASN1_TAG_VIDEOTEX_STRING:
                case ASN1_TAG_IA5_STRING:
                case ASN1_TAG_GRAPHIC_STRING:
                case ASN1_TAG_VISIBLE_STRING:
                case ASN1_TAG_UNIVERSAL_STRING:
                case ASN1_TAG_GENERAL_STRING:
                case ASN1_TAG_BMP_STRING:
                    pDynType->enmType = RTASN1TYPE_STRING;
                    break;
                //case ASN1_TAG_CHARACTER_STRING:
                //    pDynType->enmType = RTASN1TYPE_CHARACTER_STRING;
                //    break;

                default:
                    RT_ZERO(*pDynType);
                    return RTAsn1CursorSetInfo(pCursor, VERR_ASN1_DYNTYPE_TAG_NOT_IMPL,
                                               "Constructed tag %u (%#x) not implemented.",
                                               pDynType->u.Core.uTag, pDynType->u.Core.uTag);
            }
        else
        {
            RTAsn1CursorSkip(pCursor, pDynType->u.Core.cb);
            return VINF_SUCCESS;
        }

        /*
         * Restore the cursor and redo with specific type.
         */
        pCursor->pbCur  = pbSavedCur;
        pCursor->cbLeft = cbSavedLeft;

        switch (pDynType->enmType)
        {
            case RTASN1TYPE_INTEGER:
                rc = RTAsn1Integer_DecodeAsn1(pCursor, 0, &pDynType->u.Integer, pszErrorTag);
                break;
            case RTASN1TYPE_BOOLEAN:
                rc = RTAsn1Boolean_DecodeAsn1(pCursor, 0, &pDynType->u.Boolean, pszErrorTag);
                break;
            case RTASN1TYPE_OBJID:
                rc = RTAsn1ObjId_DecodeAsn1(pCursor, 0, &pDynType->u.ObjId, pszErrorTag);
                break;
            case RTASN1TYPE_BIT_STRING:
                rc = RTAsn1BitString_DecodeAsn1(pCursor, 0, &pDynType->u.BitString, pszErrorTag);
                break;
            case RTASN1TYPE_OCTET_STRING:
                rc = RTAsn1OctetString_DecodeAsn1(pCursor, 0, &pDynType->u.OctetString, pszErrorTag);
                break;
            case RTASN1TYPE_NULL:
                rc = RTAsn1Null_DecodeAsn1(pCursor, 0, &pDynType->u.Asn1Null, pszErrorTag);
                break;
            case RTASN1TYPE_TIME:
                rc = RTAsn1Time_DecodeAsn1(pCursor, 0, &pDynType->u.Time, pszErrorTag);
                break;
            case RTASN1TYPE_STRING:
                rc = RTAsn1String_DecodeAsn1(pCursor, 0, &pDynType->u.String, pszErrorTag);
                break;
            case RTASN1TYPE_CORE:
                rc = RTAsn1Core_DecodeAsn1(pCursor, 0, &pDynType->u.Core, pszErrorTag);
                break;
            default:
                AssertFailedReturn(VERR_INTERNAL_ERROR_4);
        }
        if (RT_SUCCESS(rc))
            return rc;
    }
    RT_ZERO(*pDynType);
    return rc;
}