bool tryParseAttributeReference(const StringPiece16& str, ResourceNameRef* outRef) {
    StringPiece16 trimmedStr(util::trimWhitespace(str));
    if (trimmedStr.empty()) {
        return false;
    }

    if (*trimmedStr.data() == u'?') {
        StringPiece16 package;
        StringPiece16 type;
        StringPiece16 entry;
        if (!extractResourceName(trimmedStr.substr(1, trimmedStr.size() - 1),
                                 &package, &type, &entry)) {
            return false;
        }

        if (!type.empty() && type != u"attr") {
            return false;
        }

        if (entry.empty()) {
            return false;
        }

        if (outRef) {
            outRef->package = package;
            outRef->type = ResourceType::kAttr;
            outRef->entry = entry;
        }
        return true;
    }
    return false;
}
/*
 * Style parent's are a bit different. We accept the following formats:
 *
 * @[[*]package:][style/]<entry>
 * ?[[*]package:]style/<entry>
 * <[*]package>:[style/]<entry>
 * [[*]package:style/]<entry>
 */
Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string* outError) {
    if (str.empty()) {
        return {};
    }

    StringPiece16 name = str;

    bool hasLeadingIdentifiers = false;
    bool privateRef = false;

    // Skip over these identifiers. A style's parent is a normal reference.
    if (name.data()[0] == u'@' || name.data()[0] == u'?') {
        hasLeadingIdentifiers = true;
        name = name.substr(1, name.size() - 1);
    }

    if (name.data()[0] == u'*') {
        privateRef = true;
        name = name.substr(1, name.size() - 1);
    }

    ResourceNameRef ref;
    ref.type = ResourceType::kStyle;

    StringPiece16 typeStr;
    extractResourceName(name, &ref.package, &typeStr, &ref.entry);
    if (!typeStr.empty()) {
        // If we have a type, make sure it is a Style.
        const ResourceType* parsedType = parseResourceType(typeStr);
        if (!parsedType || *parsedType != ResourceType::kStyle) {
            std::stringstream err;
            err << "invalid resource type '" << typeStr << "' for parent of style";
            *outError = err.str();
            return {};
        }
    }

    if (!hasLeadingIdentifiers && ref.package.empty() && !typeStr.empty()) {
        std::stringstream err;
        err << "invalid parent reference '" << str << "'";
        *outError = err.str();
        return {};
    }

    Reference result(ref);
    result.privateReference = privateRef;
    return result;
}
bool parseResourceName(const StringPiece16& str, ResourceNameRef* outRef, bool* outPrivate) {
    if (str.empty()) {
        return false;
    }

    size_t offset = 0;
    bool priv = false;
    if (str.data()[0] == u'*') {
        priv = true;
        offset = 1;
    }

    StringPiece16 package;
    StringPiece16 type;
    StringPiece16 entry;
    if (!extractResourceName(str.substr(offset, str.size() - offset), &package, &type, &entry)) {
        return false;
    }

    const ResourceType* parsedType = parseResourceType(type);
    if (!parsedType) {
        return false;
    }

    if (entry.empty()) {
        return false;
    }

    if (outRef) {
        outRef->package = package;
        outRef->type = *parsedType;
        outRef->entry = entry;
    }

    if (outPrivate) {
        *outPrivate = priv;
    }
    return true;
}
Esempio n. 4
0
Maybe<std::u16string> getFullyQualifiedClassName(const StringPiece16& package,
                                                 const StringPiece16& className) {
    if (className.empty()) {
        return {};
    }

    if (util::isJavaClassName(className)) {
        return className.toString();
    }

    if (package.empty()) {
        return {};
    }

    std::u16string result(package.data(), package.size());
    if (className.data()[0] != u'.') {
        result += u'.';
    }
    result.append(className.data(), className.size());
    if (!isJavaClassName(result)) {
        return {};
    }
    return result;
}