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 "compile/IdAssigner.h"
18ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
19ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include <map>
20ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
21ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "android-base/logging.h"
22ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
23cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#include "ResourceTable.h"
241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "process/IResourceTableConsumer.h"
251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "util/Util.h"
261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt {
281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
29bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski/**
30cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * Assigns the intended ID to the ResourceTablePackage, ResourceTableType, and
31cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski * ResourceEntry,
32bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski * as long as there is no existing ID or the ID is the same.
33bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski */
34ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool AssignId(IDiagnostics* diag, const ResourceId& id,
35cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                     const ResourceName& name, ResourceTablePackage* pkg,
36cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                     ResourceTableType* type, ResourceEntry* entry) {
37ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (pkg->id.value() == id.package_id()) {
38ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (!type->id || type->id.value() == id.type_id()) {
39ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      type->id = id.type_id();
40cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
41ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      if (!entry->id || entry->id.value() == id.entry_id()) {
42ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        entry->id = id.entry_id();
43cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        return true;
44cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
45bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski    }
46cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
47bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski
48ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const ResourceId existing_id(pkg->id.value(), type->id ? type->id.value() : 0,
49ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                               entry->id ? entry->id.value() : 0);
50ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  diag->Error(DiagMessage() << "can't assign ID " << id << " to resource "
51ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                            << name << " with conflicting ID " << existing_id);
52cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return false;
53bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski}
54bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski
55ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool IdAssigner::Consume(IAaptContext* context, ResourceTable* table) {
56ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::map<ResourceId, ResourceName> assigned_ids;
57cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
58cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  for (auto& package : table->packages) {
59ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    CHECK(bool(package->id)) << "packages must have manually assigned IDs";
60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    for (auto& type : package->types) {
62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      for (auto& entry : type->entries) {
63cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        const ResourceName name(package->name, type->type, entry->name);
64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
65ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        if (assigned_id_map_) {
66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // Assign the pre-assigned stable ID meant for this resource.
67ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          const auto iter = assigned_id_map_->find(name);
68ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          if (iter != assigned_id_map_->end()) {
69ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            const ResourceId assigned_id = iter->second;
70cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            const bool result =
71ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                AssignId(context->GetDiagnostics(), assigned_id, name,
72cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                         package.get(), type.get(), entry.get());
73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            if (!result) {
74cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski              return false;
75bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski            }
76cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          }
77bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski        }
781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
79cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        if (package->id && type->id && entry->id) {
80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // If the ID is set for this resource, then reserve it.
81ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          ResourceId resource_id(package->id.value(), type->id.value(),
82ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                                 entry->id.value());
83ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          auto result = assigned_ids.insert({resource_id, name});
84ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          const ResourceName& existing_name = result.first->second;
85cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          if (!result.second) {
86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            context->GetDiagnostics()->Error(
87cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                DiagMessage() << "resource " << name << " has same ID "
88ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                              << resource_id << " as " << existing_name);
89cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            return false;
90cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          }
91bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski        }
92cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
93bf0bd0f9ac1ffa0231cff0f6591dede48b3c6d52Adam Lesinski    }
94cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
95cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
96ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  if (assigned_id_map_) {
97cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Reserve all the IDs mentioned in the stable ID map. That way we won't
98cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // assign
99cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // IDs that were listed in the map if they don't exist in the table.
100ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    for (const auto& stable_id_entry : *assigned_id_map_) {
101ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      const ResourceName& pre_assigned_name = stable_id_entry.first;
102ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      const ResourceId& pre_assigned_id = stable_id_entry.second;
103ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      auto result = assigned_ids.insert({pre_assigned_id, pre_assigned_name});
104ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      const ResourceName& existing_name = result.first->second;
105ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      if (!result.second && existing_name != pre_assigned_name) {
106ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        context->GetDiagnostics()->Error(
107ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            DiagMessage() << "stable ID " << pre_assigned_id << " for resource "
108ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                          << pre_assigned_name
109ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                          << " is already taken by resource " << existing_name);
110cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        return false;
111cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
112cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
113cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
114cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
115cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Assign any resources without IDs the next available ID. Gaps will be filled
116cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // if possible,
117cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // unless those IDs have been reserved.
118cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
119ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const auto assigned_ids_iter_end = assigned_ids.end();
120cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  for (auto& package : table->packages) {
121ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    CHECK(bool(package->id)) << "packages must have manually assigned IDs";
122cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
123cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Build a half filled ResourceId object, which will be used to find the
124cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // closest matching
125cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // reserved ID in the assignedId map. From that point the next available
126cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // type ID can be
127cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // found.
128ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ResourceId resource_id(package->id.value(), 0, 0);
129ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    uint8_t next_expected_type_id = 1;
130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
131cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Find the closest matching ResourceId that is <= the one with only the
132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // package set.
133ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    auto next_type_iter = assigned_ids.lower_bound(resource_id);
134cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    for (auto& type : package->types) {
135cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      if (!type->id) {
136cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        // We need to assign a type ID. Iterate over the reserved IDs until we
137cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        // find
138cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        // some type ID that is a distance of 2 greater than the last one we've
139cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        // seen.
140cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        // That means there is an available type ID between these reserved IDs.
141ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        while (next_type_iter != assigned_ids_iter_end) {
142ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          if (next_type_iter->first.package_id() != package->id.value()) {
143cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            break;
144cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          }
145cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
146ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          const uint8_t type_id = next_type_iter->first.type_id();
147ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          if (type_id > next_expected_type_id) {
148cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // There is a gap in the type IDs, so use the missing one.
149ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            type->id = next_expected_type_id++;
150cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            break;
151cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          }
152cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
153cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // Set our expectation to be the next type ID after the reserved one
154cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // we
155cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // just saw.
156ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          next_expected_type_id = type_id + 1;
157cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
158cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // Move to the next reserved ID.
159ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          ++next_type_iter;
160cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        }
1611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
162cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        if (!type->id) {
163cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // We must have hit the end of the reserved IDs and not found a gap.
164cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // That means the next ID is available.
165ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          type->id = next_expected_type_id++;
166cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        }
167cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
168cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
169ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      resource_id = ResourceId(package->id.value(), type->id.value(), 0);
170ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      uint16_t next_expected_entry_id = 0;
171cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
172cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // Find the closest matching ResourceId that is <= the one with only the
173cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // package
174cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // and type set.
175ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      auto next_entry_iter = assigned_ids.lower_bound(resource_id);
176cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      for (auto& entry : type->entries) {
177cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        if (!entry->id) {
178cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // We need to assign an entry ID. Iterate over the reserved IDs until
179cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // we find
180cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // some entry ID that is a distance of 2 greater than the last one
181cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // we've seen.
182cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // That means there is an available entry ID between these reserved
183cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          // IDs.
184ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          while (next_entry_iter != assigned_ids_iter_end) {
185ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            if (next_entry_iter->first.package_id() != package->id.value() ||
186ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                next_entry_iter->first.type_id() != type->id.value()) {
187cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski              break;
1881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            }
1891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
190ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            const uint16_t entry_id = next_entry_iter->first.entry_id();
191ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            if (entry_id > next_expected_entry_id) {
192cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski              // There is a gap in the entry IDs, so use the missing one.
193ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski              entry->id = next_expected_entry_id++;
194cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski              break;
1951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            }
196cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
197cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // Set our expectation to be the next type ID after the reserved one
198cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // we
199cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // just saw.
200ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            next_expected_entry_id = entry_id + 1;
201cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
202cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // Move to the next reserved entry ID.
203ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            ++next_entry_iter;
204cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          }
205cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
206cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          if (!entry->id) {
207cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // We must have hit the end of the reserved IDs and not found a gap.
208cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski            // That means the next ID is available.
209ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            entry->id = next_expected_entry_id++;
210cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          }
2111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
212cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
2131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
214cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
215cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return true;
2161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
2171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
218cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
219