From: Ben Pfaff Date: Sat, 3 Jan 2026 00:49:18 +0000 (-0800) Subject: Add show-legacy-series command. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=af863634a36b3eb78d79e7084f4547394351d5c7;p=pspp Add show-legacy-series command. --- diff --git a/rust/pspp/src/cli/show_spv.rs b/rust/pspp/src/cli/show_spv.rs index cdc46a8ff4..0a2cfdcf0e 100644 --- a/rust/pspp/src/cli/show_spv.rs +++ b/rust/pspp/src/cli/show_spv.rs @@ -25,13 +25,13 @@ use pspp::{ spv::{ SpvArchive, legacy_bin::LegacyBin, - read::{ReadSeek, structure::OutlineItem}, + read::{ReadSeek, legacy_xml::Visualization, structure::OutlineItem}, }, }; use std::{ collections::HashMap, fmt::Display, - io::{Cursor, Read}, + io::{BufReader, Cursor, Read}, path::PathBuf, sync::Arc, }; @@ -83,8 +83,17 @@ enum Mode { ConvertTableLook, /// Print data values in legacy tables. + /// + /// Data values come from `_tableData.bin` members inside the SPV files. + /// They do not require reading the corresponding `_table.xml` files. LegacyData, + /// Print data series in legacy tables. + /// + /// The series come from `_tableData.bin` members inside the SPV files, as + /// transformed by instructions in their paired `_table.xml` files. + LegacySeries, + /// Prints contents. View, } @@ -96,6 +105,7 @@ impl Mode { Mode::GetTableLook => "get-table-look", Mode::ConvertTableLook => "convert-table-look", Mode::LegacyData => "legacy-data", + Mode::LegacySeries => "legacy-series", Mode::View => "view", } } @@ -113,6 +123,7 @@ impl ShowSpv { Mode::Directory => self.directory(), Mode::View => self.view(), Mode::LegacyData => self.legacy_data(), + Mode::LegacySeries => self.legacy_series(), Mode::GetTableLook => todo!(), Mode::ConvertTableLook => todo!(), } @@ -205,6 +216,76 @@ impl ShowSpv { } Ok(()) } + + fn legacy_series(self) -> Result<()> { + let (mut archive, items) = self.read_outline()?; + for item in items { + for item in item.iter_in_order() { + if let Some(spv_info) = item.spv_info() + && let Some(members) = &spv_info.members + && let SpvMembers::LegacyTable { xml, binary } = &members + { + /// Read and decode binary file. + let mut bin_member = archive.0.by_name(&binary)?; + let mut bin_data = Vec::with_capacity(bin_member.size() as usize); + bin_member.read_to_end(&mut bin_data)?; + let mut cursor = Cursor::new(bin_data); + let legacy_bin = LegacyBin::read(&mut cursor).map_err(|e| { + e.with_message(format!( + "While parsing {binary:?} as legacy binary SPV member" + )) + })?; + let data = legacy_bin.decode(&mut |w| eprintln!("{w}")); + drop(bin_member); + + /// Read decode series in XML file. + let member = BufReader::new(archive.0.by_name(&xml)?); + let visualization: Visualization = match serde_path_to_error::deserialize( + &mut quick_xml::de::Deserializer::from_reader(member), + ) { + Ok(result) => result, + Err(error) => panic!("{error:?}"), + }; + let series = visualization.decode_series(data, &mut |w| { + eprintln!("{w}"); + }); + + let n_values = series + .values() + .map(|map| map.values.len()) + .max() + .unwrap_or(0); + let index = Dimension::new( + Group::new("Index") + .with_multiple(Leaf::numbers(0..n_values)) + .with_label_shown(), + ); + let variables = Dimension::new(Group::new("Series").with_multiple( + series.values().map(|series| { + series + .name + .replace("categories", "\ncategories") + .replace("labels", "\nlabels") + .replace("group", "\ngroup") + .replace("Label", "\nLabel") + }), + )); + let mut pivot_table = + PivotTable::new([(Axis3::Y, index), (Axis3::X, variables)]); + for (series_index, series) in series.values().enumerate() { + for (value_index, data_value) in series.values.iter().enumerate() { + pivot_table.insert( + [value_index, series_index], + Value::new_datum(&data_value.value), + ); + } + } + println!("{pivot_table}"); + } + } + } + Ok(()) + } } fn print_item_directory(item: &T, level: usize, show_member_names: bool) diff --git a/rust/pspp/src/spv/read.rs b/rust/pspp/src/spv/read.rs index 8cb5987df4..78902bf9e5 100644 --- a/rust/pspp/src/spv/read.rs +++ b/rust/pspp/src/spv/read.rs @@ -41,7 +41,7 @@ use crate::{ mod css; pub mod html; pub mod legacy_bin; -mod legacy_xml; +pub mod legacy_xml; mod light; pub mod structure; #[cfg(test)] diff --git a/rust/pspp/src/spv/read/legacy_xml.rs b/rust/pspp/src/spv/read/legacy_xml.rs index d4af8374ad..b953dcd402 100644 --- a/rust/pspp/src/spv/read/legacy_xml.rs +++ b/rust/pspp/src/spv/read/legacy_xml.rs @@ -647,7 +647,7 @@ impl Visualization { pub fn decode( &self, - data: IndexMap>>, + binary_data: IndexMap>>, look: Look, warn: &mut dyn FnMut(LegacyXmlWarning), ) -> Result { @@ -692,7 +692,7 @@ impl Visualization { }; let caption = LabelFrame::decode_label(caption_labels, &footnotes); - let series = self.decode_series(data, warn); + let series = self.decode_series(binary_data, warn); let (mut dims, current_layer) = self.decode_dimensions(graph, &series, &footnotes); let cell_footnotes = graph @@ -742,9 +742,9 @@ impl Visualization { } pub struct Series { - name: String, + pub name: String, label: Option, - values: Vec, + pub values: Vec, map: Map, affixes: Vec, coordinate_to_index: RefCell>, diff --git a/rust/pspp/src/spv/read/structure.rs b/rust/pspp/src/spv/read/structure.rs index 0c204914bb..a2ad34871a 100644 --- a/rust/pspp/src/spv/read/structure.rs +++ b/rust/pspp/src/spv/read/structure.rs @@ -330,7 +330,7 @@ impl Table { let pivot_table = visualization.decode(data, *self.look.unwrap_or_default(), &mut |w| { warn(Warning { - member: bin_member_name.clone(), + member: xml_member_name.clone(), details: WarningDetails::LegacyXmlWarning(w), }) })?;