1 | //! Write MO files. |
2 | |
3 | use std::{ |
4 | fs::File, |
5 | io::{BufWriter, Write}, |
6 | path::Path, |
7 | }; |
8 | |
9 | use crate::{catalog::Catalog, message::MessageView}; |
10 | |
11 | fn original_repr_len(message: &dyn MessageView) -> usize { |
12 | let mut result: usize = 0usize; |
13 | let ctxt: &str = message.msgctxt(); |
14 | if !ctxt.is_empty() { |
15 | result += ctxt.len() + 1; |
16 | } |
17 | result += message.msgid().len(); |
18 | if message.is_plural() { |
19 | result += 1 + message.msgid_plural().unwrap().len(); |
20 | } |
21 | result |
22 | } |
23 | |
24 | fn write_original_repr( |
25 | writer: &mut BufWriter<std::fs::File>, |
26 | message: &dyn MessageView, |
27 | ) -> Result<(), std::io::Error> { |
28 | let ctxt: &str = message.msgctxt(); |
29 | if !ctxt.is_empty() { |
30 | writer.write_all(buf:ctxt.as_bytes())?; |
31 | writer.write_all(&[4u8])?; |
32 | } |
33 | writer.write_all(buf:message.msgid().as_bytes())?; |
34 | if message.is_plural() { |
35 | writer.write_all(&[0u8])?; |
36 | writer.write_all(buf:message.msgid_plural().unwrap().as_bytes())?; |
37 | } |
38 | Ok(()) |
39 | } |
40 | |
41 | fn translated_repr_len(message: &dyn MessageView) -> usize { |
42 | if let true = message.is_singular() { |
43 | message.msgstr().unwrap().len() |
44 | } else { |
45 | messageimpl Iterator |
46 | .msgstr_plural() |
47 | .unwrap() |
48 | .iter() |
49 | .map(|x: &String| x.len() + 1) |
50 | .sum::<usize>() |
51 | - 1 |
52 | } |
53 | } |
54 | |
55 | fn write_translated_repr( |
56 | writer: &mut BufWriter<std::fs::File>, |
57 | message: &dyn MessageView, |
58 | ) -> Result<(), std::io::Error> { |
59 | if message.is_singular() { |
60 | writer.write_all(buf:message.msgstr().unwrap().as_bytes())?; |
61 | } else { |
62 | writer.write_all(buf:message.msgstr_plural().unwrap().join(sep:" \u{0000}" ).as_bytes())?; |
63 | } |
64 | Ok(()) |
65 | } |
66 | |
67 | /// Saves a catalog to a binary MO file. |
68 | pub fn write(catalog: &Catalog, path: &Path) -> Result<(), std::io::Error> { |
69 | let file = File::create(path)?; |
70 | let mut writer = BufWriter::new(file); |
71 | |
72 | let metadata = catalog.metadata.export_for_mo(); |
73 | |
74 | // Header |
75 | let magic_number: u32 = 0x950412de; |
76 | let format_ver: u32 = 0x00000000; |
77 | let num_strings = catalog.count() + 1; |
78 | let orig_table_offset = 28; |
79 | let trans_table_offset = orig_table_offset + 8 * num_strings; |
80 | writer.write_all(&magic_number.to_ne_bytes())?; |
81 | writer.write_all(&format_ver.to_ne_bytes())?; |
82 | writer.write_all(&(num_strings as u32).to_ne_bytes())?; |
83 | writer.write_all(&(orig_table_offset as u32).to_ne_bytes())?; |
84 | writer.write_all(&(trans_table_offset as u32).to_ne_bytes())?; |
85 | writer.write_all(&[0u8; 4])?; |
86 | writer.write_all(&[0u8; 4])?; |
87 | |
88 | // O table |
89 | let mut offset = trans_table_offset + 8 * num_strings; |
90 | writer.write_all(&0u32.to_ne_bytes())?; |
91 | writer.write_all(&(offset as u32).to_ne_bytes())?; |
92 | offset += 1; |
93 | for &index in catalog.map.values() { |
94 | let length = original_repr_len(catalog.messages[index].as_ref().unwrap()); |
95 | writer.write_all(&(length as u32).to_ne_bytes())?; |
96 | writer.write_all(&(offset as u32).to_ne_bytes())?; |
97 | offset += length + 1; |
98 | } |
99 | |
100 | // T table |
101 | writer.write_all(&(metadata.len() as u32).to_ne_bytes())?; |
102 | writer.write_all(&(offset as u32).to_ne_bytes())?; |
103 | offset += metadata.len() + 1; |
104 | for &index in catalog.map.values() { |
105 | let length = translated_repr_len(catalog.messages[index].as_ref().unwrap()); |
106 | writer.write_all(&(length as u32).to_ne_bytes())?; |
107 | writer.write_all(&(offset as u32).to_ne_bytes())?; |
108 | offset += length + 1; |
109 | } |
110 | |
111 | // O strings |
112 | writer.write_all(&[0u8])?; |
113 | for &index in catalog.map.values() { |
114 | write_original_repr(&mut writer, catalog.messages[index].as_ref().unwrap())?; |
115 | writer.write_all(&[0u8])?; |
116 | } |
117 | |
118 | // T strings |
119 | writer.write_all(metadata.as_bytes())?; |
120 | writer.write_all(&[0u8])?; |
121 | for &index in catalog.map.values() { |
122 | write_translated_repr(&mut writer, catalog.messages[index].as_ref().unwrap())?; |
123 | writer.write_all(&[0u8])?; |
124 | } |
125 | |
126 | writer.flush()?; |
127 | Ok(()) |
128 | } |
129 | |