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

Commit 1fc768da authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Relax error handling in MediaCodecsXmlParser"

parents fd771a4f ea39c524
Loading
Loading
Loading
Loading
+99 −84
Original line number Original line Diff line number Diff line
@@ -92,18 +92,18 @@ bool parseBoolean(const char* s) {
status_t limitFoundMissingAttr(const char* name, const char *attr, bool found = true) {
status_t limitFoundMissingAttr(const char* name, const char *attr, bool found = true) {
    ALOGE("limit '%s' with %s'%s' attribute", name,
    ALOGE("limit '%s' with %s'%s' attribute", name,
            (found ? "" : "no "), attr);
            (found ? "" : "no "), attr);
    return -EINVAL;
    return BAD_VALUE;
}
}


status_t limitError(const char* name, const char *msg) {
status_t limitError(const char* name, const char *msg) {
    ALOGE("limit '%s' %s", name, msg);
    ALOGE("limit '%s' %s", name, msg);
    return -EINVAL;
    return BAD_VALUE;
}
}


status_t limitInvalidAttr(const char* name, const char* attr, const char* value) {
status_t limitInvalidAttr(const char* name, const char* attr, const char* value) {
    ALOGE("limit '%s' with invalid '%s' attribute (%s)", name,
    ALOGE("limit '%s' with invalid '%s' attribute (%s)", name,
            attr, value);
            attr, value);
    return -EINVAL;
    return BAD_VALUE;
}
}


}; // unnamed namespace
}; // unnamed namespace
@@ -232,12 +232,12 @@ status_t MediaCodecsXmlParser::includeXMLFile(const char **attrs) {
    while (attrs[i] != nullptr) {
    while (attrs[i] != nullptr) {
        if (strEq(attrs[i], "href")) {
        if (strEq(attrs[i], "href")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            href = attrs[i];
            href = attrs[i];
        } else {
        } else {
            ALOGE("includeXMLFile: unrecognized attribute: %s", attrs[i]);
            ALOGE("includeXMLFile: unrecognized attribute: %s", attrs[i]);
            return -EINVAL;
            return BAD_VALUE;
        }
        }
        ++i;
        ++i;
    }
    }
@@ -252,32 +252,32 @@ status_t MediaCodecsXmlParser::includeXMLFile(const char **attrs) {
            continue;
            continue;
        }
        }
        ALOGE("invalid include file name: %s", href);
        ALOGE("invalid include file name: %s", href);
        return -EINVAL;
        return BAD_VALUE;
    }
    }


    std::string filename = href;
    std::string filename = href;
    if (filename.compare(0, 13, "media_codecs_") != 0 ||
    if (filename.compare(0, 13, "media_codecs_") != 0 ||
            filename.compare(filename.size() - 4, 4, ".xml") != 0) {
            filename.compare(filename.size() - 4, 4, ".xml") != 0) {
        ALOGE("invalid include file name: %s", href);
        ALOGE("invalid include file name: %s", href);
        return -EINVAL;
        return BAD_VALUE;
    }
    }
    filename.insert(0, mHrefBase);
    filename.insert(0, mHrefBase);


    status_t oldParsingStatus = mParsingStatus;

    parseXMLFile(filename.c_str());
    parseXMLFile(filename.c_str());
    return mParsingStatus;

    status_t newParsingStatus = mParsingStatus;
    mParsingStatus = oldParsingStatus;
    return newParsingStatus;
}
}


