Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d74110cd authored by Lajos Molnar's avatar Lajos Molnar
Browse files

stagefright: add include support for MediaCodecList xml parser

One can include full-formed XML files using <Include href=".." />.
For security/simplicity, file names must be in the form of
"media_codecs_.*\.xml"

Change-Id: Id039a4fd0ade390224485fcf5ecc1d107b2bdb9a
parent 8c75ab34
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ private:
        SECTION_DECODER,
        SECTION_ENCODERS,
        SECTION_ENCODER,
        SECTION_INCLUDE,
    };

    struct CodecInfo {
@@ -73,7 +74,9 @@ private:

    status_t mInitCheck;
    Section mCurrentSection;
    Vector<Section> mPastSections;
    int32_t mDepth;
    AString mHrefBase;

    Vector<CodecInfo> mCodecInfos;
    KeyedVector<AString, size_t> mCodecQuirks;
@@ -83,7 +86,8 @@ private:
    ~MediaCodecList();

    status_t initCheck() const;
    void parseXMLFile(FILE *file);
    void parseXMLFile(const char *path);
    void parseTopLevelXMLFile(const char *path);

    static void StartElementHandlerWrapper(
            void *me, const char *name, const char **attrs);
@@ -93,6 +97,7 @@ private:
    void startElementHandler(const char *name, const char **attrs);
    void endElementHandler(const char *name);

    status_t includeXMLFile(const char **attrs);
    status_t addMediaCodecFromAttributes(bool encoder, const char **attrs);
    void addMediaCodec(bool encoder, const char *name, const char *type = NULL);

+104 −38
Original line number Diff line number Diff line
@@ -48,22 +48,43 @@ const MediaCodecList *MediaCodecList::getInstance() {

MediaCodecList::MediaCodecList()
    : mInitCheck(NO_INIT) {
    FILE *file = fopen("/etc/media_codecs.xml", "r");
    parseTopLevelXMLFile("/etc/media_codecs.xml");
}

    if (file == NULL) {
        ALOGW("unable to open media codecs configuration xml file.");
        return;
void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) {
    // get href_base
    char *href_base_end = strrchr(codecs_xml, '/');
    if (href_base_end != NULL) {
        mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1);
    }

    parseXMLFile(file);
    mInitCheck = OK;
    mCurrentSection = SECTION_TOPLEVEL;
    mDepth = 0;

    if (mInitCheck == OK) {
        // These are currently still used by the video editing suite.
    parseXMLFile(codecs_xml);

        addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm");
    if (mInitCheck != OK) {
        mCodecInfos.clear();
        mCodecQuirks.clear();
        return;
    }

    // These are currently still used by the video editing suite.
    addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm");
    addMediaCodec(
            false /* encoder */, "OMX.google.raw.decoder", "audio/raw");

    for (size_t i = mCodecInfos.size(); i-- > 0;) {
        CodecInfo *info = &mCodecInfos.editItemAt(i);

        if (info->mTypes == 0) {
            // No types supported by this component???
            ALOGW("Component %s does not support any type of media?",
                  info->mName.c_str());

            mCodecInfos.removeAt(i);
        }
    }

#if 0
@@ -84,9 +105,6 @@ MediaCodecList::MediaCodecList()
        ALOGI("%s", line.c_str());
    }
#endif

    fclose(file);
    file = NULL;
}

MediaCodecList::~MediaCodecList() {
@@ -96,10 +114,14 @@ status_t MediaCodecList::initCheck() const {
    return mInitCheck;
}

void MediaCodecList::parseXMLFile(FILE *file) {
    mInitCheck = OK;
    mCurrentSection = SECTION_TOPLEVEL;
    mDepth = 0;
void MediaCodecList::parseXMLFile(const char *path) {
    FILE *file = fopen(path, "r");

    if (file == NULL) {
        ALOGW("unable to open media codecs configuration xml file: %s", path);
        mInitCheck = NAME_NOT_FOUND;
        return;
    }

    XML_Parser parser = ::XML_ParserCreate(NULL);
    CHECK(parser != NULL);
@@ -112,7 +134,7 @@ void MediaCodecList::parseXMLFile(FILE *file) {
    while (mInitCheck == OK) {
        void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
        if (buff == NULL) {
            ALOGE("failed to in call to XML_GetBuffer()");
            ALOGE("failed in call to XML_GetBuffer()");
            mInitCheck = UNKNOWN_ERROR;
            break;
        }
@@ -124,8 +146,9 @@ void MediaCodecList::parseXMLFile(FILE *file) {
            break;
        }

        if (::XML_ParseBuffer(parser, bytes_read, bytes_read == 0)
                != XML_STATUS_OK) {
        XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
        if (status != XML_STATUS_OK) {
            ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser)));
            mInitCheck = ERROR_MALFORMED;
            break;
        }
@@ -137,36 +160,60 @@ void MediaCodecList::parseXMLFile(FILE *file) {

    ::XML_ParserFree(parser);

    if (mInitCheck == OK) {
        for (size_t i = mCodecInfos.size(); i-- > 0;) {
            CodecInfo *info = &mCodecInfos.editItemAt(i);
    fclose(file);
    file = NULL;
}

            if (info->mTypes == 0) {
                // No types supported by this component???
// static
void MediaCodecList::StartElementHandlerWrapper(
        void *me, const char *name, const char **attrs) {
    static_cast<MediaCodecList *>(me)->startElementHandler(name, attrs);
}

                ALOGW("Component %s does not support any type of media?",
                      info->mName.c_str());
// static
void MediaCodecList::EndElementHandlerWrapper(void *me, const char *name) {
    static_cast<MediaCodecList *>(me)->endElementHandler(name);
}

                mCodecInfos.removeAt(i);
status_t MediaCodecList::includeXMLFile(const char **attrs) {
    const char *href = NULL;
    size_t i = 0;
    while (attrs[i] != NULL) {
        if (!strcmp(attrs[i], "href")) {
            if (attrs[i + 1] == NULL) {
                return -EINVAL;
            }
            href = attrs[i + 1];
            ++i;
        } else {
            return -EINVAL;
        }
        ++i;
    }

    if (mInitCheck != OK) {
        mCodecInfos.clear();
        mCodecQuirks.clear();
    // For security reasons and for simplicity, file names can only contain
    // [a-zA-Z0-9_.] and must start with  media_codecs_ and end with .xml
    for (i = 0; href[i] != '\0'; i++) {
        if (href[i] == '.' || href[i] == '_' ||
                (href[i] >= '0' && href[i] <= '9') ||
                (href[i] >= 'A' && href[i] <= 'Z') ||
                (href[i] >= 'a' && href[i] <= 'z')) {
            continue;
        }
        ALOGE("invalid include file name: %s", href);
        return -EINVAL;
    }

// static
void MediaCodecList::StartElementHandlerWrapper(
        void *me, const char *name, const char **attrs) {
    static_cast<MediaCodecList *>(me)->startElementHandler(name, attrs);
    AString filename = href;
    if (!filename.startsWith("media_codecs_") ||
        !filename.endsWith(".xml")) {
        ALOGE("invalid include file name: %s", href);
        return -EINVAL;
    }
    filename.insert(mHrefBase, 0);

// static
void MediaCodecList::EndElementHandlerWrapper(void *me, const char *name) {
    static_cast<MediaCodecList *>(me)->endElementHandler(name);
    parseXMLFile(filename.c_str());
    return mInitCheck;
}

void MediaCodecList::startElementHandler(
@@ -175,6 +222,16 @@ void MediaCodecList::startElementHandler(
        return;
    }

    if (!strcmp(name, "Include")) {
        mInitCheck = includeXMLFile(attrs);
        if (mInitCheck == OK) {
            mPastSections.push(mCurrentSection);
            mCurrentSection = SECTION_INCLUDE;
        }
        ++mDepth;
        return;
    }

    switch (mCurrentSection) {
        case SECTION_TOPLEVEL:
        {
@@ -264,6 +321,15 @@ void MediaCodecList::endElementHandler(const char *name) {
            break;
        }

        case SECTION_INCLUDE:
        {
            if (!strcmp(name, "Include") && mPastSections.size() > 0) {
                mCurrentSection = mPastSections.top();
                mPastSections.pop();
            }
            break;
        }

        default:
            break;
    }