1ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski/*
2ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski * Copyright (C) 2015 The Android Open Source Project
3ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski *
4ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
5ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski * you may not use this file except in compliance with the License.
6ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski * You may obtain a copy of the License at
7ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski *
8ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
9ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski *
10ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski * Unless required by applicable law or agreed to in writing, software
11ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
12ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski * See the License for the specific language governing permissions and
14ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski * limitations under the License.
15ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski */
16ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
17ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski#include "Source.h"
18ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski#include "java/AnnotationProcessor.h"
196cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski#include "java/ClassDefinition.h"
20ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski#include "java/ManifestClassGenerator.h"
21ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski#include "util/Maybe.h"
22467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlDom.h"
23ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
24ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski#include <algorithm>
25ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
26ca5638fd85098c3d0a699492751043545f75553aAdam Lesinskinamespace aapt {
27ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
28ca5638fd85098c3d0a699492751043545f75553aAdam Lesinskistatic Maybe<StringPiece16> extractJavaIdentifier(IDiagnostics* diag, const Source& source,
29ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski                                                  const StringPiece16& value) {
30ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    const StringPiece16 sep = u".";
31ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    auto iter = std::find_end(value.begin(), value.end(), sep.begin(), sep.end());
32ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
33ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    StringPiece16 result;
34ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    if (iter != value.end()) {
35ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        result.assign(iter + sep.size(), value.end() - (iter + sep.size()));
36ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    } else {
37ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        result = value;
38ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
39ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
40ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    if (result.empty()) {
41ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        diag->error(DiagMessage(source) << "empty symbol");
42ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        return {};
43ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
44ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
45ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    iter = util::findNonAlphaNumericAndNotInSet(result, u"_");
46ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    if (iter != result.end()) {
47ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        diag->error(DiagMessage(source)
48ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski                    << "invalid character '" << StringPiece16(iter, 1)
49ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski                    << "' in '" << result << "'");
50ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        return {};
51ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
52ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
53ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    if (*result.begin() >= u'0' && *result.begin() <= u'9') {
54ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        diag->error(DiagMessage(source) << "symbol can not start with a digit");
55ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        return {};
56ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
57ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
58ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    return result;
59ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski}
60ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
616cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinskistatic bool writeSymbol(const Source& source, IDiagnostics* diag, xml::Element* el,
626cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski                        ClassDefinition* classDef) {
632ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski    xml::Attribute* attr = el->findAttribute(xml::kSchemaAndroid, u"name");
64ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    if (!attr) {
65ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        diag->error(DiagMessage(source) << "<" << el->name << "> must define 'android:name'");
66ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        return false;
67ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
68ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
69ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    Maybe<StringPiece16> result = extractJavaIdentifier(diag, source.withLine(el->lineNumber),
70ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski                                                        attr->value);
71ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    if (!result) {
72ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        return false;
73ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
74ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
756cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    std::unique_ptr<StringMember> stringMember = util::make_unique<StringMember>(
766cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski            util::utf16ToUtf8(result.value()), util::utf16ToUtf8(attr->value));
776cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    stringMember->getCommentBuilder()->appendComment(el->comment);
786cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski
796cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    classDef->addMember(std::move(stringMember));
80ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    return true;
81ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski}
82ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
836cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinskistd::unique_ptr<ClassDefinition> generateManifestClass(IDiagnostics* diag, xml::XmlResource* res) {
84ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    xml::Element* el = xml::findRootElement(res->root.get());
85ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    if (!el) {
866cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski        diag->error(DiagMessage(res->file.source) << "no root tag defined");
876cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski        return {};
88ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
89ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
90ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    if (el->name != u"manifest" && !el->namespaceUri.empty()) {
91ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        diag->error(DiagMessage(res->file.source) << "no <manifest> root tag defined");
926cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski        return {};
93ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
94ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
956cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    std::unique_ptr<ClassDefinition> permissionClass =
966cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski            util::make_unique<ClassDefinition>("permission", ClassQualifier::Static, false);
976cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    std::unique_ptr<ClassDefinition> permissionGroupClass =
986cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski            util::make_unique<ClassDefinition>("permission_group", ClassQualifier::Static, false);
99ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
100ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    bool error = false;
101ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
1026cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    std::vector<xml::Element*> children = el->getChildElements();
103ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    for (xml::Element* childEl : children) {
1046cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski        if (childEl->namespaceUri.empty()) {
1056cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski            if (childEl->name == u"permission") {
1066cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski                error |= !writeSymbol(res->file.source, diag, childEl, permissionClass.get());
1076cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski            } else if (childEl->name == u"permission-group") {
1086cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski                error |= !writeSymbol(res->file.source, diag, childEl, permissionGroupClass.get());
1096cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski            }
110ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski        }
111ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
112ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
1136cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    if (error) {
1146cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski        return {};
115ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski    }
116ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
1176cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    std::unique_ptr<ClassDefinition> manifestClass =
1186cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski            util::make_unique<ClassDefinition>("Manifest", ClassQualifier::None, false);
1196cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    manifestClass->addMember(std::move(permissionClass));
1206cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    manifestClass->addMember(std::move(permissionGroupClass));
1216cbfb1de493e42d937158ed57495c9656864ccbaAdam Lesinski    return manifestClass;
122ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski}
123ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski
124ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski} // namespace aapt
125