shape_runtime/stdlib/
archive.rs1use super::byte_utils::bytes_from_i64_slice;
17use crate::marshal::register_typed_fn_1;
18use crate::module_exports::ModuleExports;
19use crate::typed_module_exports::{ConcreteReturn, ConcreteType, TypedReturn};
20
21pub fn create_archive_module() -> ModuleExports {
24 let mut module = ModuleExports::new("std::core::archive");
25 module.description = "Archive extraction (zip, tar)".to_string();
26
27 register_typed_fn_1::<_, Vec<i64>>(
29 &mut module,
30 "zip_extract",
31 "Extract a zip archive from a byte array into an array of entries",
32 "data",
33 "Array<int>",
34 ConcreteType::ArrayObject("Array<{name: string, data: string}>".to_string()),
35 |data, _ctx| {
36 use std::io::{Cursor, Read};
37
38 let bytes = bytes_from_i64_slice(&data)
39 .map_err(|e| format!("archive.zip_extract(): {}", e))?;
40
41 let cursor = Cursor::new(bytes);
42 let mut archive = zip::ZipArchive::new(cursor)
43 .map_err(|e| format!("archive.zip_extract() invalid zip: {}", e))?;
44
45 let mut entries: Vec<Vec<(String, ConcreteReturn)>> = Vec::new();
46 for i in 0..archive.len() {
47 let mut file = archive.by_index(i).map_err(|e| {
48 format!("archive.zip_extract() failed to read entry {}: {}", i, e)
49 })?;
50
51 if file.is_dir() {
52 continue;
53 }
54
55 let name = file.name().to_string();
56 let mut contents = String::new();
57 file.read_to_string(&mut contents).map_err(|e| {
58 format!("archive.zip_extract() failed to read '{}': {}", name, e)
59 })?;
60
61 entries.push(vec![
62 ("name".to_string(), ConcreteReturn::String(name)),
63 ("data".to_string(), ConcreteReturn::String(contents)),
64 ]);
65 }
66
67 Ok(TypedReturn::ArrayObjectPairs(entries))
68 },
69 );
70
71 register_typed_fn_1::<_, Vec<i64>>(
73 &mut module,
74 "tar_extract",
75 "Extract a tar archive from a byte array into an array of entries",
76 "data",
77 "Array<int>",
78 ConcreteType::ArrayObject("Array<{name: string, data: string}>".to_string()),
79 |data, _ctx| {
80 use std::io::{Cursor, Read};
81
82 let bytes = bytes_from_i64_slice(&data)
83 .map_err(|e| format!("archive.tar_extract(): {}", e))?;
84
85 let cursor = Cursor::new(bytes);
86 let mut archive = tar::Archive::new(cursor);
87
88 let mut entries: Vec<Vec<(String, ConcreteReturn)>> = Vec::new();
89 for entry_result in archive
90 .entries()
91 .map_err(|e| format!("archive.tar_extract() invalid tar: {}", e))?
92 {
93 let mut entry = entry_result
94 .map_err(|e| format!("archive.tar_extract() failed to read entry: {}", e))?;
95
96 if entry.header().entry_type().is_dir() {
97 continue;
98 }
99
100 let name = entry
101 .path()
102 .map_err(|e| format!("archive.tar_extract() invalid path: {}", e))?
103 .to_string_lossy()
104 .to_string();
105
106 let mut contents = String::new();
107 entry.read_to_string(&mut contents).map_err(|e| {
108 format!("archive.tar_extract() failed to read '{}': {}", name, e)
109 })?;
110
111 entries.push(vec![
112 ("name".to_string(), ConcreteReturn::String(name)),
113 ("data".to_string(), ConcreteReturn::String(contents)),
114 ]);
115 }
116
117 Ok(TypedReturn::ArrayObjectPairs(entries))
118 },
119 );
120
121 module
122}