doe 1.1.62

doe is a powerful Rust crate designed to enhance development workflow by providing an extensive collection of useful macros and utility functions. It not only simplifies common tasks but also offers convenient features for clipboard management,robust cryptographic functions,keyboard input, and mouse interaction.
Documentation
#[allow(warnings)]
#[cfg(feature = "docx")]
pub mod docx {
    use std::{fs::File, io::Read, path::PathBuf};

    use zip::ZipArchive;

    /// docx_replace
    ///
    /// finds all 'name' and replace with 'andrew'
    /// ```ignore
    ///use doe::*;
    ///docx::docx_replace("./name.docx","name","andrew").unwrap();
    /// ```
    pub fn docx_replace<T>(
        docx_path: PathBuf,
        target: T,
        new_target: T,
    ) -> Result<(), Box<dyn std::error::Error>>
    where
    T: ToString,
    {
        use std::fs::File;
        use std::io::prelude::*;
        use zip::read::ZipArchive;
        use zip::write::FileOptions;
        use zip::CompressionMethod;

        // Open the .docx file as a zip
        let file = File::open(&docx_path)?;
        let mut archive = ZipArchive::new(file)?;
        let new_archive_path = "new_archive.zip";

        let options = FileOptions::default()
            .compression_method(CompressionMethod::Stored)
            .unix_permissions(0o755);

        let file = File::create(&new_archive_path).unwrap();
        let mut new_zip = zip::ZipWriter::new(file);

        // Loop over all of the files in the .docx archive
        for i in 0..archive.len() {
            let mut file_in_archive = archive.by_index(i).unwrap();
            let file_in_archive_name = &file_in_archive.name();
            if file_in_archive_name.to_string() == "word/document.xml" {
                let mut contents = String::new();
                file_in_archive.read_to_string(&mut contents).unwrap();
                // Perform text replacement
                let new_contents = contents.replace(&target.to_string(), &new_target.to_string());
                new_zip.start_file("word/document.xml", options)?;
                new_zip.write_all(new_contents.as_bytes())?;
            } else {
                new_zip.start_file(file_in_archive_name.to_string(), options)?;
                let mut buffer = Vec::new();
                file_in_archive.read_to_end(&mut buffer)?;
                new_zip.write_all(&buffer)?;
            }
        }
        std::fs::rename(new_archive_path, docx_path).unwrap();
        Ok(())
    }
   

    pub fn docx_bytes_replace_values<T>(
        docx_bytes: Vec<u8>,
        values: Vec<(T, T)>,
    ) -> Result<Vec<u8>, Box<dyn std::error::Error>>
    where
        T: ToString,
    {
        use std::fs::File;
        use std::io::{Read, Write, Cursor};
        use std::path::PathBuf;
        use zip::read::ZipArchive;
        use zip::write::FileOptions;
        use zip::CompressionMethod;
        // Open the .docx file as a zip
        let file =  Cursor::new(docx_bytes);
        let mut archive = ZipArchive::new(file)?;
    
        let options = FileOptions::default()
            .compression_method(CompressionMethod::Stored)
            .unix_permissions(0o755);
    
        // Create a new ZIP archive in memory
        let mut new_zip_data = Cursor::new(Vec::new());
        let mut new_zip = zip::ZipWriter::new(&mut new_zip_data);
    
        // Loop over all of the files in the .docx archive
        for i in 0..archive.len() {
            let mut file_in_archive = archive.by_index(i)?;
            let file_in_archive_name = file_in_archive.name().to_string();
    
            if file_in_archive_name.ends_with(".xml") {
                let mut contents = String::new();
                file_in_archive.read_to_string(&mut contents)?;
    
                let mut new_contents = contents;
                for (target, new_target) in &values {
                    // Perform text replacement
                    new_contents = new_contents.replace(&target.to_string(), &new_target.to_string());
                }
    
                new_zip.start_file(&file_in_archive_name, options)?;
                new_zip.write_all(new_contents.as_bytes())?;
            } else {
                new_zip.start_file(&file_in_archive_name, options)?;
                let mut buffer = Vec::new();
                file_in_archive.read_to_end(&mut buffer)?;
                new_zip.write_all(&buffer)?;
            }
        }
    
        // Finalize the new zip archive
        new_zip.finish()?;
    
        // Explicitly drop `new_zip` to release the mutable borrow on `new_zip_data`
        drop(new_zip);
    
        Ok(new_zip_data.into_inner().to_vec())
    }

    

