1 /*
2  * Copyright (C) 2017 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 #include "androidfw/ResourceUtils.h"
18 
19 namespace android {
20 
ExtractResourceName(StringPiece str,StringPiece * out_package,StringPiece * out_type,StringPiece * out_entry)21 bool ExtractResourceName(StringPiece str, StringPiece* out_package, StringPiece* out_type,
22                          StringPiece* out_entry) {
23   *out_package = "";
24   *out_type = "";
25   bool has_package_separator = false;
26   bool has_type_separator = false;
27   const char* start = str.data();
28   const char* end = start + str.size();
29   if (start[0] == '@') {
30       start++;
31   }
32   const char* current = start;
33   while (current != end) {
34     if (out_type->size() == 0 && *current == '/') {
35       has_type_separator = true;
36       *out_type = StringPiece(start, current - start);
37       start = current + 1;
38     } else if (out_package->size() == 0 && *current == ':') {
39       has_package_separator = true;
40       *out_package = StringPiece(start, current - start);
41       start = current + 1;
42     }
43     current++;
44   }
45   *out_entry = StringPiece(start, end - start);
46 
47   return !(has_package_separator && out_package->empty()) &&
48          !(has_type_separator && out_type->empty());
49 }
50 
ToResourceName(const StringPoolRef & type_string_ref,const StringPoolRef & entry_string_ref,StringPiece package_name)51 base::expected<AssetManager2::ResourceName, NullOrIOError> ToResourceName(
52     const StringPoolRef& type_string_ref, const StringPoolRef& entry_string_ref,
53     StringPiece package_name) {
54   AssetManager2::ResourceName name{
55     .package = package_name.data(),
56     .package_len = package_name.size(),
57   };
58 
59   if (base::expected<StringPiece, NullOrIOError> type_str = type_string_ref.string8();
60       type_str.ok()) {
61     name.type = type_str->data();
62     name.type_len = type_str->size();
63   } else if (UNLIKELY(IsIOError(type_str))) {
64     return base::unexpected(type_str.error());
65   }
66 
67   if (name.type == nullptr) {
68     if (base::expected<StringPiece16, NullOrIOError> type16_str = type_string_ref.string16();
69         type16_str.ok()) {
70       name.type16 = type16_str->data();
71       name.type_len = type16_str->size();
72     } else if (!type16_str.has_value()) {
73       return base::unexpected(type16_str.error());
74     }
75   }
76 
77   if (base::expected<StringPiece, NullOrIOError> entry_str = entry_string_ref.string8();
78       entry_str.ok()) {
79     name.entry = entry_str->data();
80     name.entry_len = entry_str->size();
81   } else if (UNLIKELY(IsIOError(entry_str))) {
82     return base::unexpected(entry_str.error());
83   }
84 
85   if (name.entry == nullptr) {
86     if (base::expected<StringPiece16, NullOrIOError> entry16_str = entry_string_ref.string16();
87         entry16_str.ok()) {
88       name.entry16 = entry16_str->data();
89       name.entry_len = entry16_str->size();
90     } else if (!entry16_str.has_value()) {
91       return base::unexpected(entry16_str.error());
92     }
93   }
94 
95   return name;
96 }
97 
ToFormattedResourceString(const AssetManager2::ResourceName & resource_name)98 std::string ToFormattedResourceString(const AssetManager2::ResourceName& resource_name) {
99   std::string result;
100   if (resource_name.package != nullptr) {
101     result.append(resource_name.package, resource_name.package_len);
102   }
103 
104   if (resource_name.type != nullptr || resource_name.type16 != nullptr) {
105     if (!result.empty()) {
106       result += ":";
107     }
108 
109     if (resource_name.type != nullptr) {
110       result.append(resource_name.type, resource_name.type_len);
111     } else {
112       result += util::Utf16ToUtf8(StringPiece16(resource_name.type16, resource_name.type_len));
113     }
114   }
115 
116   if (resource_name.entry != nullptr || resource_name.entry16 != nullptr) {
117     if (!result.empty()) {
118       result += "/";
119     }
120 
121     if (resource_name.entry != nullptr) {
122       result.append(resource_name.entry, resource_name.entry_len);
123     } else {
124       result += util::Utf16ToUtf8(StringPiece16(resource_name.entry16, resource_name.entry_len));
125     }
126   }
127 
128   return result;
129 }
130 
131 }  // namespace android
132