Skip to content

Commit

Permalink
Added keyword and extended header output.
Browse files Browse the repository at this point in the history
  • Loading branch information
billallen256 committed Oct 31, 2024
1 parent 3630208 commit 31a92df
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 69 deletions.
95 changes: 75 additions & 20 deletions src/bluejay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::process::exit;
use bluefile::{
Error,
Header,
read_ext_header,
read_header,
read_type1000_adjunct_header,
read_type2000_adjunct_header,
Expand Down Expand Up @@ -47,15 +48,15 @@ fn get_config() -> Result<Config> {
}

fn header_lines(header: &Header, lines: &mut Vec<String>) {
lines.push(format!(" \"type_code\": \"{}\"", header.type_code));
lines.push(format!(" \"header_endianness\": \"{}\"", header.header_endianness));
lines.push(format!(" \"data_endianness\": \"{}\"", header.data_endianness));
lines.push(format!(" \"ext_header_start\": {}", header.ext_start));
lines.push(format!(" \"ext_header_size\": {}", header.ext_size));
lines.push(format!(" \"data_start\": {}", header.data_start));
lines.push(format!(" \"data_size\": {}", header.data_size));
lines.push(format!(" \"data_type\": \"{}\"", header.data_type));
lines.push(format!(" \"timecode\": {}", header.timecode));
lines.push(format!(" \"type_code\": \"{}\",", header.type_code));
lines.push(format!(" \"header_endianness\": \"{}\",", header.header_endianness));
lines.push(format!(" \"data_endianness\": \"{}\",", header.data_endianness));
lines.push(format!(" \"ext_header_start\": {},", header.ext_start));
lines.push(format!(" \"ext_header_size\": {},", header.ext_size));
lines.push(format!(" \"data_start\": {},", header.data_start));
lines.push(format!(" \"data_size\": {},", header.data_size));
lines.push(format!(" \"data_type\": \"{}\",", header.data_type));
lines.push(format!(" \"timecode\": {},", header.timecode));
}

fn adjunct_lines(file: &File, header: &Header, lines: &mut Vec<String>) {
Expand All @@ -69,9 +70,9 @@ fn adjunct_lines(file: &File, header: &Header, lines: &mut Vec<String>) {
}
};

lines.push(format!(" \"xstart\": {}", adj.xstart));
lines.push(format!(" \"xdelta\": {}", adj.xdelta));
lines.push(format!(" \"xunits\": {}", adj.xunits));
lines.push(format!(" \"xstart\": {},", adj.xstart));
lines.push(format!(" \"xdelta\": {},", adj.xdelta));
lines.push(format!(" \"xunits\": {},", adj.xunits));
},
2 => {
let adj = match read_type2000_adjunct_header(file, header) {
Expand All @@ -82,18 +83,70 @@ fn adjunct_lines(file: &File, header: &Header, lines: &mut Vec<String>) {
}
};

lines.push(format!(" \"xstart\": {}", adj.xstart));
lines.push(format!(" \"xdelta\": {}", adj.xdelta));
lines.push(format!(" \"xunits\": {}", adj.xunits));
lines.push(format!(" \"subsize\": {}", adj.subsize));
lines.push(format!(" \"ystart\": {}", adj.ystart));
lines.push(format!(" \"ydelta\": {}", adj.ydelta));
lines.push(format!(" \"yunits\": {}", adj.yunits));
lines.push(format!(" \"xstart\": {},", adj.xstart));
lines.push(format!(" \"xdelta\": {},", adj.xdelta));
lines.push(format!(" \"xunits\": {},", adj.xunits));
lines.push(format!(" \"subsize\": {},", adj.subsize));
lines.push(format!(" \"ystart\": {},", adj.ystart));
lines.push(format!(" \"ydelta\": {},", adj.ydelta));
lines.push(format!(" \"yunits\": {},", adj.yunits));
},
_ => {},
}
}

