Mercurial > minori
comparison src/sys/x11/settings.cc @ 364:99c961c91809
core: refactor out byte stream into its own file
easy dubs
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Tue, 16 Jul 2024 21:15:59 -0400 |
parents | 9aaf1e788896 |
children |
comparison
equal
deleted
inserted
replaced
363:f10507d8f686 | 364:99c961c91809 |
---|---|
1 #include "sys/x11/settings.h" | 1 #include "sys/x11/settings.h" |
2 #include "core/endian.h" | 2 #include "core/byte_stream.h" |
3 | 3 |
4 #include <cassert> | |
4 #include <cstring> | 5 #include <cstring> |
5 #include <cstdint> | 6 #include <cstdint> |
6 #include <climits> | 7 #include <climits> |
7 #include <string_view> | 8 #include <string_view> |
8 #include <memory> | 9 #include <memory> |
9 #include <array> | 10 #include <array> |
10 #include <optional> | 11 #include <optional> |
11 #include <iostream> | |
12 #include <map> | 12 #include <map> |
13 | 13 |
14 #include <xcb/xcb.h> | 14 #include <xcb/xcb.h> |
15 | 15 |
16 #include "fmt/core.h" | 16 #include "fmt/core.h" |
38 | 38 |
39 class Parser { | 39 class Parser { |
40 public: | 40 public: |
41 Parser(std::uint8_t *bytes, std::size_t size); | 41 Parser(std::uint8_t *bytes, std::size_t size); |
42 | 42 |
43 std::vector<SettingsItem> ParseAllItems(void); | 43 bool ParseHeader(void); |
44 std::optional<SettingsItem> ParseNextItem(void); | 44 std::optional<SettingsItem> ParseNextItem(void); |
45 | 45 |
46 std::uint32_t GetTotalItems(void); | 46 std::uint32_t GetTotalItems(void); |
47 | 47 |
48 private: | 48 private: |
49 /* byte order values */ | 49 enum ByteOrder { |
50 enum { | |
51 LSBFirst = 0, | 50 LSBFirst = 0, |
52 MSBFirst = 1, | 51 MSBFirst = 1, |
53 }; | 52 }; |
54 | 53 |
55 template<typename T> | 54 ByteStream stream; |
56 bool ReadData(T& ret) { | |
57 if (offset_ + sizeof(T) >= size_) | |
58 return false; | |
59 | |
60 ret = *reinterpret_cast<T*>(bytes_ + offset_); | |
61 Advance(sizeof(T)); | |
62 return true; | |
63 } | |
64 | |
65 /* will fail on signed integers; xsettings has none of those though */ | |
66 template<typename T> | |
67 bool ReadInt(T& ret) { | |
68 static_assert(std::is_integral<T>::value); | |
69 | |
70 if (!ReadData<T>(ret)) | |
71 return false; | |
72 | |
73 switch (byte_order_) { | |
74 case LSBFirst: | |
75 ret = Endian::byteswap_little_to_host(ret); | |
76 break; | |
77 case MSBFirst: | |
78 ret = Endian::byteswap_big_to_host(ret); | |
79 break; | |
80 default: | |
81 /* can't know for sure. punt */ | |
82 return false; | |
83 } | |
84 | |
85 return true; | |
86 } | |
87 | |
88 bool ReadString(std::string& str, std::size_t size); | |
89 bool Advance(std::size_t amount); | |
90 | |
91 /* raw data */ | |
92 std::uint8_t *bytes_ = nullptr; | |
93 std::size_t offset_ = 0; | |
94 std::size_t size_ = 0; | |
95 | 55 |
96 /* parsed in the constructor */ | 56 /* parsed in the constructor */ |
97 std::uint8_t byte_order_ = 0; | |
98 std::uint32_t serial_ = 0; | 57 std::uint32_t serial_ = 0; |
99 std::uint32_t total_items_ = 0; | 58 std::uint32_t total_items_ = 0; |
100 }; | 59 }; |
101 | 60 |
102 std::uint32_t Parser::GetTotalItems(void) { | 61 std::uint32_t Parser::GetTotalItems(void) { |
103 return total_items_; | 62 return total_items_; |
104 } | 63 } |
105 | 64 |
106 bool Parser::ReadString(std::string& str, std::size_t size) { | 65 Parser::Parser(std::uint8_t *bytes, std::size_t size) : stream(bytes, size) { |
107 if (offset_ + size >= size_) | 66 } |
108 return false; | 67 |
109 | 68 bool Parser::ParseHeader(void) { |
110 str.assign(reinterpret_cast<const char *>(bytes_ + offset_), size); | 69 std::uint8_t byte_order; |
111 Advance(size); | 70 if (!stream.ReadBinary<std::uint8_t>(byte_order)) |
71 return false; | |
72 | |
73 switch (byte_order) { | |
74 case MSBFirst: | |
75 stream.SetEndianness(ByteStream::ByteOrder::Big); | |
76 break; | |
77 case LSBFirst: | |
78 stream.SetEndianness(ByteStream::ByteOrder::Little); | |
79 break; | |
80 default: | |
81 return false; /* errr */ | |
82 } | |
83 | |
84 stream.Advance(3); | |
85 | |
86 if (!stream.ReadInt<std::uint32_t>(serial_)) | |
87 return false; | |
88 | |
89 if (!stream.ReadInt<std::uint32_t>(total_items_)) | |
90 return false; | |
91 | |
112 return true; | 92 return true; |
113 } | |
114 | |
115 bool Parser::Advance(std::size_t amount) { | |
116 if (offset_ + amount >= size_) | |
117 return false; | |
118 | |
119 offset_ += amount; | |
120 return true; | |
121 } | |
122 | |
123 Parser::Parser(std::uint8_t *bytes, std::size_t size) { | |
124 bytes_ = bytes; | |
125 size_ = size; | |
126 | |
127 if (!ReadData<std::uint8_t>(byte_order_)) | |
128 return; | |
129 | |
130 Advance(3); | |
131 | |
132 if (!ReadInt<std::uint32_t>(serial_)) | |
133 return; | |
134 | |
135 if (!ReadInt<std::uint32_t>(total_items_)) | |
136 return; | |
137 } | 93 } |
138 | 94 |
139 std::optional<SettingsItem> Parser::ParseNextItem(void) { | 95 std::optional<SettingsItem> Parser::ParseNextItem(void) { |
140 SettingsItem item; | 96 SettingsItem item; |
141 | 97 |
142 /* read one byte */ | 98 /* read one byte */ |
143 if (!ReadInt<std::uint8_t>(item.type)) | 99 if (!stream.ReadInt<std::uint8_t>(item.type)) |
144 return std::nullopt; | 100 return std::nullopt; |
145 | 101 |
146 if (!item.VerifyType()) | 102 if (!item.VerifyType()) |
147 return std::nullopt; | 103 return std::nullopt; |
148 | 104 |
149 /* skip padding */ | 105 /* skip padding */ |
150 if (!Advance(1)) | 106 if (!stream.Advance(1)) |
151 return std::nullopt; | 107 return std::nullopt; |
152 | 108 |
153 /* parse the name */ | 109 /* parse the name */ |
154 std::uint16_t name_size; | 110 std::uint16_t name_size; |
155 if (!ReadInt<std::uint16_t>(name_size)) | 111 if (!stream.ReadInt<std::uint16_t>(name_size)) |
156 return std::nullopt; | 112 return std::nullopt; |
157 | 113 |
158 if (!ReadString(item.name, name_size)) | 114 if (!stream.ReadString(item.name, name_size)) |
159 return std::nullopt; | 115 return std::nullopt; |
160 | 116 |
161 /* padding */ | 117 /* padding */ |
162 if (!Advance(GetPadding(name_size, 4))) | 118 if (!stream.Advance(GetPadding(name_size, 4))) |
163 return std::nullopt; | 119 return std::nullopt; |
164 | 120 |
165 if (!ReadInt<std::uint32_t>(item.serial)) | 121 if (!stream.ReadInt<std::uint32_t>(item.serial)) |
166 return std::nullopt; | 122 return std::nullopt; |
167 | 123 |
168 switch (item.type) { | 124 switch (item.type) { |
169 case SettingsItem::TypeInt: { | 125 case SettingsItem::TypeInt: { |
170 if (!ReadInt<std::uint32_t>(item.data.integer)) | 126 if (!stream.ReadInt<std::int32_t>(item.data.integer)) |
171 return std::nullopt; | 127 return std::nullopt; |
172 | 128 |
173 break; | 129 break; |
174 } | 130 } |
175 case SettingsItem::TypeStr: { | 131 case SettingsItem::TypeStr: { |
176 std::uint32_t size; | 132 std::uint32_t size; |
177 if (!ReadInt<std::uint32_t>(size)) | 133 if (!stream.ReadInt<std::uint32_t>(size)) |
178 return std::nullopt; | 134 return std::nullopt; |
179 | 135 |
180 if (!ReadString(item.data.string, size)) | 136 if (!stream.ReadString(item.data.string, size)) |
181 return std::nullopt; | 137 return std::nullopt; |
182 | 138 |
183 /* padding */ | 139 /* don't fail if advancing fails on this padding, |
184 if (!Advance(GetPadding(size, 4))) | 140 * because this causes parsing to fail for strings |
185 return std::nullopt; | 141 * at the end of the data */ |
142 stream.Advance(GetPadding(size, 4)); | |
186 | 143 |
187 break; | 144 break; |
188 } | 145 } |
189 case SettingsItem::TypeRgba: { | 146 case SettingsItem::TypeRgba: { |
190 /* The order here is important!! */ | 147 /* it's actually RBGA, but whatever. */ |
191 if (!ReadInt<std::uint16_t>(item.data.rgba.red) | 148 if (!stream.ReadInt<std::uint16_t>(item.data.rgba.red) |
192 || !ReadInt<std::uint16_t>(item.data.rgba.blue) | 149 || !stream.ReadInt<std::uint16_t>(item.data.rgba.blue) |
193 || !ReadInt<std::uint16_t>(item.data.rgba.green) | 150 || !stream.ReadInt<std::uint16_t>(item.data.rgba.green) |
194 || !ReadInt<std::uint16_t>(item.data.rgba.alpha)) | 151 || !stream.ReadInt<std::uint16_t>(item.data.rgba.alpha)) |
195 return std::nullopt; | 152 return std::nullopt; |
196 | 153 |
197 break; | 154 break; |
198 } | 155 } |
199 default: | 156 default: |
200 /* can't do anything now, can we? */ | 157 /* can't do anything now, can we? */ |
201 return std::nullopt; | 158 return std::nullopt; |
202 } | 159 } |
203 | 160 |
204 return item; | 161 return item; |
205 } | |
206 | |
207 std::vector<SettingsItem> Parser::ParseAllItems(void) { | |
208 offset_ = 0; | |
209 | |
210 std::uint32_t i; | |
211 std::vector<SettingsItem> items; | |
212 | |
213 for (i = 0; i < total_items_; i++) { | |
214 std::optional<SettingsItem> item = ParseNextItem(); | |
215 if (!item) | |
216 break; | |
217 | |
218 items.push_back(item.value()); | |
219 } | |
220 | |
221 return items; | |
222 } | 162 } |
223 | 163 |
224 /* ------------------------------------------------------------------------- */ | 164 /* ------------------------------------------------------------------------- */ |
225 /* real X11 code */ | 165 /* real X11 code */ |
226 | 166 |
321 std::vector<std::uint8_t> xsettings_raw; | 261 std::vector<std::uint8_t> xsettings_raw; |
322 if (!GetRawSettingsData(xsettings_raw)) | 262 if (!GetRawSettingsData(xsettings_raw)) |
323 return false; | 263 return false; |
324 | 264 |
325 Parser parser(xsettings_raw.data(), xsettings_raw.size()); | 265 Parser parser(xsettings_raw.data(), xsettings_raw.size()); |
326 settings = parser.ParseAllItems(); | 266 if (!parser.ParseHeader()) |
267 return false; | |
268 | |
269 std::uint32_t total = parser.GetTotalItems(); | |
270 | |
271 while (total--) { | |
272 std::optional<SettingsItem> opt_item = parser.ParseNextItem(); | |
273 if (!opt_item) | |
274 break; | |
275 | |
276 settings.push_back(opt_item.value()); | |
277 } | |
327 | 278 |
328 return true; | 279 return true; |
329 } | 280 } |
330 | 281 |
331 bool FindSetting(const std::string& name, SettingsItem& setting) { | 282 bool FindSetting(const std::string& name, SettingsItem& setting) { |
332 std::vector<std::uint8_t> xsettings_raw; | 283 std::vector<std::uint8_t> xsettings_raw; |
333 if (!GetRawSettingsData(xsettings_raw)) | 284 if (!GetRawSettingsData(xsettings_raw)) |
334 return false; | 285 return false; |
335 | 286 |
336 Parser parser(xsettings_raw.data(), xsettings_raw.size()); | 287 Parser parser(xsettings_raw.data(), xsettings_raw.size()); |
288 if (!parser.ParseHeader()) | |
289 return false; | |
337 | 290 |
338 std::uint32_t total = parser.GetTotalItems(); | 291 std::uint32_t total = parser.GetTotalItems(); |
339 | 292 |
340 for (; total; total--) { | 293 while (total--) { |
341 std::optional<SettingsItem> opt_item = parser.ParseNextItem(); | 294 std::optional<SettingsItem> opt_item = parser.ParseNextItem(); |
342 if (!opt_item) | 295 if (!opt_item) |
343 return false; | 296 return false; |
344 | 297 |
345 SettingsItem& item = opt_item.value(); | 298 SettingsItem& item = opt_item.value(); |