1 /**
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "plugins/ets/runtime/ani/ani_mangle.h"
17 #include "plugins/ets/runtime/ets_panda_file_items.h"
18
19 namespace ark::ets::ani {
20
21 static size_t ParseArrayBody(const std::string_view data, PandaStringStream &ss);
22
23 /*static*/
ConvertDescriptor(const std::string_view descriptor,bool allowArray)24 PandaString Mangle::ConvertDescriptor(const std::string_view descriptor, bool allowArray)
25 {
26 if (descriptor.empty() || descriptor.back() == ';' || descriptor.find('/') != std::string::npos) {
27 // The 'descriptor' does not have a new format, so no conversion is required.
28 return PandaString(descriptor);
29 }
30
31 PandaStringStream ss;
32 if (allowArray) {
33 // NOLINTNEXTLINE(readability-magic-numbers)
34 if (descriptor.size() >= 2U && descriptor[0] == 'A' && descriptor[1] == '{') {
35 auto bodySize = ParseArrayBody(descriptor.substr(1), ss);
36 if (bodySize == std::string_view::npos) {
37 // The 'descriptor' has wrong format, so can't be convert
38 return PandaString("");
39 }
40 return ss.str();
41 }
42 }
43
44 ss << 'L';
45 ss << descriptor;
46 ss << ';';
47 PandaString oldDescriptor = ss.str();
48 std::replace(oldDescriptor.begin(), oldDescriptor.end(), '.', '/');
49
50 return oldDescriptor;
51 }
52
53 static constexpr size_t MIN_BODY_SIZE = sizeof('{') + 1 + sizeof('}');
54
55 static size_t ParseType(char type, const std::string_view data, PandaStringStream &ss);
56
ParseArrayBody(const std::string_view data,PandaStringStream & ss)57 static size_t ParseArrayBody(const std::string_view data, PandaStringStream &ss)
58 {
59 if (data.size() < MIN_BODY_SIZE || data[0] != '{') {
60 return std::string_view::npos;
61 }
62 ss << '[';
63
64 char type = data[1];
65 const std::string_view typeData = data.substr(1);
66 size_t size = ParseType(type, typeData, ss);
67 if (size == std::string_view::npos || size >= typeData.size() || typeData[size] != '}') {
68 return std::string_view::npos;
69 }
70 return sizeof('{') + size + sizeof('}');
71 }
72
ParseBody(char type,const std::string_view data,PandaStringStream & ss)73 static size_t ParseBody(char type, const std::string_view data, PandaStringStream &ss)
74 {
75 ASSERT(type != 'A');
76
77 if (data.size() < MIN_BODY_SIZE || data[0] != '{') {
78 return std::string_view::npos;
79 }
80 for (size_t pos = 1; pos < data.size(); ++pos) {
81 if (data[pos] != '}') {
82 continue;
83 }
84 PandaString oldName(data.substr(1, pos - 1));
85 std::replace(oldName.begin(), oldName.end(), '.', '/');
86 ss << 'L';
87 ss << oldName;
88 ss << (type == 'P' ? "$partial;" : ";");
89 return pos + 1;
90 }
91 return std::string_view::npos;
92 }
93
ParseType(char type,const std::string_view data,PandaStringStream & ss)94 static size_t ParseType(char type, const std::string_view data, PandaStringStream &ss)
95 {
96 size_t bodySize = std::string_view::npos;
97 // clang-format off
98 switch (type) {
99 case 'z': ss << 'Z'; return 1;
100 case 'c': ss << 'C'; return 1;
101 case 'b': ss << 'B'; return 1;
102 case 's': ss << 'S'; return 1;
103 case 'i': ss << 'I'; return 1;
104 case 'l': ss << 'J'; return 1;
105 case 'f': ss << 'F'; return 1;
106 case 'd': ss << 'D'; return 1;
107 case 'N': ss << panda_file_items::class_descriptors::OBJECT; return 1;
108 case 'U': ss << panda_file_items::class_descriptors::OBJECT; return 1;
109 case 'A': bodySize = ParseArrayBody(data.substr(1), ss); break;
110 case 'C':
111 case 'E':
112 case 'P': bodySize = ParseBody(type, data.substr(1), ss); break;
113 default:
114 // The 'descriptor' does not have a new format, so no conversion is required.
115 return std::string_view::npos;
116 }
117 // clang-format on
118
119 if (bodySize == std::string_view::npos) {
120 return std::string_view::npos;
121 }
122 return 1 + bodySize;
123 }
124
125 /*static*/
ConvertSignature(const std::string_view descriptor)126 PandaString Mangle::ConvertSignature(const std::string_view descriptor)
127 {
128 PandaStringStream ss;
129 int nr = -1;
130 int k = -1;
131 for (size_t i = 0; i < descriptor.size(); ++i) {
132 char type = descriptor[i];
133 if (type == ':') {
134 ss << ':';
135 nr = 0;
136 k = 1;
137 continue;
138 }
139 size_t sz = ParseType(type, descriptor.substr(i), ss);
140 if (sz == std::string_view::npos) {
141 // The 'descriptor' does not have a new format, so no conversion is required.
142 return PandaString(descriptor);
143 }
144 i += sz - 1;
145 nr += k;
146 }
147 if (k == -1) {
148 // The 'descriptor' does not have a ':' symbol
149 return PandaString(descriptor);
150 }
151 if (nr == 0) {
152 ss << 'V';
153 }
154 return ss.str();
155 }
156
157 } // namespace ark::ets::ani
158