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_RESOURCEUTILS_H 18 #define AAPT_RESOURCEUTILS_H 19 20 #include <functional> 21 #include <memory> 22 23 #include "NameMangler.h" 24 #include "Resource.h" 25 #include "ResourceValues.h" 26 #include "androidfw/AssetManager2.h" 27 #include "androidfw/ConfigDescription.h" 28 #include "androidfw/ResourceTypes.h" 29 #include "androidfw/StringPiece.h" 30 #include "androidfw/StringPool.h" 31 32 namespace aapt { 33 namespace ResourceUtils { 34 35 /** 36 * Returns true if the string was parsed as a resource name 37 * ([*][package:]type/name), with 38 * `out_resource` set to the parsed resource name and `out_private` set to true 39 * if a '*' prefix was present. 40 */ 41 bool ParseResourceName(android::StringPiece str, ResourceNameRef* out_resource, 42 bool* out_private = nullptr); 43 44 /* 45 * Returns true if the string was parsed as a reference 46 * (@[+][package:]type/name), with 47 * `out_reference` set to the parsed reference. 48 * 49 * If '+' was present in the reference, `out_create` is set to true. 50 * If '*' was present in the reference, `out_private` is set to true. 51 */ 52 bool ParseReference(android::StringPiece str, ResourceNameRef* out_reference, 53 bool* out_create = nullptr, bool* out_private = nullptr); 54 55 /* 56 * Returns true if the string is in the form of a resource reference 57 * (@[+][package:]type/name). 58 */ 59 bool IsReference(android::StringPiece str); 60 61 /* 62 * Returns true if the string was parsed as an attribute reference 63 * (?[package:][type/]name), 64 * with `out_reference` set to the parsed reference. 65 */ 66 bool ParseAttributeReference(android::StringPiece str, ResourceNameRef* out_reference); 67 68 /** 69 * Returns true if the string is in the form of an attribute 70 * reference(?[package:][type/]name). 71 */ 72 bool IsAttributeReference(android::StringPiece str); 73 74 /** 75 * Convert an android::ResTable::resource_name to an aapt::ResourceName struct. 76 */ 77 std::optional<ResourceName> ToResourceName(const android::ResTable::resource_name& name); 78 79 /** 80 * Convert an android::AssetManager2::ResourceName to an aapt::ResourceName struct. 81 */ 82 std::optional<ResourceName> ToResourceName(const android::AssetManager2::ResourceName& name_in); 83 84 /** 85 * Returns a boolean value if the string is equal to TRUE, true, True, FALSE, 86 * false, or False. 87 */ 88 std::optional<bool> ParseBool(android::StringPiece str); 89 90 /** 91 * Returns a uint32_t if the string is an integer. 92 */ 93 std::optional<uint32_t> ParseInt(android::StringPiece str); 94 95 /** 96 * Returns an ID if it the string represented a valid ID. 97 */ 98 std::optional<ResourceId> ParseResourceId(android::StringPiece str); 99 100 /** 101 * Parses an SDK version, which can be an integer, or a letter from A-Z. 102 */ 103 std::optional<int> ParseSdkVersion(android::StringPiece str); 104 105 /* 106 * Returns a Reference, or None Maybe instance if the string `str` was parsed as 107 * a 108 * valid reference to a style. 109 * The format for a style parent is slightly more flexible than a normal 110 * reference: 111 * 112 * @[package:]style/<entry> or 113 * ?[package:]style/<entry> or 114 * <package>:[style/]<entry> 115 */ 116 std::optional<Reference> ParseStyleParentReference(android::StringPiece str, 117 std::string* out_error); 118 119 /* 120 * Returns a Reference if the string `str` was parsed as a valid XML attribute 121 * name. 122 * The valid format for an XML attribute name is: 123 * 124 * package:entry 125 */ 126 std::optional<Reference> ParseXmlAttributeName(android::StringPiece str); 127 128 /* 129 * Returns a Reference object if the string was parsed as a resource or 130 * attribute reference, 131 * ( @[+][package:]type/name | ?[package:]type/name ) setting outCreate to true 132 * if 133 * the '+' was present in the string. 134 */ 135 std::unique_ptr<Reference> TryParseReference(android::StringPiece str, bool* out_create = nullptr); 136 137 /* 138 * Returns a BinaryPrimitve object representing @null or @empty if the string 139 * was parsed as one. 140 */ 141 std::unique_ptr<Item> TryParseNullOrEmpty(android::StringPiece str); 142 143 // Returns a Reference representing @null. 144 // Due to runtime compatibility issues, this is encoded as a reference with ID 0. 145 // The runtime will convert this to TYPE_NULL. 146 std::unique_ptr<Reference> MakeNull(); 147 148 // Returns a BinaryPrimitive representing @empty. This is encoded as a Res_value with 149 // type Res_value::TYPE_NULL and data Res_value::DATA_NULL_EMPTY. 150 std::unique_ptr<BinaryPrimitive> MakeEmpty(); 151 152 /* 153 * Returns a BinaryPrimitve object representing a color if the string was parsed 154 * as one. 155 */ 156 std::unique_ptr<BinaryPrimitive> TryParseColor(android::StringPiece str); 157 158 /* 159 * Returns a BinaryPrimitve object representing a boolean if the string was 160 * parsed as one. 161 */ 162 std::unique_ptr<BinaryPrimitive> TryParseBool(android::StringPiece str); 163 164 // Returns a boolean BinaryPrimitive. 165 std::unique_ptr<BinaryPrimitive> MakeBool(bool val); 166 167 /* 168 * Returns a BinaryPrimitve object representing an integer if the string was 169 * parsed as one. 170 */ 171 std::unique_ptr<BinaryPrimitive> TryParseInt(android::StringPiece str); 172 173 // Returns an integer BinaryPrimitive. 174 std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t value); 175 176 /* 177 * Returns a BinaryPrimitve object representing a floating point number 178 * (float, dimension, etc) if the string was parsed as one. 179 */ 180 std::unique_ptr<BinaryPrimitive> TryParseFloat(android::StringPiece str); 181 182 /* 183 * Returns a BinaryPrimitve object representing an enum symbol if the string was 184 * parsed as one. 185 */ 186 std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr, 187 android::StringPiece str); 188 189 /* 190 * Returns a BinaryPrimitve object representing a flag symbol if the string was 191 * parsed as one. 192 */ 193 std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* enum_attr, 194 android::StringPiece str); 195 /* 196 * Try to convert a string to an Item for the given attribute. The attribute 197 * will 198 * restrict what values the string can be converted to. 199 * The callback function on_create_reference is called when the parsed item is a 200 * reference to an ID that must be created (@+id/foo). 201 */ 202 std::unique_ptr<Item> TryParseItemForAttribute( 203 android::IDiagnostics* diag, android::StringPiece value, const Attribute* attr, 204 const std::function<bool(const ResourceName&)>& on_create_reference = {}); 205 206 std::unique_ptr<Item> TryParseItemForAttribute( 207 android::IDiagnostics* diag, android::StringPiece value, uint32_t type_mask, 208 const std::function<bool(const ResourceName&)>& on_create_reference = {}); 209 210 uint32_t AndroidTypeToAttributeTypeMask(uint16_t type); 211 212 /** 213 * Returns a string path suitable for use within an APK. The path will look 214 * like: 215 * 216 * res/type[-config]/<name>.<ext> 217 * 218 * Then name may be mangled if a NameMangler is supplied (can be nullptr) and 219 * the package 220 * requires mangling. 221 */ 222 std::string BuildResourceFileName(const ResourceFile& res_file, 223 const NameMangler* mangler = nullptr); 224 225 // Parses the binary form of a resource value. `type` is used as a hint to know when a value is 226 // an ID versus a False boolean value, etc. `config` is for sorting strings in the string pool. 227 std::unique_ptr<Item> ParseBinaryResValue(const ResourceType& type, 228 const android::ConfigDescription& config, 229 const android::ResStringPool& src_pool, 230 const android::Res_value& res_value, 231 android::StringPool* dst_pool); 232 233 // A string flattened from an XML hierarchy, which maintains tags and untranslatable sections 234 // in parallel data structures. 235 struct FlattenedXmlString { 236 std::string text; 237 std::vector<UntranslatableSection> untranslatable_sections; 238 std::vector<android::Span> spans; 239 }; 240 241 // Flattens an XML hierarchy into a FlattenedXmlString, formatting the text, escaping characters, 242 // and removing whitespace, all while keeping the untranslatable sections and spans in sync with the 243 // transformations. 244 // 245 // Specifically, the StringBuilder will handle escaped characters like \t, \n, \\, \', etc. 246 // Single quotes *must* be escaped, unless within a pair of double-quotes. 247 // Pairs of double-quotes disable whitespace stripping of the enclosed text. 248 // Unicode escape codes (\u0049) are interpreted and the represented Unicode character is inserted. 249 // 250 // A NOTE ON WHITESPACE: 251 // 252 // When preserve_spaces is false, and when text is not enclosed within double-quotes, 253 // StringBuilder replaces a series of whitespace with a single space character. This happens at the 254 // start and end of the string as well, so leading and trailing whitespace is possible. 255 // 256 // When a Span is started or stopped, the whitespace counter is reset, meaning if whitespace 257 // is encountered directly after the span, it will be emitted. This leads to situations like the 258 // following: "This <b> is </b> spaced" -> "This is spaced". Without spans, this would be properly 259 // compressed: "This is spaced" -> "This is spaced". 260 // 261 // Untranslatable sections do not have the same problem: 262 // "This <xliff:g> is </xliff:g> not spaced" -> "This is not spaced". 263 // 264 // NOTE: This is all the way it is because AAPT1 did it this way. Maintaining backwards 265 // compatibility is important. 266 // 267 class StringBuilder { 268 public: 269 using SpanHandle = size_t; 270 using UntranslatableHandle = size_t; 271 272 // Creates a StringBuilder. If preserve_spaces is true, whitespace removal is not performed, and 273 // single quotations can be used without escaping them. 274 explicit StringBuilder(bool preserve_spaces = false); 275 276 // Appends a chunk of text. 277 StringBuilder& AppendText(const std::string& text); 278 279 // Starts a Span (tag) with the given name. The name is expected to be of the form: 280 // "tag_name;attr1=value;attr2=value;" 281 // Which is how Spans are encoded in the ResStringPool. 282 // To end the span, pass back the SpanHandle received from this method to the EndSpan() method. 283 SpanHandle StartSpan(const std::string& name); 284 285 // Ends a Span (tag). Pass in the matching SpanHandle previously obtained from StartSpan(). 286 void EndSpan(SpanHandle handle); 287 288 // Starts an Untranslatable section. 289 // To end the section, pass back the UntranslatableHandle received from this method to 290 // the EndUntranslatable() method. 291 UntranslatableHandle StartUntranslatable(); 292 293 // Ends an Untranslatable section. Pass in the matching UntranslatableHandle previously obtained 294 // from StartUntranslatable(). 295 void EndUntranslatable(UntranslatableHandle handle); 296 297 // Returns the flattened XML string, with all spans and untranslatable sections encoded as 298 // parallel data structures. 299 FlattenedXmlString GetFlattenedString() const; 300 301 // Returns just the flattened XML text, with no spans or untranslatable sections. 302 std::string to_string() const; 303 304 // Returns true if there was no error. 305 explicit operator bool() const; 306 307 std::string GetError() const; 308 309 private: 310 DISALLOW_COPY_AND_ASSIGN(StringBuilder); 311 312 void ResetTextState(); 313 314 std::string error_; 315 FlattenedXmlString xml_string_; 316 uint32_t utf16_len_ = 0u; 317 bool preserve_spaces_; 318 bool quote_; 319 bool last_codepoint_was_space_ = false; 320 }; 321 322 } // namespace ResourceUtils 323 } // namespace aapt 324 325 #endif /* AAPT_RESOURCEUTILS_H */ 326