use crate::{
parse_subset,
tokenizer::Tokenizer,
types::{ChangeDate, Note, SourceCitation, Xref},
Parser,
};
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
pub struct MultimediaRecord {
pub xref: Option<Xref>,
pub file: Option<MultimediaFileRef>,
pub form: Option<MultimediaFormat>,
pub title: Option<String>,
pub user_reference_number: Option<UserReferenceNumber>,
pub automated_record_id: Option<String>,
pub source_citation: Option<SourceCitation>,
pub change_date: Option<ChangeDate>,
pub note_structure: Option<Note>,
}
impl MultimediaRecord {
#[must_use]
pub fn new(tokenizer: &mut Tokenizer, level: u8, xref: Option<Xref>) -> MultimediaRecord {
let mut obje = MultimediaRecord::default();
obje.xref = xref;
obje.parse(tokenizer, level);
obje
}
}
impl Parser for MultimediaRecord {
fn parse(&mut self, tokenizer: &mut Tokenizer, level: u8) {
tokenizer.next_token();
let handle_subset = |tag: &str, tokenizer: &mut Tokenizer| match tag {
"FILE" => self.file = Some(MultimediaFileRef::new(tokenizer, level + 1)),
"FORM" => self.form = Some(MultimediaFormat::new(tokenizer, level + 1)),
"TITL" => self.title = Some(tokenizer.take_line_value()),
"REFN" => {
self.user_reference_number = Some(UserReferenceNumber::new(tokenizer, level + 1))
}
"RIN" => self.automated_record_id = Some(tokenizer.take_line_value()),
"NOTE" => self.note_structure = Some(Note::new(tokenizer, level + 1)),
"SOUR" => self.source_citation = Some(SourceCitation::new(tokenizer, level + 1)),
"CHAN" => self.change_date = Some(ChangeDate::new(tokenizer, level + 1)),
_ => panic!("{} Unhandled Multimedia Tag: {}", tokenizer.debug(), tag),
};
parse_subset(tokenizer, level, handle_subset);
}
}
#[derive(Debug, Default)]
#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
pub struct MultimediaLink {
pub xref: Option<Xref>,
pub file: Option<MultimediaFileRef>,
pub form: Option<MultimediaFormat>,
pub title: Option<String>,
}
impl MultimediaLink {
#[must_use]
pub fn new(tokenizer: &mut Tokenizer, level: u8, xref: Option<Xref>) -> MultimediaLink {
let mut obje = MultimediaLink {
xref,
file: None,
form: None,
title: None,
};
obje.parse(tokenizer, level);
obje
}
}
impl Parser for MultimediaLink {
fn parse(&mut self, tokenizer: &mut Tokenizer, level: u8) {
tokenizer.next_token();
let handle_subset = |tag: &str, tokenizer: &mut Tokenizer| match tag {
"FILE" => self.file = Some(MultimediaFileRef::new(tokenizer, level + 1)),
"FORM" => self.form = Some(MultimediaFormat::new(tokenizer, level + 1)),
"TITL" => self.title = Some(tokenizer.take_line_value()),
_ => panic!("{} Unhandled Multimedia Tag: {}", tokenizer.debug(), tag),
};
parse_subset(tokenizer, level, handle_subset);
}
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
pub struct MultimediaFileRef {
pub value: Option<String>,
pub title: Option<String>,
pub form: Option<MultimediaFormat>,
}
impl MultimediaFileRef {
#[must_use]
pub fn new(tokenizer: &mut Tokenizer, level: u8) -> MultimediaFileRef {
let mut file = MultimediaFileRef::default();
file.parse(tokenizer, level);
file
}
}
impl Parser for MultimediaFileRef {
fn parse(&mut self, tokenizer: &mut Tokenizer, level: u8) {
self.value = Some(tokenizer.take_line_value());
let handle_subset = |tag: &str, tokenizer: &mut Tokenizer| match tag {
"TITL" => self.title = Some(tokenizer.take_line_value()),
"FORM" => self.form = Some(MultimediaFormat::new(tokenizer, level + 1)),
_ => panic!(
"{} Unhandled MultimediaFileRefn Tag: {}",
tokenizer.debug(),
tag
),
};
parse_subset(tokenizer, level, handle_subset);
}
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
pub struct MultimediaFormat {
pub value: Option<String>,
pub source_media_type: Option<String>,
}
impl MultimediaFormat {
#[must_use]
pub fn new(tokenizer: &mut Tokenizer, level: u8) -> MultimediaFormat {
let mut form = MultimediaFormat::default();
form.parse(tokenizer, level);
form
}
}
impl Parser for MultimediaFormat {
fn parse(&mut self, tokenizer: &mut Tokenizer, level: u8) {
self.value = Some(tokenizer.take_line_value());
let handle_subset = |tag: &str, tokenizer: &mut Tokenizer| match tag {
"TYPE" => self.source_media_type = Some(tokenizer.take_line_value()),
_ => panic!(
"{} Unhandled MultimediaFormat Tag: {}",
tokenizer.debug(),
tag
),
};
parse_subset(tokenizer, level, handle_subset);
}
}
#[derive(Debug, Default)]
#[cfg_attr(feature = "json", derive(Serialize, Deserialize))]
#[derive(Clone)]
pub struct UserReferenceNumber {
pub value: Option<String>,
pub user_reference_type: Option<String>,
}
impl UserReferenceNumber {
#[must_use]
pub fn new(tokenizer: &mut Tokenizer, level: u8) -> UserReferenceNumber {
let mut refn = UserReferenceNumber::default();
refn.parse(tokenizer, level);
refn
}
}
impl Parser for UserReferenceNumber {
fn parse(&mut self, tokenizer: &mut Tokenizer, level: u8) {
self.value = Some(tokenizer.take_line_value());
let handle_subset = |tag: &str, tokenizer: &mut Tokenizer| match tag {
"TYPE" => self.user_reference_type = Some(tokenizer.take_line_value()),
_ => panic!(
"{} Unhandled UserReferenceNumber Tag: {}",
tokenizer.debug(),
tag
),
};
parse_subset(tokenizer, level, handle_subset);
}
}
#[cfg(test)]
mod tests {
use crate::GedcomDocument;
#[test]
fn test_parse_multimedia_record() {
let sample = "\
0 HEAD\n\
1 GEDC\n\
2 VERS 5.5\n\
2 FORM LINEAGE-LINKED\n\
0 @MEDIA1@ OBJE\n\
1 FILE /home/user/media/file_name.bmp\n\
1 TITL A Title\n\
1 RIN Automated Id\n\
0 TRLR";
let mut doc = GedcomDocument::new(sample.chars());
let data = doc.parse_document();
assert_eq!(data.multimedia.len(), 1);
let obje = &data.multimedia[0];
let xref = obje.xref.as_ref().unwrap();
assert_eq!(xref, "@MEDIA1@");
let titl = obje.title.as_ref().unwrap();
assert_eq!(titl, "A Title");
let rin = obje.automated_record_id.as_ref().unwrap();
assert_eq!(rin, "Automated Id");
}
#[test]
fn test_parse_multimedia_link() {
let sample = "\
0 HEAD\n\
1 CHAR UTF-8\n\
1 SOUR Ancestry.com Family Trees\n\
2 VERS (2010.3)\n\
2 NAME Ancestry.com Family Trees\n\
2 CORP Ancestry.com\n\
1 GEDC\n\
2 VERS 5.5\n\
2 FORM LINEAGE-LINKED\n\
0 OBJE\n\
1 FILE http://trees.ancestry.com/rd?f=image&guid=Xxxxxxxx-Xxxx-Xxxx-Xxxx-Xxxxxxxxxxxx&tid=Xxxxxxxx&pid=1\n\
1 FORM jpg\n\
1 TITL In Prague\n\
0 TRLR";
let mut record = GedcomDocument::new(sample.chars());
let data = record.parse_document();
assert_eq!(data.multimedia.len(), 1);
let obje = &data.multimedia[0];
assert_eq!(obje.title.as_ref().unwrap(), "In Prague");
let form = obje.form.as_ref().unwrap();
assert_eq!(form.value.as_ref().unwrap(), "jpg");
let file = obje.file.as_ref().unwrap();
assert_eq!(file.value.as_ref().unwrap(), "http://trees.ancestry.com/rd?f=image&guid=Xxxxxxxx-Xxxx-Xxxx-Xxxx-Xxxxxxxxxxxx&tid=Xxxxxxxx&pid=1");
}
#[test]
fn test_parse_multimedia_file_ref_record() {
let sample = "\
0 HEAD\n\
1 GEDC\n\
2 VERS 5.5\n\
0 @MEDIA1@ OBJE\n\
1 FILE /home/user/media/file_name.bmp\n\
2 FORM bmp\n\
3 TYPE photo
2 TITL A Bitmap\n\
0 TRLR";
let mut doc = GedcomDocument::new(sample.chars());
let data = doc.parse_document();
assert_eq!(data.multimedia.len(), 1);
let file = data.multimedia[0].file.as_ref().unwrap();
assert_eq!(
file.value.as_ref().unwrap(),
"/home/user/media/file_name.bmp"
);
assert_eq!(file.title.as_ref().unwrap(), "A Bitmap");
let form = file.form.as_ref().unwrap();
assert_eq!(form.value.as_ref().unwrap(), "bmp");
assert_eq!(form.source_media_type.as_ref().unwrap(), "photo");
}
#[test]
fn test_parse_multimedia_format_record() {
let sample = "\
0 HEAD\n\
1 GEDC\n\
2 VERS 5.5\n\
0 @MEDIA1@ OBJE\n\
1 FILE /home/user/media/file_name.bmp\n\
2 FORM bmp\n\
3 TYPE photo
0 TRLR";
let mut doc = GedcomDocument::new(sample.chars());
let data = doc.parse_document();
assert_eq!(data.multimedia.len(), 1);
let file = data.multimedia[0].file.as_ref().unwrap();
let form = file.form.as_ref().unwrap();
assert_eq!(form.value.as_ref().unwrap(), "bmp");
assert_eq!(form.source_media_type.as_ref().unwrap(), "photo");
}
#[test]
fn test_parse_user_reference_number_record() {
let sample = "\
0 HEAD\n\
1 GEDC\n\
2 VERS 5.5\n\
2 FORM LINEAGE-LINKED\n\
0 @MEDIA1@ OBJE\n\
1 FILE /home/user/media/file_name.bmp\n\
1 REFN 000\n\
2 TYPE User Reference Type\n\
0 TRLR";
let mut doc = GedcomDocument::new(sample.chars());
let data = doc.parse_document();
assert_eq!(data.multimedia.len(), 1);
let user_ref = data.multimedia[0].user_reference_number.as_ref().unwrap();
assert_eq!(user_ref.value.as_ref().unwrap(), "000");
assert_eq!(
user_ref.user_reference_type.as_ref().unwrap(),
"User Reference Type"
);
}
}