Skip to content

vcard.tostring() folding fails (fn fold_line) #26

@Fuerst2718

Description

@Fuerst2718

Small issue:

If you format a vcard-struct the linefolding maybe not correct if you have long lines with characters consisting of more than one byte (as the german 'ö' for example). The function fold_line() (vcard.rs line 495 in Version 0.7.2) may fail, if the length in Bytes % 75 will never be 0. This can happen, if after 74 one-byte-characters a 2-Byte character like 'ö' is following. Then we have had (74 % 75 == 74) and in the next step we have (76 % 75 == 1), so a line-break with a following space will not be generated here.

Below you see a test-program with a suggested correction for the function fold_line.

// use unicode_segmentation::UnicodeSegmentation;
fn main() {

    // copied from vcard4 V0.7.2 vcard.rs Line 495ff...
    fn fold_line(line: String, wrap_at: usize) -> String {
        use unicode_segmentation::UnicodeSegmentation;
        let mut length = 0;
        let mut folded_line = String::new();
        for grapheme in UnicodeSegmentation::graphemes(&line[..], true) {
            length += grapheme.len();
            if length % wrap_at == 0 {
                folded_line.push_str("\r\n ");
            }
            folded_line.push_str(grapheme);
        }
        folded_line
    }

    // Correction of the above function
    fn xfold_line(line: String, wrap_at: usize) -> String {
        use unicode_segmentation::UnicodeSegmentation;
        // first line -> no whitespace at start
        let mut length = 0;
        let mut folded_line = String::new();
        for grapheme in UnicodeSegmentation::graphemes(&line[..], true) {
            length += grapheme.len();
            if length > wrap_at {
                folded_line.push_str("\r\n ");
                // actual length of the next line
                length = 1 + grapheme.len();
            }
            folded_line.push_str(grapheme);
        }
        folded_line
    }

    let lineal = format!("{} < Lineal", "1234567890".repeat(8));
    let line70 = "1234567890".repeat(7);  
    
    let line76 = format!("{line70}1234ö{line70}{line70}{line70}{line70}");

    println!("Org fold_line");
    let fold76 = fold_line(line76.clone(), 75);
    
    println!("{lineal}");
    println!("{fold76}");

    println!("Correction xfold_line");
    let fold76 = xfold_line(line76.clone(), 75);
    println!("{lineal}");
    println!("{fold76}");
}

and the output of the programm ('ö' in Col 75)

´´´
Org fold_line
12345678901234567890123456789012345678901234567890123456789012345678901234567890 < Lineal
12345678901234567890123456789012345678901234567890123456789012345678901234ö1234567890123456789012345678901234567890123456789012345678901234567890123
456789012345678901234567890123456789012345678901234567890123456789012345678
901234567890123456789012345678901234567890123456789012345678901234567890123
456789012345678901234567890123456789012345678901234567890
Correction xfold_line
12345678901234567890123456789012345678901234567890123456789012345678901234567890 < Lineal
12345678901234567890123456789012345678901234567890123456789012345678901234
ö123456789012345678901234567890123456789012345678901234567890123456789012
34567890123456789012345678901234567890123456789012345678901234567890123456
78901234567890123456789012345678901234567890123456789012345678901234567890
123456789012345678901234567890123456789012345678901234567890
´´´

Rust-Info
´´´
rustc 1.92.0 (ded5c06cf 2025-12-08)
binary: rustc
commit-hash: ded5c06cf21d2b93bffd5d884aa6e96934ee4234
commit-date: 2025-12-08
host: x86_64-pc-windows-msvc
release: 1.92.0
LLVM version: 21.1.3
´´´

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions