\n",
- id_desc.0, id_desc.1, id_desc.2, value)
-}
-
-fn row_id_desc(key: Key, tree_id: u64) -> (String, String, String) {
- let x = format!("{:X}", key.key_id);
- let y = format!("{:?}", key.key_type);
- let z = if key.key_type == ItemType::RootRef || key.key_type == ItemType::Ref {
- format!("{:X}", tree_id, key.key_offset, key.key_offset)
- } else {
- format!("{:X}", key.key_offset)
- };
- (x,y,z)
-}
-*/
diff --git a/src/render_common.rs b/src/render_common.rs
new file mode 100644
index 0000000..d36c425
--- /dev/null
+++ b/src/render_common.rs
@@ -0,0 +1,38 @@
+use maud::Render;
+use std::fmt::{Debug, UpperHex};
+
+pub struct DebugRender(pub T);
+
+impl Render for DebugRender {
+ fn render_to(&self, w: &mut String) {
+ format_args!("{0:#?}", self.0).render_to(w);
+ }
+}
+
+pub struct Hex(pub T);
+
+impl Render for Hex {
+ fn render_to(&self, w: &mut String) {
+ format_args!("{0:X}", self.0).render_to(w);
+ }
+}
+
+pub fn size_name(x: u64) -> String {
+ if x == 0 {
+ format!("0 B")
+ } else if x % (1<<10) != 0 {
+ format!("{} B", x)
+ } else if x % (1<<20) != 0 {
+ format!("{} KiB", x / (1<<10))
+ } else if x % (1<<30) != 0 {
+ format!("{} MiB", x / (1<<20))
+ } else if x % (1<<40) != 0 {
+ format!("{} GiB", x / (1<<30))
+ } else if x % (1<<50) != 0 {
+ format!("{} TiB", x / (1<<40))
+ } else if x % (1<<60) != 0 {
+ format!("{} PiB", x / (1<<50))
+ } else {
+ format!("{} EiB", x / (1<<60))
+ }
+}
diff --git a/src/render_tree.rs b/src/render_tree.rs
index b849780..6c2f206 100644
--- a/src/render_tree.rs
+++ b/src/render_tree.rs
@@ -1,4 +1,6 @@
use crate::btrfs_structs::{Item, Key, ItemType, Value, ExtentDataBody};
+use crate::render_common::{DebugRender, Hex, size_name};
+use maud::{Markup, html, DOCTYPE, PreEscaped};
#[derive(Debug)]
pub struct TableResult<'a> {
@@ -10,92 +12,124 @@ pub struct TableResult<'a> {
pub last_key: Key,
}
-static HTML_HEADER: &str = r###"
-
-
-
-
-
-"###;
+pub fn render_table(table: TableResult) -> Markup {
-static HTML_FOOTER: &str = r###"
-
-
-
-"###;
-
-pub fn render_table(table: TableResult) -> String {
- let mut result = String::new();
-
- result.push_str(HTML_HEADER);
-
- // header
- if let Some(desc) = table.tree_desc {
- result.push_str(&format!("
Tree {} ({})
", table.tree_id, desc));
+ let header: String = if let Some(desc) = table.tree_desc {
+ format!("Tree {} ({})", table.tree_id, desc)
} else {
- result.push_str(&format!("
Tree {}
", table.tree_id));
- }
+ format!("Tree {}", table.tree_id)
+ };
- // link to root tree
- if table.tree_id != 1 {
- result.push_str(&format!("go back to root tree"));
- }
-
- // search field
let key_input_value = table.key_id.map_or(String::new(), |x| format!("{:X}", x));
- result.push_str(&format!("\n");
- // navigation links
- // technically, adding one to offset in "next" is not correct if offset is -1
- // it would show an entry twice in that case, but who cares, that never actually happens anyway
- let first = table.first_key;
- let last = table.last_key;
- result.push_str(&format!("first\n",
- table.tree_id));
- result.push_str(&format!("prev\n",
- table.tree_id, first.key_id, u8::from(first.key_type), first.key_offset));
- result.push_str(&format!("next\n",
- table.tree_id, last.key_id, u8::from(last.key_type), last.key_offset));
- result.push_str(&format!("last\n",
- table.tree_id, u64::wrapping_sub(0,1), u8::wrapping_sub(0,1), u64::wrapping_sub(0,1)));
+ let first_key_url = format!("/tree/{}",
+ table.tree_id);
+ let prev_key_url = format!("/tree/{}/to/{:016X}-{:02X}-{:016X}",
+ table.tree_id,
+ table.first_key.key_id,
+ u8::from(table.first_key.key_type),
+ table.first_key.key_offset);
+ let next_key_url = format!("/tree/{}/from/{:016X}-{:02X}-{:016X}",
+ table.tree_id,
+ table.last_key.key_id,
+ u8::from(table.last_key.key_type),
+ table.first_key.key_offset);
+ let last_key_url = format!("/tree/{}/to/{:016X}-{:02X}-{:016X}",
+ table.tree_id,
+ u64::wrapping_sub(0,1),
+ u8::wrapping_sub(0,1),
+ u64::wrapping_sub(0,1));
- // the actual table
- result.push_str("
\n");
- for (idx, (it, _it_data)) in table.items.iter().enumerate() {
- let highlighted = table.key_id.filter(|x|*x == it.key.key_id).is_some();
- let value_string = item_value_string(table.tree_id, it.key, &it.value);
- let raw_string = format!("{:#?}", it);
+ let mut rows: Vec = Vec::new();
+
+ for &(it, _it_data) in table.items.iter() {
+ let highlighted = if table.key_id.filter(|x|*x == it.key.key_id).is_some() { "highlight" } else { "" };
+ let value_string = item_value_string(table.tree_id, it);
+ let details_string = item_details_string(table.tree_id, it);
+ let raw_string = format!("{:#?}", &it.value);
let id_desc = row_id_desc(it.key, table.tree_id);
- let key_type_class = match it.key.key_type {
- ItemType::Inode => "inode",
- ItemType::Ref => "ref",
- ItemType::RootRef => "ref",
- ItemType::RootBackRef => "ref",
- ItemType::ExtentData => "extent",
- ItemType::Dir => "dir",
- ItemType::DirIndex => "dir",
- ItemType::Root => "root",
- _ => "",
- };
- let row = format!("{}{}{}{}