16f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/* 26f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 36f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 46f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 56f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * you may not use this file except in compliance with the License. 66f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * You may obtain a copy of the License at 76f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 86f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 96f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * 106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Unless required by applicable law or agreed to in writing, software 116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * See the License for the specific language governing permissions and 146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * limitations under the License. 156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 176f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceParser.h" 181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceTable.h" 191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceUtils.h" 206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski#include "ResourceValues.h" 211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ValueVisitor.h" 227ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski#include "util/ImmutableMap.h" 239e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski#include "util/Util.h" 24467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski#include "xml/XmlPullParser.h" 259e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski 267ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski#include <functional> 27769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski#include <sstream> 28769de98f2dd41bfe39a1c9f76aefd1ad58942733Adam Lesinski 296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinskinamespace aapt { 306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskiconstexpr const char16_t* sXliffNamespaceUri = u"urn:oasis:names:tc:xliff:document:1.2"; 326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski/** 3427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski * Returns true if the element is <skip> or <eat-comment> and can be safely ignored. 3527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski */ 3627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinskistatic bool shouldIgnoreElement(const StringPiece16& ns, const StringPiece16& name) { 3727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski return ns.empty() && (name == u"skip" || name == u"eat-comment"); 3827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski} 3927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 407ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskistatic uint32_t parseFormatType(const StringPiece16& piece) { 417ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (piece == u"reference") return android::ResTable_map::TYPE_REFERENCE; 427ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski else if (piece == u"string") return android::ResTable_map::TYPE_STRING; 437ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski else if (piece == u"integer") return android::ResTable_map::TYPE_INTEGER; 447ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski else if (piece == u"boolean") return android::ResTable_map::TYPE_BOOLEAN; 457ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski else if (piece == u"color") return android::ResTable_map::TYPE_COLOR; 467ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski else if (piece == u"float") return android::ResTable_map::TYPE_FLOAT; 477ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION; 487ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski else if (piece == u"fraction") return android::ResTable_map::TYPE_FRACTION; 497ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski else if (piece == u"enum") return android::ResTable_map::TYPE_ENUM; 507ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski else if (piece == u"flags") return android::ResTable_map::TYPE_FLAGS; 517ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return 0; 527ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 537ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 547ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskistatic uint32_t parseFormatAttribute(const StringPiece16& str) { 557ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski uint32_t mask = 0; 567ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski for (StringPiece16 part : util::tokenize(str, u'|')) { 577ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski StringPiece16 trimmedPart = util::trimWhitespace(part); 587ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski uint32_t type = parseFormatType(trimmedPart); 597ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (type == 0) { 607ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return 0; 617ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 627ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mask |= type; 637ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 647ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return mask; 657ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 667ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 677ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski/** 687ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski * A parsed resource ready to be added to the ResourceTable. 697ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski */ 707ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskistruct ParsedResource { 717ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski ResourceName name; 7252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski ConfigDescription config; 73e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski std::string product; 747ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski Source source; 757ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski ResourceId id; 767ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski Maybe<SymbolState> symbolState; 777ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski std::u16string comment; 787ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski std::unique_ptr<Value> value; 797ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski std::list<ParsedResource> childResources; 807ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski}; 817ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 827ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski// Recursively adds resources to the ResourceTable. 8352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinskistatic bool addResourcesToTable(ResourceTable* table, IDiagnostics* diag, ParsedResource* res) { 847656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski StringPiece16 trimmedComment = util::trimWhitespace(res->comment); 857656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski if (trimmedComment.size() != res->comment.size()) { 867656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski // Only if there was a change do we re-assign. 877656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski res->comment = trimmedComment.toString(); 887656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski } 897656554f91b40bc93bf94c89afcad4a9a8ced884Adam Lesinski 907ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (res->symbolState) { 917ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski Symbol symbol; 927ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski symbol.state = res->symbolState.value(); 937ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski symbol.source = res->source; 947ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski symbol.comment = res->comment; 957ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!table->setSymbolState(res->name, res->id, symbol, diag)) { 967ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 977ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 987ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 997ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 1007ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (res->value) { 1017ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // Attach the comment, source and config to the value. 1027ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski res->value->setComment(std::move(res->comment)); 1037ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski res->value->setSource(std::move(res->source)); 1047ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 105e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski if (!table->addResource(res->name, res->id, res->config, res->product, 106e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski std::move(res->value), diag)) { 1077ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 1087ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 1097ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 1107ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 1117ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski bool error = false; 1127ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski for (ParsedResource& child : res->childResources) { 11352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski error |= !addResourcesToTable(table, diag, &child); 1147ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 1157ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return !error; 1167ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 1177ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 1187ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski// Convenient aliases for more readable function calls. 1197ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskienum { 1207ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski kAllowRawString = true, 1217ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski kNoRawString = false 1227ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski}; 1237ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 1241ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source, 1259ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski const ConfigDescription& config, 1269ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski const ResourceParserOptions& options) : 1279ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski mDiag(diag), mTable(table), mSource(source), mConfig(config), mOptions(options) { 1286f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 1296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/** 1316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Build a string from XML that converts nested elements into Span objects. 1326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 133467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::flattenXmlSubtree(xml::XmlPullParser* parser, std::u16string* outRawString, 1346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski StyleString* outStyleString) { 1356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::vector<Span> spanStack; 1366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 137b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski bool error = false; 1386f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski outRawString->clear(); 1396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski outStyleString->spans.clear(); 1406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski util::StringBuilder builder; 1416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski size_t depth = 1; 142467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski while (xml::XmlPullParser::isGoodEvent(parser->next())) { 143467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski const xml::XmlPullParser::Event event = parser->getEvent(); 144467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (event == xml::XmlPullParser::Event::kEndElement) { 1451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!parser->getElementNamespace().empty()) { 1461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // We already warned and skipped the start element, so just skip here too 1471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski continue; 1481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski depth--; 1516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (depth == 0) { 1526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski break; 1536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski spanStack.back().lastChar = builder.str().size(); 1566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski outStyleString->spans.push_back(spanStack.back()); 1576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski spanStack.pop_back(); 1586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 159467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } else if (event == xml::XmlPullParser::Event::kText) { 1606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski outRawString->append(parser->getText()); 1616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski builder.append(parser->getText()); 1626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 163467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } else if (event == xml::XmlPullParser::Event::kStartElement) { 1641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!parser->getElementNamespace().empty()) { 1651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (parser->getElementNamespace() != sXliffNamespaceUri) { 1661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Only warn if this isn't an xliff namespace. 1671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber())) 1681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "skipping element '" 1691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << parser->getElementName() 1701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "' with unknown namespace '" 1711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << parser->getElementNamespace() 1721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "'"); 1731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 1756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski depth++; 1776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Build a span object out of the nested element. 1796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::u16string spanName = parser->getElementName(); 1806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const auto endAttrIter = parser->endAttributes(); 1816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski for (auto attrIter = parser->beginAttributes(); attrIter != endAttrIter; ++attrIter) { 1826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski spanName += u";"; 1836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski spanName += attrIter->name; 1846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski spanName += u"="; 1856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski spanName += attrIter->value; 1866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (builder.str().size() > std::numeric_limits<uint32_t>::max()) { 1891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 1901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "style string '" << builder.str() << "' is too long"); 191b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski error = true; 192b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } else { 193b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski spanStack.push_back(Span{ spanName, static_cast<uint32_t>(builder.str().size()) }); 1946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 196467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } else if (event == xml::XmlPullParser::Event::kComment) { 1976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Skip 1986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else { 1991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski assert(false); 2006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski assert(spanStack.empty() && "spans haven't been fully processed"); 2036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski outStyleString->str = builder.str(); 205b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski return !error; 2066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 208467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parse(xml::XmlPullParser* parser) { 2091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski bool error = false; 2101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const size_t depth = parser->getDepth(); 211467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski while (xml::XmlPullParser::nextChildNode(parser, depth)) { 212467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { 2131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Skip comments and text. 2146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 2156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!parser->getElementNamespace().empty() || parser->getElementName() != u"resources") { 2181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 2191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "root element must be <resources>"); 2206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 2216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error |= !parseResources(parser); 2241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski break; 2251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski }; 2266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 227467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (parser->getEvent() == xml::XmlPullParser::Event::kBadDocument) { 2281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 2291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "xml parser error: " << parser->getLastError()); 2306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 2316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return !error; 2336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 2346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 235467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parseResources(xml::XmlPullParser* parser) { 2369ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski std::set<ResourceName> strippedResources; 2379ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 2381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski bool error = false; 2396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::u16string comment; 2401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const size_t depth = parser->getDepth(); 241467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski while (xml::XmlPullParser::nextChildNode(parser, depth)) { 242467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski const xml::XmlPullParser::Event event = parser->getEvent(); 243467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (event == xml::XmlPullParser::Event::kComment) { 2446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski comment = parser->getComment(); 2456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 2466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 248467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (event == xml::XmlPullParser::Event::kText) { 2496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!util::trimWhitespace(parser->getText()).empty()) { 2501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 2511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "plain text not allowed here"); 2521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 2536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 2556f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2566f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 257467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski assert(event == xml::XmlPullParser::Event::kStartElement); 2586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!parser->getElementNamespace().empty()) { 2606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Skip unknown namespace. 2616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 2626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::u16string elementName = parser->getElementName(); 2651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (elementName == u"skip" || elementName == u"eat-comment") { 2661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski comment = u""; 2676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 2686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 2709ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ParsedResource parsedResource; 27152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski parsedResource.config = mConfig; 2729ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski parsedResource.source = mSource.withLine(parser->getLineNumber()); 273e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski parsedResource.comment = std::move(comment); 2741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 2757751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski // Extract the product name if it exists. 2767751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) { 277e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski parsedResource.product = util::utf16ToUtf8(maybeProduct.value()); 2787751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski } 27927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 2807751afc796842bbb24bfbb19bd0fee4a7b7c8a4eAdam Lesinski // Parse the resource regardless of product. 2817ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!parseResource(parser, &parsedResource)) { 28227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski error = true; 28327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski continue; 28427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 28527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 286e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski if (!addResourcesToTable(mTable, mDiag, &parsedResource)) { 2879ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski error = true; 2889ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski } 2896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 2909ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 2919ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski // Check that we included at least one variant of each stripped resource. 2929ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski for (const ResourceName& strippedResource : strippedResources) { 2939ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski if (!mTable->findResource(strippedResource)) { 2949ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski // Failed to find the resource. 2959ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski mDiag->error(DiagMessage(mSource) << "resource '" << strippedResource << "' " 2969ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski "was filtered out but no product variant remains"); 2979ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski error = true; 2989ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski } 2999ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski } 3009ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 3011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return !error; 3026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 3036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 3047ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3057ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskibool ResourceParser::parseResource(xml::XmlPullParser* parser, ParsedResource* outResource) { 3067ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski struct ItemTypeFormat { 3077ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski ResourceType type; 3087ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski uint32_t format; 3097ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski }; 3107ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3117ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*, ParsedResource*)>; 3127ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3137ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski static const auto elToItemMap = ImmutableMap<std::u16string, ItemTypeFormat>::createPreSorted({ 3147ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"bool", { ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN } }, 3157ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"color", { ResourceType::kColor, android::ResTable_map::TYPE_COLOR } }, 3167ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"dimen", { ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT 3177ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski | android::ResTable_map::TYPE_FRACTION 3187ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski | android::ResTable_map::TYPE_DIMENSION } }, 3197ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"drawable", { ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR } }, 3207ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"fraction", { ResourceType::kFraction, android::ResTable_map::TYPE_FLOAT 3217ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski | android::ResTable_map::TYPE_FRACTION 3227ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski | android::ResTable_map::TYPE_DIMENSION } }, 3237ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"integer", { ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER } }, 3247ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"string", { ResourceType::kString, android::ResTable_map::TYPE_STRING } }, 3257ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski }); 3267ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3277ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski static const auto elToBagMap = ImmutableMap<std::u16string, BagParseFunc>::createPreSorted({ 3287ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"add-resource", std::mem_fn(&ResourceParser::parseAddResource) }, 3297ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"array", std::mem_fn(&ResourceParser::parseArray) }, 3307ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"attr", std::mem_fn(&ResourceParser::parseAttr) }, 3317ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"declare-styleable", std::mem_fn(&ResourceParser::parseDeclareStyleable) }, 3327ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"integer-array", std::mem_fn(&ResourceParser::parseIntegerArray) }, 3337ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"java-symbol", std::mem_fn(&ResourceParser::parseSymbol) }, 3347ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"plurals", std::mem_fn(&ResourceParser::parsePlural) }, 3357ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"public", std::mem_fn(&ResourceParser::parsePublic) }, 3367ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"public-group", std::mem_fn(&ResourceParser::parsePublicGroup) }, 3377ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"string-array", std::mem_fn(&ResourceParser::parseStringArray) }, 3387ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"style", std::mem_fn(&ResourceParser::parseStyle) }, 3397ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski { u"symbol", std::mem_fn(&ResourceParser::parseSymbol) }, 3407ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski }); 3417ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3427ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski std::u16string resourceType = parser->getElementName(); 3437ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3447ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // The value format accepted for this resource. 3457ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski uint32_t resourceFormat = 0u; 3467ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3477ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (resourceType == u"item") { 3487ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // Items have their type encoded in the type attribute. 3497ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) { 3507ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski resourceType = maybeType.value().toString(); 3517ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } else { 3527ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 3537ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "<item> must have a 'type' attribute"); 3547ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 3557ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 3567ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3577ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (Maybe<StringPiece16> maybeFormat = xml::findNonEmptyAttribute(parser, u"format")) { 3587ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // An explicit format for this resource was specified. The resource will retain 3597ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // its type in its name, but the accepted value for this type is overridden. 3607ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski resourceFormat = parseFormatType(maybeFormat.value()); 3617ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!resourceFormat) { 3627ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 3637ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "'" << maybeFormat.value() << "' is an invalid format"); 3647ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 3657ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 3667ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 3677ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 3687ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3697ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // Get the name of the resource. This will be checked later, because not all 3707ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // XML elements require a name. 3717ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name"); 3727ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3737ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (resourceType == u"id") { 3747ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!maybeName) { 3757ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 3767ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "<" << parser->getElementName() << "> missing 'name' attribute"); 3777ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 3787ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 3797ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3807ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.type = ResourceType::kId; 3817ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.entry = maybeName.value().toString(); 3827ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->value = util::make_unique<Id>(); 3837ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return true; 3847ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 3857ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3867ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski const auto itemIter = elToItemMap.find(resourceType); 3877ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (itemIter != elToItemMap.end()) { 3887ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // This is an item, record its type and format and start parsing. 3897ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3907ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!maybeName) { 3917ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 3927ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "<" << parser->getElementName() << "> missing 'name' attribute"); 3937ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 3947ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 3957ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3967ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.type = itemIter->second.type; 3977ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.entry = maybeName.value().toString(); 3987ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 3997ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // Only use the implicit format for this type if it wasn't overridden. 4007ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!resourceFormat) { 4017ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski resourceFormat = itemIter->second.format; 4027ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4037ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 4047ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!parseItem(parser, outResource, resourceFormat)) { 4057ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 4067ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4077ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return true; 4087ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4097ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 4107ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // This might be a bag or something. 4117ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski const auto bagIter = elToBagMap.find(resourceType); 4127ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (bagIter != elToBagMap.end()) { 4137ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // Ensure we have a name (unless this is a <public-group>). 4147ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (resourceType != u"public-group") { 4157ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!maybeName) { 4167ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 4177ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "<" << parser->getElementName() << "> missing 'name' attribute"); 4187ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 4197ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4207ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 4217ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.entry = maybeName.value().toString(); 4227ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4237ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 4247ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // Call the associated parse method. The type will be filled in by the 4257ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // parse func. 4267ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!bagIter->second(this, parser, outResource)) { 4277ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 4287ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4297ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return true; 4307ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4317ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 4327ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // Try parsing the elementName (or type) as a resource. These shall only be 4337ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski // resources like 'layout' or 'xml' and they can only be references. 4347ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski const ResourceType* parsedType = parseResourceType(resourceType); 4357ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (parsedType) { 4367ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!maybeName) { 4377ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 4387ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "<" << parser->getElementName() << "> missing 'name' attribute"); 4397ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 4407ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4417ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 4427ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.type = *parsedType; 4437ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.entry = maybeName.value().toString(); 4447ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->value = parseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString); 4457ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!outResource->value) { 4467ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 4477ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "invalid value for type '" << *parsedType << "'. Expected a reference"); 4487ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 4497ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4507ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return true; 4517ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4527ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 4537ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->warn(DiagMessage(outResource->source) 4547ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "unknown resource type '" << parser->getElementName() << "'"); 4557ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 4567ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 4577ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 4587ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskibool ResourceParser::parseItem(xml::XmlPullParser* parser, ParsedResource* outResource, 4597ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski const uint32_t format) { 4607ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (format == android::ResTable_map::TYPE_STRING) { 4617ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return parseString(parser, outResource); 4627ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4637ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 4647ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->value = parseXml(parser, format, kNoRawString); 4657ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski if (!outResource->value) { 4667ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) << "invalid " << outResource->name.type); 4677ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return false; 4687ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski } 4697ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return true; 4707ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 4716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski/** 4736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * Reads the entire XML subtree and attempts to parse it as some Item, 4746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * with typeMask denoting which items it can be. If allowRawValue is 4756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * true, a RawString is returned if the XML couldn't be parsed as 4766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * an Item. If allowRawValue is false, nullptr is returned in this 4776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski * case. 4786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski */ 479467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskistd::unique_ptr<Item> ResourceParser::parseXml(xml::XmlPullParser* parser, const uint32_t typeMask, 480e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski const bool allowRawValue) { 4816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const size_t beginXmlLine = parser->getLineNumber(); 4826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::u16string rawValue; 4846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski StyleString styleString; 4856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!flattenXmlSubtree(parser, &rawValue, &styleString)) { 4866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return {}; 4876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!styleString.spans.empty()) { 4906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // This can only be a StyledString. 4916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return util::make_unique<StyledString>( 4921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mTable->stringPool.makeRef(styleString, StringPool::Context{ 1, mConfig })); 4936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 4946f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 4956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski auto onCreateReference = [&](const ResourceName& name) { 49624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski // name.package can be empty here, as it will assume the package name of the table. 497e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski std::unique_ptr<Id> id = util::make_unique<Id>(); 498e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski id->setSource(mSource.withLine(beginXmlLine)); 499e4bb9eb5af5b0899dc0921d5580220b20e15bd5aAdam Lesinski mTable->addResource(name, {}, {}, std::move(id), mDiag); 5006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski }; 5016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Process the raw value. 5031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::unique_ptr<Item> processedItem = ResourceUtils::parseItemForAttribute(rawValue, typeMask, 5041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski onCreateReference); 5056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (processedItem) { 50624aad163bc88cb10d2275385e9afc3de7f342d65Adam Lesinski // Fix up the reference. 5071ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (Reference* ref = valueCast<Reference>(processedItem.get())) { 508467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski transformReferenceFromNamespace(parser, u"", ref); 5091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 5106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return processedItem; 5116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 5126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Try making a regular string. 5146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (typeMask & android::ResTable_map::TYPE_STRING) { 5156f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // Use the trimmed, escaped string. 5166f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return util::make_unique<String>( 5171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mTable->stringPool.makeRef(styleString.str, StringPool::Context{ 1, mConfig })); 5186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 5196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (allowRawValue) { 521e78fd617ec60139a973a01925fa7adad31febb39Adam Lesinski // We can't parse this so return a RawString if we are allowed. 5226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return util::make_unique<RawString>( 5231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mTable->stringPool.makeRef(rawValue, StringPool::Context{ 1, mConfig })); 5246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 5256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return {}; 5266f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 5276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 528467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* outResource) { 529b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski bool formatted = true; 530467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (Maybe<StringPiece16> formattedAttr = xml::findAttribute(parser, u"formatted")) { 531b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (!ResourceUtils::tryParseBool(formattedAttr.value(), &formatted)) { 5327ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 5337ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "invalid value for 'formatted'. Must be a boolean"); 534b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski return false; 535b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 536b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 537b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 5389f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski bool translateable = mOptions.translatable; 539467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (Maybe<StringPiece16> translateableAttr = xml::findAttribute(parser, u"translatable")) { 5409f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) { 5417ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 5429f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski << "invalid value for 'translatable'. Must be a boolean"); 543b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski return false; 544b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 545b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 5461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5479ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->value = parseXml(parser, android::ResTable_map::TYPE_STRING, kNoRawString); 5489ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski if (!outResource->value) { 5497ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) << "not a valid string"); 5506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 5516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 552b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 553393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski if (String* stringValue = valueCast<String>(outResource->value.get())) { 554393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski stringValue->setTranslateable(translateable); 555393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 556393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski if (formatted && translateable) { 557b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski if (!util::verifyJavaStringFormat(*stringValue->value)) { 558979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski DiagMessage msg(outResource->source); 559979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski msg << "multiple substitutions specified in non-positional format; " 560979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski "did you mean to add the formatted=\"false\" attribute?"; 561979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski if (mOptions.errorOnPositionalArguments) { 562979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski mDiag->error(msg); 563979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski return false; 564979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski } 565979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski 566979ccb2e6f3f1f7f00a448eb440a85daf033dc9eAdam Lesinski mDiag->warn(msg); 567b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 568b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 569393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski 570393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski } else if (StyledString* stringValue = valueCast<StyledString>(outResource->value.get())) { 571393b5f0d6130d3848dd82075986a5cf40c09ce44Adam Lesinski stringValue->setTranslateable(translateable); 572b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski } 5739ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return true; 5746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 5756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 576467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource) { 577467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type"); 5781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!maybeType) { 5797ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) << "<public> must have a 'type' attribute"); 5806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 5816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 5826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const ResourceType* parsedType = parseResourceType(maybeType.value()); 5846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!parsedType) { 5857ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 5867ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "invalid resource type '" << maybeType.value() << "' in <public>"); 5876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 5886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 5896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 5909ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->name.type = *parsedType; 5916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 592467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (Maybe<StringPiece16> maybeId = xml::findNonEmptyAttribute(parser, u"id")) { 5936f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski android::Res_value val; 5941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski bool result = android::ResTable::stringToInt(maybeId.value().data(), 5951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski maybeId.value().size(), &val); 5969ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ResourceId resourceId(val.data); 5976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!result || !resourceId.isValid()) { 5987ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 5997ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "invalid resource ID '" << maybeId.value() << "' in <public>"); 6006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 6016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 6029ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->id = resourceId; 6036f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 6046f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 6056f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (*parsedType == ResourceType::kId) { 6066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski // An ID marked as public is also the definition of an ID. 6079ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->value = util::make_unique<Id>(); 6086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 6099ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 6109e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski outResource->symbolState = SymbolState::kPublic; 6119e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski return true; 6129e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski} 6139e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski 614467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource) { 615467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type"); 61627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski if (!maybeType) { 6177ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 6187ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "<public-group> must have a 'type' attribute"); 61927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski return false; 62027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 62127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 62227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski const ResourceType* parsedType = parseResourceType(maybeType.value()); 62327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski if (!parsedType) { 6247ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 6257ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "invalid resource type '" << maybeType.value() << "' in <public-group>"); 62627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski return false; 62727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 62827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 629467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeId = xml::findNonEmptyAttribute(parser, u"first-id"); 63027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski if (!maybeId) { 6317ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 6327ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "<public-group> must have a 'first-id' attribute"); 63327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski return false; 63427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 63527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 63627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski android::Res_value val; 63727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski bool result = android::ResTable::stringToInt(maybeId.value().data(), 63827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski maybeId.value().size(), &val); 63927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski ResourceId nextId(val.data); 64027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski if (!result || !nextId.isValid()) { 6417ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 6427ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "invalid resource ID '" << maybeId.value() << "' in <public-group>"); 64327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski return false; 64427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 64527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 64627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski std::u16string comment; 64727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski bool error = false; 64827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski const size_t depth = parser->getDepth(); 649467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski while (xml::XmlPullParser::nextChildNode(parser, depth)) { 650467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (parser->getEvent() == xml::XmlPullParser::Event::kComment) { 65127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski comment = util::trimWhitespace(parser->getComment()).toString(); 65227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski continue; 653467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } else if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { 65427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski // Skip text. 65527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski continue; 65627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 65727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 65827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski const Source itemSource = mSource.withLine(parser->getLineNumber()); 65927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski const std::u16string& elementNamespace = parser->getElementNamespace(); 66027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski const std::u16string& elementName = parser->getElementName(); 66127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski if (elementNamespace.empty() && elementName == u"public") { 662467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name"); 66327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski if (!maybeName) { 66427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski mDiag->error(DiagMessage(itemSource) << "<public> must have a 'name' attribute"); 66527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski error = true; 66627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski continue; 66727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 66827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 669467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (xml::findNonEmptyAttribute(parser, u"id")) { 67027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski mDiag->error(DiagMessage(itemSource) << "'id' is ignored within <public-group>"); 67127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski error = true; 67227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski continue; 67327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 67427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 675467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (xml::findNonEmptyAttribute(parser, u"type")) { 67627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski mDiag->error(DiagMessage(itemSource) << "'type' is ignored within <public-group>"); 67727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski error = true; 67827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski continue; 67927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 68027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 68127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski ParsedResource childResource; 68227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski childResource.name.type = *parsedType; 68327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski childResource.name.entry = maybeName.value().toString(); 68427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski childResource.id = nextId; 68527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski childResource.comment = std::move(comment); 68627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski childResource.source = itemSource; 68727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski childResource.symbolState = SymbolState::kPublic; 68827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski outResource->childResources.push_back(std::move(childResource)); 68927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 69027afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski nextId.id += 1; 69127afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 69227afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } else if (!shouldIgnoreElement(elementNamespace, elementName)) { 69327afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski mDiag->error(DiagMessage(itemSource) << ":" << elementName << ">"); 69427afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski error = true; 69527afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 69627afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski } 69727afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski return !error; 69827afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski} 69927afb9e8894b512b21fcca6ce142f40f1ee16cbbAdam Lesinski 700a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskibool ResourceParser::parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource) { 701467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type"); 7029e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski if (!maybeType) { 7037ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 7047ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "<" << parser->getElementName() << "> must have a 'type' attribute"); 7059e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski return false; 7069e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski } 7079e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski 7089e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski const ResourceType* parsedType = parseResourceType(maybeType.value()); 7099e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski if (!parsedType) { 7107ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) 7117ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski << "invalid resource type '" << maybeType.value() 7129e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski << "' in <" << parser->getElementName() << ">"); 7139e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski return false; 7149e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski } 7159e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski 7169e10ac70155c993e7053323ad36beaea7bf7d54fAdam Lesinski outResource->name.type = *parsedType; 7179ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return true; 7186f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 7196f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 720a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskibool ResourceParser::parseSymbol(xml::XmlPullParser* parser, ParsedResource* outResource) { 721a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (parseSymbolImpl(parser, outResource)) { 722a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski outResource->symbolState = SymbolState::kPrivate; 723a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return true; 724a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 725a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return false; 726a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 727a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 728a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskibool ResourceParser::parseAddResource(xml::XmlPullParser* parser, ParsedResource* outResource) { 729a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (parseSymbolImpl(parser, outResource)) { 730a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski outResource->symbolState = SymbolState::kUndefined; 731a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return true; 732a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 733a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return false; 734a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 735a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 7366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 737467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parseAttr(xml::XmlPullParser* parser, ParsedResource* outResource) { 7389ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return parseAttrImpl(parser, outResource, false); 7396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 7406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 741467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* outResource, 742467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski bool weak) { 7437ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.type = ResourceType::kAttr; 7447ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 74552364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski // Attributes only end up in default configuration. 74652364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski if (outResource->config != ConfigDescription::defaultConfig()) { 74752364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski mDiag->warn(DiagMessage(outResource->source) << "ignoring configuration '" 74852364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski << outResource->config << "' for attribute " << outResource->name); 74952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski outResource->config = ConfigDescription::defaultConfig(); 75052364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski } 75152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 7526f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski uint32_t typeMask = 0; 7536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 754467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeFormat = xml::findAttribute(parser, u"format"); 7551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (maybeFormat) { 7561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski typeMask = parseFormatAttribute(maybeFormat.value()); 7576f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (typeMask == 0) { 7581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 7591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "invalid attribute format '" << maybeFormat.value() << "'"); 7609ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return false; 7616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 7626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 7636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 764a587065721053ad54e34f484868142407d59512dAdam Lesinski Maybe<int32_t> maybeMin, maybeMax; 765a587065721053ad54e34f484868142407d59512dAdam Lesinski 766a587065721053ad54e34f484868142407d59512dAdam Lesinski if (Maybe<StringPiece16> maybeMinStr = xml::findAttribute(parser, u"min")) { 767a587065721053ad54e34f484868142407d59512dAdam Lesinski StringPiece16 minStr = util::trimWhitespace(maybeMinStr.value()); 768a587065721053ad54e34f484868142407d59512dAdam Lesinski if (!minStr.empty()) { 769a587065721053ad54e34f484868142407d59512dAdam Lesinski android::Res_value value; 770a587065721053ad54e34f484868142407d59512dAdam Lesinski if (android::ResTable::stringToInt(minStr.data(), minStr.size(), &value)) { 771a587065721053ad54e34f484868142407d59512dAdam Lesinski maybeMin = static_cast<int32_t>(value.data); 772a587065721053ad54e34f484868142407d59512dAdam Lesinski } 773a587065721053ad54e34f484868142407d59512dAdam Lesinski } 774a587065721053ad54e34f484868142407d59512dAdam Lesinski 775a587065721053ad54e34f484868142407d59512dAdam Lesinski if (!maybeMin) { 776a587065721053ad54e34f484868142407d59512dAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 777a587065721053ad54e34f484868142407d59512dAdam Lesinski << "invalid 'min' value '" << minStr << "'"); 778a587065721053ad54e34f484868142407d59512dAdam Lesinski return false; 779a587065721053ad54e34f484868142407d59512dAdam Lesinski } 780a587065721053ad54e34f484868142407d59512dAdam Lesinski } 781a587065721053ad54e34f484868142407d59512dAdam Lesinski 782a587065721053ad54e34f484868142407d59512dAdam Lesinski if (Maybe<StringPiece16> maybeMaxStr = xml::findAttribute(parser, u"max")) { 783a587065721053ad54e34f484868142407d59512dAdam Lesinski StringPiece16 maxStr = util::trimWhitespace(maybeMaxStr.value()); 784a587065721053ad54e34f484868142407d59512dAdam Lesinski if (!maxStr.empty()) { 785a587065721053ad54e34f484868142407d59512dAdam Lesinski android::Res_value value; 786a587065721053ad54e34f484868142407d59512dAdam Lesinski if (android::ResTable::stringToInt(maxStr.data(), maxStr.size(), &value)) { 787a587065721053ad54e34f484868142407d59512dAdam Lesinski maybeMax = static_cast<int32_t>(value.data); 788a587065721053ad54e34f484868142407d59512dAdam Lesinski } 789a587065721053ad54e34f484868142407d59512dAdam Lesinski } 790a587065721053ad54e34f484868142407d59512dAdam Lesinski 791a587065721053ad54e34f484868142407d59512dAdam Lesinski if (!maybeMax) { 792a587065721053ad54e34f484868142407d59512dAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 793a587065721053ad54e34f484868142407d59512dAdam Lesinski << "invalid 'max' value '" << maxStr << "'"); 794a587065721053ad54e34f484868142407d59512dAdam Lesinski return false; 795a587065721053ad54e34f484868142407d59512dAdam Lesinski } 796a587065721053ad54e34f484868142407d59512dAdam Lesinski } 797a587065721053ad54e34f484868142407d59512dAdam Lesinski 798a587065721053ad54e34f484868142407d59512dAdam Lesinski if ((maybeMin || maybeMax) && (typeMask & android::ResTable_map::TYPE_INTEGER) == 0) { 799a587065721053ad54e34f484868142407d59512dAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 800a587065721053ad54e34f484868142407d59512dAdam Lesinski << "'min' and 'max' can only be used when format='integer'"); 801a587065721053ad54e34f484868142407d59512dAdam Lesinski return false; 802a587065721053ad54e34f484868142407d59512dAdam Lesinski } 803a587065721053ad54e34f484868142407d59512dAdam Lesinski 804abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski struct SymbolComparator { 805abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski bool operator()(const Attribute::Symbol& a, const Attribute::Symbol& b) { 806abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski return a.symbol.name.value() < b.symbol.name.value(); 807abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski } 808abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski }; 809abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski 810abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski std::set<Attribute::Symbol, SymbolComparator> items; 8116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 8121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::u16string comment; 8136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski bool error = false; 8141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const size_t depth = parser->getDepth(); 815467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski while (xml::XmlPullParser::nextChildNode(parser, depth)) { 816467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (parser->getEvent() == xml::XmlPullParser::Event::kComment) { 817ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski comment = util::trimWhitespace(parser->getComment()).toString(); 818ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski continue; 819467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } else if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { 820ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski // Skip text. 8216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 8226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 8236f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 824ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski const Source itemSource = mSource.withLine(parser->getLineNumber()); 8251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementNamespace = parser->getElementNamespace(); 8261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementName = parser->getElementName(); 827ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski if (elementNamespace.empty() && (elementName == u"flag" || elementName == u"enum")) { 8281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (elementName == u"enum") { 8291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (typeMask & android::ResTable_map::TYPE_FLAGS) { 830ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski mDiag->error(DiagMessage(itemSource) 8311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "can not define an <enum>; already defined a <flag>"); 8321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 8331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski continue; 8341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 8351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski typeMask |= android::ResTable_map::TYPE_ENUM; 836ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 8371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else if (elementName == u"flag") { 8381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (typeMask & android::ResTable_map::TYPE_ENUM) { 839ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski mDiag->error(DiagMessage(itemSource) 8401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "can not define a <flag>; already defined an <enum>"); 8411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 8421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski continue; 8431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 8441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski typeMask |= android::ResTable_map::TYPE_FLAGS; 8456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 8466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 8471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (Maybe<Attribute::Symbol> s = parseEnumOrFlagItem(parser, elementName)) { 848abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski Attribute::Symbol& symbol = s.value(); 8499ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ParsedResource childResource; 850abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski childResource.name = symbol.symbol.name.value(); 851ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski childResource.source = itemSource; 8529ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski childResource.value = util::make_unique<Id>(); 8539ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->childResources.push_back(std::move(childResource)); 854ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 855abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski symbol.symbol.setComment(std::move(comment)); 856abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski symbol.symbol.setSource(itemSource); 857abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski 858abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski auto insertResult = items.insert(std::move(symbol)); 859abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski if (!insertResult.second) { 860abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski const Attribute::Symbol& existingSymbol = *insertResult.first; 861abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski mDiag->error(DiagMessage(itemSource) 862abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski << "duplicate symbol '" << existingSymbol.symbol.name.value().entry 863abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski << "'"); 864abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski 865abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski mDiag->note(DiagMessage(existingSymbol.symbol.getSource()) 866abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski << "first defined here"); 867abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski error = true; 868abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski } 8696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } else { 8701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 8716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 872ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski } else if (!shouldIgnoreElement(elementNamespace, elementName)) { 873ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski mDiag->error(DiagMessage(itemSource) << ":" << elementName << ">"); 8746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski error = true; 8756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 876ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 877ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski comment = {}; 8786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 8796f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 8806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (error) { 8819ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return false; 8826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 8836f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 8846f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(weak); 885abf83cbe4f63cd76043aab89cd0e08525560fea2Adam Lesinski attr->symbols = std::vector<Attribute::Symbol>(items.begin(), items.end()); 886ca2fc353c2b07e24e297fdc8426c7abd601d908bAdam Lesinski attr->typeMask = typeMask ? typeMask : uint32_t(android::ResTable_map::TYPE_ANY); 887a587065721053ad54e34f484868142407d59512dAdam Lesinski if (maybeMin) { 888a587065721053ad54e34f484868142407d59512dAdam Lesinski attr->minInt = maybeMin.value(); 889a587065721053ad54e34f484868142407d59512dAdam Lesinski } 890a587065721053ad54e34f484868142407d59512dAdam Lesinski 891a587065721053ad54e34f484868142407d59512dAdam Lesinski if (maybeMax) { 892a587065721053ad54e34f484868142407d59512dAdam Lesinski attr->maxInt = maybeMax.value(); 893a587065721053ad54e34f484868142407d59512dAdam Lesinski } 8949ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->value = std::move(attr); 8959ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return true; 8966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 8976f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 898467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam LesinskiMaybe<Attribute::Symbol> ResourceParser::parseEnumOrFlagItem(xml::XmlPullParser* parser, 8991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const StringPiece16& tag) { 9001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const Source source = mSource.withLine(parser->getLineNumber()); 9011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 902467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name"); 9031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!maybeName) { 9041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(source) << "no attribute 'name' found for tag <" << tag << ">"); 9051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return {}; 9066f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 9076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 908467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeValue = xml::findNonEmptyAttribute(parser, u"value"); 9091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!maybeValue) { 9101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(source) << "no attribute 'value' found for tag <" << tag << ">"); 9111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return {}; 9126f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 9136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 9146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski android::Res_value val; 9151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!android::ResTable::stringToInt(maybeValue.value().data(), 9161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski maybeValue.value().size(), &val)) { 9171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(source) << "invalid value '" << maybeValue.value() 9181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "' for <" << tag << ">; must be an integer"); 9191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return {}; 9206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 9216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 9221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return Attribute::Symbol{ 92352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski Reference(ResourceNameRef({}, ResourceType::kId, maybeName.value())), val.data }; 9246f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 9256f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 926467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskistatic Maybe<Reference> parseXmlAttributeName(StringPiece16 str) { 9276f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski str = util::trimWhitespace(str); 928467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski const char16_t* start = str.data(); 9296f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const char16_t* const end = start + str.size(); 9306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski const char16_t* p = start; 9316f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 932467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Reference ref; 933467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (p != end && *p == u'*') { 934467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski ref.privateReference = true; 935467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski start++; 936467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski p++; 937467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } 938467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 9396f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski StringPiece16 package; 9406f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski StringPiece16 name; 9416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski while (p != end) { 9426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (*p == u':') { 9436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski package = StringPiece16(start, p - start); 9446f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski name = StringPiece16(p + 1, end - (p + 1)); 9456f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski break; 9466f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 9476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski p++; 9486f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 9496f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 950467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski ref.name = ResourceName(package.toString(), ResourceType::kAttr, 951ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski name.empty() ? str.toString() : name.toString()); 952467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski return Maybe<Reference>(std::move(ref)); 9536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 9546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 955467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parseStyleItem(xml::XmlPullParser* parser, Style* style) { 9561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const Source source = mSource.withLine(parser->getLineNumber()); 9571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 958467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name"); 9591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!maybeName) { 9601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(source) << "<item> must have a 'name' attribute"); 9616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 9626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 9636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 964467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<Reference> maybeKey = parseXmlAttributeName(maybeName.value()); 9651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!maybeKey) { 9661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(source) << "invalid attribute name '" << maybeName.value() << "'"); 9676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 9686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 9696f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 970467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski transformReferenceFromNamespace(parser, u"", &maybeKey.value()); 97128cacf091ad2b1c2749e77f590e9523e58735252Adam Lesinski maybeKey.value().setSource(source); 9726f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 9736f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::unique_ptr<Item> value = parseXml(parser, 0, kAllowRawString); 9746f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (!value) { 9751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(source) << "could not parse style item"); 9766f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 9776f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 9786f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 979467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski style->entries.push_back(Style::Entry{ std::move(maybeKey.value()), std::move(value) }); 9806f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return true; 9816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 9826f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 983467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource) { 9847ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.type = ResourceType::kStyle; 9857ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 986bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski std::unique_ptr<Style> style = util::make_unique<Style>(); 9876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 988467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeParent = xml::findAttribute(parser, u"parent"); 9891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (maybeParent) { 9901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // If the parent is empty, we don't have a parent, but we also don't infer either. 9911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!maybeParent.value().empty()) { 9921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::string errStr; 9931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski style->parent = ResourceUtils::parseStyleParentReference(maybeParent.value(), &errStr); 9941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!style->parent) { 9957ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski mDiag->error(DiagMessage(outResource->source) << errStr); 9961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski return false; 9971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 9986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 999467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski // Transform the namespace prefix to the actual package name, and mark the reference as 1000467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski // private if appropriate. 1001467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski transformReferenceFromNamespace(parser, u"", &style->parent.value()); 10026f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1004bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski } else { 1005bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski // No parent was specified, so try inferring it from the style name. 10069ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski std::u16string styleName = outResource->name.entry; 1007bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski size_t pos = styleName.find_last_of(u'.'); 1008bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski if (pos != std::string::npos) { 1009bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski style->parentInferred = true; 1010467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski style->parent = Reference(ResourceName({}, ResourceType::kStyle, 1011467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski styleName.substr(0, pos))); 1012bdaa092a193d8ddccbd9ad8434be97878e6ded59Adam Lesinski } 10136f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10146f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 10151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski bool error = false; 10161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const size_t depth = parser->getDepth(); 1017467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski while (xml::XmlPullParser::nextChildNode(parser, depth)) { 1018467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { 10191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Skip text and comments. 10206f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 10216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10226f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 10231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementNamespace = parser->getElementNamespace(); 10241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementName = parser->getElementName(); 10251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (elementNamespace == u"" && elementName == u"item") { 10261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error |= !parseStyleItem(parser, style.get()); 10271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1028ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski } else if (!shouldIgnoreElement(elementNamespace, elementName)) { 10291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 10301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << ":" << elementName << ">"); 10311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 10326f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 10351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (error) { 10366f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 10376f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10389ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 10399ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->value = std::move(style); 10409ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return true; 10416f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 10426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 10437ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskibool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outResource) { 10447ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_ANY); 10457ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 10467ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 10477ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskibool ResourceParser::parseIntegerArray(xml::XmlPullParser* parser, ParsedResource* outResource) { 10487ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_INTEGER); 10497ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 10507ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 10517ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskibool ResourceParser::parseStringArray(xml::XmlPullParser* parser, ParsedResource* outResource) { 10527ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_STRING); 10537ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski} 10547ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 10557ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinskibool ResourceParser::parseArrayImpl(xml::XmlPullParser* parser, ParsedResource* outResource, 10567ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski const uint32_t typeMask) { 10577ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.type = ResourceType::kArray; 10587ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 10596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::unique_ptr<Array> array = util::make_unique<Array>(); 10606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 10616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski bool error = false; 10621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const size_t depth = parser->getDepth(); 1063467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski while (xml::XmlPullParser::nextChildNode(parser, depth)) { 1064467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { 10651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Skip text and comments. 10666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 10676f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10686f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 10691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const Source itemSource = mSource.withLine(parser->getLineNumber()); 10701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementNamespace = parser->getElementNamespace(); 10711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementName = parser->getElementName(); 10721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (elementNamespace.empty() && elementName == u"item") { 10731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::unique_ptr<Item> item = parseXml(parser, typeMask, kNoRawString); 10741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!item) { 10751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(itemSource) << "could not parse array item"); 10761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 10771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski continue; 10781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1079ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski item->setSource(itemSource); 10801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski array->items.emplace_back(std::move(item)); 10816f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1082ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski } else if (!shouldIgnoreElement(elementNamespace, elementName)) { 10831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) 10841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "unknown tag <" << elementNamespace << ":" << elementName << ">"); 10856f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski error = true; 10866f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10876f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10886f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 10896f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski if (error) { 10906f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 10916f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 10929ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 10939ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->value = std::move(array); 10949ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return true; 10956f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 10966f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1097467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinskibool ResourceParser::parsePlural(xml::XmlPullParser* parser, ParsedResource* outResource) { 10987ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.type = ResourceType::kPlurals; 10997ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 11006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski std::unique_ptr<Plural> plural = util::make_unique<Plural>(); 11016f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 11021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski bool error = false; 11031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const size_t depth = parser->getDepth(); 1104467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski while (xml::XmlPullParser::nextChildNode(parser, depth)) { 1105467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { 11061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski // Skip text and comments. 11076f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 11086f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 11096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1110ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski const Source itemSource = mSource.withLine(parser->getLineNumber()); 11111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementNamespace = parser->getElementNamespace(); 11121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementName = parser->getElementName(); 11131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (elementNamespace.empty() && elementName == u"item") { 1114467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeQuantity = xml::findNonEmptyAttribute(parser, u"quantity"); 1115467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (!maybeQuantity) { 1116ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski mDiag->error(DiagMessage(itemSource) << "<item> in <plurals> requires attribute " 11171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "'quantity'"); 11181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 11191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski continue; 11201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 11216f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1122467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski StringPiece16 trimmedQuantity = util::trimWhitespace(maybeQuantity.value()); 11231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski size_t index = 0; 11241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (trimmedQuantity == u"zero") { 11251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski index = Plural::Zero; 11261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else if (trimmedQuantity == u"one") { 11271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski index = Plural::One; 11281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else if (trimmedQuantity == u"two") { 11291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski index = Plural::Two; 11301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else if (trimmedQuantity == u"few") { 11311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski index = Plural::Few; 11321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else if (trimmedQuantity == u"many") { 11331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski index = Plural::Many; 11341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else if (trimmedQuantity == u"other") { 11351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski index = Plural::Other; 11361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } else { 1137ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski mDiag->error(DiagMessage(itemSource) 11381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "<item> in <plural> has invalid value '" << trimmedQuantity 11391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "' for attribute 'quantity'"); 11401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 11411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski continue; 11421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 11436f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 11441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (plural->values[index]) { 1145ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski mDiag->error(DiagMessage(itemSource) 11461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << "duplicate quantity '" << trimmedQuantity << "'"); 11471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 11481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski continue; 11491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 11506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 11511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (!(plural->values[index] = parseXml(parser, android::ResTable_map::TYPE_STRING, 11521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski kNoRawString))) { 11531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 11541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1155ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski plural->values[index]->setSource(itemSource); 1156ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 1157ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski } else if (!shouldIgnoreElement(elementNamespace, elementName)) { 1158ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski mDiag->error(DiagMessage(itemSource) << "unknown tag <" << elementNamespace << ":" 11591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << elementName << ">"); 11601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 11616f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 11626f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 11636f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 11641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (error) { 11656f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 11666f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 11679ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 11689ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->value = std::move(plural); 11699ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return true; 11706f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 11716f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 117252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinskibool ResourceParser::parseDeclareStyleable(xml::XmlPullParser* parser, 117352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski ParsedResource* outResource) { 11747ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski outResource->name.type = ResourceType::kStyleable; 11756f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1176b274e35abfbbd09e0fce983a215c11522c56cce2Adam Lesinski // Declare-styleable is kPrivate by default, because it technically only exists in R.java. 11779f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski outResource->symbolState = SymbolState::kPublic; 11789f22204c3a9ddac4f92573c9ab098e6cf3ed1cb4Adam Lesinski 117952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski // Declare-styleable only ends up in default config; 118052364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski if (outResource->config != ConfigDescription::defaultConfig()) { 118152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski mDiag->warn(DiagMessage(outResource->source) << "ignoring configuration '" 118252364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski << outResource->config << "' for styleable " 118352364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski << outResource->name.entry); 118452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski outResource->config = ConfigDescription::defaultConfig(); 118552364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski } 118652364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 11877ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); 11887ff3ee19f4b831a526baf4b928d1ac172d070d82Adam Lesinski 11891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski std::u16string comment; 11901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski bool error = false; 11911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const size_t depth = parser->getDepth(); 1192467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski while (xml::XmlPullParser::nextChildNode(parser, depth)) { 1193467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (parser->getEvent() == xml::XmlPullParser::Event::kComment) { 1194ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski comment = util::trimWhitespace(parser->getComment()).toString(); 1195ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski continue; 1196467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } else if (parser->getEvent() != xml::XmlPullParser::Event::kStartElement) { 1197ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski // Ignore text. 11986f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 11996f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 12006f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1201ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski const Source itemSource = mSource.withLine(parser->getLineNumber()); 12021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementNamespace = parser->getElementNamespace(); 12031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski const std::u16string& elementName = parser->getElementName(); 12041ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (elementNamespace.empty() && elementName == u"attr") { 1205467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name"); 1206467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (!maybeName) { 1207ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski mDiag->error(DiagMessage(itemSource) << "<attr> tag must have a 'name' attribute"); 12081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 12096f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 12106f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 12116f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1212467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski // If this is a declaration, the package name may be in the name. Separate these out. 1213467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski // Eg. <attr name="android:text" /> 1214467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Maybe<Reference> maybeRef = parseXmlAttributeName(maybeName.value()); 1215467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski if (!maybeRef) { 1216467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski mDiag->error(DiagMessage(itemSource) << "<attr> tag has invalid name '" 1217467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski << maybeName.value() << "'"); 1218467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski error = true; 1219467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski continue; 1220467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } 1221467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 1222467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski Reference& childRef = maybeRef.value(); 1223467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski xml::transformReferenceFromNamespace(parser, u"", &childRef); 1224467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 1225ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski // Create the ParsedResource that will add the attribute to the table. 12269ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski ParsedResource childResource; 1227467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski childResource.name = childRef.name.value(); 1228ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski childResource.source = itemSource; 1229ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski childResource.comment = std::move(comment); 12306f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 12319ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski if (!parseAttrImpl(parser, &childResource, true)) { 12321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 12336f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski continue; 12346f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 12356f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1236ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski // Create the reference to this attribute. 1237ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski childRef.setComment(childResource.comment); 1238ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski childRef.setSource(itemSource); 1239ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski styleable->entries.push_back(std::move(childRef)); 12401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 1241ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski outResource->childResources.push_back(std::move(childResource)); 12426f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 1243ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski } else if (!shouldIgnoreElement(elementNamespace, elementName)) { 1244ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski mDiag->error(DiagMessage(itemSource) << "unknown tag <" << elementNamespace << ":" 12451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski << elementName << ">"); 12461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski error = true; 12476f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 1248ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski 1249ca5638fd85098c3d0a699492751043545f75553aAdam Lesinski comment = {}; 12506f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 12516f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 12521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski if (error) { 12536f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski return false; 12546f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski } 12559ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski 12569ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski outResource->value = std::move(styleable); 12579ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski return true; 12586f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} 12596f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski 12606f6ceb7e1456698b1f33e04536bfb3227f9fcfcbAdam Lesinski} // namespace aapt 1261