Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 1 | /* |
| 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 Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 17 | #include "proto/ProtoSerialize.h" |
| 18 | |
| 19 | #include "android-base/logging.h" |
| 20 | #include "androidfw/ResourceTypes.h" |
| 21 | |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 22 | #include "ResourceTable.h" |
| 23 | #include "ResourceUtils.h" |
| 24 | #include "ValueVisitor.h" |
| 25 | #include "proto/ProtoHelpers.h" |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 26 | |
| 27 | namespace aapt { |
| 28 | |
| 29 | namespace { |
| 30 | |
| 31 | class ReferenceIdToNameVisitor : public ValueVisitor { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 32 | public: |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 33 | using ValueVisitor::Visit; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 34 | |
Adam Lesinski | 4488f1c | 2017-05-26 17:33:38 -0700 | [diff] [blame] | 35 | explicit ReferenceIdToNameVisitor(const std::map<ResourceId, ResourceNameRef>* mapping) |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 36 | : mapping_(mapping) { |
| 37 | CHECK(mapping_ != nullptr); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 38 | } |
| 39 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 40 | void Visit(Reference* reference) override { |
| 41 | if (!reference->id || !reference->id.value().is_valid()) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 42 | return; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 43 | } |
| 44 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 45 | ResourceId id = reference->id.value(); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 46 | auto cache_iter = mapping_->find(id); |
| 47 | if (cache_iter != mapping_->end()) { |
| 48 | reference->name = cache_iter->second.ToResourceName(); |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 49 | } |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 50 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 51 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 52 | private: |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 53 | const std::map<ResourceId, ResourceNameRef>* mapping_; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 54 | }; |
| 55 | |
| 56 | class PackagePbDeserializer { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 57 | public: |
| 58 | PackagePbDeserializer(const android::ResStringPool* valuePool, |
| 59 | const android::ResStringPool* sourcePool, |
| 60 | const android::ResStringPool* symbolPool, |
| 61 | const Source& source, IDiagnostics* diag) |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 62 | : value_pool_(valuePool), |
| 63 | source_pool_(sourcePool), |
| 64 | symbol_pool_(symbolPool), |
| 65 | source_(source), |
| 66 | diag_(diag) {} |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 67 | |
| 68 | public: |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 69 | bool DeserializeFromPb(const pb::Package& pbPackage, ResourceTable* table) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 70 | Maybe<uint8_t> id; |
| 71 | if (pbPackage.has_package_id()) { |
| 72 | id = static_cast<uint8_t>(pbPackage.package_id()); |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 73 | } |
| 74 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 75 | std::map<ResourceId, ResourceNameRef> idIndex; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 76 | |
Adam Lesinski | 4488f1c | 2017-05-26 17:33:38 -0700 | [diff] [blame] | 77 | ResourceTablePackage* pkg = table->CreatePackage(pbPackage.package_name(), id); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 78 | for (const pb::Type& pbType : pbPackage.types()) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 79 | const ResourceType* resType = ParseResourceType(pbType.name()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 80 | if (!resType) { |
Adam Lesinski | 4488f1c | 2017-05-26 17:33:38 -0700 | [diff] [blame] | 81 | diag_->Error(DiagMessage(source_) << "unknown type '" << pbType.name() << "'"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 82 | return {}; |
| 83 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 84 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 85 | ResourceTableType* type = pkg->FindOrCreateType(*resType); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 86 | |
| 87 | for (const pb::Entry& pbEntry : pbType.entries()) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 88 | ResourceEntry* entry = type->FindOrCreateEntry(pbEntry.name()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 89 | |
| 90 | // Deserialize the symbol status (public/private with source and |
| 91 | // comments). |
| 92 | if (pbEntry.has_symbol_status()) { |
| 93 | const pb::SymbolStatus& pbStatus = pbEntry.symbol_status(); |
| 94 | if (pbStatus.has_source()) { |
Adam Lesinski | 4488f1c | 2017-05-26 17:33:38 -0700 | [diff] [blame] | 95 | DeserializeSourceFromPb(pbStatus.source(), *source_pool_, &entry->symbol_status.source); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 96 | } |
| 97 | |
| 98 | if (pbStatus.has_comment()) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 99 | entry->symbol_status.comment = pbStatus.comment(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 100 | } |
| 101 | |
Adam Lesinski | 4488f1c | 2017-05-26 17:33:38 -0700 | [diff] [blame] | 102 | entry->symbol_status.allow_new = pbStatus.allow_new(); |
| 103 | |
| 104 | SymbolState visibility = DeserializeVisibilityFromPb(pbStatus.visibility()); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 105 | entry->symbol_status.state = visibility; |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 106 | |
| 107 | if (visibility == SymbolState::kPublic) { |
Adam Lesinski | 4488f1c | 2017-05-26 17:33:38 -0700 | [diff] [blame] | 108 | // This is a public symbol, we must encode the ID now if there is one. |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 109 | if (pbEntry.has_id()) { |
| 110 | entry->id = static_cast<uint16_t>(pbEntry.id()); |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 111 | } |
| 112 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 113 | if (type->symbol_status.state != SymbolState::kPublic) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 114 | // If the type has not been made public, do so now. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 115 | type->symbol_status.state = SymbolState::kPublic; |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 116 | if (pbType.has_id()) { |
| 117 | type->id = static_cast<uint8_t>(pbType.id()); |
| 118 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 119 | } |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 120 | } else if (visibility == SymbolState::kPrivate) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 121 | if (type->symbol_status.state == SymbolState::kUndefined) { |
| 122 | type->symbol_status.state = SymbolState::kPrivate; |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 123 | } |
| 124 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 125 | } |
| 126 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 127 | ResourceId resId(pbPackage.package_id(), pbType.id(), pbEntry.id()); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 128 | if (resId.is_valid()) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 129 | idIndex[resId] = ResourceNameRef(pkg->name, type->type, entry->name); |
| 130 | } |
| 131 | |
| 132 | for (const pb::ConfigValue& pbConfigValue : pbEntry.config_values()) { |
| 133 | const pb::ConfigDescription& pbConfig = pbConfigValue.config(); |
| 134 | |
| 135 | ConfigDescription config; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 136 | if (!DeserializeConfigDescriptionFromPb(pbConfig, &config)) { |
| 137 | diag_->Error(DiagMessage(source_) << "invalid configuration"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 138 | return {}; |
| 139 | } |
| 140 | |
Adam Lesinski | 4488f1c | 2017-05-26 17:33:38 -0700 | [diff] [blame] | 141 | ResourceConfigValue* configValue = entry->FindOrCreateValue(config, pbConfig.product()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 142 | if (configValue->value) { |
| 143 | // Duplicate config. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 144 | diag_->Error(DiagMessage(source_) << "duplicate configuration"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 145 | return {}; |
| 146 | } |
| 147 | |
Adam Lesinski | 4488f1c | 2017-05-26 17:33:38 -0700 | [diff] [blame] | 148 | configValue->value = |
| 149 | DeserializeValueFromPb(pbConfigValue.value(), config, &table->string_pool); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 150 | if (!configValue->value) { |
| 151 | return {}; |
| 152 | } |
| 153 | } |
| 154 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 155 | } |
| 156 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 157 | ReferenceIdToNameVisitor visitor(&idIndex); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 158 | VisitAllValuesInPackage(pkg, &visitor); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 159 | return true; |
| 160 | } |
| 161 | |
| 162 | private: |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 163 | std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item, |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 164 | const ConfigDescription& config, |
| 165 | StringPool* pool) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 166 | if (pb_item.has_ref()) { |
| 167 | const pb::Reference& pb_ref = pb_item.ref(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 168 | std::unique_ptr<Reference> ref = util::make_unique<Reference>(); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 169 | if (!DeserializeReferenceFromPb(pb_ref, ref.get())) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 170 | return {}; |
| 171 | } |
| 172 | return std::move(ref); |
| 173 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 174 | } else if (pb_item.has_prim()) { |
| 175 | const pb::Primitive& pb_prim = pb_item.prim(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 176 | android::Res_value prim = {}; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 177 | prim.dataType = static_cast<uint8_t>(pb_prim.type()); |
| 178 | prim.data = pb_prim.data(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 179 | return util::make_unique<BinaryPrimitive>(prim); |
| 180 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 181 | } else if (pb_item.has_id()) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 182 | return util::make_unique<Id>(); |
| 183 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 184 | } else if (pb_item.has_str()) { |
| 185 | const uint32_t idx = pb_item.str().idx(); |
| 186 | const std::string str = util::GetString(*value_pool_, idx); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 187 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 188 | const android::ResStringPool_span* spans = value_pool_->styleAt(idx); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 189 | if (spans && spans->name.index != android::ResStringPool_span::END) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 190 | StyleString style_str = {str}; |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 191 | while (spans->name.index != android::ResStringPool_span::END) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 192 | style_str.spans.push_back( |
| 193 | Span{util::GetString(*value_pool_, spans->name.index), |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 194 | spans->firstChar, spans->lastChar}); |
| 195 | spans++; |
| 196 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 197 | return util::make_unique<StyledString>(pool->MakeRef( |
Adam Lesinski | 5b6ee11 | 2017-07-28 17:10:35 -0700 | [diff] [blame] | 198 | style_str, StringPool::Context(StringPool::Context::kNormalPriority, config))); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 199 | } |
| 200 | return util::make_unique<String>( |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 201 | pool->MakeRef(str, StringPool::Context(config))); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 202 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 203 | } else if (pb_item.has_raw_str()) { |
| 204 | const uint32_t idx = pb_item.raw_str().idx(); |
| 205 | const std::string str = util::GetString(*value_pool_, idx); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 206 | return util::make_unique<RawString>( |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 207 | pool->MakeRef(str, StringPool::Context(config))); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 208 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 209 | } else if (pb_item.has_file()) { |
| 210 | const uint32_t idx = pb_item.file().path_idx(); |
| 211 | const std::string str = util::GetString(*value_pool_, idx); |
| 212 | return util::make_unique<FileReference>(pool->MakeRef( |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 213 | str, |
| 214 | StringPool::Context(StringPool::Context::kHighPriority, config))); |
| 215 | |
| 216 | } else { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 217 | diag_->Error(DiagMessage(source_) << "unknown item"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 218 | } |
| 219 | return {}; |
| 220 | } |
| 221 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 222 | std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value, |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 223 | const ConfigDescription& config, |
| 224 | StringPool* pool) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 225 | const bool is_weak = pb_value.has_weak() ? pb_value.weak() : false; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 226 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 227 | std::unique_ptr<Value> value; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 228 | if (pb_value.has_item()) { |
| 229 | value = DeserializeItemFromPb(pb_value.item(), config, pool); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 230 | if (!value) { |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 231 | return {}; |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 232 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 233 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 234 | } else if (pb_value.has_compound_value()) { |
| 235 | const pb::CompoundValue& pb_compound_value = pb_value.compound_value(); |
| 236 | if (pb_compound_value.has_attr()) { |
| 237 | const pb::Attribute& pb_attr = pb_compound_value.attr(); |
| 238 | std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(is_weak); |
| 239 | attr->type_mask = pb_attr.format_flags(); |
| 240 | attr->min_int = pb_attr.min_int(); |
| 241 | attr->max_int = pb_attr.max_int(); |
| 242 | for (const pb::Attribute_Symbol& pb_symbol : pb_attr.symbols()) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 243 | Attribute::Symbol symbol; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 244 | DeserializeItemCommon(pb_symbol, &symbol.symbol); |
| 245 | if (!DeserializeReferenceFromPb(pb_symbol.name(), &symbol.symbol)) { |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 246 | return {}; |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 247 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 248 | symbol.value = pb_symbol.value(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 249 | attr->symbols.push_back(std::move(symbol)); |
| 250 | } |
| 251 | value = std::move(attr); |
| 252 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 253 | } else if (pb_compound_value.has_style()) { |
| 254 | const pb::Style& pb_style = pb_compound_value.style(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 255 | std::unique_ptr<Style> style = util::make_unique<Style>(); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 256 | if (pb_style.has_parent()) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 257 | style->parent = Reference(); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 258 | if (!DeserializeReferenceFromPb(pb_style.parent(), |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 259 | &style->parent.value())) { |
| 260 | return {}; |
| 261 | } |
| 262 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 263 | if (pb_style.has_parent_source()) { |
| 264 | Source parent_source; |
| 265 | DeserializeSourceFromPb(pb_style.parent_source(), *source_pool_, |
| 266 | &parent_source); |
| 267 | style->parent.value().SetSource(std::move(parent_source)); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 268 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 269 | } |
| 270 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 271 | for (const pb::Style_Entry& pb_entry : pb_style.entries()) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 272 | Style::Entry entry; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 273 | DeserializeItemCommon(pb_entry, &entry.key); |
| 274 | if (!DeserializeReferenceFromPb(pb_entry.key(), &entry.key)) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 275 | return {}; |
| 276 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 277 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 278 | entry.value = DeserializeItemFromPb(pb_entry.item(), config, pool); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 279 | if (!entry.value) { |
| 280 | return {}; |
| 281 | } |
| 282 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 283 | DeserializeItemCommon(pb_entry, entry.value.get()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 284 | style->entries.push_back(std::move(entry)); |
| 285 | } |
| 286 | value = std::move(style); |
| 287 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 288 | } else if (pb_compound_value.has_styleable()) { |
| 289 | const pb::Styleable& pb_styleable = pb_compound_value.styleable(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 290 | std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 291 | for (const pb::Styleable_Entry& pb_entry : pb_styleable.entries()) { |
| 292 | Reference attr_ref; |
| 293 | DeserializeItemCommon(pb_entry, &attr_ref); |
| 294 | DeserializeReferenceFromPb(pb_entry.attr(), &attr_ref); |
| 295 | styleable->entries.push_back(std::move(attr_ref)); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 296 | } |
| 297 | value = std::move(styleable); |
| 298 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 299 | } else if (pb_compound_value.has_array()) { |
| 300 | const pb::Array& pb_array = pb_compound_value.array(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 301 | std::unique_ptr<Array> array = util::make_unique<Array>(); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 302 | for (const pb::Array_Entry& pb_entry : pb_array.entries()) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 303 | std::unique_ptr<Item> item = |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 304 | DeserializeItemFromPb(pb_entry.item(), config, pool); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 305 | if (!item) { |
| 306 | return {}; |
| 307 | } |
| 308 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 309 | DeserializeItemCommon(pb_entry, item.get()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 310 | array->items.push_back(std::move(item)); |
| 311 | } |
| 312 | value = std::move(array); |
| 313 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 314 | } else if (pb_compound_value.has_plural()) { |
| 315 | const pb::Plural& pb_plural = pb_compound_value.plural(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 316 | std::unique_ptr<Plural> plural = util::make_unique<Plural>(); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 317 | for (const pb::Plural_Entry& pb_entry : pb_plural.entries()) { |
| 318 | size_t pluralIdx = DeserializePluralEnumFromPb(pb_entry.arity()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 319 | plural->values[pluralIdx] = |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 320 | DeserializeItemFromPb(pb_entry.item(), config, pool); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 321 | if (!plural->values[pluralIdx]) { |
| 322 | return {}; |
| 323 | } |
| 324 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 325 | DeserializeItemCommon(pb_entry, plural->values[pluralIdx].get()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 326 | } |
| 327 | value = std::move(plural); |
| 328 | |
| 329 | } else { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 330 | diag_->Error(DiagMessage(source_) << "unknown compound value"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 331 | return {}; |
| 332 | } |
| 333 | } else { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 334 | diag_->Error(DiagMessage(source_) << "unknown value"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 335 | return {}; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 336 | } |
| 337 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 338 | CHECK(value) << "forgot to set value"; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 339 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 340 | value->SetWeak(is_weak); |
| 341 | DeserializeItemCommon(pb_value, value.get()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 342 | return value; |
| 343 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 344 | |
Adam Lesinski | bab4ef5 | 2017-06-01 15:22:57 -0700 | [diff] [blame] | 345 | bool DeserializeReferenceFromPb(const pb::Reference& pb_ref, Reference* out_ref) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 346 | out_ref->reference_type = DeserializeReferenceTypeFromPb(pb_ref.type()); |
| 347 | out_ref->private_reference = pb_ref.private_(); |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 348 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 349 | if (pb_ref.has_id()) { |
| 350 | out_ref->id = ResourceId(pb_ref.id()); |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 351 | } |
| 352 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 353 | if (pb_ref.has_symbol_idx()) { |
Adam Lesinski | bab4ef5 | 2017-06-01 15:22:57 -0700 | [diff] [blame] | 354 | const std::string str_symbol = util::GetString(*symbol_pool_, pb_ref.symbol_idx()); |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 355 | ResourceNameRef name_ref; |
| 356 | if (!ResourceUtils::ParseResourceName(str_symbol, &name_ref, nullptr)) { |
Adam Lesinski | bab4ef5 | 2017-06-01 15:22:57 -0700 | [diff] [blame] | 357 | diag_->Error(DiagMessage(source_) << "invalid reference name '" << str_symbol << "'"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 358 | return false; |
| 359 | } |
| 360 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 361 | out_ref->name = name_ref.ToResourceName(); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 362 | } |
| 363 | return true; |
| 364 | } |
| 365 | |
| 366 | template <typename T> |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 367 | void DeserializeItemCommon(const T& pb_item, Value* out_value) { |
| 368 | if (pb_item.has_source()) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 369 | Source source; |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 370 | DeserializeSourceFromPb(pb_item.source(), *source_pool_, &source); |
| 371 | out_value->SetSource(std::move(source)); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 372 | } |
| 373 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 374 | if (pb_item.has_comment()) { |
| 375 | out_value->SetComment(pb_item.comment()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 376 | } |
| 377 | } |
| 378 | |
| 379 | private: |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 380 | const android::ResStringPool* value_pool_; |
| 381 | const android::ResStringPool* source_pool_; |
| 382 | const android::ResStringPool* symbol_pool_; |
| 383 | const Source source_; |
| 384 | IDiagnostics* diag_; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 385 | }; |
| 386 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 387 | } // namespace |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 388 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 389 | std::unique_ptr<ResourceTable> DeserializeTableFromPb( |
| 390 | const pb::ResourceTable& pb_table, const Source& source, |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 391 | IDiagnostics* diag) { |
| 392 | // We import the android namespace because on Windows NO_ERROR is a macro, not |
| 393 | // an enum, which |
| 394 | // causes errors when qualifying it with android:: |
| 395 | using namespace android; |
Adam Lesinski | 803c7c8 | 2016-04-06 16:09:43 -0700 | [diff] [blame] | 396 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 397 | std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>(); |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 398 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 399 | if (!pb_table.has_string_pool()) { |
| 400 | diag->Error(DiagMessage(source) << "no string pool found"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 401 | return {}; |
| 402 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 403 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 404 | ResStringPool value_pool; |
| 405 | status_t result = value_pool.setTo(pb_table.string_pool().data().data(), |
| 406 | pb_table.string_pool().data().size()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 407 | if (result != NO_ERROR) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 408 | diag->Error(DiagMessage(source) << "invalid string pool"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 409 | return {}; |
| 410 | } |
| 411 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 412 | ResStringPool source_pool; |
| 413 | if (pb_table.has_source_pool()) { |
| 414 | result = source_pool.setTo(pb_table.source_pool().data().data(), |
| 415 | pb_table.source_pool().data().size()); |
Adam Lesinski | 803c7c8 | 2016-04-06 16:09:43 -0700 | [diff] [blame] | 416 | if (result != NO_ERROR) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 417 | diag->Error(DiagMessage(source) << "invalid source pool"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 418 | return {}; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 419 | } |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 420 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 421 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 422 | ResStringPool symbol_pool; |
| 423 | if (pb_table.has_symbol_pool()) { |
| 424 | result = symbol_pool.setTo(pb_table.symbol_pool().data().data(), |
| 425 | pb_table.symbol_pool().data().size()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 426 | if (result != NO_ERROR) { |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 427 | diag->Error(DiagMessage(source) << "invalid symbol pool"); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 428 | return {}; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 429 | } |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 430 | } |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 431 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 432 | PackagePbDeserializer package_pb_deserializer(&value_pool, &source_pool, |
| 433 | &symbol_pool, source, diag); |
| 434 | for (const pb::Package& pb_package : pb_table.packages()) { |
| 435 | if (!package_pb_deserializer.DeserializeFromPb(pb_package, table.get())) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 436 | return {}; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 437 | } |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 438 | } |
| 439 | return table; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 440 | } |
| 441 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 442 | std::unique_ptr<ResourceFile> DeserializeCompiledFileFromPb( |
| 443 | const pb::CompiledFile& pb_file, const Source& source, IDiagnostics* diag) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 444 | std::unique_ptr<ResourceFile> file = util::make_unique<ResourceFile>(); |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 445 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 446 | ResourceNameRef name_ref; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 447 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 448 | // Need to create an lvalue here so that nameRef can point to something real. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 449 | if (!ResourceUtils::ParseResourceName(pb_file.resource_name(), &name_ref)) { |
| 450 | diag->Error(DiagMessage(source) |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 451 | << "invalid resource name in compiled file header: " |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 452 | << pb_file.resource_name()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 453 | return {}; |
| 454 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 455 | file->name = name_ref.ToResourceName(); |
| 456 | file->source.path = pb_file.source_path(); |
| 457 | DeserializeConfigDescriptionFromPb(pb_file.config(), &file->config); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 458 | |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 459 | for (const pb::CompiledFile_Symbol& pb_symbol : pb_file.exported_symbols()) { |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 460 | // Need to create an lvalue here so that nameRef can point to something |
| 461 | // real. |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 462 | if (!ResourceUtils::ParseResourceName(pb_symbol.resource_name(), |
| 463 | &name_ref)) { |
| 464 | diag->Error(DiagMessage(source) |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 465 | << "invalid resource name for exported symbol in " |
| 466 | "compiled file header: " |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 467 | << pb_file.resource_name()); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 468 | return {}; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 469 | } |
Adam Lesinski | ce5e56e | 2016-10-21 17:56:45 -0700 | [diff] [blame] | 470 | file->exported_symbols.push_back( |
| 471 | SourcedResourceName{name_ref.ToResourceName(), pb_symbol.line_no()}); |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 472 | } |
| 473 | return file; |
Adam Lesinski | 59e04c6 | 2016-02-04 15:59:23 -0800 | [diff] [blame] | 474 | } |
| 475 | |
Adam Lesinski | b54ef10 | 2016-10-21 13:38:42 -0700 | [diff] [blame] | 476 | } // namespace aapt |