Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2015 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 | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 17 | #include "link/TableMerger.h" |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 18 | #include "ResourceTable.h" |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 19 | #include "ResourceUtils.h" |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 20 | #include "ResourceValues.h" |
| 21 | #include "ValueVisitor.h" |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 22 | #include "util/Util.h" |
| 23 | |
| 24 | #include <cassert> |
| 25 | |
| 26 | namespace aapt { |
| 27 | |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 28 | TableMerger::TableMerger(IAaptContext* context, ResourceTable* outTable, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 29 | const TableMergerOptions& options) |
| 30 | : mContext(context), mMasterTable(outTable), mOptions(options) { |
| 31 | // Create the desired package that all tables will be merged into. |
| 32 | mMasterPackage = mMasterTable->createPackage( |
| 33 | mContext->getCompilationPackage(), mContext->getPackageId()); |
| 34 | assert(mMasterPackage && "package name or ID already taken"); |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 35 | } |
| 36 | |
Adam Lesinski | 64587af | 2016-02-18 18:33:06 -0800 | [diff] [blame] | 37 | bool TableMerger::merge(const Source& src, ResourceTable* table, |
| 38 | io::IFileCollection* collection) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 39 | return mergeImpl(src, table, collection, false /* overlay */, |
| 40 | true /* allow new */); |
Adam Lesinski | 64587af | 2016-02-18 18:33:06 -0800 | [diff] [blame] | 41 | } |
| 42 | |
| 43 | bool TableMerger::mergeOverlay(const Source& src, ResourceTable* table, |
| 44 | io::IFileCollection* collection) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 45 | return mergeImpl(src, table, collection, true /* overlay */, |
| 46 | mOptions.autoAddOverlay); |
Adam Lesinski | 64587af | 2016-02-18 18:33:06 -0800 | [diff] [blame] | 47 | } |
| 48 | |
Adam Lesinski | 83f2255 | 2015-11-07 11:51:23 -0800 | [diff] [blame] | 49 | /** |
| 50 | * This will merge packages with the same package name (or no package name). |
| 51 | */ |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 52 | bool TableMerger::mergeImpl(const Source& src, ResourceTable* table, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 53 | io::IFileCollection* collection, bool overlay, |
| 54 | bool allowNew) { |
| 55 | const uint8_t desiredPackageId = mContext->getPackageId(); |
Adam Lesinski | 085f495 | 2016-08-30 14:25:51 -0700 | [diff] [blame] | 56 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 57 | bool error = false; |
| 58 | for (auto& package : table->packages) { |
| 59 | // Warn of packages with an unrelated ID. |
| 60 | const Maybe<ResourceId>& id = package->id; |
| 61 | if (id && id.value() != 0x0 && id.value() != desiredPackageId) { |
| 62 | mContext->getDiagnostics()->warn(DiagMessage(src) << "ignoring package " |
| 63 | << package->name); |
| 64 | continue; |
Adam Lesinski | 83f2255 | 2015-11-07 11:51:23 -0800 | [diff] [blame] | 65 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 66 | |
| 67 | // Only merge an empty package or the package we're building. |
| 68 | // Other packages may exist, which likely contain attribute definitions. |
| 69 | // This is because at compile time it is unknown if the attributes are |
| 70 | // simply |
| 71 | // uses of the attribute or definitions. |
| 72 | if (package->name.empty() || |
| 73 | mContext->getCompilationPackage() == package->name) { |
| 74 | FileMergeCallback callback; |
| 75 | if (collection) { |
| 76 | callback = [&](const ResourceNameRef& name, |
| 77 | const ConfigDescription& config, FileReference* newFile, |
| 78 | FileReference* oldFile) -> bool { |
| 79 | // The old file's path points inside the APK, so we can use it as is. |
| 80 | io::IFile* f = collection->findFile(*oldFile->path); |
| 81 | if (!f) { |
| 82 | mContext->getDiagnostics()->error(DiagMessage(src) |
| 83 | << "file '" << *oldFile->path |
| 84 | << "' not found"); |
| 85 | return false; |
| 86 | } |
| 87 | |
| 88 | newFile->file = f; |
| 89 | return true; |
| 90 | }; |
| 91 | } |
| 92 | |
| 93 | // Merge here. Once the entries are merged and mangled, any references to |
| 94 | // them are still valid. This is because un-mangled references are |
| 95 | // mangled, then looked up at resolution time. |
| 96 | // Also, when linking, we convert references with no package name to use |
| 97 | // the compilation package name. |
| 98 | error |= !doMerge(src, table, package.get(), false /* mangle */, overlay, |
| 99 | allowNew, callback); |
| 100 | } |
| 101 | } |
| 102 | return !error; |
Adam Lesinski | 83f2255 | 2015-11-07 11:51:23 -0800 | [diff] [blame] | 103 | } |
| 104 | |
| 105 | /** |
| 106 | * This will merge and mangle resources from a static library. |
| 107 | */ |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 108 | bool TableMerger::mergeAndMangle(const Source& src, |
| 109 | const StringPiece& packageName, |
| 110 | ResourceTable* table, |
| 111 | io::IFileCollection* collection) { |
| 112 | bool error = false; |
| 113 | for (auto& package : table->packages) { |
| 114 | // Warn of packages with an unrelated ID. |
| 115 | if (packageName != package->name) { |
| 116 | mContext->getDiagnostics()->warn(DiagMessage(src) << "ignoring package " |
| 117 | << package->name); |
| 118 | continue; |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 119 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 120 | |
| 121 | bool mangle = packageName != mContext->getCompilationPackage(); |
| 122 | mMergedPackages.insert(package->name); |
| 123 | |
| 124 | auto callback = [&](const ResourceNameRef& name, |
| 125 | const ConfigDescription& config, FileReference* newFile, |
| 126 | FileReference* oldFile) -> bool { |
| 127 | // The old file's path points inside the APK, so we can use it as is. |
| 128 | io::IFile* f = collection->findFile(*oldFile->path); |
| 129 | if (!f) { |
| 130 | mContext->getDiagnostics()->error( |
| 131 | DiagMessage(src) << "file '" << *oldFile->path << "' not found"); |
| 132 | return false; |
| 133 | } |
| 134 | |
| 135 | newFile->file = f; |
| 136 | return true; |
| 137 | }; |
| 138 | |
| 139 | error |= !doMerge(src, table, package.get(), mangle, false /* overlay */, |
| 140 | true /* allow new */, callback); |
| 141 | } |
| 142 | return !error; |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 143 | } |
| 144 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 145 | static bool mergeType(IAaptContext* context, const Source& src, |
| 146 | ResourceTableType* dstType, ResourceTableType* srcType) { |
| 147 | if (dstType->symbolStatus.state < srcType->symbolStatus.state) { |
| 148 | // The incoming type's visibility is stronger, so we should override |
| 149 | // the visibility. |
| 150 | if (srcType->symbolStatus.state == SymbolState::kPublic) { |
| 151 | // Only copy the ID if the source is public, or else the ID is |
| 152 | // meaningless. |
| 153 | dstType->id = srcType->id; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 154 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 155 | dstType->symbolStatus = std::move(srcType->symbolStatus); |
| 156 | } else if (dstType->symbolStatus.state == SymbolState::kPublic && |
| 157 | srcType->symbolStatus.state == SymbolState::kPublic && |
| 158 | dstType->id && srcType->id && |
| 159 | dstType->id.value() != srcType->id.value()) { |
| 160 | // Both types are public and have different IDs. |
| 161 | context->getDiagnostics()->error(DiagMessage(src) |
| 162 | << "cannot merge type '" << srcType->type |
| 163 | << "': conflicting public IDs"); |
| 164 | return false; |
| 165 | } |
| 166 | return true; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 167 | } |
| 168 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 169 | static bool mergeEntry(IAaptContext* context, const Source& src, |
| 170 | ResourceEntry* dstEntry, ResourceEntry* srcEntry) { |
| 171 | if (dstEntry->symbolStatus.state < srcEntry->symbolStatus.state) { |
| 172 | // The incoming type's visibility is stronger, so we should override |
| 173 | // the visibility. |
| 174 | if (srcEntry->symbolStatus.state == SymbolState::kPublic) { |
| 175 | // Only copy the ID if the source is public, or else the ID is |
| 176 | // meaningless. |
| 177 | dstEntry->id = srcEntry->id; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 178 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 179 | dstEntry->symbolStatus = std::move(srcEntry->symbolStatus); |
| 180 | } else if (srcEntry->symbolStatus.state == SymbolState::kPublic && |
| 181 | dstEntry->symbolStatus.state == SymbolState::kPublic && |
| 182 | dstEntry->id && srcEntry->id && |
| 183 | dstEntry->id.value() != srcEntry->id.value()) { |
| 184 | // Both entries are public and have different IDs. |
| 185 | context->getDiagnostics()->error(DiagMessage(src) |
| 186 | << "cannot merge entry '" << srcEntry->name |
| 187 | << "': conflicting public IDs"); |
| 188 | return false; |
| 189 | } |
| 190 | return true; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 191 | } |
| 192 | |
| 193 | /** |
| 194 | * Modified CollisionResolver which will merge Styleables. Used with overlays. |
| 195 | * |
| 196 | * Styleables are not actual resources, but they are treated as such during the |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 197 | * compilation phase. Styleables don't simply overlay each other, their |
| 198 | * definitions merge |
| 199 | * and accumulate. If both values are Styleables, we just merge them into the |
| 200 | * existing value. |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 201 | */ |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 202 | static ResourceTable::CollisionResult resolveMergeCollision(Value* existing, |
| 203 | Value* incoming) { |
| 204 | if (Styleable* existingStyleable = valueCast<Styleable>(existing)) { |
| 205 | if (Styleable* incomingStyleable = valueCast<Styleable>(incoming)) { |
| 206 | // Styleables get merged. |
| 207 | existingStyleable->mergeWith(incomingStyleable); |
| 208 | return ResourceTable::CollisionResult::kKeepOriginal; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 209 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 210 | } |
| 211 | // Delegate to the default handler. |
| 212 | return ResourceTable::resolveValueCollision(existing, incoming); |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 213 | } |
| 214 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 215 | static ResourceTable::CollisionResult mergeConfigValue( |
| 216 | IAaptContext* context, const ResourceNameRef& resName, const bool overlay, |
| 217 | ResourceConfigValue* dstConfigValue, ResourceConfigValue* srcConfigValue) { |
| 218 | using CollisionResult = ResourceTable::CollisionResult; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 219 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 220 | Value* dstValue = dstConfigValue->value.get(); |
| 221 | Value* srcValue = srcConfigValue->value.get(); |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 222 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 223 | CollisionResult collisionResult; |
| 224 | if (overlay) { |
| 225 | collisionResult = resolveMergeCollision(dstValue, srcValue); |
| 226 | } else { |
| 227 | collisionResult = ResourceTable::resolveValueCollision(dstValue, srcValue); |
| 228 | } |
| 229 | |
| 230 | if (collisionResult == CollisionResult::kConflict) { |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 231 | if (overlay) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 232 | return CollisionResult::kTakeNew; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 233 | } |
| 234 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 235 | // Error! |
| 236 | context->getDiagnostics()->error( |
| 237 | DiagMessage(srcValue->getSource()) |
| 238 | << "resource '" << resName << "' has a conflicting value for " |
| 239 | << "configuration (" << srcConfigValue->config << ")"); |
| 240 | context->getDiagnostics()->note(DiagMessage(dstValue->getSource()) |
| 241 | << "originally defined here"); |
| 242 | return CollisionResult::kConflict; |
| 243 | } |
| 244 | return collisionResult; |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 245 | } |
| 246 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 247 | bool TableMerger::doMerge(const Source& src, ResourceTable* srcTable, |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 248 | ResourceTablePackage* srcPackage, |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 249 | const bool manglePackage, const bool overlay, |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 250 | const bool allowNewResources, |
Chih-Hung Hsieh | 9b8528f | 2016-08-10 14:15:30 -0700 | [diff] [blame] | 251 | const FileMergeCallback& callback) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 252 | bool error = false; |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 253 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 254 | for (auto& srcType : srcPackage->types) { |
| 255 | ResourceTableType* dstType = |
| 256 | mMasterPackage->findOrCreateType(srcType->type); |
| 257 | if (!mergeType(mContext, src, dstType, srcType.get())) { |
| 258 | error = true; |
| 259 | continue; |
| 260 | } |
| 261 | |
| 262 | for (auto& srcEntry : srcType->entries) { |
| 263 | std::string entryName = srcEntry->name; |
| 264 | if (manglePackage) { |
| 265 | entryName = NameMangler::mangleEntry(srcPackage->name, srcEntry->name); |
| 266 | } |
| 267 | |
| 268 | ResourceEntry* dstEntry; |
| 269 | if (allowNewResources) { |
| 270 | dstEntry = dstType->findOrCreateEntry(entryName); |
| 271 | } else { |
| 272 | dstEntry = dstType->findEntry(entryName); |
| 273 | } |
| 274 | |
| 275 | const ResourceNameRef resName(srcPackage->name, srcType->type, |
| 276 | srcEntry->name); |
| 277 | |
| 278 | if (!dstEntry) { |
| 279 | mContext->getDiagnostics()->error( |
| 280 | DiagMessage(src) << "resource " << resName |
| 281 | << " does not override an existing resource"); |
| 282 | mContext->getDiagnostics()->note( |
| 283 | DiagMessage(src) << "define an <add-resource> tag or use " |
| 284 | << "--auto-add-overlay"); |
| 285 | error = true; |
| 286 | continue; |
| 287 | } |
| 288 | |
| 289 | if (!mergeEntry(mContext, src, dstEntry, srcEntry.get())) { |
| 290 | error = true; |
| 291 | continue; |
| 292 | } |
| 293 | |
| 294 | for (auto& srcConfigValue : srcEntry->values) { |
| 295 | using CollisionResult = ResourceTable::CollisionResult; |
| 296 | |
| 297 | ResourceConfigValue* dstConfigValue = dstEntry->findValue( |
| 298 | srcConfigValue->config, srcConfigValue->product); |
| 299 | if (dstConfigValue) { |
| 300 | CollisionResult collisionResult = mergeConfigValue( |
| 301 | mContext, resName, overlay, dstConfigValue, srcConfigValue.get()); |
| 302 | if (collisionResult == CollisionResult::kConflict) { |
Adam Lesinski | 5c3464c | 2016-08-24 16:03:48 -0700 | [diff] [blame] | 303 | error = true; |
| 304 | continue; |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 305 | } else if (collisionResult == CollisionResult::kKeepOriginal) { |
| 306 | continue; |
| 307 | } |
| 308 | } else { |
| 309 | dstConfigValue = dstEntry->findOrCreateValue(srcConfigValue->config, |
| 310 | srcConfigValue->product); |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 311 | } |
| 312 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 313 | // Continue if we're taking the new resource. |
| 314 | |
| 315 | if (FileReference* f = |
| 316 | valueCast<FileReference>(srcConfigValue->value.get())) { |
| 317 | std::unique_ptr<FileReference> newFileRef; |
| 318 | if (manglePackage) { |
| 319 | newFileRef = cloneAndMangleFile(srcPackage->name, *f); |
| 320 | } else { |
| 321 | newFileRef = std::unique_ptr<FileReference>( |
| 322 | f->clone(&mMasterTable->stringPool)); |
| 323 | } |
| 324 | |
| 325 | if (callback) { |
| 326 | if (!callback(resName, srcConfigValue->config, newFileRef.get(), |
| 327 | f)) { |
| 328 | error = true; |
| 329 | continue; |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 330 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 331 | } |
| 332 | dstConfigValue->value = std::move(newFileRef); |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 333 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 334 | } else { |
| 335 | dstConfigValue->value = std::unique_ptr<Value>( |
| 336 | srcConfigValue->value->clone(&mMasterTable->stringPool)); |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 337 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 338 | } |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 339 | } |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 340 | } |
| 341 | return !error; |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 342 | } |
| 343 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 344 | std::unique_ptr<FileReference> TableMerger::cloneAndMangleFile( |
| 345 | const std::string& package, const FileReference& fileRef) { |
| 346 | StringPiece prefix, entry, suffix; |
| 347 | if (util::extractResFilePathParts(*fileRef.path, &prefix, &entry, &suffix)) { |
| 348 | std::string mangledEntry = |
| 349 | NameMangler::mangleEntry(package, entry.toString()); |
| 350 | std::string newPath = prefix.toString() + mangledEntry + suffix.toString(); |
| 351 | std::unique_ptr<FileReference> newFileRef = |
| 352 | util::make_unique<FileReference>( |
| 353 | mMasterTable->stringPool.makeRef(newPath)); |
| 354 | newFileRef->setComment(fileRef.getComment()); |
| 355 | newFileRef->setSource(fileRef.getSource()); |
| 356 | return newFileRef; |
| 357 | } |
| 358 | return std::unique_ptr<FileReference>( |
| 359 | fileRef.clone(&mMasterTable->stringPool)); |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 360 | } |
| 361 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 362 | bool TableMerger::mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, |
| 363 | bool overlay) { |
| 364 | ResourceTable table; |
| 365 | std::string path = ResourceUtils::buildResourceFileName(fileDesc, nullptr); |
| 366 | std::unique_ptr<FileReference> fileRef = |
| 367 | util::make_unique<FileReference>(table.stringPool.makeRef(path)); |
| 368 | fileRef->setSource(fileDesc.source); |
| 369 | fileRef->file = file; |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 370 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 371 | ResourceTablePackage* pkg = table.createPackage(fileDesc.name.package, 0x0); |
| 372 | pkg->findOrCreateType(fileDesc.name.type) |
| 373 | ->findOrCreateEntry(fileDesc.name.entry) |
| 374 | ->findOrCreateValue(fileDesc.config, {}) |
| 375 | ->value = std::move(fileRef); |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 376 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 377 | return doMerge(file->getSource(), &table, pkg, false /* mangle */, |
| 378 | overlay /* overlay */, true /* allow new */, {}); |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 379 | } |
| 380 | |
| 381 | bool TableMerger::mergeFile(const ResourceFile& fileDesc, io::IFile* file) { |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 382 | return mergeFileImpl(fileDesc, file, false /* overlay */); |
Adam Lesinski | a6fe345 | 2015-12-09 15:20:52 -0800 | [diff] [blame] | 383 | } |
| 384 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 385 | bool TableMerger::mergeFileOverlay(const ResourceFile& fileDesc, |
| 386 | io::IFile* file) { |
| 387 | return mergeFileImpl(fileDesc, file, true /* overlay */); |
Adam Lesinski | 1ab598f | 2015-08-14 14:26:04 -0700 | [diff] [blame] | 388 | } |
| 389 | |
Adam Lesinski | cacb28f | 2016-10-19 12:18:14 -0700 | [diff] [blame^] | 390 | } // namespace aapt |