rtf_parser/
document.rs

1use std::error::Error;
2use std::fs;
3use std::io::Read;
4
5use serde::{Deserialize, Serialize};
6use wasm_bindgen::prelude::wasm_bindgen;
7
8use crate::header::RtfHeader;
9use crate::lexer::Lexer;
10use crate::parser::{Parser, StyleBlock};
11
12// Interface to WASM to be used in JS
13#[wasm_bindgen]
14pub fn parse_rtf(rtf: String) -> RtfDocument {
15    return RtfDocument::try_from(rtf).unwrap();
16}
17
18#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)]
19#[wasm_bindgen(getter_with_clone)]
20pub struct RtfDocument {
21    pub header: RtfHeader,
22    pub body: Vec<StyleBlock>,
23}
24
25// Create a RTF document from a String content
26impl TryFrom<String> for RtfDocument {
27    type Error = Box<dyn Error>;
28    fn try_from(file_content: String) -> Result<Self, Self::Error> {
29        let tokens = Lexer::scan(file_content.as_str())?;
30        let document = Parser::new(tokens).parse()?;
31        return Ok(document);
32    }
33}
34
35// Create a RTF document from file content
36impl TryFrom<&str> for RtfDocument {
37    type Error = Box<dyn Error>;
38    fn try_from(file_content: &str) -> Result<Self, Self::Error> {
39        let tokens = Lexer::scan(file_content)?;
40        let document = Parser::new(tokens).parse()?;
41        return Ok(document);
42    }
43}
44
45// Create an RTF document from a file
46impl TryFrom<&mut fs::File> for RtfDocument {
47    type Error = Box<dyn Error>;
48    fn try_from(file: &mut fs::File) -> Result<Self, Self::Error> {
49        let mut file_content = String::new();
50        file.read_to_string(&mut file_content)?;
51        return Self::try_from(file_content);
52    }
53}
54
55impl RtfDocument {
56    /// Create an `RtfDocument` from a rtf file path
57    pub fn from_filepath(filename: &str) -> Result<RtfDocument, Box<dyn Error>> {
58        let file_content = fs::read_to_string(filename)?;
59        return Self::try_from(file_content);
60    }
61
62    /// Get the raw text of an RTF document
63    pub fn get_text(&self) -> String {
64        let mut result = String::new();
65        for style_block in &self.body {
66            result.push_str(&style_block.text);
67        }
68        return result;
69    }
70}
71
72#[cfg(test)]
73pub(crate) mod tests {
74    use super::*;
75    use crate::document::RtfDocument;
76
77    #[test]
78    fn get_text_from_document() {
79        let rtf = r#"{ \rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard Voici du texte en {\b gras}.\par }"#;
80        let document = RtfDocument::try_from(rtf).unwrap();
81        assert_eq!(document.get_text(), "Voici du texte en gras.")
82    }
83
84    #[test]
85    fn create_document_from_file() {
86        let mut file = fs::File::open("./resources/tests/test-file.rtf").unwrap();
87        let document = RtfDocument::try_from(&mut file).unwrap();
88        assert_eq!(document.header.font_table.get(&0).unwrap().name, String::from("Helvetica"));
89    }
90
91    #[test]
92    fn create_document_from_filepath() {
93        let filename = "./resources/tests/test-file.rtf";
94        let document = RtfDocument::from_filepath(filename).unwrap();
95        assert_eq!(document.header.font_table.get(&0).unwrap().name, String::from("Helvetica"));
96    }
97}