void MediaCodecsXmlParser::startElementHandler(
void MediaCodecsXmlParser::startElementHandler(
        const char *name, const char **attrs) {
        const char *name, const char **attrs) {
    if (mParsingStatus != OK) {
        return;
    }

    bool inType = true;
    bool inType = true;


    if (strEq(name, "Include")) {
    if (strEq(name, "Include")) {
        mParsingStatus = includeXMLFile(attrs);
        if (includeXMLFile(attrs) == OK) {
        if (mParsingStatus == OK) {
            mSectionStack.push_back(mCurrentSection);
            mSectionStack.push_back(mCurrentSection);
            mCurrentSection = SECTION_INCLUDE;
            mCurrentSection = SECTION_INCLUDE;
        }
        }
@@ -300,7 +300,7 @@ void MediaCodecsXmlParser::startElementHandler(
        case SECTION_SETTINGS:
        case SECTION_SETTINGS:
        {
        {
            if (strEq(name, "Setting")) {
            if (strEq(name, "Setting")) {
                mParsingStatus = addSettingFromAttributes(attrs);
                (void)addSettingFromAttributes(attrs);
            }
            }
            break;
            break;
        }
        }
@@ -308,9 +308,7 @@ void MediaCodecsXmlParser::startElementHandler(
        case SECTION_DECODERS:
        case SECTION_DECODERS:
        {
        {
            if (strEq(name, "MediaCodec")) {
            if (strEq(name, "MediaCodec")) {
                mParsingStatus =
                (void)addMediaCodecFromAttributes(false /* encoder */, attrs);
                    addMediaCodecFromAttributes(false /* encoder */, attrs);

                mCurrentSection = SECTION_DECODER;
                mCurrentSection = SECTION_DECODER;
            }
            }
            break;
            break;
@@ -319,9 +317,7 @@ void MediaCodecsXmlParser::startElementHandler(
        case SECTION_ENCODERS:
        case SECTION_ENCODERS:
        {
        {
            if (strEq(name, "MediaCodec")) {
            if (strEq(name, "MediaCodec")) {
                mParsingStatus =
                (void)addMediaCodecFromAttributes(true /* encoder */, attrs);
                    addMediaCodecFromAttributes(true /* encoder */, attrs);

                mCurrentSection = SECTION_ENCODER;
                mCurrentSection = SECTION_ENCODER;
            }
            }
            break;
            break;
@@ -331,9 +327,9 @@ void MediaCodecsXmlParser::startElementHandler(
        case SECTION_ENCODER:
        case SECTION_ENCODER:
        {
        {
            if (strEq(name, "Quirk")) {
            if (strEq(name, "Quirk")) {
                mParsingStatus = addQuirk(attrs);
                (void)addQuirk(attrs);
            } else if (strEq(name, "Type")) {
            } else if (strEq(name, "Type")) {
                mParsingStatus = addTypeFromAttributes(attrs,
                (void)addTypeFromAttributes(attrs,
                        (mCurrentSection == SECTION_ENCODER));
                        (mCurrentSection == SECTION_ENCODER));
                mCurrentSection =
                mCurrentSection =
                        (mCurrentSection == SECTION_DECODER ?
                        (mCurrentSection == SECTION_DECODER ?
@@ -353,9 +349,9 @@ void MediaCodecsXmlParser::startElementHandler(
                    (strEq(name, "Limit") || strEq(name, "Feature"))) {
                    (strEq(name, "Limit") || strEq(name, "Feature"))) {
                ALOGW("ignoring %s specified outside of a Type", name);
                ALOGW("ignoring %s specified outside of a Type", name);
            } else if (strEq(name, "Limit")) {
            } else if (strEq(name, "Limit")) {
                mParsingStatus = addLimit(attrs);
                (void)addLimit(attrs);
            } else if (strEq(name, "Feature")) {
            } else if (strEq(name, "Feature")) {
                mParsingStatus = addFeature(attrs);
                (void)addFeature(attrs);
            }
            }
            break;
            break;
        }
        }
@@ -367,10 +363,6 @@ void MediaCodecsXmlParser::startElementHandler(
}
}


void MediaCodecsXmlParser::endElementHandler(const char *name) {
void MediaCodecsXmlParser::endElementHandler(const char *name) {
    if (mParsingStatus != OK) {
        return;
    }

    switch (mCurrentSection) {
    switch (mCurrentSection) {
        case SECTION_SETTINGS:
        case SECTION_SETTINGS:
        {
        {
@@ -452,31 +444,31 @@ status_t MediaCodecsXmlParser::addSettingFromAttributes(const char **attrs) {
        if (strEq(attrs[i], "name")) {
        if (strEq(attrs[i], "name")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addSettingFromAttributes: name is null");
                ALOGE("addSettingFromAttributes: name is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            name = attrs[i];
            name = attrs[i];
        } else if (strEq(attrs[i], "value")) {
        } else if (strEq(attrs[i], "value")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addSettingFromAttributes: value is null");
                ALOGE("addSettingFromAttributes: value is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            value = attrs[i];
            value = attrs[i];
        } else if (strEq(attrs[i], "update")) {
        } else if (strEq(attrs[i], "update")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addSettingFromAttributes: update is null");
                ALOGE("addSettingFromAttributes: update is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            update = attrs[i];
            update = attrs[i];
        } else {
        } else {
            ALOGE("addSettingFromAttributes: unrecognized attribute: %s", attrs[i]);
            ALOGE("addSettingFromAttributes: unrecognized attribute: %s", attrs[i]);
            return -EINVAL;
            return BAD_VALUE;
        }
        }
        ++i;
        ++i;
    }
    }


    if (name == nullptr || value == nullptr) {
    if (name == nullptr || value == nullptr) {
        ALOGE("addSettingFromAttributes: name or value unspecified");
        ALOGE("addSettingFromAttributes: name or value unspecified");
        return -EINVAL;
        return BAD_VALUE;
    }
    }


    // Boolean values are converted to "0" or "1".
    // Boolean values are converted to "0" or "1".
@@ -489,7 +481,7 @@ status_t MediaCodecsXmlParser::addSettingFromAttributes(const char **attrs) {
    if (attribute == mServiceAttributeMap.end()) { // New attribute name
    if (attribute == mServiceAttributeMap.end()) { // New attribute name
        if (mUpdate) {
        if (mUpdate) {
            ALOGE("addSettingFromAttributes: updating non-existing setting");
            ALOGE("addSettingFromAttributes: updating non-existing setting");
            return -EINVAL;
            return BAD_VALUE;
        }
        }
        mServiceAttributeMap.insert(Attribute(name, value));
        mServiceAttributeMap.insert(Attribute(name, value));
    } else { // Existing attribute name
    } else { // Existing attribute name
@@ -513,39 +505,40 @@ status_t MediaCodecsXmlParser::addMediaCodecFromAttributes(
        if (strEq(attrs[i], "name")) {
        if (strEq(attrs[i], "name")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addMediaCodecFromAttributes: name is null");
                ALOGE("addMediaCodecFromAttributes: name is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            name = attrs[i];
            name = attrs[i];
        } else if (strEq(attrs[i], "type")) {
        } else if (strEq(attrs[i], "type")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addMediaCodecFromAttributes: type is null");
                ALOGE("addMediaCodecFromAttributes: type is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            type = attrs[i];
            type = attrs[i];
        } else if (strEq(attrs[i], "update")) {
        } else if (strEq(attrs[i], "update")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addMediaCodecFromAttributes: update is null");
                ALOGE("addMediaCodecFromAttributes: update is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            update = attrs[i];
            update = attrs[i];
        } else {
        } else {
            ALOGE("addMediaCodecFromAttributes: unrecognized attribute: %s", attrs[i]);
            ALOGE("addMediaCodecFromAttributes: unrecognized attribute: %s", attrs[i]);
            return -EINVAL;
            return BAD_VALUE;
        }
        }
        ++i;
        ++i;
    }
    }


    if (name == nullptr) {
    if (name == nullptr) {
        ALOGE("addMediaCodecFromAttributes: name not found");
        ALOGE("addMediaCodecFromAttributes: name not found");
        return -EINVAL;
        return BAD_VALUE;
    }
    }


    mUpdate = (update != nullptr) && parseBoolean(update);
    mUpdate = (update != nullptr) && parseBoolean(update);
    mCurrentCodec = mCodecMap.find(name);
    mCurrentCodec = mCodecMap.find(name);
    if (mCurrentCodec == mCodecMap.end()) { // New codec name
    if (mCurrentCodec == mCodecMap.end()) { // New codec name
        if (mUpdate) {
        if (mUpdate) {
            ALOGE("addMediaCodecFromAttributes: updating non-existing codec");
            ALOGW("addMediaCodecFromAttributes: cannot update "
            return -EINVAL;
                  "non-existing codec \"%s\".", name);
            return BAD_VALUE;
        }
        }
        // Create a new codec in mCodecMap
        // Create a new codec in mCodecMap
        mCurrentCodec = mCodecMap.insert(
        mCurrentCodec = mCodecMap.insert(
@@ -560,18 +553,26 @@ status_t MediaCodecsXmlParser::addMediaCodecFromAttributes(
        mCurrentCodec->second.order = mCodecCounter++;
        mCurrentCodec->second.order = mCodecCounter++;
    } else { // Existing codec name
    } else { // Existing codec name
        if (!mUpdate) {
        if (!mUpdate) {
            ALOGE("addMediaCodecFromAttributes: adding existing codec");
            ALOGW("addMediaCodecFromAttributes: trying to add "
            return -EINVAL;
                  "existing codec \"%s\"", name);
            return ALREADY_EXISTS;
        }
        }
        if (type != nullptr) {
        if (type != nullptr) {
            mCurrentType = mCurrentCodec->second.typeMap.find(type);
            mCurrentType = mCurrentCodec->second.typeMap.find(type);
            if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
            if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
                ALOGE("addMediaCodecFromAttributes: updating non-existing type");
                ALOGE("addMediaCodecFromAttributes: cannot update "
                return -EINVAL;
                      "non-existing type \"%s\" for codec \"%s\"",
                        type, name);
                return BAD_VALUE;
            }
            }
        } else {
        } else {
            // This should happen only when the codec has at most one type.
            // This should happen only when the codec has at most one type.
            mCurrentType = mCurrentCodec->second.typeMap.begin();
            mCurrentType = mCurrentCodec->second.typeMap.begin();
            if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
                ALOGE("addMediaCodecFromAttributes: cannot update "
                      "codec \"%s\" without type specified", name);
                return BAD_VALUE;
            }
        }
        }
    }
    }


@@ -579,6 +580,10 @@ status_t MediaCodecsXmlParser::addMediaCodecFromAttributes(
}
}


status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
    if (mCurrentCodec == mCodecMap.end()) {
        return BAD_VALUE;
    }

    const char *name = nullptr;
    const char *name = nullptr;


    size_t i = 0;
    size_t i = 0;
@@ -586,19 +591,19 @@ status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
        if (strEq(attrs[i], "name")) {
        if (strEq(attrs[i], "name")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addQuirk: name is null");
                ALOGE("addQuirk: name is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            name = attrs[i];
            name = attrs[i];
        } else {
        } else {
            ALOGE("addQuirk: unrecognized attribute: %s", attrs[i]);
            ALOGE("addQuirk: unrecognized attribute: %s", attrs[i]);
            return -EINVAL;
            return BAD_VALUE;
        }
        }
        ++i;
        ++i;
    }
    }


    if (name == nullptr) {
    if (name == nullptr) {
        ALOGE("addQuirk: name not found");
        ALOGE("addQuirk: name not found");
        return -EINVAL;
        return BAD_VALUE;
    }
    }


    mCurrentCodec->second.quirkSet.emplace(name);
    mCurrentCodec->second.quirkSet.emplace(name);
@@ -606,6 +611,10 @@ status_t MediaCodecsXmlParser::addQuirk(const char **attrs) {
}
}


status_t MediaCodecsXmlParser::addTypeFromAttributes(const char **attrs, bool encoder) {
status_t MediaCodecsXmlParser::addTypeFromAttributes(const char **attrs, bool encoder) {
    if (mCurrentCodec == mCodecMap.end()) {
        return BAD_VALUE;
    }

    const char *name = nullptr;
    const char *name = nullptr;
    const char *update = nullptr;
    const char *update = nullptr;


@@ -614,42 +623,51 @@ status_t MediaCodecsXmlParser::addTypeFromAttributes(const char **attrs, bool en
        if (strEq(attrs[i], "name")) {
        if (strEq(attrs[i], "name")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addTypeFromAttributes: name is null");
                ALOGE("addTypeFromAttributes: name is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            name = attrs[i];
            name = attrs[i];
        } else if (strEq(attrs[i], "update")) {
        } else if (strEq(attrs[i], "update")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addTypeFromAttributes: update is null");
                ALOGE("addTypeFromAttributes: update is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            update = attrs[i];
            update = attrs[i];
        } else {
        } else {
            ALOGE("addTypeFromAttributes: unrecognized attribute: %s", attrs[i]);
            ALOGE("addTypeFromAttributes: unrecognized attribute: %s", attrs[i]);
            return -EINVAL;
            return BAD_VALUE;
        }
        }
        ++i;
        ++i;
    }
    }


    if (name == nullptr) {
    if (name == nullptr) {
        return -EINVAL;
        return BAD_VALUE;
    }
    }


    mCurrentCodec->second.isEncoder = encoder;
    mCurrentCodec->second.isEncoder = encoder;
    mCurrentType = mCurrentCodec->second.typeMap.find(name);
    mCurrentType = mCurrentCodec->second.typeMap.find(name);
    if (!mUpdate) {
    if (!mUpdate) {
        if (mCurrentType != mCurrentCodec->second.typeMap.end()) {
        if (mCurrentType != mCurrentCodec->second.typeMap.end()) {
            ALOGE("addTypeFromAttributes: re-defining existing type without update");
            ALOGW("addTypeFromAttributes: trying to update "
            return -EINVAL;
                  "existing type \"%s\"", name);
            return ALREADY_EXISTS;
        }
        }
        mCurrentType = mCurrentCodec->second.typeMap.insert(
        mCurrentType = mCurrentCodec->second.typeMap.insert(
                Type(name, AttributeMap())).first;
                Type(name, AttributeMap())).first;
    } else if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
    } else if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
        ALOGE("addTypeFromAttributes: updating non-existing type");
        ALOGE("addTypeFromAttributes: updating non-existing type");
        return BAD_VALUE;
    }
    }
    return OK;
    return OK;
}
}


status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
    if (mCurrentCodec == mCodecMap.end()) {
        return BAD_VALUE;
    }
    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
        return BAD_VALUE;
    }

    const char* a_name = nullptr;
    const char* a_name = nullptr;
    const char* a_default = nullptr;
    const char* a_default = nullptr;
    const char* a_in = nullptr;
    const char* a_in = nullptr;
@@ -665,78 +683,73 @@ status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
        if (strEq(attrs[i], "name")) {
        if (strEq(attrs[i], "name")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addLimit: name is null");
                ALOGE("addLimit: name is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            a_name = attrs[i];
            a_name = attrs[i];
        } else if (strEq(attrs[i], "default")) {
        } else if (strEq(attrs[i], "default")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addLimit: default is null");
                ALOGE("addLimit: default is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            a_default = attrs[i];
            a_default = attrs[i];
        } else if (strEq(attrs[i], "in")) {
        } else if (strEq(attrs[i], "in")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addLimit: in is null");
                ALOGE("addLimit: in is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            a_in = attrs[i];
            a_in = attrs[i];
        } else if (strEq(attrs[i], "max")) {
        } else if (strEq(attrs[i], "max")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addLimit: max is null");
                ALOGE("addLimit: max is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            a_max = attrs[i];
            a_max = attrs[i];
        } else if (strEq(attrs[i], "min")) {
        } else if (strEq(attrs[i], "min")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addLimit: min is null");
                ALOGE("addLimit: min is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            a_min = attrs[i];
            a_min = attrs[i];
        } else if (strEq(attrs[i], "range")) {
        } else if (strEq(attrs[i], "range")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addLimit: range is null");
                ALOGE("addLimit: range is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            a_range = attrs[i];
            a_range = attrs[i];
        } else if (strEq(attrs[i], "ranges")) {
        } else if (strEq(attrs[i], "ranges")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addLimit: ranges is null");
                ALOGE("addLimit: ranges is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            a_ranges = attrs[i];
            a_ranges = attrs[i];
        } else if (strEq(attrs[i], "scale")) {
        } else if (strEq(attrs[i], "scale")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addLimit: scale is null");
                ALOGE("addLimit: scale is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            a_scale = attrs[i];
            a_scale = attrs[i];
        } else if (strEq(attrs[i], "value")) {
        } else if (strEq(attrs[i], "value")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addLimit: value is null");
                ALOGE("addLimit: value is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            a_value = attrs[i];
            a_value = attrs[i];
        } else {
        } else {
            ALOGE("addLimit: unrecognized limit: %s", attrs[i]);
            ALOGE("addLimit: unrecognized limit: %s", attrs[i]);
            return -EINVAL;
            return BAD_VALUE;
        }
        }
        ++i;
        ++i;
    }
    }


    if (a_name == nullptr) {
    if (a_name == nullptr) {
        ALOGE("limit with no 'name' attribute");
        ALOGE("limit with no 'name' attribute");
        return -EINVAL;
        return BAD_VALUE;
    }
    }


    // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio,
    // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio,
    // measured-frame-rate, measured-blocks-per-second: range
    // measured-frame-rate, measured-blocks-per-second: range
    // quality: range + default + [scale]
    // quality: range + default + [scale]
    // complexity: range + default
    // complexity: range + default
    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
        ALOGW("ignoring null type");
        return OK;
    }

    std::string range;
    std::string range;
    if (strEq(a_name, "aspect-ratio") ||
    if (strEq(a_name, "aspect-ratio") ||
            strEq(a_name, "bitrate") ||
            strEq(a_name, "bitrate") ||
@@ -880,6 +893,13 @@ status_t MediaCodecsXmlParser::addLimit(const char **attrs) {
}
}


status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
    if (mCurrentCodec == mCodecMap.end()) {
        return BAD_VALUE;
    }
    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
        return BAD_VALUE;
    }

    size_t i = 0;
    size_t i = 0;
    const char *name = nullptr;
    const char *name = nullptr;
    int32_t optional = -1;
    int32_t optional = -1;
@@ -890,30 +910,30 @@ status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
        if (strEq(attrs[i], "name")) {
        if (strEq(attrs[i], "name")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addFeature: name is null");
                ALOGE("addFeature: name is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            name = attrs[i];
            name = attrs[i];
        } else if (strEq(attrs[i], "optional")) {
        } else if (strEq(attrs[i], "optional")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addFeature: optional is null");
                ALOGE("addFeature: optional is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            optional = parseBoolean(attrs[i]) ? 1 : 0;
            optional = parseBoolean(attrs[i]) ? 1 : 0;
        } else if (strEq(attrs[i], "required")) {
        } else if (strEq(attrs[i], "required")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addFeature: required is null");
                ALOGE("addFeature: required is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            required = parseBoolean(attrs[i]) ? 1 : 0;
            required = parseBoolean(attrs[i]) ? 1 : 0;
        } else if (strEq(attrs[i], "value")) {
        } else if (strEq(attrs[i], "value")) {
            if (attrs[++i] == nullptr) {
            if (attrs[++i] == nullptr) {
                ALOGE("addFeature: value is null");
                ALOGE("addFeature: value is null");
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            value = attrs[i];
            value = attrs[i];
        } else {
        } else {
            ALOGE("addFeature: unrecognized attribute: %s", attrs[i]);
            ALOGE("addFeature: unrecognized attribute: %s", attrs[i]);
            return -EINVAL;
            return BAD_VALUE;
        }
        }
        ++i;
        ++i;
    }
    }
@@ -921,23 +941,18 @@ status_t MediaCodecsXmlParser::addFeature(const char **attrs) {
    // Every feature must have a name.
    // Every feature must have a name.
    if (name == nullptr) {
    if (name == nullptr) {
        ALOGE("feature with no 'name' attribute");
        ALOGE("feature with no 'name' attribute");
        return -EINVAL;
        return BAD_VALUE;
    }

    if (mCurrentType == mCurrentCodec->second.typeMap.end()) {
        ALOGW("ignoring null type");
        return OK;
    }
    }


    if ((optional != -1) || (required != -1)) {
    if ((optional != -1) || (required != -1)) {
        if (optional == required) {
        if (optional == required) {
            ALOGE("feature '%s' is both/neither optional and required", name);
            ALOGE("feature '%s' is both/neither optional and required", name);
            return -EINVAL;
            return BAD_VALUE;
        }
        }
        if ((optional == 1) || (required == 1)) {
        if ((optional == 1) || (required == 1)) {
            if (value != nullptr) {
            if (value != nullptr) {
                ALOGE("feature '%s' cannot have extra 'value'", name);
                ALOGE("feature '%s' cannot have extra 'value'", name);
                return -EINVAL;
                return BAD_VALUE;
            }
            }
            mCurrentType->second[std::string("feature-") + name] =
            mCurrentType->second[std::string("feature-") + name] =
                    optional == 1 ? "0" : "1";
                    optional == 1 ? "0" : "1";