blob: f0a77477560bf631a88845578a8867170cd788e4 [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 III226bc422021-05-05 17:08:36 -07006
7namespace sdbusplus
8{
9namespace message
10{
11namespace details
12{
13
William A. Kennington III285f78b2021-05-01 18:35:11 -070014constexpr std::array<char, 16> hex{'0', '1', '2', '3', '4', '5', '6', '7',
15 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
16
17constexpr std::array<char, 256> unhex = [] {
William A. Kennington III2bba5532021-05-26 22:58:54 -070018 std::array<char, 256> ret{};
William A. Kennington III285f78b2021-05-01 18:35:11 -070019 for (size_t i = 0; i < ret.size(); ++i)
20 {
21 ret[i] = -1;
22 }
23 for (char i = 0; i < 10; ++i)
24 {
25 ret['0' + i] = i;
26 }
27 for (char i = 0; i < 6; ++i)
28 {
29 ret['A' + i] = i + 10;
30 ret['a' + i] = i + 10;
31 }
32 return ret;
33}();
34
35inline bool pathShouldEscape(char c)
36{
37 return !std::isalnum(c);
38}
39
William A. Kennington III8db46a02021-05-05 17:53:35 -070040inline bool pathRequiresEscape(char c)
41{
42 return pathShouldEscape(c) && c != '_';
43}
44
William A. Kennington III285f78b2021-05-01 18:35:11 -070045inline void pathAppendEscape(std::string& s, char c)
46{
47 s.append(1, '_');
48 s.append(1, hex[(c >> 4) & 0xf]);
49 s.append(1, hex[c & 0xf]);
50}
51
William A. Kennington III226bc422021-05-05 17:08:36 -070052std::string string_path_wrapper::filename() const
53{
William A. Kennington III285f78b2021-05-01 18:35:11 -070054 std::string_view strv(str);
55 size_t firstIndex = strv.rfind('/');
William A. Kennington III226bc422021-05-05 17:08:36 -070056
57 // Dbus paths must start with /, if we don't find one, it's an error
58 if (firstIndex == std::string::npos)
59 {
60 return "";
61 }
William A. Kennington III285f78b2021-05-01 18:35:11 -070062 auto filename = strv.substr(firstIndex + 1);
63
William A. Kennington III226bc422021-05-05 17:08:36 -070064 // If we don't see that this was encoded by sdbusplus, return the naive
65 // version of the filename path.
William A. Kennington III285f78b2021-05-01 18:35:11 -070066 if (filename[0] != '_')
William A. Kennington III226bc422021-05-05 17:08:36 -070067 {
68 return std::string(filename);
69 }
70
William A. Kennington III285f78b2021-05-01 18:35:11 -070071 std::string out;
72 out.reserve(filename.size());
73 for (size_t i = 0; i < filename.size(); ++i)
William A. Kennington III226bc422021-05-05 17:08:36 -070074 {
William A. Kennington III285f78b2021-05-01 18:35:11 -070075 if (filename[i] != '_')
76 {
77 out.append(1, filename[i]);
78 continue;
79 }
80 if (i + 2 >= filename.size())
81 {
82 return "";
83 }
84 auto ch = unhex[filename[i + 1]];
85 auto cl = unhex[filename[i + 2]];
86 if (ch == -1 || cl == -1)
87 {
88 return "";
89 }
90 out.append(1, (ch << 4) | cl);
91 i += 2;
William A. Kennington III226bc422021-05-05 17:08:36 -070092 }
William A. Kennington III285f78b2021-05-01 18:35:11 -070093 return out;
William A. Kennington III226bc422021-05-05 17:08:36 -070094}
95
96string_path_wrapper string_path_wrapper::parent_path() const
97{
98 auto index = str.rfind('/');
99 if (index == std::string::npos)
100 {
101 return string_path_wrapper("/");
102 }
103 if (index <= 1)
104 {
105 return string_path_wrapper("/");
106 }
107
108 return str.substr(0, index);
109}
110
William A. Kennington III285f78b2021-05-01 18:35:11 -0700111string_path_wrapper string_path_wrapper::operator/(std::string_view extId) const
William A. Kennington III226bc422021-05-05 17:08:36 -0700112{
113 string_path_wrapper out;
William A. Kennington III285f78b2021-05-01 18:35:11 -0700114 out.str.reserve(str.size() + 1 + extId.size() * 3);
115 out.str.append(str);
116 return out /= extId;
William A. Kennington III226bc422021-05-05 17:08:36 -0700117}
118
William A. Kennington III285f78b2021-05-01 18:35:11 -0700119string_path_wrapper& string_path_wrapper::operator/=(std::string_view extId)
William A. Kennington III226bc422021-05-05 17:08:36 -0700120{
William A. Kennington III285f78b2021-05-01 18:35:11 -0700121 str.reserve(str.size() + 1 + extId.size() * 3);
122 if (!str.empty() && str[str.size() - 1] != '/')
123 {
124 str.append(1, '/');
125 }
William A. Kennington III8db46a02021-05-05 17:53:35 -0700126 if (extId.empty() ||
127 (!pathShouldEscape(extId[0]) &&
128 std::none_of(extId.begin() + 1, extId.end(), pathRequiresEscape)))
William A. Kennington III285f78b2021-05-01 18:35:11 -0700129 {
William A. Kennington III8db46a02021-05-05 17:53:35 -0700130 str.append(extId);
William A. Kennington III285f78b2021-05-01 18:35:11 -0700131 return *this;
132 }
133 pathAppendEscape(str, extId[0]);
134 for (auto c : extId.substr(1))
135 {
136 if (pathShouldEscape(c))
137 {
138 pathAppendEscape(str, c);
139 }
140 else
141 {
142 str.append(1, c);
143 }
144 }
William A. Kennington III226bc422021-05-05 17:08:36 -0700145 return *this;
146}
147
148} // namespace details
149} // namespace message
150} // namespace sdbusplus