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 
17 #ifndef AAPT_STRING_POOL_H
18 #define AAPT_STRING_POOL_H
19 
20 #include <functional>
21 #include <memory>
22 #include <string>
23 #include <unordered_map>
24 #include <vector>
25 
26 #include "android-base/macros.h"
27 #include "androidfw/ConfigDescription.h"
28 #include "androidfw/StringPiece.h"
29 
30 #include "Diagnostics.h"
31 #include "util/BigBuffer.h"
32 
33 namespace aapt {
34 
35 struct Span {
36   std::string name;
37   uint32_t first_char;
38   uint32_t last_char;
39 };
40 
41 struct StyleString {
42   std::string str;
43   std::vector<Span> spans;
44 };
45 
46 // A StringPool for storing the value of String and StyledString resources.
47 // Styles and Strings are stored separately, since the runtime variant of this
48 // class -- ResStringPool -- requires that styled strings *always* appear first, since their
49 // style data is stored as an array indexed by the same indices as the main string pool array.
50 // Otherwise, the style data array would have to be sparse and take up more space.
51 class StringPool {
52  public:
53   using size_type = size_t;
54 
55   class Context {
56    public:
57     enum : uint32_t {
58       kHighPriority = 1u,
59       kNormalPriority = 0x7fffffffu,
60       kLowPriority = 0xffffffffu,
61     };
62     uint32_t priority = kNormalPriority;
63     android::ConfigDescription config;
64 
65     Context() = default;
Context(uint32_t p,const android::ConfigDescription & c)66     Context(uint32_t p, const android::ConfigDescription& c) : priority(p), config(c) {}
Context(uint32_t p)67     explicit Context(uint32_t p) : priority(p) {}
Context(const android::ConfigDescription & c)68     explicit Context(const android::ConfigDescription& c) : priority(kNormalPriority), config(c) {
69     }
70   };
71 
72   class Entry;
73 
74   class Ref {
75    public:
76     Ref();
77     Ref(const Ref&);
78     ~Ref();
79 
80     Ref& operator=(const Ref& rhs);
81     bool operator==(const Ref& rhs) const;
82     bool operator!=(const Ref& rhs) const;
83     const std::string* operator->() const;
84     const std::string& operator*() const;
85 
86     size_t index() const;
87     const Context& GetContext() const;
88 
89    private:
90     friend class StringPool;
91 
92     explicit Ref(Entry* entry);
93 
94     Entry* entry_;
95   };
96 
97   class StyleEntry;
98 
99   class StyleRef {
100    public:
101     StyleRef();
102     StyleRef(const StyleRef&);
103     ~StyleRef();
104 
105     StyleRef& operator=(const StyleRef& rhs);
106     bool operator==(const StyleRef& rhs) const;
107     bool operator!=(const StyleRef& rhs) const;
108     const StyleEntry* operator->() const;
109     const StyleEntry& operator*() const;
110 
111     size_t index() const;
112     const Context& GetContext() const;
113 
114    private:
115     friend class StringPool;
116 
117     explicit StyleRef(StyleEntry* entry);
118 
119     StyleEntry* entry_;
120   };
121 
122   class Entry {
123    public:
124     std::string value;
125     Context context;
126 
127    private:
128     friend class StringPool;
129     friend class Ref;
130 
131     size_t index_;
132     int ref_;
133     const StringPool* pool_;
134   };
135 
136   struct Span {
137     Ref name;
138     uint32_t first_char;
139     uint32_t last_char;
140   };
141 
142   class StyleEntry {
143    public:
144     std::string value;
145     Context context;
146     std::vector<Span> spans;
147 
148    private:
149     friend class StringPool;
150     friend class StyleRef;
151 
152     size_t index_;
153     int ref_;
154   };
155 
156   static bool FlattenUtf8(BigBuffer* out, const StringPool& pool, IDiagnostics* diag);
157   static bool FlattenUtf16(BigBuffer* out, const StringPool& pool, IDiagnostics* diag);
158 
159   StringPool() = default;
160   StringPool(StringPool&&) = default;
161   StringPool& operator=(StringPool&&) = default;
162 
163   // Adds a string to the pool, unless it already exists. Returns a reference to the string in the
164   // pool.
165   Ref MakeRef(const android::StringPiece& str);
166 
167   // Adds a string to the pool, unless it already exists, with a context object that can be used
168   // when sorting the string pool. Returns a reference to the string in the pool.
169   Ref MakeRef(const android::StringPiece& str, const Context& context);
170 
171   // Adds a string from another string pool. Returns a reference to the string in the string pool.
172   Ref MakeRef(const Ref& ref);
173 
174   // Adds a style to the string pool and returns a reference to it.
175   StyleRef MakeRef(const StyleString& str);
176 
177   // Adds a style to the string pool with a context object that can be used when sorting the string
178   // pool. Returns a reference to the style in the string pool.
179   StyleRef MakeRef(const StyleString& str, const Context& context);
180 
181   // Adds a style from another string pool. Returns a reference to the style in the string pool.
182   StyleRef MakeRef(const StyleRef& ref);
183 
184   // Moves pool into this one without coalescing strings. When this function returns, pool will be
185   // empty.
186   void Merge(StringPool&& pool);
187 
strings()188   inline const std::vector<std::unique_ptr<Entry>>& strings() const {
189     return strings_;
190   }
191 
192   // Returns the number of strings in the table.
size()193   inline size_t size() const {
194     return styles_.size() + strings_.size();
195   }
196 
197   // Reserves space for strings and styles as an optimization.
198   void HintWillAdd(size_t string_count, size_t style_count);
199 
200   // Sorts the strings according to their Context using some comparison function.
201   // Equal Contexts are further sorted by string value, lexicographically.
202   // If no comparison function is provided, values are only sorted lexicographically.
203   void Sort(const std::function<int(const Context&, const Context&)>& cmp = nullptr);
204 
205   // Removes any strings that have no references.
206   void Prune();
207 
208  private:
209   DISALLOW_COPY_AND_ASSIGN(StringPool);
210 
211   static bool Flatten(BigBuffer* out, const StringPool& pool, bool utf8, IDiagnostics* diag);
212 
213   Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique);
214   void ReAssignIndices();
215 
216   std::vector<std::unique_ptr<Entry>> strings_;
217   std::vector<std::unique_ptr<StyleEntry>> styles_;
218   std::unordered_multimap<android::StringPiece, Entry*> indexed_strings_;
219 };
220 
221 }  // namespace aapt
222 
223 #endif  // AAPT_STRING_POOL_H
224