diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 4b5a0d9..c2e1444 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -19,7 +19,7 @@ packet_capture = ["gamedig/packet_capture"] # Output formats bson = ["dep:serde", "dep:bson", "dep:hex", "dep:base64", "gamedig/serde"] json = ["dep:serde", "dep:serde_json", "gamedig/serde"] -xml = ["dep:serde", "dep:serde-xml-rs", "gamedig/serde"] +xml = ["dep:serde", "dep:quick-xml", "gamedig/serde"] # Misc browser = ["dep:webbrowser"] @@ -47,7 +47,7 @@ hex = { version = "0.4.3", optional = true, default-features = false } serde_json = { version = "1", optional = true, default-features = false } # XML -serde-xml-rs = { version = "0.6.0", optional = true, default-features = false } +quick-xml = { version = "0.31.0", optional = true, default-features = false } # Browser webbrowser = { version = "0.8.12", optional = true, default-features = false } diff --git a/crates/cli/src/error.rs b/crates/cli/src/error.rs index d5db795..396abc0 100644 --- a/crates/cli/src/error.rs +++ b/crates/cli/src/error.rs @@ -11,6 +11,12 @@ pub enum Error { #[error("Gamedig Error: {0}")] Gamedig(#[from] gamedig::errors::GDError), + #[error("Serde Error: {0}")] + Serde(#[from] serde_json::Error), + + #[error("Xml Error: {0}")] + Xml(#[from] quick_xml::Error), + #[error("Unknown Game: {0}")] UnknownGame(String), diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 66c50b6..bce0fda 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -278,7 +278,67 @@ fn output_result_json_pretty(result: T) { /// * `result` - A serde serializable result. #[cfg(feature = "xml")] fn output_result_xml(result: T) { - println!("{}", serde_xml_rs::to_string(&result).unwrap()); + use quick_xml::events::{BytesEnd, BytesStart, Event, BytesText}; + use quick_xml::Writer; + use serde_json::Value; + use std::io::Cursor; + + // Serialize the struct to a JSON Value first + let json = serde_json::to_value(result).expect("Failed to serialize struct to JSON"); + + // Create a buffer and a writer for XML output + let buffer = Cursor::new(Vec::new()); + let mut writer = Writer::new(buffer); + + // Recursive function to convert JSON to XML + fn json_to_xml( + writer: &mut Writer, + key: Option<&str>, + value: &Value, + ) -> Result<()> { + match value { + Value::Object(obj) => { + if let Some(key) = key { + writer.write_event(Event::Start(BytesStart::new(key)))?; + } + for (k, v) in obj { + json_to_xml(writer, Some(k), v)?; + } + if let Some(key) = key { + writer.write_event(Event::End(BytesEnd::new(key)))?; + } + }, + Value::Array(arr) => { + for v in arr { + json_to_xml(writer, key.or(Some("item")), v)?; + } + }, + _ => { + if let Some(key) = key { + writer.write_event(Event::Start(BytesStart::new(key)))?; + } + let text_string = match value { + Value::String(s) => s.to_string(), + _ => value.to_string().trim_matches('"').to_string(), + }; + let text = text_string.as_str(); + writer.write_event(Event::Text(BytesText::new(text)))?; + if let Some(key) = key { + writer.write_event(Event::End(BytesEnd::new(key)))?; + } + } + } + Ok(()) + } + + writer.write_event(Event::Start(BytesStart::new("data"))).expect("Failed to write start tag"); + json_to_xml(&mut writer, None, &json).expect("Failed to convert JSON to XML"); + writer.write_event(Event::End(BytesEnd::new("data"))).expect("Failed to write end tag"); + + let xml_bytes = writer.into_inner().into_inner(); + let xml_string = String::from_utf8(xml_bytes).expect("Failed to convert XML bytes to string"); + + println!("{}", xml_string); } /// Output the result as a BSON object encoded as a hex string.