Skip to main content

robinpath_modules/modules/
zip_mod.rs

1use robinpath::{RobinPath, Value};
2
3pub fn register(rp: &mut RobinPath) {
4    // zip.gzip str → base64 gzipped
5    rp.register_builtin("zip.gzip", |args, _| {
6        let input = args.first().map(|v| v.to_display_string()).unwrap_or_default();
7        let compressed = gzip_compress(input.as_bytes())?;
8        Ok(Value::String(base64_encode(&compressed)))
9    });
10
11    // zip.gunzip base64 → decompressed string
12    rp.register_builtin("zip.gunzip", |args, _| {
13        let input = args.first().map(|v| v.to_display_string()).unwrap_or_default();
14        let data = base64_decode(&input)?;
15        let decompressed = gzip_decompress(&data)?;
16        Ok(Value::String(String::from_utf8_lossy(&decompressed).to_string()))
17    });
18
19    // zip.deflate str → base64 deflated
20    rp.register_builtin("zip.deflate", |args, _| {
21        let input = args.first().map(|v| v.to_display_string()).unwrap_or_default();
22        let compressed = deflate_compress(input.as_bytes())?;
23        Ok(Value::String(base64_encode(&compressed)))
24    });
25
26    // zip.inflate base64 → decompressed string
27    rp.register_builtin("zip.inflate", |args, _| {
28        let input = args.first().map(|v| v.to_display_string()).unwrap_or_default();
29        let data = base64_decode(&input)?;
30        let decompressed = deflate_decompress(&data)?;
31        Ok(Value::String(String::from_utf8_lossy(&decompressed).to_string()))
32    });
33
34    // zip.gzipFile inputPath outputPath? → outputPath
35    rp.register_builtin("zip.gzipFile", |args, _| {
36        let input_path = args.first().map(|v| v.to_display_string()).unwrap_or_default();
37        let output_path = args.get(1).map(|v| v.to_display_string())
38            .unwrap_or_else(|| format!("{}.gz", input_path));
39        let data = std::fs::read(&input_path)
40            .map_err(|e| format!("zip.gzipFile read error: {}", e))?;
41        let compressed = gzip_compress(&data)?;
42        std::fs::write(&output_path, &compressed)
43            .map_err(|e| format!("zip.gzipFile write error: {}", e))?;
44        Ok(Value::String(output_path))
45    });
46
47    // zip.gunzipFile inputPath outputPath? → outputPath
48    rp.register_builtin("zip.gunzipFile", |args, _| {
49        let input_path = args.first().map(|v| v.to_display_string()).unwrap_or_default();
50        let output_path = args.get(1).map(|v| v.to_display_string())
51            .unwrap_or_else(|| {
52                if input_path.ends_with(".gz") {
53                    input_path[..input_path.len() - 3].to_string()
54                } else {
55                    format!("{}.out", input_path)
56                }
57            });
58        let data = std::fs::read(&input_path)
59            .map_err(|e| format!("zip.gunzipFile read error: {}", e))?;
60        let decompressed = gzip_decompress(&data)?;
61        std::fs::write(&output_path, &decompressed)
62            .map_err(|e| format!("zip.gunzipFile write error: {}", e))?;
63        Ok(Value::String(output_path))
64    });
65
66    // zip.isGzipped base64 → bool
67    rp.register_builtin("zip.isGzipped", |args, _| {
68        let input = args.first().map(|v| v.to_display_string()).unwrap_or_default();
69        match base64_decode(&input) {
70            Ok(buf) => Ok(Value::Bool(buf.len() >= 2 && buf[0] == 0x1f && buf[1] == 0x8b)),
71            Err(_) => Ok(Value::Bool(false)),
72        }
73    });
74
75    // zip.compressString str → base64 (alias for gzip)
76    rp.register_builtin("zip.compressString", |args, _| {
77        let input = args.first().map(|v| v.to_display_string()).unwrap_or_default();
78        let compressed = gzip_compress(input.as_bytes())?;
79        Ok(Value::String(base64_encode(&compressed)))
80    });
81
82    // zip.decompressString base64 → string (alias for gunzip)
83    rp.register_builtin("zip.decompressString", |args, _| {
84        let input = args.first().map(|v| v.to_display_string()).unwrap_or_default();
85        let data = base64_decode(&input)?;
86        let decompressed = gzip_decompress(&data)?;
87        Ok(Value::String(String::from_utf8_lossy(&decompressed).to_string()))
88    });
89}
90
91fn gzip_compress(data: &[u8]) -> Result<Vec<u8>, String> {
92    use flate2::write::GzEncoder;
93    use flate2::Compression;
94    use std::io::Write;
95    let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
96    encoder.write_all(data).map_err(|e| format!("gzip compress error: {}", e))?;
97    encoder.finish().map_err(|e| format!("gzip finish error: {}", e))
98}
99
100fn gzip_decompress(data: &[u8]) -> Result<Vec<u8>, String> {
101    use flate2::read::GzDecoder;
102    use std::io::Read;
103    let mut decoder = GzDecoder::new(data);
104    let mut result = Vec::new();
105    decoder.read_to_end(&mut result).map_err(|e| format!("gzip decompress error: {}", e))?;
106    Ok(result)
107}
108
109fn deflate_compress(data: &[u8]) -> Result<Vec<u8>, String> {
110    use flate2::write::DeflateEncoder;
111    use flate2::Compression;
112    use std::io::Write;
113    let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
114    encoder.write_all(data).map_err(|e| format!("deflate compress error: {}", e))?;
115    encoder.finish().map_err(|e| format!("deflate finish error: {}", e))
116}
117
118fn deflate_decompress(data: &[u8]) -> Result<Vec<u8>, String> {
119    use flate2::read::DeflateDecoder;
120    use std::io::Read;
121    let mut decoder = DeflateDecoder::new(data);
122    let mut result = Vec::new();
123    decoder.read_to_end(&mut result).map_err(|e| format!("deflate decompress error: {}", e))?;
124    Ok(result)
125}
126
127fn base64_encode(data: &[u8]) -> String {
128    use base64::Engine;
129    base64::engine::general_purpose::STANDARD.encode(data)
130}
131
132fn base64_decode(s: &str) -> Result<Vec<u8>, String> {
133    use base64::Engine;
134    base64::engine::general_purpose::STANDARD.decode(s)
135        .map_err(|e| format!("base64 decode error: {}", e))
136}