blob: 08ccd0226a6e34ce8c676a7006da04453b04951c [file] [log] [blame]
William A. Kennington III226bc422021-05-05 17:08:36 -07001#include <sdbusplus/message/native_types.hpp>
William A. Kennington III226bc422021-05-05 17:08:36 -07002
William A. Kennington III8db46a02021-05-05 17:53:35 -07003#include <algorithm>
William A. Kennington III226bc422021-05-05 17:08:36 -07004#include <array>
William A. Kennington III285f78b2021-05-01 18:35:11 -07005#include <cctype>
William A. Kennington III2dcf64b2021-07-30 16:15:25 -07006#include <cstdint>
William A. Kennington III226bc422021-05-05 17:08:36 -07007
8namespace sdbusplus
9{
10namespace message
11{
12namespace details
13{
14
William A. Kennington III285f78b2021-05-01 18:35:11 -070015constexpr std::array<char, 16> hex{'0', '1', '2', '3', '4', '5', '6', '7',
16 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
17
William A. Kennington III2dcf64b2021-07-30 16:15:25 -070018constexpr std::array<int8_t, 256> unhex = [] {
19 std::array<int8_t, 256> ret{};
William A. Kennington III285f78b2021-05-01 18:35:11 -070020 for (size_t i = 0; i < ret.size(); ++i)
21 {
22 ret[i] = -1;
23 }
24 for (char i = 0; i < 10; ++i)
25 {
26 ret['0' + i] = i;
27 }
28 for (char i = 0; i < 6; ++i)
29 {
30 ret['A' + i] = i + 10;
31 ret['a' + i] = i + 10;
32 }
33 return ret;
34}();
35
36inline bool pathShouldEscape(char c)
37{
38 return !std::isalnum(c);
39}
40
William A. Kennington III8db46a02021-05-05 17:53:35 -070041inline bool pathRequiresEscape(char c)
42{
43 return pathShouldEscape(c) && c != '_';
44}
45
William A. Kennington III285f78b2021-05-01 18:35:11 -070046inline void pathAppendEscape(std::string& s, char c)
47{
48 s.append(1, '_');
49 s.append(1, hex[(c >> 4) & 0xf]);
50 s.append(1, hex[c & 0xf]);
51}
52
William A. Kennington III226bc422021-05-05 17:08:36 -070053std::string string_path_wrapper::filename() const
54{
William A. Kennington III285f78b2021-05-01 18:35:11 -070055 std::string_view strv(str);
56 size_t firstIndex = strv.rfind('/');
William A. Kennington III226bc422021-05-05 17:08:36 -070057
58 // Dbus paths must start with /, if we don't find one, it's an error
59 if (firstIndex == std::string::npos)
60 {
61 return "";
62 }
William A. Kennington III285f78b2021-05-01 18:35:11 -070063 auto filename = strv.substr(firstIndex + 1);
64
William A. Kennington III226bc422021-05-05 17:08:36 -070065 // If we don't see that this was encoded by sdbusplus, return the naive
66 // version of the filename path.
William A. Kennington III285f78b2021-05-01 18:35:11 -070067 if (filename[0] != '_')
William A. Kennington III226bc422021-05-05 17:08:36 -070068 {
69 return std::string(filename);
70 }
71
William A. Kennington III285f78b2021-05-01 18:35:11 -070072 std::string out;
73 out.reserve(filename.size());
74 for (size_t i = 0; i < filename.size(); ++i)
William A. Kennington III226bc422021-05-05 17:08:36 -070075 {
William A. Kennington III285f78b2021-05-01 18:35:11 -070076 if (filename[i] != '_')
77 {
78 out.append(1, filename[i]);
79 continue;
80 }
81 if (i + 2 >= filename.size())
82 {
83 return "";
84 }
85 auto ch = unhex[filename[i + 1]];
86 auto cl = unhex[filename[i + 2]];
87 if (ch == -1 || cl == -1)
88 {
89 return "";
90 }
91 out.append(1, (ch << 4) | cl);
92 i += 2;
William A. Kennington III226bc422021-05-05 17:08:36 -070093 }
William A. Kennington III285f78b2021-05-01 18:35:11 -070094 return out;
William A. Kennington III226bc422021-05-05 17:08:36 -070095}
96
97string_path_wrapper string_path_wrapper::parent_path() const
98{
99 auto index = str.rfind('/');
100 if (index == std::string::npos)
101 {
102 return string_path_wrapper("/");
103 }
104 if (index <= 1)
105 {
106 return string_path_wrapper("/");
107 }
108
109 return str.substr(0, index);
110}
111
William A. Kennington III285f78b2021-05-01 18:35:11 -0700112string_path_wrapper string_path_wrapper::operator/(std::string_view extId) const
William A. Kennington III226bc422021-05-05 17:08:36 -0700113{
114 string_path_wrapper out;
William A. Kennington III285f78b2021-05-01 18:35:11 -0700115 out.str.reserve(str.size() + 1 + extId.size() * 3);
116 out.str.append(str);
117 return out /= extId;
William A. Kennington III226bc422021-05-05 17:08:36 -0700118}
119
William A. Kennington III285f78b2021-05-01 18:35:11 -0700120string_path_wrapper& string_path_wrapper::operator/=(std::string_view extId)
William A. Kennington III226bc422021-05-05 17:08:36 -0700121{
William A. Kennington III285f78b2021-05-01 18:35:11 -0700122 str.reserve(str.size() + 1 + extId.size() * 3);
123 if (!str.empty() && str[str.size() - 1] != '/')
124 {
125 str.append(1, '/');
126 }
William A. Kennington III8db46a02021-05-05 17:53:35 -0700127 if (extId.empty() ||
128 (!pathShouldEscape(extId[0]) &&
129 std::none_of(extId.begin() + 1, extId.end(), pathRequiresEscape)))
William A. Kennington III285f78b2021-05-01 18:35:11 -0700130 {
William A. Kennington III8db46a02021-05-05 17:53:35 -0700131 str.append(extId);
William A. Kennington III285f78b2021-05-01 18:35:11 -0700132 return *this;
133 }
134 pathAppendEscape(str, extId[0]);
135 for (auto c : extId.substr(1))
136 {
137 if (pathShouldEscape(c))
138 {
139 pathAppendEscape(str, c);
140 }
141 else
142 {
143 str.append(1, c);
144 }
145 }
William A. Kennington III226bc422021-05-05 17:08:36 -0700146 return *this;
147}
148
149} // namespace details
150} // namespace message
151} // namespace sdbusplus