1use crate::ValidationWarning;
4use std::fmt::Write;
5
6pub struct TfmToPlOutput {
8 pub pl_data: Result<String, crate::DeserializationError>,
9 pub error_messages: Vec<TfmToPlErrorMessage>,
10}
11
12pub enum TfmToPlErrorMessage {
14 DeserializationWarning(crate::DeserializationWarning),
15 ValidationWarning(crate::ValidationWarning),
16}
17
18impl TfmToPlErrorMessage {
19 pub fn tftopl_message(&self) -> String {
20 match self {
21 TfmToPlErrorMessage::DeserializationWarning(warning) => warning.tftopl_message(),
22 TfmToPlErrorMessage::ValidationWarning(warning) => warning.tftopl_message(),
23 }
24 }
25}
26pub fn pl_to_tfm(pl_data: &str) -> (Vec<u8>, Vec<crate::pl::ParseWarning>) {
30 let (pl_file, warnings) = crate::pl::File::from_pl_source_code(pl_data);
31 let tfm_file: crate::File = pl_file.into();
32 let tfm_output: Vec<u8> = tfm_file.serialize();
33 (tfm_output, warnings)
34}
35
36pub fn tfm_to_pl(
40 tfm_data: &[u8],
41 indent: usize,
42 display_format: &dyn Fn(&crate::pl::File) -> crate::pl::CharDisplayFormat,
43) -> Result<TfmToPlOutput, std::fmt::Error> {
44 let mut error_messages = Vec::<TfmToPlErrorMessage>::new();
45 let (tfm_file_or, warnings) = crate::File::deserialize(tfm_data);
46 for warning in warnings {
47 error_messages.push(TfmToPlErrorMessage::DeserializationWarning(warning));
48 }
49 let mut tfm_file = match tfm_file_or {
50 Ok(tfm_file) => tfm_file,
51 Err(err) => {
52 return Ok(TfmToPlOutput {
53 pl_data: Err(err),
54 error_messages,
55 });
56 }
57 };
58 let warnings = tfm_file.validate_and_fix();
59 let infinite_loop = warnings.iter().any(|w| {
60 matches!(
61 w,
62 crate::ValidationWarning::LigKernWarning(
63 crate::ligkern::lang::ValidationWarning::InfiniteLoop(_),
64 )
65 )
66 });
67 let warnings = filter_lig_kern_warnings(warnings);
68 let tfm_modified = warnings
69 .iter()
70 .any(crate::ValidationWarning::tfm_file_modified);
71 for warning in warnings {
72 error_messages.push(TfmToPlErrorMessage::ValidationWarning(warning));
73 }
74 let pl_file: crate::pl::File = tfm_file.into();
75 let suffix = if infinite_loop {
76 "(INFINITE LIGATURE LOOP MUST BE BROKEN!)"
77 } else if tfm_modified {
78 "(COMMENT THE TFM FILE WAS BAD, SO THE DATA HAS BEEN CHANGED!)\n"
79 } else {
80 ""
81 };
82 let mut s = String::new();
83 write![
84 &mut s,
85 "{}{}",
86 pl_file.display(indent, display_format(&pl_file),),
87 suffix
88 ]?;
89 Ok(TfmToPlOutput {
90 pl_data: Ok(s),
91 error_messages,
92 })
93}
94
95fn filter_lig_kern_warnings(mut warnings: Vec<ValidationWarning>) -> Vec<ValidationWarning> {
96 let mut out = Vec::with_capacity(warnings.len());
97 let mut seen_lig_kern = false;
98 while let Some(warning) = warnings.pop() {
99 if matches!(
100 warning,
101 crate::ValidationWarning::LigKernWarning(
102 crate::ligkern::lang::ValidationWarning::InfiniteLoop(_),
103 )
104 ) {
105 if seen_lig_kern {
106 continue;
107 }
108 seen_lig_kern = true;
109 }
110 out.push(warning);
111 }
112 out.reverse();
113 out
114}