diff 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
line wrap: on
line diff
--- a/src/sys/x11/settings.cc	Mon Jul 15 01:33:51 2024 -0400
+++ b/src/sys/x11/settings.cc	Tue Jul 16 21:15:59 2024 -0400
@@ -1,6 +1,7 @@
 #include "sys/x11/settings.h"
-#include "core/endian.h"
+#include "core/byte_stream.h"
 
+#include <cassert>
 #include <cstring>
 #include <cstdint>
 #include <climits>
@@ -8,7 +9,6 @@
 #include <memory>
 #include <array>
 #include <optional>
-#include <iostream>
 #include <map>
 
 #include <xcb/xcb.h>
@@ -40,61 +40,20 @@
 public:
 	Parser(std::uint8_t *bytes, std::size_t size);
 
-	std::vector<SettingsItem> ParseAllItems(void);
+	bool ParseHeader(void);
 	std::optional<SettingsItem> ParseNextItem(void);
 
 	std::uint32_t GetTotalItems(void);
 
 private:
-	/* byte order values */
-	enum {
+	enum ByteOrder {
 		LSBFirst = 0,
 		MSBFirst = 1,
 	};
 
-	template<typename T>
-	bool ReadData(T& ret) {
-		if (offset_ + sizeof(T) >= size_)
-			return false;
-
-		ret = *reinterpret_cast<T*>(bytes_ + offset_);
-		Advance(sizeof(T));
-		return true;
-	}
-
-	/* will fail on signed integers; xsettings has none of those though */
-	template<typename T>
-	bool ReadInt(T& ret) {
-		static_assert(std::is_integral<T>::value);
-
-		if (!ReadData<T>(ret))
-			return false;
-
-		switch (byte_order_) {
-			case LSBFirst:
-				ret = Endian::byteswap_little_to_host(ret);
-				break;
-			case MSBFirst:
-				ret = Endian::byteswap_big_to_host(ret);
-				break;
-			default:
-				/* can't know for sure. punt */
-				return false;
-		}
-
-		return true;
-	}
-
-	bool ReadString(std::string& str, std::size_t size);
-	bool Advance(std::size_t amount);
-
-	/* raw data */
-	std::uint8_t *bytes_ = nullptr;
-	std::size_t offset_ = 0;
-	std::size_t size_ = 0;
+	ByteStream stream;
 
 	/* parsed in the constructor */
-	std::uint8_t byte_order_ = 0;
 	std::uint32_t serial_ = 0;
 	std::uint32_t total_items_ = 0;
 };
@@ -103,95 +62,93 @@
 	return total_items_;
 }
 