fn keyword_lines(header: &Header, lines: &mut Vec<String>) {
if header.keywords.len() == 0 {

Check warning on line 99 in src/bluejay.rs

View workflow job for this annotation

GitHub Actions / test

length comparison to zero

warning: length comparison to zero --> src/bluejay.rs:99:8 | 99 | if header.keywords.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `header.keywords.is_empty()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#len_zero = note: `#[warn(clippy::len_zero)]` on by default
lines.push(" \"keywords\": [],".to_string());
return;
}

lines.push(" \"keywords\": [".to_string());
let last_index = header.keywords.len() - 1;

for i in 0..header.keywords.len() {
let keyword = &header.keywords[i];

if i == last_index {
lines.push(format!(" {{ \"name\": \"{}\", \"value\": \"{}\" }}", keyword.name, keyword.value));
} else {
lines.push(format!(" {{ \"name\": \"{}\", \"value\": \"{}\" }},", keyword.name, keyword.value));
}
}

lines.push(" ],".to_string());
}

fn ext_header_lines(file: &File, header: &Header, lines: &mut Vec<String>) {
let keywords = match read_ext_header(file, header) {
Ok(x) => x,
Err(_) => {
println!("Could not read extended header");
exit(1);
},
};

if keywords.len() == 0 {

Check warning on line 129 in src/bluejay.rs

View workflow job for this annotation

GitHub Actions / test

length comparison to zero

warning: length comparison to zero --> src/bluejay.rs:129:8 | 129 | if keywords.len() == 0 { | ^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `keywords.is_empty()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#len_zero
lines.push(" \"ext_header\": []".to_string());
return;
}

lines.push(" \"ext_header\": [".to_string());
let last_index = keywords.len() - 1;

for i in 0..keywords.len() {

Check warning on line 137 in src/bluejay.rs

View workflow job for this annotation

GitHub Actions / test

the loop variable `i` is used to index `keywords`

warning: the loop variable `i` is used to index `keywords` --> src/bluejay.rs:137:14 | 137 | for i in 0..keywords.len() { | ^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop = note: `#[warn(clippy::needless_range_loop)]` on by default help: consider using an iterator and enumerate() | 137 | for (i, <item>) in keywords.iter().enumerate() { | ~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
let keyword = &keywords[i];

if i == last_index {
lines.push(format!(" {{ \"name\": \"{}\", \"value\": {}, \"format\": \"{}\" }}", keyword.tag, keyword.value, keyword.value.format));
} else {
lines.push(format!(" {{ \"name\": \"{}\", \"value\": {}, \"format\": \"{}\" }},", keyword.tag, keyword.value, keyword.value.format));
}
}

lines.push(" ]".to_string());
}

fn main() {
let config = match get_config() {
Ok(c) => c,
Expand All @@ -111,7 +164,9 @@ fn main() {
let mut lines: Vec<String> = vec![];
header_lines(&header, &mut lines);
adjunct_lines(&config.file, &header, &mut lines);
let all_lines = lines.join(",\n");
keyword_lines(&header, &mut lines);
ext_header_lines(&config.file, &header, &mut lines);
let all_lines = lines.join("\n");

println!("{{");
println!("{}", all_lines);
Expand Down
89 changes: 40 additions & 49 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,68 +118,57 @@ impl DataType {
}
}

/// Tracks information necesary to iterate through the extended header.
pub struct ExtHeaderIter {
reader: BufReader<File>,
consumed: usize,
offset: usize,
size: usize,
endianness: Endianness,
}

/// Additional functions for the extended header iterator.
impl ExtHeaderIter {
fn new(file: File, offset: usize, size: usize, endianness: Endianness) -> Result<Self> {
let mut reader = BufReader::new(file);

match reader.seek(SeekFrom::Start(offset as u64)) {
Ok(x) => x,
Err(_) => return Err(Error::ExtHeaderSeekError),
};
Ok(ExtHeaderIter{
reader,
consumed: 0,
offset,
size,
endianness,
})
}
}
/// Reads the extended header keywords.
pub fn read_ext_header(mut file: &File, header: &Header) -> Result<Vec<ExtKeyword>> {
match file.seek(SeekFrom::Start(header.ext_start as u64)) {
Ok(x) => x,
Err(_) => return Err(Error::ExtHeaderSeekError),
};

/// Implements the iterator trait for the extended header.
impl Iterator for ExtHeaderIter {
type Item = ExtKeyword;

fn next(&mut self) -> Option<Self::Item> {
if self.consumed >= self.size {
return None;
}
let mut keywords: Vec<ExtKeyword> = vec![];
let mut consumed: usize = 0;

while consumed < header.ext_size {
let mut key_length_buf = vec![0_u8; EXT_KEYWORD_LENGTH];
self.consumed += match self.reader.read_exact(&mut key_length_buf) {
consumed += match file.read_exact(&mut key_length_buf) {
Ok(_) => EXT_KEYWORD_LENGTH,
Err(_) => return None,
Err(_) => break,
};

// entire length of keyword block: tag, data, kwhdr & padding
let key_length = bytes_to_i32(&key_length_buf, self.endianness).unwrap() as usize;
let key_length = bytes_to_i32(&key_length_buf, header.header_endianness).unwrap() as usize;
let mut key_buf = vec![0_u8; key_length-EXT_KEYWORD_LENGTH];
self.consumed += match self.reader.read_exact(&mut key_buf) {
consumed += match file.read_exact(&mut key_buf) {
Ok(_) => key_length-EXT_KEYWORD_LENGTH,
Err(_) => return None,
Err(_) => break,
};
let keyword = parse_ext_keyword(&key_buf, key_length, self.endianness).unwrap();
Some(keyword)
let keyword = parse_ext_keyword(&key_buf, key_length, header.header_endianness).unwrap();
keywords.push(keyword);
}

Ok(keywords)
}

pub struct ExtKeywordValue {
pub format: char,
pub endianness: Endianness,
pub raw_value: Vec<u8>,
}

impl fmt::Display for ExtKeywordValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.format {
'A' => write!(f, "\"{}\"", from_utf8(&self.raw_value).unwrap().to_string()),

Check warning on line 161 in src/lib.rs

View workflow job for this annotation

GitHub Actions / test

`to_string` applied to a type that implements `Display` in `write!` args

warning: `to_string` applied to a type that implements `Display` in `write!` args --> src/lib.rs:161:75 | 161 | 'A' => write!(f, "\"{}\"", from_utf8(&self.raw_value).unwrap().to_string()), | ^^^^^^^^^^^^ help: remove this | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#to_string_in_format_args = note: `#[warn(clippy::to_string_in_format_args)]` on by default
_ => write!(f, "\"?\""),
}
}
}

/// Raw extended header keyword properties.
/// Extended header keyword.
pub struct ExtKeyword {
pub length: usize,
pub tag: String,
pub format: char,
pub value: Vec<u8>,
pub value: ExtKeywordValue,
}

fn parse_ext_keyword(v: &[u8], key_length: usize, endianness: Endianness) -> Result<ExtKeyword> {
Expand All @@ -193,18 +182,20 @@ fn parse_ext_keyword(v: &[u8], key_length: usize, endianness: Endianness) -> Res
let tag_offset: usize = value_offset + value_length;

let tag = from_utf8(&v[tag_offset..tag_offset+tag_length]).unwrap().to_string();
let value = v[value_offset..value_offset+value_length].to_vec();
let raw_value = v[value_offset..value_offset+value_length].to_vec();
let value = ExtKeywordValue{
format,
endianness,
raw_value,
};

Ok(ExtKeyword{
length: key_length,
tag,
format,
value,
})
}



#[derive(Debug, Clone, PartialEq)]
pub struct HeaderKeyword {
pub name: String,
Expand Down

0 comments on commit 31a92df

Please sign in to comment.