UA_decodeJson(const UA_ByteString *src, void *dst, const UA_DataType *type) {
    
#ifndef UA_ENABLE_TYPEDESCRIPTION
    return UA_STATUSCODE_BADNOTSUPPORTED;
#endif
    
    if(dst == NULL || src == NULL || type == NULL) {
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    }
    
    /* Set up the context */
    CtxJson ctx;
    ParseCtx parseCtx;
    parseCtx.tokenArray = (jsmntok_t*)UA_malloc(sizeof(jsmntok_t) * UA_JSON_MAXTOKENCOUNT);
    if(!parseCtx.tokenArray)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    
    status ret = tokenize(&parseCtx, &ctx, src);
    if(ret != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Assume the top-level element is an object */
    if(parseCtx.tokenCount < 1 || parseCtx.tokenArray[0].type != JSMN_OBJECT) {
        if(parseCtx.tokenCount == 1) {
            if(parseCtx.tokenArray[0].type == JSMN_PRIMITIVE ||
               parseCtx.tokenArray[0].type == JSMN_STRING) {
               /* Only a primitive to parse. Do it directly. */
               memset(dst, 0, type->memSize); /* Initialize the value */
               ret = decodeJsonJumpTable[type->typeKind](dst, type, &ctx, &parseCtx, true);
               goto cleanup;
            }
        }
        ret = UA_STATUSCODE_BADDECODINGERROR;
        goto cleanup;
    }

    /* Decode */
    memset(dst, 0, type->memSize); /* Initialize the value */
    ret = decodeJsonJumpTable[type->typeKind](dst, type, &ctx, &parseCtx, true);

    cleanup:
    UA_free(parseCtx.tokenArray);
    
    /* sanity check if all Tokens were processed */
    if(!(parseCtx.index == parseCtx.tokenCount ||
         parseCtx.index == parseCtx.tokenCount-1)) {
        ret = UA_STATUSCODE_BADDECODINGERROR;
    }
    
    if(ret != UA_STATUSCODE_GOOD)
        UA_deleteMembers(dst, type); /* Clean up */
    return ret;
}
UA_decodeJson(const UA_ByteString *src, void *dst, const UA_DataType *type) {
    
#ifndef UA_ENABLE_TYPEDESCRIPTION
    return UA_STATUSCODE_BADNOTSUPPORTED;
#endif
    
    if(dst == NULL || src == NULL || type == NULL) {
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    }
    
     
    CtxJson ctx;
    ParseCtx parseCtx;
    parseCtx.tokenArray = (jsmntok_t*)UA_malloc(sizeof(jsmntok_t) * UA_JSON_MAXTOKENCOUNT);
    if(!parseCtx.tokenArray)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    
    status ret = tokenize(&parseCtx, &ctx, src);
    if(ret != UA_STATUSCODE_GOOD)
        goto cleanup;

     
    if(parseCtx.tokenCount < 1 || parseCtx.tokenArray[0].type != JSMN_OBJECT) {
        if(parseCtx.tokenCount == 1) {
            if(parseCtx.tokenArray[0].type == JSMN_PRIMITIVE ||
               parseCtx.tokenArray[0].type == JSMN_STRING) {
                
               memset(dst, 0, type->memSize);  
               ret = decodeJsonJumpTable[type->typeKind](dst, type, &ctx, &parseCtx, true);
               goto cleanup;
            }
        }
        ret = UA_STATUSCODE_BADDECODINGERROR;
        goto cleanup;
    }

     
    memset(dst, 0, type->memSize);  
    ret = decodeJsonJumpTable[type->typeKind](dst, type, &ctx, &parseCtx, true);

    cleanup:
    UA_free(parseCtx.tokenArray);
    
     
    if(!(parseCtx.index == parseCtx.tokenCount ||
         parseCtx.index == parseCtx.tokenCount-1)) {
        ret = UA_STATUSCODE_BADDECODINGERROR;
    }
    
    if(ret != UA_STATUSCODE_GOOD)
        UA_deleteMembers(dst, type);  
    return ret;
}