-bool Parser::ReadString(std::string& str, std::size_t size) {
-	if (offset_ + size >= size_)
-		return false;
-
-	str.assign(reinterpret_cast<const char *>(bytes_ + offset_), size);
-	Advance(size);
-	return true;
+Parser::Parser(std::uint8_t *bytes, std::size_t size) : stream(bytes, size) {
 }
 
-bool Parser::Advance(std::size_t amount) {
-	if (offset_ + amount >= size_)
+bool Parser::ParseHeader(void) {
+	std::uint8_t byte_order;
+	if (!stream.ReadBinary<std::uint8_t>(byte_order))
 		return false;
 
-	offset_ += amount;
-	return true;
-}
-
-Parser::Parser(std::uint8_t *bytes, std::size_t size) {
-	bytes_ = bytes;
-	size_ = size;
+	switch (byte_order) {
+		case MSBFirst:
+			stream.SetEndianness(ByteStream::ByteOrder::Big);
+			break;
+		case LSBFirst:
+			stream.SetEndianness(ByteStream::ByteOrder::Little);
+			break;
+		default:
+			return false; /* errr */
+	}
 
-	if (!ReadData<std::uint8_t>(byte_order_))
-		return;
+	stream.Advance(3);
 
-	Advance(3);
+	if (!stream.ReadInt<std::uint32_t>(serial_))
+		return false;
 
-	if (!ReadInt<std::uint32_t>(serial_))
-		return;
+	if (!stream.ReadInt<std::uint32_t>(total_items_))
+		return false;
 
-	if (!ReadInt<std::uint32_t>(total_items_))
-		return;
+	return true;
 }
 
 std::optional<SettingsItem> Parser::ParseNextItem(void) {
 	SettingsItem item;
 
 	/* read one byte */
-	if (!ReadInt<std::uint8_t>(item.type))
+	if (!stream.ReadInt<std::uint8_t>(item.type))
 		return std::nullopt;
 
 	if (!item.VerifyType())
 		return std::nullopt;
 
 	/* skip padding */
-	if (!Advance(1))
+	if (!stream.Advance(1))
 		return std::nullopt;
 
 	/* parse the name */
 	std::uint16_t name_size;
-	if (!ReadInt<std::uint16_t>(name_size))
+	if (!stream.ReadInt<std::uint16_t>(name_size))
 		return std::nullopt;
 
-	if (!ReadString(item.name, name_size))
+	if (!stream.ReadString(item.name, name_size))
 		return std::nullopt;
 
 	/* padding */
-	if (!Advance(GetPadding(name_size, 4)))
+	if (!stream.Advance(GetPadding(name_size, 4)))
 		return std::nullopt;
 
-	if (!ReadInt<std::uint32_t>(item.serial))
+	if (!stream.ReadInt<std::uint32_t>(item.serial))
 		return std::nullopt;
 
 	switch (item.type) {
 		case SettingsItem::TypeInt: {
-			if (!ReadInt<std::uint32_t>(item.data.integer))
+			if (!stream.ReadInt<std::int32_t>(item.data.integer))
 				return std::nullopt;
 
 			break;
 		}
 		case SettingsItem::TypeStr: {
 			std::uint32_t size;
-			if (!ReadInt<std::uint32_t>(size))
+			if (!stream.ReadInt<std::uint32_t>(size))
 				return std::nullopt;
 
-			if (!ReadString(item.data.string, size))
+			if (!stream.ReadString(item.data.string, size))
 				return std::nullopt;
 
-			/* padding */
-			if (!Advance(GetPadding(size, 4)))
-				return std::nullopt;
+			/* don't fail if advancing fails on this padding,
+			 * because this causes parsing to fail for strings
+			 * at the end of the data */
+			stream.Advance(GetPadding(size, 4));
 
 			break;
 		}
 		case SettingsItem::TypeRgba: {
-			/* The order here is important!! */
-			if (!ReadInt<std::uint16_t>(item.data.rgba.red)
-				|| !ReadInt<std::uint16_t>(item.data.rgba.blue)
-				|| !ReadInt<std::uint16_t>(item.data.rgba.green)
-				|| !ReadInt<std::uint16_t>(item.data.rgba.alpha))
+			/* it's actually RBGA, but whatever. */
+			if (!stream.ReadInt<std::uint16_t>(item.data.rgba.red)
+				|| !stream.ReadInt<std::uint16_t>(item.data.rgba.blue)
+				|| !stream.ReadInt<std::uint16_t>(item.data.rgba.green)
+				|| !stream.ReadInt<std::uint16_t>(item.data.rgba.alpha))
 				return std::nullopt;
 
 			break;
@@ -204,23 +161,6 @@
 	return item;
 }
 
-std::vector<SettingsItem> Parser::ParseAllItems(void) {
-	offset_ = 0;
-
-	std::uint32_t i;
-	std::vector<SettingsItem> items;
-
-	for (i = 0; i < total_items_; i++) {
-		std::optional<SettingsItem> item = ParseNextItem();
-		if (!item)
-			break;
-
-		items.push_back(item.value());
-	}
-
-	return items;
-}
-
 /* ------------------------------------------------------------------------- */
 /* real X11 code */
 
@@ -323,7 +263,18 @@
 		return false;
 
 	Parser parser(xsettings_raw.data(), xsettings_raw.size());
-	settings = parser.ParseAllItems();
+	if (!parser.ParseHeader())
+		return false;
+
+	std::uint32_t total = parser.GetTotalItems();
+
+	while (total--) {
+		std::optional<SettingsItem> opt_item = parser.ParseNextItem();
+		if (!opt_item)
+			break;
+
+		settings.push_back(opt_item.value());
+	}
 
 	return true;
 }
@@ -334,10 +285,12 @@
 		return false;
 
 	Parser parser(xsettings_raw.data(), xsettings_raw.size());
+	if (!parser.ParseHeader())
+		return false;
 
 	std::uint32_t total = parser.GetTotalItems();
 
-	for (; total; total--) {
+	while (total--) {
 		std::optional<SettingsItem> opt_item = parser.ParseNextItem();
 		if (!opt_item)
 			return false;