blob: 71919fdbb7361c9f043227419cf43988d70af33b [file] [log] [blame]
Adam Lesinski4452e132016-10-12 07:47:28 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Adam Lesinski4452e132016-10-12 07:47:28 -070017#include "androidfw/AttributeResolution.h"
Adam Lesinski4c67a472016-11-10 16:43:59 -080018
19#include <cstdint>
Adam Lesinski4452e132016-10-12 07:47:28 -070020
Mark Salyzyn6f773a02016-09-28 16:15:30 -070021#include <log/log.h>
Adam Lesinski4c67a472016-11-10 16:43:59 -080022
Adam Lesinskibebfcc42018-02-12 14:27:46 -080023#include "androidfw/AssetManager2.h"
Adam Lesinski4c67a472016-11-10 16:43:59 -080024#include "androidfw/AttributeFinder.h"
Adam Lesinski4452e132016-10-12 07:47:28 -070025
26constexpr bool kDebugStyles = false;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -070027#define DEBUG_LOG(...) do { if (kDebugStyles) { ALOGI(__VA_ARGS__); } } while(0)
Adam Lesinski4452e132016-10-12 07:47:28 -070028
29namespace android {
30
Ryan Mitchellc75c2e02020-08-17 08:42:48 -070031namespace {
32
Adam Lesinskibebfcc42018-02-12 14:27:46 -080033// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
34static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
35 return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1);
36}
37
Adam Lesinski4c67a472016-11-10 16:43:59 -080038class XmlAttributeFinder
39 : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
Adam Lesinski7a37b742016-10-12 14:05:55 -070040 public:
41 explicit XmlAttributeFinder(const ResXMLParser* parser)
Adam Lesinski4c67a472016-11-10 16:43:59 -080042 : BackTrackingAttributeFinder(
43 0, parser != nullptr ? parser->getAttributeCount() : 0),
Adam Lesinski7a37b742016-10-12 14:05:55 -070044 parser_(parser) {}
Adam Lesinski4452e132016-10-12 07:47:28 -070045
Adam Lesinski4c67a472016-11-10 16:43:59 -080046 inline uint32_t GetAttribute(size_t index) const {
47 return parser_->getAttributeNameResID(index);
48 }
Adam Lesinski4452e132016-10-12 07:47:28 -070049
Adam Lesinski7a37b742016-10-12 14:05:55 -070050 private:
51 const ResXMLParser* parser_;
Adam Lesinski4452e132016-10-12 07:47:28 -070052};
53
Adam Lesinski7a37b742016-10-12 14:05:55 -070054class BagAttributeFinder
Adam Lesinskibebfcc42018-02-12 14:27:46 -080055 : public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> {
Adam Lesinski7a37b742016-10-12 14:05:55 -070056 public:
Chih-Hung Hsiehc2ace0c2018-12-20 13:46:53 -080057 explicit BagAttributeFinder(const ResolvedBag* bag)
Adam Lesinskibebfcc42018-02-12 14:27:46 -080058 : BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr,
59 bag != nullptr ? bag->entries + bag->entry_count : nullptr) {
60 }
Adam Lesinski4452e132016-10-12 07:47:28 -070061
Adam Lesinskibebfcc42018-02-12 14:27:46 -080062 inline uint32_t GetAttribute(const ResolvedBag::Entry* entry) const {
63 return entry->key;
Adam Lesinski7a37b742016-10-12 14:05:55 -070064 }
Adam Lesinski4452e132016-10-12 07:47:28 -070065};
66
Ryan Mitchellc75c2e02020-08-17 08:42:48 -070067base::expected<const ResolvedBag*, NullOrIOError> GetStyleBag(Theme* theme,
68 uint32_t theme_attribute_resid,
69 uint32_t fallback_resid,
70 uint32_t* out_theme_flags) {
71 // Load the style from the attribute if specified.
72 if (theme_attribute_resid != 0U) {
73 std::optional<AssetManager2::SelectedValue> value = theme->GetAttribute(theme_attribute_resid);
74 if (value.has_value()) {
75 *out_theme_flags |= value->flags;
76 auto result = theme->GetAssetManager()->ResolveBag(*value);
77 if (result.has_value() || IsIOError(result)) {
78 return result;
Adam Lesinski7a37b742016-10-12 14:05:55 -070079 }
80 }
81 }
82
Ryan Mitchellc75c2e02020-08-17 08:42:48 -070083 // Fallback to loading the style from the resource id if specified.
84 if (fallback_resid != 0U) {
85 return theme->GetAssetManager()->GetBag(fallback_resid);
86 }
87
88 return base::unexpected(std::nullopt);
89}
90
91base::expected<const ResolvedBag*, NullOrIOError> GetXmlStyleBag(Theme* theme,
92 ResXMLParser* xml_parser,
93 uint32_t* out_theme_flags) {
94 if (xml_parser == nullptr) {
95 return base::unexpected(std::nullopt);
96 }
97
98 // Retrieve the style resource ID associated with the current XML tag's style attribute.
99 Res_value value;
100 const ssize_t idx = xml_parser->indexOfStyle();
101 if (idx < 0 || xml_parser->getAttributeValue(idx, &value) < 0) {
102 return base::unexpected(std::nullopt);
103 }
104
105 if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
106 // Resolve the attribute with out theme.
107 if (std::optional<AssetManager2::SelectedValue> result = theme->GetAttribute(value.data)) {
108 *out_theme_flags |= result->flags;
109 return theme->GetAssetManager()->ResolveBag(*result);
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800110 }
111 }
112
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700113 if (value.dataType == Res_value::TYPE_REFERENCE) {
114 return theme->GetAssetManager()->GetBag(value.data);
115 }
116
117 return base::unexpected(std::nullopt);
118}
119
120} // namespace
121
122base::expected<std::monostate, IOError> ResolveAttrs(Theme* theme, uint32_t def_style_attr,
123 uint32_t def_style_res, uint32_t* src_values,
124 size_t src_values_length, uint32_t* attrs,
125 size_t attrs_length, uint32_t* out_values,
126 uint32_t* out_indices) {
127 DEBUG_LOG("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme, def_style_attr,
128 def_style_res);
129
130 int indices_idx = 0;
131 const AssetManager2* assetmanager = theme->GetAssetManager();
132
133 // Load default style from attribute or resource id, if specified...
134 uint32_t def_style_theme_flags = 0U;
135 const auto default_style_bag = GetStyleBag(theme, def_style_attr, def_style_res,
136 &def_style_theme_flags);
137 if (UNLIKELY(IsIOError(default_style_bag))) {
138 return base::unexpected(GetIOError(default_style_bag.error()));
139 }
140
141 BagAttributeFinder def_style_attr_finder(default_style_bag.value_or(nullptr));
Adam Lesinski7a37b742016-10-12 14:05:55 -0700142
143 // Now iterate through all of the attributes that the client has requested,
144 // filling in each with whatever data we can find.
145 for (size_t ii = 0; ii < attrs_length; ii++) {
146 const uint32_t cur_ident = attrs[ii];
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700147 DEBUG_LOG("RETRIEVING ATTR 0x%08x...", cur_ident);
Adam Lesinski4452e132016-10-12 07:47:28 -0700148
Adam Lesinski7a37b742016-10-12 14:05:55 -0700149 // Try to find a value for this attribute... we prioritize values
150 // coming from, first XML attributes, then XML style, then default
151 // style, and finally the theme.
152
153 // Retrieve the current input value if available.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700154 AssetManager2::SelectedValue value{};
Adam Lesinski7a37b742016-10-12 14:05:55 -0700155 if (src_values_length > 0 && src_values[ii] != 0) {
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700156 value.type = Res_value::TYPE_ATTRIBUTE;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700157 value.data = src_values[ii];
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700158 DEBUG_LOG("-> From values: type=0x%x, data=0x%08x", value.type, value.data);
Adam Lesinski32e75012017-05-09 15:25:37 -0700159 } else {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800160 const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident);
161 if (entry != def_style_attr_finder.end()) {
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700162 value = AssetManager2::SelectedValue(*default_style_bag, *entry);
163 value.flags |= def_style_theme_flags;
164 DEBUG_LOG("-> From def style: type=0x%x, data=0x%08x", value.type, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700165 }
166 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700167
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700168 if (value.type != Res_value::TYPE_NULL) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700169 // Take care of resolving the found resource to its final value.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700170 const auto result = theme->ResolveAttributeReference(value);
171 if (UNLIKELY(IsIOError(result))) {
172 return base::unexpected(GetIOError(result.error()));
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800173 }
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700174 DEBUG_LOG("-> Resolved attr: type=0x%x, data=0x%08x", value.type, value.data);
Adam Lesinski32e75012017-05-09 15:25:37 -0700175 } else if (value.data != Res_value::DATA_NULL_EMPTY) {
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800176 // If we still don't have a value for this attribute, try to find it in the theme!
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700177 if (auto attr_value = theme->GetAttribute(cur_ident)) {
178 value = *attr_value;
179 DEBUG_LOG("-> From theme: type=0x%x, data=0x%08x", value.type, value.data);
180
181 const auto result = assetmanager->ResolveReference(value);
182 if (UNLIKELY(IsIOError(result))) {
183 return base::unexpected(GetIOError(result.error()));
Adam Lesinski4452e132016-10-12 07:47:28 -0700184 }
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700185 DEBUG_LOG("-> Resolved theme: type=0x%x, data=0x%08x", value.type, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700186 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700187 }
188
Adam Lesinski7a37b742016-10-12 14:05:55 -0700189 // Deal with the special @null value -- it turns back to TYPE_NULL.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700190 if (value.type == Res_value::TYPE_REFERENCE && value.data == 0) {
191 DEBUG_LOG("-> Setting to @null!");
192 value.type = Res_value::TYPE_NULL;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700193 value.data = Res_value::DATA_NULL_UNDEFINED;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700194 value.cookie = kInvalidCookie;
Adam Lesinski4452e132016-10-12 07:47:28 -0700195 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700196
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700197 DEBUG_LOG("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.type, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700198
Adam Lesinski7a37b742016-10-12 14:05:55 -0700199 // Write the final value back to Java.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700200 out_values[STYLE_TYPE] = value.type;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700201 out_values[STYLE_DATA] = value.data;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700202 out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(value.cookie);
203 out_values[STYLE_RESOURCE_ID] = value.resid;
204 out_values[STYLE_CHANGING_CONFIGURATIONS] = value.flags;
205 out_values[STYLE_DENSITY] = value.config.density;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700206
Adam Lesinski32e75012017-05-09 15:25:37 -0700207 if (out_indices != nullptr &&
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700208 (value.type != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
209 out_indices[++indices_idx] = ii;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700210 }
211
212 out_values += STYLE_NUM_ENTRIES;
213 }
214
Adam Lesinski4c67a472016-11-10 16:43:59 -0800215 if (out_indices != nullptr) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700216 out_indices[0] = indices_idx;
217 }
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700218 return {};
Adam Lesinski7a37b742016-10-12 14:05:55 -0700219}
220
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700221base::expected<std::monostate, IOError> ApplyStyle(Theme* theme, ResXMLParser* xml_parser,
222 uint32_t def_style_attr,
223 uint32_t def_style_resid,
224 const uint32_t* attrs, size_t attrs_length,
225 uint32_t* out_values, uint32_t* out_indices) {
226 DEBUG_LOG("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
227 def_style_attr, def_style_resid, xml_parser);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700228
229 int indices_idx = 0;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700230 const AssetManager2* assetmanager = theme->GetAssetManager();
Adam Lesinski7a37b742016-10-12 14:05:55 -0700231
232 // Load default style from attribute, if specified...
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700233 uint32_t def_style_theme_flags = 0U;
234 const auto default_style_bag = GetStyleBag(theme, def_style_attr, def_style_resid,
235 &def_style_theme_flags);
236 if (IsIOError(default_style_bag)) {
237 return base::unexpected(GetIOError(default_style_bag.error()));
Adam Lesinski7a37b742016-10-12 14:05:55 -0700238 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700239
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800240 // Retrieve the style resource ID associated with the current XML tag's style attribute.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700241 uint32_t xml_style_theme_flags = 0U;
242 const auto xml_style_bag = GetXmlStyleBag(theme, xml_parser, &def_style_theme_flags);
243 if (IsIOError(xml_style_bag)) {
244 return base::unexpected(GetIOError(xml_style_bag.error()));
Adam Lesinski7a37b742016-10-12 14:05:55 -0700245 }
246
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700247 BagAttributeFinder def_style_attr_finder(default_style_bag.value_or(nullptr));
248 BagAttributeFinder xml_style_attr_finder(xml_style_bag.value_or(nullptr));
Adam Lesinski7a37b742016-10-12 14:05:55 -0700249 XmlAttributeFinder xml_attr_finder(xml_parser);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700250
251 // Now iterate through all of the attributes that the client has requested,
252 // filling in each with whatever data we can find.
253 for (size_t ii = 0; ii < attrs_length; ii++) {
254 const uint32_t cur_ident = attrs[ii];
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700255 DEBUG_LOG("RETRIEVING ATTR 0x%08x...", cur_ident);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700256
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700257 AssetManager2::SelectedValue value{};
Aurimas Liutikas949b05d2019-01-30 17:20:41 -0800258 uint32_t value_source_resid = 0;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700259
260 // Try to find a value for this attribute... we prioritize values
261 // coming from, first XML attributes, then XML style, then default
262 // style, and finally the theme.
263
264 // Walk through the xml attributes looking for the requested attribute.
265 const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800266 if (xml_attr_idx != xml_attr_finder.end()) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700267 // We found the attribute we were looking for.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700268 Res_value attribute_value;
269 xml_parser->getAttributeValue(xml_attr_idx, &attribute_value);
270 value.type = attribute_value.dataType;
271 value.data = attribute_value.data;
Aurimas Liutikas949b05d2019-01-30 17:20:41 -0800272 value_source_resid = xml_parser->getSourceResourceId();
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700273 DEBUG_LOG("-> From XML: type=0x%x, data=0x%08x", value.type, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700274 }
275
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700276 if (value.type == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700277 // Walk through the style class values looking for the requested attribute.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800278 const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident);
279 if (entry != xml_style_attr_finder.end()) {
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700280 value = AssetManager2::SelectedValue(*xml_style_bag, *entry);
281 value.flags |= xml_style_theme_flags;
Aurimas Liutikas949b05d2019-01-30 17:20:41 -0800282 value_source_resid = entry->style;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700283 DEBUG_LOG("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.type, value.data,
284 value_source_resid);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700285 }
286 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700287
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700288 if (value.type == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
Adam Lesinski32e75012017-05-09 15:25:37 -0700289 // Walk through the default style values looking for the requested attribute.
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800290 const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident);
291 if (entry != def_style_attr_finder.end()) {
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700292 value = AssetManager2::SelectedValue(*default_style_bag, *entry);
293 value.flags |= def_style_theme_flags;
Aurimas Liutikas949b05d2019-01-30 17:20:41 -0800294 value_source_resid = entry->style;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700295 DEBUG_LOG("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.type, value.data,
296 entry->style);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700297 }
298 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700299
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700300 if (value.type != Res_value::TYPE_NULL) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700301 // Take care of resolving the found resource to its final value.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700302 auto result = theme->ResolveAttributeReference(value);
303 if (UNLIKELY(IsIOError(result))) {
304 return base::unexpected(GetIOError(result.error()));
Adam Lesinski7a37b742016-10-12 14:05:55 -0700305 }
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700306 DEBUG_LOG("-> Resolved attr: type=0x%x, data=0x%08x", value.type, value.data);
Adam Lesinski32e75012017-05-09 15:25:37 -0700307 } else if (value.data != Res_value::DATA_NULL_EMPTY) {
308 // If we still don't have a value for this attribute, try to find it in the theme!
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700309 if (auto attr_value = theme->GetAttribute(cur_ident)) {
310 value = *attr_value;
311 DEBUG_LOG("-> From theme: type=0x%x, data=0x%08x", value.type, value.data);
Adam Lesinski4452e132016-10-12 07:47:28 -0700312
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700313 auto result = assetmanager->ResolveReference(value);
314 if (UNLIKELY(IsIOError(result))) {
315 return base::unexpected(GetIOError(result.error()));
Adam Lesinski4452e132016-10-12 07:47:28 -0700316 }
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700317 DEBUG_LOG("-> Resolved theme: type=0x%x, data=0x%08x", value.type, value.data);
318 // TODO: set value_source_resid for the style in the theme that was used.
Adam Lesinski7a37b742016-10-12 14:05:55 -0700319 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700320 }
321
Adam Lesinski7a37b742016-10-12 14:05:55 -0700322 // Deal with the special @null value -- it turns back to TYPE_NULL.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700323 if (value.type == Res_value::TYPE_REFERENCE && value.data == 0U) {
324 DEBUG_LOG("-> Setting to @null!");
325 value.type = Res_value::TYPE_NULL;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700326 value.data = Res_value::DATA_NULL_UNDEFINED;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700327 value.cookie = kInvalidCookie;
Adam Lesinski4452e132016-10-12 07:47:28 -0700328 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700329
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700330 DEBUG_LOG("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.type, value.data);
Adam Lesinski7a37b742016-10-12 14:05:55 -0700331
332 // Write the final value back to Java.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700333 out_values[STYLE_TYPE] = value.type;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700334 out_values[STYLE_DATA] = value.data;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700335 out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(value.cookie);
336 out_values[STYLE_RESOURCE_ID] = value.resid;
337 out_values[STYLE_CHANGING_CONFIGURATIONS] = value.flags;
338 out_values[STYLE_DENSITY] = value.config.density;
Aurimas Liutikasf9dbd5f2019-03-07 11:21:51 -0800339 out_values[STYLE_SOURCE_RESOURCE_ID] = value_source_resid;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700340
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700341 if (value.type != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
Adam Lesinski06d3e8f2017-01-05 17:03:55 -0800342 // out_indices must NOT be nullptr.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700343 out_indices[++indices_idx] = ii;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700344 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700345 out_values += STYLE_NUM_ENTRIES;
346 }
347
Adam Lesinski06d3e8f2017-01-05 17:03:55 -0800348 // out_indices must NOT be nullptr.
349 out_indices[0] = indices_idx;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700350 return {};
Adam Lesinski4452e132016-10-12 07:47:28 -0700351}
352
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700353base::expected<std::monostate, IOError> RetrieveAttributes(AssetManager2* assetmanager,
354 ResXMLParser* xml_parser,
355 uint32_t* attrs,
356 size_t attrs_length,
357 uint32_t* out_values,
358 uint32_t* out_indices) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700359 int indices_idx = 0;
Adam Lesinski4452e132016-10-12 07:47:28 -0700360
Adam Lesinski7a37b742016-10-12 14:05:55 -0700361 // Retrieve the XML attributes, if requested.
Adam Lesinski7a37b742016-10-12 14:05:55 -0700362 size_t ix = 0;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700363 const size_t xml_attr_count = xml_parser->getAttributeCount();
Adam Lesinski7a37b742016-10-12 14:05:55 -0700364 uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
Adam Lesinski4452e132016-10-12 07:47:28 -0700365
Adam Lesinski7a37b742016-10-12 14:05:55 -0700366 // Now iterate through all of the attributes that the client has requested,
367 // filling in each with whatever data we can find.
368 for (size_t ii = 0; ii < attrs_length; ii++) {
369 const uint32_t cur_ident = attrs[ii];
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700370 AssetManager2::SelectedValue value{};
Adam Lesinski4452e132016-10-12 07:47:28 -0700371
Adam Lesinski7a37b742016-10-12 14:05:55 -0700372 // Try to find a value for this attribute...
373 // Skip through XML attributes until the end or the next possible match.
374 while (ix < xml_attr_count && cur_ident > cur_xml_attr) {
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700375 cur_xml_attr = xml_parser->getAttributeNameResID(++ix);
Adam Lesinski4452e132016-10-12 07:47:28 -0700376 }
377
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700378 // Retrieve the current XML attribute if it matches, and step to next.
379 if (ix < xml_attr_count && cur_ident == cur_xml_attr) {
380 Res_value attribute_value;
381 xml_parser->getAttributeValue(ix, &attribute_value);
382 value.type = attribute_value.dataType;
383 value.data = attribute_value.data;
384 cur_xml_attr = xml_parser->getAttributeNameResID(++ix);
385 }
386
387 if (value.type != Res_value::TYPE_NULL) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700388 // Take care of resolving the found resource to its final value.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700389 auto result = assetmanager->ResolveReference(value);
390 if (UNLIKELY(IsIOError(result))) {
391 return base::unexpected(GetIOError(result.error()));
Adam Lesinskibebfcc42018-02-12 14:27:46 -0800392 }
Adam Lesinski4452e132016-10-12 07:47:28 -0700393 }
Adam Lesinski7a37b742016-10-12 14:05:55 -0700394
395 // Deal with the special @null value -- it turns back to TYPE_NULL.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700396 if (value.type == Res_value::TYPE_REFERENCE && value.data == 0U) {
397 value.type = Res_value::TYPE_NULL;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700398 value.data = Res_value::DATA_NULL_UNDEFINED;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700399 value.cookie = kInvalidCookie;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700400 }
401
402 // Write the final value back to Java.
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700403 out_values[STYLE_TYPE] = value.type;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700404 out_values[STYLE_DATA] = value.data;
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700405 out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(value.cookie);
406 out_values[STYLE_RESOURCE_ID] = value.resid;
407 out_values[STYLE_CHANGING_CONFIGURATIONS] = value.flags;
408 out_values[STYLE_DENSITY] = value.config.density;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700409
Adam Lesinski32e75012017-05-09 15:25:37 -0700410 if (out_indices != nullptr &&
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700411 (value.type != Res_value::TYPE_NULL ||
412 value.data == Res_value::DATA_NULL_EMPTY)) {
413 out_indices[++indices_idx] = ii;
Adam Lesinski7a37b742016-10-12 14:05:55 -0700414 }
415
416 out_values += STYLE_NUM_ENTRIES;
417 }
418
Adam Lesinski4c67a472016-11-10 16:43:59 -0800419 if (out_indices != nullptr) {
Adam Lesinski7a37b742016-10-12 14:05:55 -0700420 out_indices[0] = indices_idx;
421 }
Ryan Mitchellc75c2e02020-08-17 08:42:48 -0700422 return {};
Adam Lesinski4452e132016-10-12 07:47:28 -0700423}
424
Adam Lesinski7a37b742016-10-12 14:05:55 -0700425} // namespace android