11ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/* 21ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 31ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 41ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 51ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * you may not use this file except in compliance with the License. 61ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * You may obtain a copy of the License at 71ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 81ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 91ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Unless required by applicable law or agreed to in writing, software 111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * See the License for the specific language governing permissions and 141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * limitations under the License. 151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */ 161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "ResourceUtils.h" 18ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 19ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <sstream> 20ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 212eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski#include "android-base/stringprintf.h" 22ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "androidfw/ResourceTypes.h" 23929d6517dfd338f0d481dbe6587643d5aef27ec6Adam Lesinski#include "androidfw/ResourceUtils.h" 24ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski 25cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#include "NameMangler.h" 26fb6312fe93a8544e6a95d1c619c8cea3940cbe1aAdam Lesinski#include "SdkConstants.h" 274670805ea441edb8b280f9312571e7799f1284cfAdam Lesinski#include "format/binary/ResourceTypeExtensions.h" 282eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski#include "text/Unicode.h" 292eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski#include "text/Utf8Iterator.h" 30a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski#include "util/Files.h" 311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h" 321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 332eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinskiusing ::aapt::text::Utf8Iterator; 344670805ea441edb8b280f9312571e7799f1284cfAdam Lesinskiusing ::android::StringPiece; 354670805ea441edb8b280f9312571e7799f1284cfAdam Lesinskiusing ::android::StringPiece16; 362eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinskiusing ::android::base::StringPrintf; 37d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski 381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt { 391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace ResourceUtils { 401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 41ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiMaybe<ResourceName> ToResourceName( 42ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const android::ResTable::resource_name& name_in) { 43ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ResourceName name_out; 44ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!name_in.package) { 45cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 46cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 47cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 48ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski name_out.package = 49ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski util::Utf16ToUtf8(StringPiece16(name_in.package, name_in.packageLen)); 50cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 51cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski const ResourceType* type; 52ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (name_in.type) { 53ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski type = ParseResourceType( 54ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski util::Utf16ToUtf8(StringPiece16(name_in.type, name_in.typeLen))); 55ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else if (name_in.type8) { 56ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski type = ParseResourceType(StringPiece(name_in.type8, name_in.typeLen)); 57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 58cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 59cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 60d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski 61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!type) { 62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 63cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 64d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski 65ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski name_out.type = *type; 66d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski 67ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (name_in.name) { 68ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski name_out.entry = 69ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski util::Utf16ToUtf8(StringPiece16(name_in.name, name_in.nameLen)); 70ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else if (name_in.name8) { 71d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski name_out.entry.assign(name_in.name8, name_in.nameLen); 72cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 74cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 75ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return name_out; 76d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski} 77d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski 78ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref, 79ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool* out_private) { 80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (str.empty()) { 81cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 82cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 83cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 84cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski size_t offset = 0; 85cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool priv = false; 86cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (str.data()[0] == '*') { 87cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski priv = true; 88cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski offset = 1; 89cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 90cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 91cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece package; 92cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece type; 93cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece entry; 94929d6517dfd338f0d481dbe6587643d5aef27ec6Adam Lesinski if (!android::ExtractResourceName(str.substr(offset, str.size() - offset), &package, &type, 95929d6517dfd338f0d481dbe6587643d5aef27ec6Adam Lesinski &entry)) { 96cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 97cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 98cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 99ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const ResourceType* parsed_type = ParseResourceType(type); 100ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!parsed_type) { 101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 102cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 1037298bc9c857541b444b2f1639dbed17599cbe5e9Adam Lesinski 104cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (entry.empty()) { 105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 106cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 108ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (out_ref) { 109ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out_ref->package = package; 110ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out_ref->type = *parsed_type; 111ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out_ref->entry = entry; 112cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 113cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 114ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (out_private) { 115ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *out_private = priv; 116cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 117cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 1181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 1191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 120ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ParseReference(const StringPiece& str, ResourceNameRef* out_ref, 121ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool* out_create, bool* out_private) { 122ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece trimmed_str(util::TrimWhitespace(str)); 123ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (trimmed_str.empty()) { 124cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 125cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 12659e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski 127cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool create = false; 128cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool priv = false; 129ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (trimmed_str.data()[0] == '@') { 130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski size_t offset = 1; 131ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (trimmed_str.data()[1] == '+') { 132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski create = true; 133cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski offset += 1; 134467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } 135467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 136cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceNameRef name; 137ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!ParseResourceName( 138ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski trimmed_str.substr(offset, trimmed_str.size() - offset), &name, 139cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski &priv)) { 140cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 141467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } 142467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 143cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (create && priv) { 144cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 145467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } 146467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 147cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (create && name.type != ResourceType::kId) { 148cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 149467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } 150467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 151ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (out_ref) { 152ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *out_ref = name; 153467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } 154467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 155ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (out_create) { 156ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *out_create = create; 157467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski } 158467f171315f9c2037fcd3eb5edcfabc40671bf7bAdam Lesinski 159ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (out_private) { 160ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *out_private = priv; 1611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 162cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 163cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 164cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 1651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 1661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 167ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool IsReference(const StringPiece& str) { 168ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return ParseReference(str, nullptr, nullptr, nullptr); 1692ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski} 1702ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski 171ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool ParseAttributeReference(const StringPiece& str, ResourceNameRef* out_ref) { 172ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece trimmed_str(util::TrimWhitespace(str)); 173ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (trimmed_str.empty()) { 174cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 175cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 176cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 177ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (*trimmed_str.data() == '?') { 178cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece package; 179cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece type; 180cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece entry; 181929d6517dfd338f0d481dbe6587643d5aef27ec6Adam Lesinski if (!android::ExtractResourceName(trimmed_str.substr(1, trimmed_str.size() - 1), &package, 182929d6517dfd338f0d481dbe6587643d5aef27ec6Adam Lesinski &type, &entry)) { 183cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 1841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 1851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 186cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!type.empty() && type != "attr") { 187cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 1881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 189cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 190cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (entry.empty()) { 191cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 192cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 193cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 194ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (out_ref) { 195ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out_ref->package = package; 196ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out_ref->type = ResourceType::kAttr; 197ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out_ref->entry = entry; 198cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 199cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return true; 200cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return false; 2021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 2031ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 204ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool IsAttributeReference(const StringPiece& str) { 205ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return ParseAttributeReference(str, nullptr); 2067298bc9c857541b444b2f1639dbed17599cbe5e9Adam Lesinski} 2077298bc9c857541b444b2f1639dbed17599cbe5e9Adam Lesinski 2081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/* 2091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Style parent's are a bit different. We accept the following formats: 2101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * 21152364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski * @[[*]package:][style/]<entry> 21224b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski * ?[[*]package:]style/<entry> 21324b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski * <[*]package>:[style/]<entry> 21424b8ff0faf7c59323d0171cdd825ca09e712aa1eAdam Lesinski * [[*]package:style/]<entry> 2151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */ 216ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiMaybe<Reference> ParseStyleParentReference(const StringPiece& str, 217ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::string* out_error) { 218cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (str.empty()) { 219cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 220cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 221cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 222cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece name = str; 223cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 224ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool has_leading_identifiers = false; 225ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool private_ref = false; 226cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 227cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Skip over these identifiers. A style's parent is a normal reference. 228cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (name.data()[0] == '@' || name.data()[0] == '?') { 229ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski has_leading_identifiers = true; 230cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski name = name.substr(1, name.size() - 1); 231cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 233cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (name.data()[0] == '*') { 234ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski private_ref = true; 235cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski name = name.substr(1, name.size() - 1); 236cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 237cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 238cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceNameRef ref; 239cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ref.type = ResourceType::kStyle; 240cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 241ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece type_str; 242929d6517dfd338f0d481dbe6587643d5aef27ec6Adam Lesinski android::ExtractResourceName(name, &ref.package, &type_str, &ref.entry); 243ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!type_str.empty()) { 244cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // If we have a type, make sure it is a Style. 245ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const ResourceType* parsed_type = ParseResourceType(type_str); 246ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!parsed_type || *parsed_type != ResourceType::kStyle) { 247cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::stringstream err; 248ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski err << "invalid resource type '" << type_str << "' for parent of style"; 249ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *out_error = err.str(); 250cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 251cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 252cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 253cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 254ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!has_leading_identifiers && ref.package.empty() && !type_str.empty()) { 255cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::stringstream err; 256cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski err << "invalid parent reference '" << str << "'"; 257ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *out_error = err.str(); 258cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 259cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 2601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 261cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Reference result(ref); 262ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski result.private_reference = private_ref; 263cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return result; 2641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 2651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 266ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiMaybe<Reference> ParseXmlAttributeName(const StringPiece& str) { 267ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece trimmed_str = util::TrimWhitespace(str); 268ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const char* start = trimmed_str.data(); 269ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const char* const end = start + trimmed_str.size(); 270cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski const char* p = start; 271cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 272cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski Reference ref; 273cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (p != end && *p == '*') { 274ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski ref.private_reference = true; 275cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski start++; 276cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski p++; 277cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 278cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 279cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece package; 280cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski StringPiece name; 281cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski while (p != end) { 282cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (*p == ':') { 283cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski package = StringPiece(start, p - start); 284cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski name = StringPiece(p + 1, end - (p + 1)); 285cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski break; 286cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 287cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski p++; 288cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 289cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 290d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski ref.name = ResourceName(package, ResourceType::kAttr, name.empty() ? trimmed_str : name); 291cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return Maybe<Reference>(std::move(ref)); 2925eeaaddffd23d8d85aeb321e3ceea626e42cf9deAdam Lesinski} 2935eeaaddffd23d8d85aeb321e3ceea626e42cf9deAdam Lesinski 294ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<Reference> TryParseReference(const StringPiece& str, 295ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool* out_create) { 296cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceNameRef ref; 297ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool private_ref = false; 298ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (ParseReference(str, &ref, out_create, &private_ref)) { 299cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::unique_ptr<Reference> value = util::make_unique<Reference>(ref); 300ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value->private_reference = private_ref; 301cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return value; 302cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 303cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 304ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (ParseAttributeReference(str, &ref)) { 305ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (out_create) { 306ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *out_create = false; 307cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 308cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return util::make_unique<Reference>(ref, Reference::Type::kAttribute); 309cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 310cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 3111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 313bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskistd::unique_ptr<Item> TryParseNullOrEmpty(const StringPiece& str) { 314bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski const StringPiece trimmed_str(util::TrimWhitespace(str)); 315ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (trimmed_str == "@null") { 316bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski return MakeNull(); 317ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else if (trimmed_str == "@empty") { 318bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski return MakeEmpty(); 319cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 320bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski return {}; 321bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski} 322bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski 323bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskistd::unique_ptr<Reference> MakeNull() { 324bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski // TYPE_NULL with data set to 0 is interpreted by the runtime as an error. 325bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski // Instead we set the data type to TYPE_REFERENCE with a value of 0. 326bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski return util::make_unique<Reference>(); 327bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski} 328bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski 329bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskistd::unique_ptr<BinaryPrimitive> MakeEmpty() { 330bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_NULL, 331bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski android::Res_value::DATA_NULL_EMPTY); 3321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 334ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr, 335d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski const StringPiece& str) { 336ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece trimmed_str(util::TrimWhitespace(str)); 337ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (const Attribute::Symbol& symbol : enum_attr->symbols) { 338cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Enum symbols are stored as @package:id/symbol resources, 339cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // so we need to match against the 'entry' part of the identifier. 340ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const ResourceName& enum_symbol_resource_name = symbol.symbol.name.value(); 341ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (trimmed_str == enum_symbol_resource_name.entry) { 342cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::Res_value value = {}; 343cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski value.dataType = android::Res_value::TYPE_INT_DEC; 344cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski value.data = symbol.value; 345cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return util::make_unique<BinaryPrimitive>(value); 346cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 347cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 348cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 3491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 351ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* flag_attr, 352d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski const StringPiece& str) { 353cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::Res_value flags = {}; 354cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski flags.dataType = android::Res_value::TYPE_INT_HEX; 355cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski flags.data = 0u; 356cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 357ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (util::TrimWhitespace(str).empty()) { 358cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Empty string is a valid flag (0). 359cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return util::make_unique<BinaryPrimitive>(flags); 360cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 361cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 362ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (StringPiece part : util::Tokenize(str, '|')) { 363ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece trimmed_part = util::TrimWhitespace(part); 36452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski 365ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski bool flag_set = false; 366ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski for (const Attribute::Symbol& symbol : flag_attr->symbols) { 367cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Flag symbols are stored as @package:id/symbol resources, 368cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // so we need to match against the 'entry' part of the identifier. 369ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const ResourceName& flag_symbol_resource_name = 370ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski symbol.symbol.name.value(); 371ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (trimmed_part == flag_symbol_resource_name.entry) { 372cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski flags.data |= symbol.value; 373ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski flag_set = true; 374cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski break; 375cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 37652364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski } 3771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 378ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (!flag_set) { 379cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 3801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski } 381cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 382cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return util::make_unique<BinaryPrimitive>(flags); 3831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 385ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic uint32_t ParseHex(char c, bool* out_error) { 386cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (c >= '0' && c <= '9') { 387cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return c - '0'; 388cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else if (c >= 'a' && c <= 'f') { 389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return c - 'a' + 0xa; 390cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else if (c >= 'A' && c <= 'F') { 391cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return c - 'A' + 0xa; 392cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 393ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski *out_error = true; 394cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 0xffffffffu; 395cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 3961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 3971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 398ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<BinaryPrimitive> TryParseColor(const StringPiece& str) { 399ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece color_str(util::TrimWhitespace(str)); 400ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const char* start = color_str.data(); 401ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const size_t len = color_str.size(); 402cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (len == 0 || start[0] != '#') { 403cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 404cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 405cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 406cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::Res_value value = {}; 407cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool error = false; 408cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (len == 4) { 409cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski value.dataType = android::Res_value::TYPE_INT_COLOR_RGB4; 410cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski value.data = 0xff000000u; 411ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[1], &error) << 20; 412ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[1], &error) << 16; 413ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[2], &error) << 12; 414ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[2], &error) << 8; 415ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[3], &error) << 4; 416ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[3], &error); 417cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else if (len == 5) { 418cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski value.dataType = android::Res_value::TYPE_INT_COLOR_ARGB4; 419ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[1], &error) << 28; 420ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[1], &error) << 24; 421ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[2], &error) << 20; 422ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[2], &error) << 16; 423ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[3], &error) << 12; 424ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[3], &error) << 8; 425ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[4], &error) << 4; 426ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[4], &error); 427cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else if (len == 7) { 428cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski value.dataType = android::Res_value::TYPE_INT_COLOR_RGB8; 429cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski value.data = 0xff000000u; 430ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[1], &error) << 20; 431ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[2], &error) << 16; 432ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[3], &error) << 12; 433ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[4], &error) << 8; 434ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[5], &error) << 4; 435ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[6], &error); 436cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else if (len == 9) { 437cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski value.dataType = android::Res_value::TYPE_INT_COLOR_ARGB8; 438ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[1], &error) << 28; 439ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[2], &error) << 24; 440ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[3], &error) << 20; 441ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[4], &error) << 16; 442ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[5], &error) << 12; 443ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[6], &error) << 8; 444ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[7], &error) << 4; 445ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski value.data |= ParseHex(start[8], &error); 446cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 447cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 448cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 449cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return error ? std::unique_ptr<BinaryPrimitive>() 450cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski : util::make_unique<BinaryPrimitive>(value); 4511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 4521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 453ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiMaybe<bool> ParseBool(const StringPiece& str) { 454ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece trimmed_str(util::TrimWhitespace(str)); 455ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (trimmed_str == "true" || trimmed_str == "TRUE" || trimmed_str == "True") { 456cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return Maybe<bool>(true); 457ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski } else if (trimmed_str == "false" || trimmed_str == "FALSE" || 458ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski trimmed_str == "False") { 459cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return Maybe<bool>(false); 460cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 461cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 46236c73a595910e96f3552f938eeb81d46356067a1Adam Lesinski} 46336c73a595910e96f3552f938eeb81d46356067a1Adam Lesinski 464ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiMaybe<uint32_t> ParseInt(const StringPiece& str) { 465ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::u16string str16 = util::Utf8ToUtf16(str); 466cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::Res_value value; 467cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) { 468cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return value.data; 469cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 470cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 471b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski} 472b23f1e077b02a1d62bcf5e34655e8dc979e124faAdam Lesinski 473ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiMaybe<ResourceId> ParseResourceId(const StringPiece& str) { 474ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece trimmed_str(util::TrimWhitespace(str)); 475cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 476ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::u16string str16 = util::Utf8ToUtf16(trimmed_str); 477cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::Res_value value; 478cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) { 479cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (value.dataType == android::Res_value::TYPE_INT_HEX) { 480cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski ResourceId id(value.data); 481ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski if (id.is_valid_dynamic()) { 482cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return id; 483cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 484cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 485cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 486cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 487bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski} 488bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski 489ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiMaybe<int> ParseSdkVersion(const StringPiece& str) { 490ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski StringPiece trimmed_str(util::TrimWhitespace(str)); 491cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 492ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::u16string str16 = util::Utf8ToUtf16(trimmed_str); 493cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::Res_value value; 494cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) { 495cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return static_cast<int>(value.data); 496cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 497cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 498cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Try parsing the code name. 499ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski std::pair<StringPiece, int> entry = GetDevelopmentSdkCodeNameAndVersion(); 500ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (entry.first == trimmed_str) { 501cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return entry.second; 502cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 503cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 504fb6312fe93a8544e6a95d1c619c8cea3940cbe1aAdam Lesinski} 505fb6312fe93a8544e6a95d1c619c8cea3940cbe1aAdam Lesinski 506ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<BinaryPrimitive> TryParseBool(const StringPiece& str) { 507ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (Maybe<bool> maybe_result = ParseBool(str)) { 5085924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski const uint32_t data = maybe_result.value() ? 0xffffffffu : 0u; 5095924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, data); 510cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 511cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 5121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 5131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5145924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinskistd::unique_ptr<BinaryPrimitive> MakeBool(bool val) { 5155924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, 5165924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski val ? 0xffffffffu : 0u); 5175924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski} 5185924d8c9ab7bd8614e8bd99864903ce9d50f3bf7Adam Lesinski 519ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<BinaryPrimitive> TryParseInt(const StringPiece& str) { 5208a3bffea4926aa691ea1fbc0e7b67ed954e83d2cAdam Lesinski std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str)); 521cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::Res_value value; 522cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!android::ResTable::stringToInt(str16.data(), str16.size(), &value)) { 523cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 524cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 525cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return util::make_unique<BinaryPrimitive>(value); 5261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 5271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 528d05b9130fdbff8062084b566a380c5b058273d75Shane Farmerstd::unique_ptr<BinaryPrimitive> MakeInt(uint32_t val) { 529d05b9130fdbff8062084b566a380c5b058273d75Shane Farmer return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_DEC, val); 530d05b9130fdbff8062084b566a380c5b058273d75Shane Farmer} 531d05b9130fdbff8062084b566a380c5b058273d75Shane Farmer 532ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<BinaryPrimitive> TryParseFloat(const StringPiece& str) { 5338a3bffea4926aa691ea1fbc0e7b67ed954e83d2cAdam Lesinski std::u16string str16 = util::Utf8ToUtf16(util::TrimWhitespace(str)); 534cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::Res_value value; 535cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (!android::ResTable::stringToFloat(str16.data(), str16.size(), &value)) { 536cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 537cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 538cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return util::make_unique<BinaryPrimitive>(value); 5391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 5401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 541ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiuint32_t AndroidTypeToAttributeTypeMask(uint16_t type) { 542cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski switch (type) { 5431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_NULL: 5441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_REFERENCE: 5451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_ATTRIBUTE: 5461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_DYNAMIC_REFERENCE: 547b5dc4bd49a036e3403ca17e961d2c8e13e038295Adam Lesinski case android::Res_value::TYPE_DYNAMIC_ATTRIBUTE: 548cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return android::ResTable_map::TYPE_REFERENCE; 5491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_STRING: 551cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return android::ResTable_map::TYPE_STRING; 5521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_FLOAT: 554cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return android::ResTable_map::TYPE_FLOAT; 5551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_DIMENSION: 557cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return android::ResTable_map::TYPE_DIMENSION; 5581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_FRACTION: 560cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return android::ResTable_map::TYPE_FRACTION; 5611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_INT_DEC: 5631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_INT_HEX: 564cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return android::ResTable_map::TYPE_INTEGER | 565cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::ResTable_map::TYPE_ENUM | 566cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski android::ResTable_map::TYPE_FLAGS; 5671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_INT_BOOLEAN: 569cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return android::ResTable_map::TYPE_BOOLEAN; 5701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_INT_COLOR_ARGB8: 5721ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_INT_COLOR_RGB8: 5731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_INT_COLOR_ARGB4: 5741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski case android::Res_value::TYPE_INT_COLOR_RGB4: 575cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return android::ResTable_map::TYPE_COLOR; 5761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 5771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski default: 578cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return 0; 579cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski }; 5801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 5811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 582ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<Item> TryParseItemForAttribute( 583ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const StringPiece& value, uint32_t type_mask, 584ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const std::function<void(const ResourceName&)>& on_create_reference) { 585bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski using android::ResTable_map; 586bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski 587bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski auto null_or_empty = TryParseNullOrEmpty(value); 588ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (null_or_empty) { 589bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski return null_or_empty; 590cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 591cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 592cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski bool create = false; 593bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski auto reference = TryParseReference(value, &create); 594cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (reference) { 595ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (create && on_create_reference) { 596ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski on_create_reference(reference->name.value()); 597cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 598cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return std::move(reference); 599cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 600cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 601bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski if (type_mask & ResTable_map::TYPE_COLOR) { 602cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Try parsing this as a color. 603bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski auto color = TryParseColor(value); 604cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (color) { 605cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return std::move(color); 606cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 607cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 608cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 609bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski if (type_mask & ResTable_map::TYPE_BOOLEAN) { 610cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Try parsing this as a boolean. 611bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski auto boolean = TryParseBool(value); 612cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (boolean) { 613cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return std::move(boolean); 614cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 615cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 616cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 617bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski if (type_mask & ResTable_map::TYPE_INTEGER) { 618cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Try parsing this as an integer. 619bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski auto integer = TryParseInt(value); 620cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (integer) { 621cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return std::move(integer); 622cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 623cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 624cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 625bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski const uint32_t float_mask = 626bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski ResTable_map::TYPE_FLOAT | ResTable_map::TYPE_DIMENSION | ResTable_map::TYPE_FRACTION; 627ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (type_mask & float_mask) { 628cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Try parsing this as a float. 629bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski auto floating_point = TryParseFloat(value); 630ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (floating_point) { 631bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski if (type_mask & AndroidTypeToAttributeTypeMask(floating_point->value.dataType)) { 632ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return std::move(floating_point); 633cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 634cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 635cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 636cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 6371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 6381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 6391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/** 6401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * We successively try to parse the string as a resource type that the Attribute 6411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * allows. 6421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */ 643ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistd::unique_ptr<Item> TryParseItemForAttribute( 644cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski const StringPiece& str, const Attribute* attr, 645ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const std::function<void(const ResourceName&)>& on_create_reference) { 646bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski using android::ResTable_map; 647bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski 648ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski const uint32_t type_mask = attr->type_mask; 649bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski auto value = TryParseItemForAttribute(str, type_mask, on_create_reference); 650cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski if (value) { 651cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return value; 652cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 653cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 654bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski if (type_mask & ResTable_map::TYPE_ENUM) { 655cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Try parsing this as an enum. 656bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski auto enum_value = TryParseEnumSymbol(attr, str); 657ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (enum_value) { 658ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return std::move(enum_value); 659cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 660cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 661cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 662bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski if (type_mask & ResTable_map::TYPE_FLAGS) { 663cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski // Try parsing this as a flag. 664bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski auto flag_value = TryParseFlagSymbol(attr, str); 665ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (flag_value) { 666ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski return std::move(flag_value); 667cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 668cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 669cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return {}; 6701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} 6711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski 672bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinskistd::string BuildResourceFileName(const ResourceFile& res_file, const NameMangler* mangler) { 673cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski std::stringstream out; 674ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out << "res/" << res_file.name.type; 675ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (res_file.config != ConfigDescription{}) { 676ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out << "-" << res_file.config; 677cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 678cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski out << "/"; 679cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski 680ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski if (mangler && mangler->ShouldMangle(res_file.name.package)) { 681ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out << NameMangler::MangleEntry(res_file.name.package, res_file.name.entry); 682cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } else { 683ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out << res_file.name.entry; 684cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski } 685ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski out << file::GetExtension(res_file.source.path); 686cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski return out.str(); 687a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 688a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 689d0f492db038c6210c1138865d816bfb134376538Adam Lesinskistd::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, const ConfigDescription& config, 690d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const android::ResStringPool& src_pool, 691d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const android::Res_value& res_value, 692d0f492db038c6210c1138865d816bfb134376538Adam Lesinski StringPool* dst_pool) { 693d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (type == ResourceType::kId) { 694d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return util::make_unique<Id>(); 695d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 696d0f492db038c6210c1138865d816bfb134376538Adam Lesinski 697d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const uint32_t data = util::DeviceToHost32(res_value.data); 698d0f492db038c6210c1138865d816bfb134376538Adam Lesinski switch (res_value.dataType) { 699d0f492db038c6210c1138865d816bfb134376538Adam Lesinski case android::Res_value::TYPE_STRING: { 700d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const std::string str = util::GetString(src_pool, data); 701d0f492db038c6210c1138865d816bfb134376538Adam Lesinski const android::ResStringPool_span* spans = src_pool.styleAt(data); 702d0f492db038c6210c1138865d816bfb134376538Adam Lesinski 703d0f492db038c6210c1138865d816bfb134376538Adam Lesinski // Check if the string has a valid style associated with it. 704d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (spans != nullptr && spans->name.index != android::ResStringPool_span::END) { 705d0f492db038c6210c1138865d816bfb134376538Adam Lesinski StyleString style_str = {str}; 706d0f492db038c6210c1138865d816bfb134376538Adam Lesinski while (spans->name.index != android::ResStringPool_span::END) { 707d0f492db038c6210c1138865d816bfb134376538Adam Lesinski style_str.spans.push_back(Span{util::GetString(src_pool, spans->name.index), 708d0f492db038c6210c1138865d816bfb134376538Adam Lesinski spans->firstChar, spans->lastChar}); 709d0f492db038c6210c1138865d816bfb134376538Adam Lesinski spans++; 710d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 711d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return util::make_unique<StyledString>(dst_pool->MakeRef( 712060b53d0287f9e685fb5b49b52a864ef85315a22Adam Lesinski style_str, StringPool::Context(StringPool::Context::kNormalPriority, config))); 713d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } else { 714d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (type != ResourceType::kString && util::StartsWith(str, "res/")) { 715d0f492db038c6210c1138865d816bfb134376538Adam Lesinski // This must be a FileReference. 716e59f0d80ec19249f72c07ae191ad673d040443e3Adam Lesinski std::unique_ptr<FileReference> file_ref = 717e59f0d80ec19249f72c07ae191ad673d040443e3Adam Lesinski util::make_unique<FileReference>(dst_pool->MakeRef( 718e59f0d80ec19249f72c07ae191ad673d040443e3Adam Lesinski str, StringPool::Context(StringPool::Context::kHighPriority, config))); 71970fdf76c52224217179529be868c47b3194f1551Pierre Lecesne if (type == ResourceType::kRaw) { 72070fdf76c52224217179529be868c47b3194f1551Pierre Lecesne file_ref->type = ResourceFile::Type::kUnknown; 72170fdf76c52224217179529be868c47b3194f1551Pierre Lecesne } else if (util::EndsWith(*file_ref->path, ".xml")) { 722e59f0d80ec19249f72c07ae191ad673d040443e3Adam Lesinski file_ref->type = ResourceFile::Type::kBinaryXml; 723e59f0d80ec19249f72c07ae191ad673d040443e3Adam Lesinski } else if (util::EndsWith(*file_ref->path, ".png")) { 724e59f0d80ec19249f72c07ae191ad673d040443e3Adam Lesinski file_ref->type = ResourceFile::Type::kPng; 725e59f0d80ec19249f72c07ae191ad673d040443e3Adam Lesinski } 726e59f0d80ec19249f72c07ae191ad673d040443e3Adam Lesinski return std::move(file_ref); 727d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 728d0f492db038c6210c1138865d816bfb134376538Adam Lesinski 729d0f492db038c6210c1138865d816bfb134376538Adam Lesinski // There are no styles associated with this string, so treat it as a simple string. 730d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return util::make_unique<String>(dst_pool->MakeRef(str, StringPool::Context(config))); 731d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 732d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } break; 733d0f492db038c6210c1138865d816bfb134376538Adam Lesinski 734d0f492db038c6210c1138865d816bfb134376538Adam Lesinski case android::Res_value::TYPE_REFERENCE: 735d0f492db038c6210c1138865d816bfb134376538Adam Lesinski case android::Res_value::TYPE_ATTRIBUTE: 736d0f492db038c6210c1138865d816bfb134376538Adam Lesinski case android::Res_value::TYPE_DYNAMIC_REFERENCE: 737d0f492db038c6210c1138865d816bfb134376538Adam Lesinski case android::Res_value::TYPE_DYNAMIC_ATTRIBUTE: { 738d0f492db038c6210c1138865d816bfb134376538Adam Lesinski Reference::Type ref_type = Reference::Type::kResource; 739d0f492db038c6210c1138865d816bfb134376538Adam Lesinski if (res_value.dataType == android::Res_value::TYPE_ATTRIBUTE || 740d0f492db038c6210c1138865d816bfb134376538Adam Lesinski res_value.dataType == android::Res_value::TYPE_DYNAMIC_ATTRIBUTE) { 741d0f492db038c6210c1138865d816bfb134376538Adam Lesinski ref_type = Reference::Type::kAttribute; 742d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 743d0f492db038c6210c1138865d816bfb134376538Adam Lesinski 744bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski if (data == 0u) { 745d0f492db038c6210c1138865d816bfb134376538Adam Lesinski // A reference of 0, must be the magic @null reference. 746bab4ef56d7803f3a50ccfaca2729509338fcbb23Adam Lesinski return util::make_unique<Reference>(); 747d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 748d0f492db038c6210c1138865d816bfb134376538Adam Lesinski 749d0f492db038c6210c1138865d816bfb134376538Adam Lesinski // This is a normal reference. 750d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return util::make_unique<Reference>(data, ref_type); 751d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } break; 752d0f492db038c6210c1138865d816bfb134376538Adam Lesinski } 753d0f492db038c6210c1138865d816bfb134376538Adam Lesinski 754d0f492db038c6210c1138865d816bfb134376538Adam Lesinski // Treat this as a raw binary primitive. 755d0f492db038c6210c1138865d816bfb134376538Adam Lesinski return util::make_unique<BinaryPrimitive>(res_value); 756d0f492db038c6210c1138865d816bfb134376538Adam Lesinski} 757d0f492db038c6210c1138865d816bfb134376538Adam Lesinski 7582eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski// Converts the codepoint to UTF-8 and appends it to the string. 7592eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinskistatic bool AppendCodepointToUtf8String(char32_t codepoint, std::string* output) { 7602eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski ssize_t len = utf32_to_utf8_length(&codepoint, 1); 7612eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (len < 0) { 7622eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return false; 7632eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 7642eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 7652eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski const size_t start_append_pos = output->size(); 7662eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 7672eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // Make room for the next character. 7682eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski output->resize(output->size() + len); 7692eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 7702eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski char* dst = &*(output->begin() + start_append_pos); 7712eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski utf32_to_utf8(&codepoint, 1, dst, len + 1); 7722eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return true; 7732eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 7742eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 7752eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski// Reads up to 4 UTF-8 characters that represent a Unicode escape sequence, and appends the 7762eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski// Unicode codepoint represented by the escape sequence to the string. 7772eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinskistatic bool AppendUnicodeEscapeSequence(Utf8Iterator* iter, std::string* output) { 7782eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski char32_t code = 0; 7792eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski for (size_t i = 0; i < 4 && iter->HasNext(); i++) { 7802eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski char32_t codepoint = iter->Next(); 7812eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski char32_t a; 7822eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (codepoint >= U'0' && codepoint <= U'9') { 7832eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski a = codepoint - U'0'; 7842eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } else if (codepoint >= U'a' && codepoint <= U'f') { 7852eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski a = codepoint - U'a' + 10; 7862eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } else if (codepoint >= U'A' && codepoint <= U'F') { 7872eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski a = codepoint - U'A' + 10; 7882eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } else { 7892eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return {}; 7902eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 7912eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski code = (code << 4) | a; 7922eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 7932eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return AppendCodepointToUtf8String(code, output); 7942eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 7952eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 7962eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam LesinskiStringBuilder::StringBuilder(bool preserve_spaces) 7972eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski : preserve_spaces_(preserve_spaces), quote_(preserve_spaces) { 7982eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 7992eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8002eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam LesinskiStringBuilder& StringBuilder::AppendText(const std::string& text) { 8012eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (!error_.empty()) { 8022eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return *this; 8032eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8042eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8052eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski const size_t previous_len = xml_string_.text.size(); 8062eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski Utf8Iterator iter(text); 8072eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski while (iter.HasNext()) { 8082eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski char32_t codepoint = iter.Next(); 8099beaa9cfe3bd8c7c59eed053ff6ca18951c34a86Ryan Mitchell if (!quote_ && iswspace(codepoint)) { 8102eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (!last_codepoint_was_space_) { 8112eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // Emit a space if it's the first. 8122eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski xml_string_.text += ' '; 8132eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski last_codepoint_was_space_ = true; 8142eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8152eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8162eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // Keep eating spaces. 8172eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski continue; 8182eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8192eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8202eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // This is not a space. 8212eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski last_codepoint_was_space_ = false; 8222eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8232eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (codepoint == U'\\') { 8242eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (iter.HasNext()) { 8252eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski codepoint = iter.Next(); 8262eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski switch (codepoint) { 8272eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski case U't': 8282eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski xml_string_.text += '\t'; 8292eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski break; 8302eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8312eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski case U'n': 8322eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski xml_string_.text += '\n'; 8332eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski break; 8342eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8352eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski case U'#': 8362eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski case U'@': 8372eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski case U'?': 8382eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski case U'"': 8392eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski case U'\'': 8402eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski case U'\\': 8412eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski xml_string_.text += static_cast<char>(codepoint); 8422eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski break; 8432eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8442eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski case U'u': 8452eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (!AppendUnicodeEscapeSequence(&iter, &xml_string_.text)) { 8462eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski error_ = 8472eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski StringPrintf("invalid unicode escape sequence in string\n\"%s\"", text.c_str()); 8482eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return *this; 8492eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8502eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski break; 8512eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8522eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski default: 8532eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // Ignore the escape character and just include the codepoint. 8542eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski AppendCodepointToUtf8String(codepoint, &xml_string_.text); 8552eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski break; 8562eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8572eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8582eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } else if (!preserve_spaces_ && codepoint == U'"') { 8592eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // Only toggle the quote state when we are not preserving spaces. 8602eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski quote_ = !quote_; 8612eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8622eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } else if (!quote_ && codepoint == U'\'') { 8632eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // This should be escaped. 8642eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski error_ = StringPrintf("unescaped apostrophe in string\n\"%s\"", text.c_str()); 8652eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return *this; 8662eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8672eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } else { 8682eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski AppendCodepointToUtf8String(codepoint, &xml_string_.text); 8692eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8702eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8712eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8722eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // Accumulate the added string's UTF-16 length. 8732eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(xml_string_.text.c_str()); 8742eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski const size_t utf8_length = xml_string_.text.size(); 8752eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski ssize_t len = utf8_to_utf16_length(utf8_data + previous_len, utf8_length - previous_len); 8762eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (len < 0) { 8772eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski error_ = StringPrintf("invalid unicode code point in string\n\"%s\"", utf8_data + previous_len); 8782eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return *this; 8792eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8802eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8812eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski utf16_len_ += static_cast<uint32_t>(len); 8822eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return *this; 8832eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 8842eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8852eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam LesinskiStringBuilder::SpanHandle StringBuilder::StartSpan(const std::string& name) { 8862eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (!error_.empty()) { 8872eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return 0u; 8882eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 8892eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8902eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // When we start a span, all state associated with whitespace truncation and quotation is ended. 8912eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski ResetTextState(); 8922eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski Span span; 8932eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski span.name = name; 8942eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski span.first_char = span.last_char = utf16_len_; 8952eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski xml_string_.spans.push_back(std::move(span)); 8962eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return xml_string_.spans.size() - 1; 8972eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 8982eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 8992eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinskivoid StringBuilder::EndSpan(SpanHandle handle) { 9002eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (!error_.empty()) { 9012eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return; 9022eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 9032eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 9042eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski // When we end a span, all state associated with whitespace truncation and quotation is ended. 9052eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski ResetTextState(); 9062eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski xml_string_.spans[handle].last_char = utf16_len_ - 1u; 9072eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 9082eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 9092eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam LesinskiStringBuilder::UntranslatableHandle StringBuilder::StartUntranslatable() { 9102eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (!error_.empty()) { 9112eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return 0u; 9122eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 9132eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 9142eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski UntranslatableSection section; 9152eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski section.start = section.end = xml_string_.text.size(); 9162eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski xml_string_.untranslatable_sections.push_back(section); 9172eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return xml_string_.untranslatable_sections.size() - 1; 9182eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 9192eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 9202eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinskivoid StringBuilder::EndUntranslatable(UntranslatableHandle handle) { 9212eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski if (!error_.empty()) { 9222eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return; 9232eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski } 9242eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski xml_string_.untranslatable_sections[handle].end = xml_string_.text.size(); 9252eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 9262eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 9272eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam LesinskiFlattenedXmlString StringBuilder::GetFlattenedString() const { 9282eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return xml_string_; 9292eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 9302eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 9312eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinskistd::string StringBuilder::to_string() const { 9322eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return xml_string_.text; 9332eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 9342eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 9352eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam LesinskiStringBuilder::operator bool() const { 9362eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return error_.empty(); 9372eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 9382eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 9392eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinskistd::string StringBuilder::GetError() const { 9402eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski return error_; 9412eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 9422eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 9432eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinskivoid StringBuilder::ResetTextState() { 9442eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski quote_ = preserve_spaces_; 9452eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski last_codepoint_was_space_ = false; 9462eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski} 9472eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfcAdam Lesinski 948cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} // namespace ResourceUtils 949cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski} // namespace aapt 950