    ///```ignore
    /// use doe::*;
    /// docx::docx_replace_values("./rust.docx", &[("[name]","andrew")]).unwrap();
    /// ```
    pub fn docx_replace_values<T>(
        docx_path: PathBuf,
        values: Vec<(T, T)>,
    ) -> Result<(), Box<dyn std::error::Error>>
    where
        T: ToString,
    {
        use std::fs::File;
        use std::io::{Read, Write, Cursor};
        use std::path::PathBuf;
        use zip::read::ZipArchive;
        use zip::write::FileOptions;
        use zip::CompressionMethod;
        // Open the .docx file as a zip
        let file = File::open(&docx_path)?;
        let mut archive = ZipArchive::new(file)?;
    
        let options = FileOptions::default()
            .compression_method(CompressionMethod::Stored)
            .unix_permissions(0o755);
    
        // Create a new ZIP archive in memory
        let mut new_zip_data = Cursor::new(Vec::new());
        let mut new_zip = zip::ZipWriter::new(&mut new_zip_data);
    
        // Loop over all of the files in the .docx archive
        for i in 0..archive.len() {
            let mut file_in_archive = archive.by_index(i)?;
            let file_in_archive_name = file_in_archive.name().to_string();
    
            if file_in_archive_name.ends_with(".xml") {
                let mut contents = String::new();
                file_in_archive.read_to_string(&mut contents)?;
    
                let mut new_contents = contents;
                for (target, new_target) in &values {
                    // Perform text replacement
                    new_contents = new_contents.replace(&target.to_string(), &new_target.to_string());
                }
    
                new_zip.start_file(&file_in_archive_name, options)?;
                new_zip.write_all(new_contents.as_bytes())?;
            } else {
                new_zip.start_file(&file_in_archive_name, options)?;
                let mut buffer = Vec::new();
                file_in_archive.read_to_end(&mut buffer)?;
                new_zip.write_all(&buffer)?;
            }
        }
    
        // Finalize the new zip archive
        new_zip.finish()?;
    
        // Explicitly drop `new_zip` to release the mutable borrow on `new_zip_data`
        drop(new_zip);
    
        // Replace the original .docx file with the new one
        let mut file = File::create(&docx_path)?;
        file.write_all(&new_zip_data.into_inner())?;
    
        Ok(())
    }
    ///```ignore
    /// use doe::*;
    /// docx::docx_replace_values("./rust.docx", &[("[name]","andrew")]).unwrap();
    /// ```
    pub fn docx_replace_values_old<T>(
        docx_path: PathBuf,
        values: Vec<(T, T)>,
    ) -> Result<(), Box<dyn std::error::Error>> 
    where
    T: ToString,
    {
        use std::fs::File;
        use std::io::prelude::*;
        use zip::read::ZipArchive;
        use zip::write::FileOptions;
        use zip::CompressionMethod;

        // Open the .docx file as a zip
        let file = File::open(docx_path.clone())?;
        let mut archive = ZipArchive::new(file)?;
        let new_archive_path = "new_archive.zip";

        let options = FileOptions::default()
            .compression_method(CompressionMethod::Stored)
            .unix_permissions(0o755);

        let file = File::create(&new_archive_path).unwrap();
        let mut new_zip = zip::ZipWriter::new(file);

        // Loop over all of the files in the .docx archive
        for i in 0..archive.len() {
            let mut file_in_archive = archive.by_index(i).unwrap();
            let file_in_archive_name = &file_in_archive.name().to_string();
            if file_in_archive_name.to_string().ends_with(".xml"){
                let mut contents = String::new();
                file_in_archive.read_to_string(&mut contents).unwrap();
                let mut new_contents = contents.to_string();
                for value in &values {
                    let (target, new_target) = value;
                    // Perform text replacement
                    new_contents = new_contents.replace(&target.to_string(), &new_target.to_string());
                }
                new_zip.start_file(file_in_archive_name, options)?;
                new_zip.write_all(new_contents.as_bytes())?;
            } else {
                new_zip.start_file(file_in_archive_name.to_string(), options)?;
                let mut buffer = Vec::new();
                file_in_archive.read_to_end(&mut buffer)?;
                new_zip.write_all(&buffer)?;
            }
        }
        std::fs::rename(new_archive_path, docx_path).unwrap();
        Ok(())
    }

