1use std::io::Write;
6
7#[cfg(test)]
8use std::io::Cursor;
9
10use byteorder::{LittleEndian, WriteBytesExt};
11use encoding_rs::WINDOWS_1252;
12use flate2::Compression;
13use flate2::write::ZlibEncoder;
14
15use crate::error::Result;
16use crate::types::{Coord, CoordPoint, ParameterCollection};
17
18pub fn write_block<W: Write>(writer: &mut W, data: &[u8], flags: u8) -> Result<()> {
23 let size = data.len() as i32;
24 let header = ((flags as i32) << 24) | size;
25 writer.write_i32::<LittleEndian>(header)?;
26 if !data.is_empty() {
27 writer.write_all(data)?;
28 }
29 Ok(())
30}
31
32pub fn write_block_with<W: Write, F>(writer: &mut W, serializer: F, flags: u8) -> Result<()>
37where
38 F: FnOnce(&mut Vec<u8>) -> Result<()>,
39{
40 let mut buffer = Vec::new();
41 serializer(&mut buffer)?;
42 write_block(writer, &buffer, flags)
43}
44
45pub fn compress_zlib(data: &[u8]) -> Result<Vec<u8>> {
49 let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
50 encoder.write_all(data)?;
51 let compressed = encoder.finish()?;
52 Ok(compressed)
53}
54
55pub fn encode_windows_1252(s: &str) -> Vec<u8> {
57 let (bytes, _, _) = WINDOWS_1252.encode(s);
58 bytes.into_owned()
59}
60
61pub fn write_raw_string<W: Write>(writer: &mut W, s: &str) -> Result<()> {
63 let bytes = encode_windows_1252(s);
64 writer.write_all(&bytes)?;
65 Ok(())
66}
67
68pub fn write_c_string<W: Write>(writer: &mut W, s: &str) -> Result<()> {
70 write_raw_string(writer, s)?;
71 writer.write_u8(0)?;
72 Ok(())
73}
74
75pub fn write_pascal_string<W: Write>(writer: &mut W, s: &str) -> Result<()> {
77 let mut buffer = Vec::new();
78 write_c_string(&mut buffer, s)?;
79 write_block(writer, &buffer, 0)
80}
81
82pub fn write_pascal_short_string<W: Write>(writer: &mut W, s: &str) -> Result<()> {
84 let bytes = encode_windows_1252(s);
85 if bytes.len() > 255 {
86 writer.write_u8(255)?;
88 writer.write_all(&bytes[..255])?;
89 } else {
90 writer.write_u8(bytes.len() as u8)?;
91 writer.write_all(&bytes)?;
92 }
93 Ok(())
94}
95
96pub fn write_font_name<W: Write>(writer: &mut W, s: &str) -> Result<()> {
105 let utf16: Vec<u16> = s.encode_utf16().take(16).collect();
107
108 for &code in &utf16 {
110 writer.write_u16::<LittleEndian>(code)?;
111 }
112
113 let written = utf16.len() * 2;
115
116 if utf16.len() < 16 {
118 writer.write_u16::<LittleEndian>(0)?; let with_null = written + 2;
120
121 for _ in with_null..32 {
123 writer.write_u8(0)?;
124 }
125 }
126 Ok(())
129}
130
131pub fn write_string_block<W: Write>(writer: &mut W, s: &str) -> Result<()> {
133 let mut buffer = Vec::new();
134 write_pascal_short_string(&mut buffer, s)?;
135 write_block(writer, &buffer, 0)
136}
137
138pub fn write_parameters<W: Write>(writer: &mut W, params: &ParameterCollection) -> Result<()> {
140 let s = params.to_string();
141 write_c_string(writer, &s)
142}
143
144pub fn write_parameters_raw<W: Write>(writer: &mut W, params: &ParameterCollection) -> Result<()> {
146 let s = params.to_string();
147 write_raw_string(writer, &s)
148}
149
150pub fn write_parameters_block<W: Write>(
152 writer: &mut W,
153 params: &ParameterCollection,
154) -> Result<()> {
155 let mut buffer = Vec::new();
156 write_parameters(&mut buffer, params)?;
157 write_block(writer, &buffer, 0)
158}
159
160pub fn write_coord_point<W: Write>(writer: &mut W, point: CoordPoint) -> Result<()> {
162 writer.write_i32::<LittleEndian>(point.x.to_raw())?;
163 writer.write_i32::<LittleEndian>(point.y.to_raw())?;
164 Ok(())
165}
166
167pub fn write_header<W: Write>(writer: &mut W, record_count: u32) -> Result<()> {
169 writer.write_u32::<LittleEndian>(record_count)?;
170 Ok(())
171}
172
173pub fn write_compressed_storage<W: Write>(writer: &mut W, id: &str, data: &[u8]) -> Result<()> {
177 write_block_with(
178 writer,
179 |buffer| {
180 buffer.write_u8(0xD0)?;
182
183 write_pascal_short_string(buffer, id)?;
185
186 let compressed = compress_zlib(data)?;
188 write_block(buffer, &compressed, 0)?;
189
190 Ok(())
191 },
192 0x01,
193 ) }
195
196pub fn write_compressed_storage_with<W: Write, F>(
198 writer: &mut W,
199 id: &str,
200 serializer: F,
201) -> Result<()>
202where
203 F: FnOnce(&mut Vec<u8>) -> Result<()>,
204{
205 let mut data = Vec::new();
206 serializer(&mut data)?;
207 write_compressed_storage(writer, id, &data)
208}
209
210pub trait WriteExt: Write {
212 fn write_coord(&mut self, value: Coord) -> Result<()>
214 where
215 Self: Sized,
216 {
217 self.write_i32::<LittleEndian>(value.to_raw())?;
218 Ok(())
219 }
220
221 fn write_bool8(&mut self, value: bool) -> Result<()>
223 where
224 Self: Sized,
225 {
226 self.write_u8(if value { 1 } else { 0 })?;
227 Ok(())
228 }
229}
230
231impl<W: Write> WriteExt for W {}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236
237 #[test]
238 fn test_write_block() {
239 let mut buffer = Vec::new();
240 write_block(&mut buffer, b"hello", 0).unwrap();
241
242 assert_eq!(buffer, [5, 0, 0, 0, b'h', b'e', b'l', b'l', b'o']);
244 }
245
246 #[test]
247 fn test_write_block_with_flags() {
248 let mut buffer = Vec::new();
249 write_block(&mut buffer, b"test", 0x01).unwrap();
250
251 assert_eq!(buffer[0], 4);
253 assert_eq!(buffer[3], 0x01);
254 }
255
256 #[test]
257 fn test_write_pascal_short_string() {
258 let mut buffer = Vec::new();
259 write_pascal_short_string(&mut buffer, "hello").unwrap();
260
261 assert_eq!(buffer, [5, b'h', b'e', b'l', b'l', b'o']);
263 }
264
265 #[test]
266 fn test_write_c_string() {
267 let mut buffer = Vec::new();
268 write_c_string(&mut buffer, "test").unwrap();
269
270 assert_eq!(buffer, [b't', b'e', b's', b't', 0]);
271 }
272
273 #[test]
274 fn test_write_coord_point() {
275 let mut buffer = Vec::new();
276 let point = CoordPoint::from_raw(65536, 131072);
277 write_coord_point(&mut buffer, point).unwrap();
278
279 assert_eq!(buffer.len(), 8);
281 let mut cursor = Cursor::new(&buffer);
282 use byteorder::ReadBytesExt;
283 assert_eq!(cursor.read_i32::<LittleEndian>().unwrap(), 65536);
284 assert_eq!(cursor.read_i32::<LittleEndian>().unwrap(), 131072);
285 }
286
287 #[test]
288 fn test_encode_windows_1252() {
289 let bytes = encode_windows_1252("Hello World");
290 assert_eq!(bytes, b"Hello World");
291 }
292
293 #[test]
294 fn test_write_font_name_empty() {
295 let mut buffer = Vec::new();
296 write_font_name(&mut buffer, "").unwrap();
297
298 assert_eq!(buffer.len(), 32);
300 assert_eq!(&buffer[0..2], &[0, 0]); assert!(buffer[2..].iter().all(|&b| b == 0)); }
303
304 #[test]
305 fn test_write_font_name_short() {
306 let mut buffer = Vec::new();
307 write_font_name(&mut buffer, "Arial").unwrap();
308
309 assert_eq!(buffer.len(), 32);
311
312 let expected_utf16: Vec<u16> = "Arial".encode_utf16().collect();
314 for (i, &code) in expected_utf16.iter().enumerate() {
315 let offset = i * 2;
316 let actual = u16::from_le_bytes([buffer[offset], buffer[offset + 1]]);
317 assert_eq!(actual, code);
318 }
319
320 let null_offset = 5 * 2;
322 assert_eq!(buffer[null_offset], 0);
323 assert_eq!(buffer[null_offset + 1], 0);
324
325 assert!(buffer[null_offset + 2..].iter().all(|&b| b == 0));
327 }
328
329 #[test]
330 fn test_write_font_name_15_chars() {
331 let mut buffer = Vec::new();
332 let name = "Times New Roman"; write_font_name(&mut buffer, name).unwrap();
334
335 assert_eq!(buffer.len(), 32);
337
338 let utf16: Vec<u16> = name.encode_utf16().collect();
340 assert_eq!(utf16.len(), 15);
341
342 for (i, &code) in utf16.iter().enumerate() {
343 let offset = i * 2;
344 let actual = u16::from_le_bytes([buffer[offset], buffer[offset + 1]]);
345 assert_eq!(actual, code);
346 }
347
348 assert_eq!(buffer[30], 0);
350 assert_eq!(buffer[31], 0);
351 }
352
353 #[test]
354 fn test_write_font_name_16_chars() {
355 let mut buffer = Vec::new();
356 let name = "1234567890ABCDEF"; write_font_name(&mut buffer, name).unwrap();
358
359 assert_eq!(buffer.len(), 32);
361
362 let utf16: Vec<u16> = name.encode_utf16().collect();
364 assert_eq!(utf16.len(), 16);
365
366 for (i, &code) in utf16.iter().enumerate() {
367 let offset = i * 2;
368 let actual = u16::from_le_bytes([buffer[offset], buffer[offset + 1]]);
369 assert_eq!(actual, code);
370 }
371
372 }
374
375 #[test]
376 fn test_write_font_name_too_long() {
377 let mut buffer = Vec::new();
378 let name = "ThisIsAVeryLongFontNameThatExceeds16Characters"; write_font_name(&mut buffer, name).unwrap();
380
381 assert_eq!(buffer.len(), 32);
383
384 let utf16: Vec<u16> = name.encode_utf16().take(16).collect();
386 assert_eq!(utf16.len(), 16);
387
388 for (i, &code) in utf16.iter().enumerate() {
389 let offset = i * 2;
390 let actual = u16::from_le_bytes([buffer[offset], buffer[offset + 1]]);
391 assert_eq!(actual, code);
392 }
393 }
394
395 #[test]
396 fn test_write_font_name_unicode() {
397 let mut buffer = Vec::new();
398 write_font_name(&mut buffer, "微软雅黑").unwrap(); assert_eq!(buffer.len(), 32);
401
402 let utf16: Vec<u16> = "微软雅黑".encode_utf16().collect();
404 for (i, &code) in utf16.iter().enumerate() {
405 let offset = i * 2;
406 let actual = u16::from_le_bytes([buffer[offset], buffer[offset + 1]]);
407 assert_eq!(actual, code);
408 }
409
410 let null_offset = utf16.len() * 2;
412 assert_eq!(buffer[null_offset], 0);
413 assert_eq!(buffer[null_offset + 1], 0);
414 }
415}