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 "flatten/TableFlattener.h"
181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
19803c7c807969bea1f1c50f348832f5b60ad05d8eAdam Lesinski#include <algorithm>
20cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski#include <numeric>
21d0f116b619feede0cfdb647157ce5ab4d50a1c46Adam Lesinski#include <sstream>
221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <type_traits>
231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
24ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "android-base/logging.h"
25ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "android-base/macros.h"
26ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
27ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "ResourceTable.h"
28ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "ResourceValues.h"
29c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski#include "SdkConstants.h"
30ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "ValueVisitor.h"
31ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "flatten/ChunkWriter.h"
32ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "flatten/ResourceTypeExtensions.h"
33ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "util/BigBuffer.h"
34ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskiusing namespace android;
361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt {
381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace {
401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskitemplate <typename T>
42ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool cmp_ids(const T* a, const T* b) {
43cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return a->id.value() < b->id.value();
441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistatic void strcpy16_htod(uint16_t* dst, size_t len, const StringPiece16& src) {
47cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (len == 0) {
48cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return;
49cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
50cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
51cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  size_t i;
52ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  const char16_t* src_data = src.data();
53cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  for (i = 0; i < len - 1 && i < src.size(); i++) {
54ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    dst[i] = util::HostToDevice16((uint16_t)src_data[i]);
55cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
56cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  dst[i] = 0;
571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
59ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskistatic bool cmp_style_entries(const Style::Entry& a, const Style::Entry& b) {
60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  if (a.key.id) {
61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (b.key.id) {
62cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return a.key.id.value() < b.key.id.value();
63cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
65cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  } else if (!b.key.id) {
66cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return a.key.name.value() < b.key.name.value();
67cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
68cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return false;
6959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski}
7059e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski
711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskistruct FlatEntry {
72cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  ResourceEntry* entry;
73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  Value* value;
743b4cd94034ff3e5567a2ba6da35d640ff61db4b9Adam Lesinski
75cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // The entry string pool index to the entry's name.
76ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  uint32_t entry_key;
771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski};
781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
7959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinskiclass MapFlattenVisitor : public RawValueVisitor {
80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski public:
81ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  using RawValueVisitor::Visit;
821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
83ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  MapFlattenVisitor(ResTable_entry_ext* out_entry, BigBuffer* buffer)
84ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      : out_entry_(out_entry), buffer_(buffer) {}
85a587065721053ad54e34f484868142407d59512dAdam Lesinski
86ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void Visit(Attribute* attr) override {
87cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    {
88cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      Reference key = Reference(ResourceId(ResTable_map::ATTR_TYPE));
89ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      BinaryPrimitive val(Res_value::TYPE_INT_DEC, attr->type_mask);
90ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      FlattenEntry(&key, &val);
911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
93ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (attr->min_int != std::numeric_limits<int32_t>::min()) {
94cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      Reference key = Reference(ResourceId(ResTable_map::ATTR_MIN));
95cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      BinaryPrimitive val(Res_value::TYPE_INT_DEC,
96ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                          static_cast<uint32_t>(attr->min_int));
97ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      FlattenEntry(&key, &val);
981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
100ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (attr->max_int != std::numeric_limits<int32_t>::max()) {
101cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      Reference key = Reference(ResourceId(ResTable_map::ATTR_MAX));
102cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      BinaryPrimitive val(Res_value::TYPE_INT_DEC,
103ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                          static_cast<uint32_t>(attr->max_int));
104ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      FlattenEntry(&key, &val);
1051ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1061ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    for (Attribute::Symbol& s : attr->symbols) {
108cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      BinaryPrimitive val(Res_value::TYPE_INT_DEC, s.value);
109ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      FlattenEntry(&s.symbol, &val);
1101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
111cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
1121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
113ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void Visit(Style* style) override {
114cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (style->parent) {
115ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      const Reference& parent_ref = style->parent.value();
116ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      CHECK(bool(parent_ref.id)) << "parent has no ID";
117ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      out_entry_->parent.ident = util::HostToDevice32(parent_ref.id.value().id);
1181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
11959e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski
120cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Sort the style.
121ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    std::sort(style->entries.begin(), style->entries.end(), cmp_style_entries);
12259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski
123cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    for (Style::Entry& entry : style->entries) {
124ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      FlattenEntry(&entry.key, entry.value.get());
12559e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski    }
126cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
12759e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski
128ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void Visit(Styleable* styleable) override {
129ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    for (auto& attr_ref : styleable->entries) {
130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      BinaryPrimitive val(Res_value{});
131ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      FlattenEntry(&attr_ref, &val);
13259e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski    }
133cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
134cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
135ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void Visit(Array* array) override {
136b791721cd1a6154e5582d824f5d20b2c8b8d5ac5Adam Lesinski    for (auto& item : array->elements) {
137ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      ResTable_map* out_entry = buffer_->NextBlock<ResTable_map>();
138ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      FlattenValue(item.get(), out_entry);
139ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      out_entry->value.size = util::HostToDevice16(sizeof(out_entry->value));
140ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      entry_count_++;
14159e04c6f92da584b322c87072f18e6cab4de4c60Adam Lesinski    }
142cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
143cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
144ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void Visit(Plural* plural) override {
145cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    const size_t count = plural->values.size();
146cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    for (size_t i = 0; i < count; i++) {
147cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      if (!plural->values[i]) {
148cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        continue;
149cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
150cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
151cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      ResourceId q;
152cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      switch (i) {
153cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        case Plural::Zero:
154cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          q.id = android::ResTable_map::ATTR_ZERO;
155cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          break;
156cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
157cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        case Plural::One:
158cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          q.id = android::ResTable_map::ATTR_ONE;
159cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          break;
160cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
161cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        case Plural::Two:
162cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          q.id = android::ResTable_map::ATTR_TWO;
163cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          break;
164cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
165cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        case Plural::Few:
166cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          q.id = android::ResTable_map::ATTR_FEW;
167cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          break;
168cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
169cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        case Plural::Many:
170cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          q.id = android::ResTable_map::ATTR_MANY;
171cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          break;
172cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
173cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        case Plural::Other:
174cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          q.id = android::ResTable_map::ATTR_OTHER;
175cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          break;
176cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
177cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        default:
178ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          LOG(FATAL) << "unhandled plural type";
179cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          break;
180cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
181cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
182cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      Reference key(q);
183ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      FlattenEntry(&key, plural->values[i].get());
184cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
185cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
186cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
187cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  /**
188cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * Call this after visiting a Value. This will finish any work that
189cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   * needs to be done to prepare the entry.
190cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski   */
191ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void Finish() { out_entry_->count = util::HostToDevice32(entry_count_); }
192cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
193cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski private:
194ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  DISALLOW_COPY_AND_ASSIGN(MapFlattenVisitor);
195ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
196ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void FlattenKey(Reference* key, ResTable_map* out_entry) {
197ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    CHECK(bool(key->id)) << "key has no ID";
198ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    out_entry->name.ident = util::HostToDevice32(key->id.value().id);
199cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
200cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
201ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void FlattenValue(Item* value, ResTable_map* out_entry) {
202ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    CHECK(value->Flatten(&out_entry->value)) << "flatten failed";
203cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
204cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
205ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  void FlattenEntry(Reference* key, Item* value) {
206ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ResTable_map* out_entry = buffer_->NextBlock<ResTable_map>();
207ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    FlattenKey(key, out_entry);
208ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    FlattenValue(value, out_entry);
209ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    out_entry->value.size = util::HostToDevice16(sizeof(out_entry->value));
210ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    entry_count_++;
211cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
212cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
213ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResTable_entry_ext* out_entry_;
214ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  BigBuffer* buffer_;
215ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  size_t entry_count_ = 0;
2161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski};
2171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
2189ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinskiclass PackageFlattener {
219cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski public:
220ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  PackageFlattener(IAaptContext* context, ResourceTablePackage* package,
221ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski                   const std::map<size_t, std::string>* shared_libs, bool use_sparse_entries)
222c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      : context_(context),
223c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        diag_(context->GetDiagnostics()),
224c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        package_(package),
225ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski        shared_libs_(shared_libs),
226c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        use_sparse_entries_(use_sparse_entries) {}
227cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
228ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  bool FlattenPackage(BigBuffer* buffer) {
229ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ChunkWriter pkg_writer(buffer);
230ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    ResTable_package* pkg_header = pkg_writer.StartChunk<ResTable_package>(RES_TABLE_PACKAGE_TYPE);
231ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    pkg_header->id = util::HostToDevice32(package_->id.value());
232cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
233b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski    // AAPT truncated the package name, so do the same.
234b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski    // Shared libraries require full package names, so don't truncate theirs.
235b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski    if (context_->GetPackageType() != PackageType::kApp &&
236b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski        package_->name.size() >= arraysize(pkg_header->name)) {
237ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      diag_->Error(DiagMessage() << "package name '" << package_->name
238b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski                                 << "' is too long. "
239b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski                                    "Shared libraries cannot have truncated package names");
240cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return false;
2419ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski    }
2429ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
243cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Copy the package name in device endianness.
244b522f04bc2a581e2877bef4a44ac00b827f879edAdam Lesinski    strcpy16_htod(pkg_header->name, arraysize(pkg_header->name), util::Utf8ToUtf16(package_->name));
2459ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
246cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Serialize the types. We do this now so that our type and key strings
247cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // are populated. We write those first.
248ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    BigBuffer type_buffer(1024);
249ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    FlattenTypes(&type_buffer);
2509ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
251ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    pkg_header->typeStrings = util::HostToDevice32(pkg_writer.size());
252ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    StringPool::FlattenUtf16(pkg_writer.buffer(), type_pool_);
2539ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
254ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    pkg_header->keyStrings = util::HostToDevice32(pkg_writer.size());
255ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    StringPool::FlattenUtf8(pkg_writer.buffer(), key_pool_);
2569ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
257cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Append the types.
258ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    buffer->AppendBuffer(std::move(type_buffer));
2599ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
260ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    // If there are libraries (or if the package ID is 0x00), encode a library chunk.
261ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    if (package_->id.value() == 0x00 || !shared_libs_->empty()) {
262ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      FlattenLibrarySpec(buffer);
263ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    }
264ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski
265ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    pkg_writer.Finish();
266cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
267cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
2689ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
269cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski private:
270ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  DISALLOW_COPY_AND_ASSIGN(PackageFlattener);
2711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
272cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  template <typename T, bool IsItem>
273ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  T* WriteEntry(FlatEntry* entry, BigBuffer* buffer) {
274cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    static_assert(std::is_same<ResTable_entry, T>::value ||
2751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                      std::is_same<ResTable_entry_ext, T>::value,
276cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                  "T must be ResTable_entry or ResTable_entry_ext");
2771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
278ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    T* result = buffer->NextBlock<T>();
279ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ResTable_entry* out_entry = (ResTable_entry*)result;
280ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (entry->entry->symbol_status.state == SymbolState::kPublic) {
281ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      out_entry->flags |= ResTable_entry::FLAG_PUBLIC;
282cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
2831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
284ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (entry->value->IsWeak()) {
285ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      out_entry->flags |= ResTable_entry::FLAG_WEAK;
2861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
2871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
288cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (!IsItem) {
289ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      out_entry->flags |= ResTable_entry::FLAG_COMPLEX;
2901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
2911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
292ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    out_entry->flags = util::HostToDevice16(out_entry->flags);
293ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    out_entry->key.index = util::HostToDevice32(entry->entry_key);
294ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    out_entry->size = util::HostToDevice16(sizeof(T));
295cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return result;
296cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
297cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
298ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  bool FlattenValue(FlatEntry* entry, BigBuffer* buffer) {
299ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (Item* item = ValueCast<Item>(entry->value)) {
300ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      WriteEntry<ResTable_entry, true>(entry, buffer);
301ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      Res_value* outValue = buffer->NextBlock<Res_value>();
302ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      CHECK(item->Flatten(outValue)) << "flatten failed";
303ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      outValue->size = util::HostToDevice16(sizeof(*outValue));
304cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    } else {
305ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      ResTable_entry_ext* out_entry =
306ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          WriteEntry<ResTable_entry_ext, false>(entry, buffer);
307ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      MapFlattenVisitor visitor(out_entry, buffer);
308ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      entry->value->Accept(&visitor);
309ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      visitor.Finish();
310cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
311cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
312cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
313cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
314c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski  bool FlattenConfig(const ResourceTableType* type, const ConfigDescription& config,
315c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski                     const size_t num_total_entries, std::vector<FlatEntry>* entries,
316c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski                     BigBuffer* buffer) {
317c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    CHECK(num_total_entries != 0);
318c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    CHECK(num_total_entries <= std::numeric_limits<uint16_t>::max());
319c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
320ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ChunkWriter type_writer(buffer);
321ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ResTable_type* type_header =
322ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        type_writer.StartChunk<ResTable_type>(RES_TABLE_TYPE_TYPE);
323ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    type_header->id = type->id.value();
324ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    type_header->config = config;
325ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    type_header->config.swapHtoD();
326ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
327c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    std::vector<uint32_t> offsets;
328c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    offsets.resize(num_total_entries, 0xffffffffu);
329cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
330c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    BigBuffer values_buffer(512);
331ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    for (FlatEntry& flat_entry : *entries) {
332c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      CHECK(static_cast<size_t>(flat_entry.entry->id.value()) < num_total_entries);
333c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      offsets[flat_entry.entry->id.value()] = values_buffer.size();
334c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      if (!FlattenValue(&flat_entry, &values_buffer)) {
335ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        diag_->Error(DiagMessage()
336cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                     << "failed to flatten resource '"
337c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski                     << ResourceNameRef(package_->name, type->type, flat_entry.entry->name)
338cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                     << "' for configuration '" << config << "'");
339cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        return false;
340cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
3411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
342c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
343c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    bool sparse_encode = use_sparse_entries_;
344c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
345c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    // Only sparse encode if the entries will be read on platforms O+.
346c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    sparse_encode =
347c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        sparse_encode && (context_->GetMinSdkVersion() >= SDK_O || config.sdkVersion >= SDK_O);
348c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
349c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    // Only sparse encode if the offsets are representable in 2 bytes.
350c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    sparse_encode =
351c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        sparse_encode && (values_buffer.size() / 4u) <= std::numeric_limits<uint16_t>::max();
352c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
353c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    // Only sparse encode if the ratio of populated entries to total entries is below some
354c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    // threshold.
355c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    sparse_encode =
356c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        sparse_encode && ((100 * entries->size()) / num_total_entries) < kSparseEncodingThreshold;
357c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
358c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    if (sparse_encode) {
359c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      type_header->entryCount = util::HostToDevice32(entries->size());
360c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      type_header->flags |= ResTable_type::FLAG_SPARSE;
361c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      ResTable_sparseTypeEntry* indices =
362c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski          type_writer.NextBlock<ResTable_sparseTypeEntry>(entries->size());
363c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      for (size_t i = 0; i < num_total_entries; i++) {
364c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        if (offsets[i] != ResTable_type::NO_ENTRY) {
365c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski          CHECK((offsets[i] & 0x03) == 0);
366c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski          indices->idx = util::HostToDevice16(i);
367c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski          indices->offset = util::HostToDevice16(offsets[i] / 4u);
368c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski          indices++;
369c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        }
370c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      }
371c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    } else {
372c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      type_header->entryCount = util::HostToDevice32(num_total_entries);
373c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      uint32_t* indices = type_writer.NextBlock<uint32_t>(num_total_entries);
374c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      for (size_t i = 0; i < num_total_entries; i++) {
375c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        indices[i] = util::HostToDevice32(offsets[i]);
376c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      }
377c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    }
378c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
379c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    type_header->entriesStart = util::HostToDevice32(type_writer.size());
380c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    type_writer.buffer()->AppendBuffer(std::move(values_buffer));
381ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    type_writer.Finish();
382cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
383cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
3841ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
385ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::vector<ResourceTableType*> CollectAndSortTypes() {
386ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    std::vector<ResourceTableType*> sorted_types;
387ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    for (auto& type : package_->types) {
388cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      if (type->type == ResourceType::kStyleable) {
389cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        // Styleables aren't real Resource Types, they are represented in the
390ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        // R.java file.
391cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        continue;
392cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
3931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
394ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      CHECK(bool(type->id)) << "type must have an ID set";
3951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
396ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      sorted_types.push_back(type.get());
3971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
398ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    std::sort(sorted_types.begin(), sorted_types.end(),
399ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski              cmp_ids<ResourceTableType>);
400ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    return sorted_types;
401cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
402cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
403ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  std::vector<ResourceEntry*> CollectAndSortEntries(ResourceTableType* type) {
404cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Sort the entries by entry ID.
405ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    std::vector<ResourceEntry*> sorted_entries;
406cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    for (auto& entry : type->entries) {
407ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      CHECK(bool(entry->id)) << "entry must have an ID set";
408ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      sorted_entries.push_back(entry.get());
409cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
410c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski    std::sort(sorted_entries.begin(), sorted_entries.end(), cmp_ids<ResourceEntry>);
411ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    return sorted_entries;
412cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
413cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
414ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  bool FlattenTypeSpec(ResourceTableType* type,
415ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                       std::vector<ResourceEntry*>* sorted_entries,
416cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                       BigBuffer* buffer) {
417ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ChunkWriter type_spec_writer(buffer);
418ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    ResTable_typeSpec* spec_header =
419ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        type_spec_writer.StartChunk<ResTable_typeSpec>(
420ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            RES_TABLE_TYPE_SPEC_TYPE);
421ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    spec_header->id = type->id.value();
422ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
423ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (sorted_entries->empty()) {
424ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      type_spec_writer.Finish();
425cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return true;
4261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
4271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
428cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // We can't just take the size of the vector. There may be holes in the
429cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // entry ID space.
430cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Since the entries are sorted by ID, the last one will be the biggest.
431ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    const size_t num_entries = sorted_entries->back()->id.value() + 1;
4321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
433ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    spec_header->entryCount = util::HostToDevice32(num_entries);
4341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
435cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Reserve space for the masks of each resource in this type. These
436cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // show for which configuration axis the resource changes.
437ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    uint32_t* config_masks = type_spec_writer.NextBlock<uint32_t>(num_entries);
4381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
439ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    const size_t actual_num_entries = sorted_entries->size();
440ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    for (size_t entryIndex = 0; entryIndex < actual_num_entries; entryIndex++) {
441ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      ResourceEntry* entry = sorted_entries->at(entryIndex);
4421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
443cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // Populate the config masks for this entry.
4441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
445ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      if (entry->symbol_status.state == SymbolState::kPublic) {
446ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        config_masks[entry->id.value()] |=
447ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            util::HostToDevice32(ResTable_typeSpec::SPEC_PUBLIC);
448cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
4491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
450ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      const size_t config_count = entry->values.size();
451ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      for (size_t i = 0; i < config_count; i++) {
452cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        const ConfigDescription& config = entry->values[i]->config;
453ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        for (size_t j = i + 1; j < config_count; j++) {
454ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          config_masks[entry->id.value()] |=
455ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski              util::HostToDevice32(config.diff(entry->values[j]->config));
4561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
457cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
4581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
459ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    type_spec_writer.Finish();
460cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
461cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
462cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
463ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  bool FlattenTypes(BigBuffer* buffer) {
464cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Sort the types by their IDs. They will be inserted into the StringPool in
465cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // this order.
466ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    std::vector<ResourceTableType*> sorted_types = CollectAndSortTypes();
467cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
468ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    size_t expected_type_id = 1;
469ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    for (ResourceTableType* type : sorted_types) {
470cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // If there is a gap in the type IDs, fill in the StringPool
471cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // with empty values until we reach the ID we expect.
472ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      while (type->id.value() > expected_type_id) {
473ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        std::stringstream type_name;
474ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        type_name << "?" << expected_type_id;
475ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        type_pool_.MakeRef(type_name.str());
476ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        expected_type_id++;
477cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
478ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      expected_type_id++;
479ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      type_pool_.MakeRef(ToString(type->type));
480cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
481ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      std::vector<ResourceEntry*> sorted_entries = CollectAndSortEntries(type);
482ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      if (sorted_entries.empty()) {
483ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski        continue;
484ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      }
485ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski
486ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      if (!FlattenTypeSpec(type, &sorted_entries, buffer)) {
487cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        return false;
488cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
489cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
490c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      // Since the entries are sorted by ID, the last ID will be the largest.
491c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      const size_t num_entries = sorted_entries.back()->id.value() + 1;
492c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski
493cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // The binary resource table lists resource entries for each
494cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // configuration.
495cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // We store them inverted, where a resource entry lists the values for
496cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // each
497cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // configuration available. Here we reverse this to match the binary
498cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // table.
499c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski      std::map<ConfigDescription, std::vector<FlatEntry>> config_to_entry_list_map;
500ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      for (ResourceEntry* entry : sorted_entries) {
501c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        const uint32_t key_index = (uint32_t)key_pool_.MakeRef(entry->name).index();
502cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
503cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        // Group values by configuration.
504ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        for (auto& config_value : entry->values) {
505ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski          config_to_entry_list_map[config_value->config].push_back(
506ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski              FlatEntry{entry, config_value->value.get(), key_index});
507cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        }
508cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
5091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
510cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      // Flatten a configuration value.
511ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      for (auto& entry : config_to_entry_list_map) {
512c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski        if (!FlattenConfig(type, entry.first, num_entries, &entry.second, buffer)) {
513cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          return false;
5141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
515cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
5161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
517cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
518cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
519ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
520ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  void FlattenLibrarySpec(BigBuffer* buffer) {
521ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    ChunkWriter lib_writer(buffer);
522ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    ResTable_lib_header* lib_header =
523ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski        lib_writer.StartChunk<ResTable_lib_header>(RES_TABLE_LIBRARY_TYPE);
524ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski
525ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    const size_t num_entries = (package_->id.value() == 0x00 ? 1 : 0) + shared_libs_->size();
526ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    CHECK(num_entries > 0);
527ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski
528ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    lib_header->count = util::HostToDevice32(num_entries);
529ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski
530ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    ResTable_lib_entry* lib_entry = buffer->NextBlock<ResTable_lib_entry>(num_entries);
531ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    if (package_->id.value() == 0x00) {
532ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      // Add this package
533ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      lib_entry->packageId = util::HostToDevice32(0x00);
534ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      strcpy16_htod(lib_entry->packageName, arraysize(lib_entry->packageName),
535ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski                    util::Utf8ToUtf16(package_->name));
536ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      ++lib_entry;
537ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    }
538ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski
539ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    for (auto& map_entry : *shared_libs_) {
540ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      lib_entry->packageId = util::HostToDevice32(map_entry.first);
541ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      strcpy16_htod(lib_entry->packageName, arraysize(lib_entry->packageName),
542ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski                    util::Utf8ToUtf16(map_entry.second));
543ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski      ++lib_entry;
544ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    }
545ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    lib_writer.Finish();
546ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  }
547ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski
548c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski  IAaptContext* context_;
549ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  IDiagnostics* diag_;
550ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ResourceTablePackage* package_;
551ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski  const std::map<size_t, std::string>* shared_libs_;
552c8f71aa67ea599cb80205496cb67e9e7a121299cAdam Lesinski  bool use_sparse_entries_;
553ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  StringPool type_pool_;
554ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  StringPool key_pool_;
5559ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski};
5561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
557cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace
5581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
559ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool TableFlattener::Consume(IAaptContext* context, ResourceTable* table) {
5605b6ee115489ce93dafce57d7f5ac33564cd6ef52Adam Lesinski  // We must do this before writing the resources, since the string pool IDs may change.
561ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  table->string_pool.Prune();
5625b6ee115489ce93dafce57d7f5ac33564cd6ef52Adam Lesinski  table->string_pool.Sort([](const StringPool::Context& a, const StringPool::Context& b) -> int {
5635b6ee115489ce93dafce57d7f5ac33564cd6ef52Adam Lesinski    int diff = util::compare(a.priority, b.priority);
5645b6ee115489ce93dafce57d7f5ac33564cd6ef52Adam Lesinski    if (diff == 0) {
5655b6ee115489ce93dafce57d7f5ac33564cd6ef52Adam Lesinski      diff = a.config.compare(b.config);
5665b6ee115489ce93dafce57d7f5ac33564cd6ef52Adam Lesinski    }
5675b6ee115489ce93dafce57d7f5ac33564cd6ef52Adam Lesinski    return diff;
5685b6ee115489ce93dafce57d7f5ac33564cd6ef52Adam Lesinski  });
5699ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
570cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Write the ResTable header.
571ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  ChunkWriter table_writer(buffer_);
5724ca56978a9aea3f021a54ed9265de10811984d94Adam Lesinski  ResTable_header* table_header = table_writer.StartChunk<ResTable_header>(RES_TABLE_TYPE);
573ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  table_header->packageCount = util::HostToDevice32(table->packages.size());
5749ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
5754ca56978a9aea3f021a54ed9265de10811984d94Adam Lesinski  // Write a self mapping entry for this package if the ID is non-standard (0x7f).
5764ca56978a9aea3f021a54ed9265de10811984d94Adam Lesinski  if (context->GetPackageType() == PackageType::kApp) {
5774ca56978a9aea3f021a54ed9265de10811984d94Adam Lesinski    const uint8_t package_id = context->GetPackageId();
5784ca56978a9aea3f021a54ed9265de10811984d94Adam Lesinski    if (package_id != kFrameworkPackageId && package_id != kAppPackageId) {
5794ca56978a9aea3f021a54ed9265de10811984d94Adam Lesinski      table->included_packages_[package_id] = context->GetCompilationPackage();
5804ca56978a9aea3f021a54ed9265de10811984d94Adam Lesinski    }
5814ca56978a9aea3f021a54ed9265de10811984d94Adam Lesinski  }
5824ca56978a9aea3f021a54ed9265de10811984d94Adam Lesinski
583cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Flatten the values string pool.
584ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool);
5859ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
586ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  BigBuffer package_buffer(1024);
5879ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski
588cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Flatten each package.
589cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  for (auto& package : table->packages) {
590ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski    PackageFlattener flattener(context, package.get(), &table->included_packages_,
591ceb9b2f80f853059233cdd29057f39a5960a74aeAdam Lesinski                               options_.use_sparse_entries);
592ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (!flattener.FlattenPackage(&package_buffer)) {
593cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return false;
5949ba47d813075fcb05c5e1532c137c93b394631cbAdam Lesinski    }
595cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
5961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
597cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  // Finally merge all the packages into the main buffer.
598ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  table_writer.buffer()->AppendBuffer(std::move(package_buffer));
599ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  table_writer.Finish();
600cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return true;
6011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
6021ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
603cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
604