    pub fn docx_replace_values_save(
        docx_path: PathBuf,
        values: Vec<(String, String)>,
        new_docx_path: PathBuf,
    ) -> Result<(), Box<dyn std::error::Error>> {
        use std::fs::File;
        use std::io::prelude::*;
        use zip::read::ZipArchive;
        use zip::write::FileOptions;
        use zip::CompressionMethod;

        // Open the .docx file as a zip
        let file = File::open(docx_path.clone())?;
        let mut archive = ZipArchive::new(file)?;
        let new_archive_path = "new_archive.zip";

        let options = FileOptions::default()
            .compression_method(CompressionMethod::Stored)
            .unix_permissions(0o755);

        let file = File::create(&new_archive_path).unwrap();
        let mut new_zip = zip::ZipWriter::new(file);

        // Loop over all of the files in the .docx archive
        for i in 0..archive.len() {
            let mut file_in_archive = archive.by_index(i).unwrap();
            let file_in_archive_name = &file_in_archive.name();
            if file_in_archive_name.to_string() == "word/document.xml" {
                let mut contents = String::new();
                file_in_archive.read_to_string(&mut contents).unwrap();
                let mut new_contents = contents.to_string();
                for value in &values {
                    let (target, new_target) = value;
                    // Perform text replacement
                    new_contents = new_contents.replace(target, &new_target);
                }
                new_zip.start_file("word/document.xml", options)?;
                new_zip.write_all(new_contents.as_bytes())?;
            } else {
                new_zip.start_file(file_in_archive_name.to_string(), options)?;
                let mut buffer = Vec::new();
                file_in_archive.read_to_end(&mut buffer)?;
                new_zip.write_all(&buffer)?;
            }
        }
        std::fs::rename(new_archive_path, new_docx_path).unwrap();
        Ok(())
    }

    pub fn docx_get_xml(docx_path: impl AsRef<str>) -> Result<String, Box<dyn std::error::Error>> {
        let reader = File::open(docx_path.as_ref())?;
        let mut zip = ZipArchive::new(reader)?;
        let mut file = zip.by_name("word/document.xml")?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        Ok(contents)
    }
    #[cfg(target_os = "unix")]
    pub fn docx_remove_read_only(
        docx_path: impl AsRef<str>,
    ) -> Result<(), Box<dyn std::error::Error>> {
        use std::fs::{metadata, set_permissions};
        use std::os::unix::fs::PermissionsExt;
        let docx_path = docx_path.as_ref();
        let meta = metadata(docx_path)?;
        let mut permissions = meta.permissions();
        let mode = permissions.mode();
        let new_mode = mode & !0o400;
        permissions.set_mode(new_mode);
        set_permissions(docx_path, permissions)?;
        Ok(())
    }

    pub fn parse_xml_get_content(xml: impl AsRef<str>) -> Vec<String> {
        use xml::reader::{EventReader, XmlEvent};
        let parser = EventReader::from_str(xml.as_ref());
        let mut content = vec![];
        for e in parser {
            match e {
                #[allow(warnings)]
                Ok(XmlEvent::StartElement { name, .. }) => {}
                #[allow(warnings)]
                Ok(XmlEvent::EndElement { name }) => {}
                Ok(XmlEvent::Characters(chars)) => {
                    content.push(chars);
                }
                Err(e) => {
                    println!("Error: {}", e);
                    break;
                }
                _ => {}
            }
        }
        content
    }
    pub fn docx_get_content(
        docx_path: impl AsRef<str>,
    ) -> Result<Vec<String>, Box<dyn std::error::Error>> {
        let xml = crate::docx::docx_get_xml(docx_path)?;
        Ok(crate::docx::parse_xml_get_content(xml))
    }
}

#[cfg(feature = "docx")]
pub use docx::*;