ns_keyed_archive/
encode.rs1use nskeyedarchiver_converter::ConverterError;
3use plist::{Dictionary, Uid, Value};
4
5const ARCHIVER: &str = "NSKeyedArchiver";
6const ARCHIVER_VERSION: u64 = 100000;
7
8const ARCHIVER_KEY_NAME: &str = "$archiver";
9const TOP_KEY_NAME: &str = "$top";
10const OBJECTS_KEY_NAME: &str = "$objects";
11const VERSION_KEY_NAME: &str = "$version";
12const NULL_OBJECT_REFERENCE_NAME: &str = "$null";
13
14pub fn encode(value: Value) -> Result<Value, ConverterError> {
18 let mut objects = vec![Value::String(NULL_OBJECT_REFERENCE_NAME.to_string())];
20
21 let mut root_dict = Dictionary::new();
23
24 root_dict.insert(
26 ARCHIVER_KEY_NAME.to_string(),
27 Value::String(ARCHIVER.to_string()),
28 );
29 root_dict.insert(
30 VERSION_KEY_NAME.to_string(),
31 Value::Integer(ARCHIVER_VERSION.into()),
32 );
33
34 let mut top_dict = Dictionary::new();
36 let uid = encode_object(value, &mut objects)?;
37 top_dict.insert("root".to_string(), Value::Uid(uid));
38
39 root_dict.insert(TOP_KEY_NAME.to_string(), Value::Dictionary(top_dict));
41 root_dict.insert(OBJECTS_KEY_NAME.to_string(), Value::Array(objects));
42
43 Ok(Value::Dictionary(root_dict))
44}
45
46fn encode_object(value: Value, objects: &mut Vec<Value>) -> Result<Uid, ConverterError> {
48 match value {
49 Value::Dictionary(dict) => encode_dictionary(dict, objects),
50 Value::Array(array) => encode_array(array, objects),
51 Value::Boolean(b) => {
52 objects.push(Value::Boolean(b));
54 Ok(Uid::new(objects.len() as u64 - 1))
55 }
56 Value::Real(r) => {
57 objects.push(Value::Real(r));
58 Ok(Uid::new(objects.len() as u64 - 1))
59 }
60 Value::Integer(i) => {
61 objects.push(Value::Integer(i));
62 Ok(Uid::new(objects.len() as u64 - 1))
63 }
64 Value::String(s) => {
65 if s == NULL_OBJECT_REFERENCE_NAME {
66 return Ok(Uid::new(0)); }
68 objects.push(Value::String(s));
69 Ok(Uid::new(objects.len() as u64 - 1))
70 }
71 Value::Date(d) => {
72 objects.push(Value::Date(d));
73 Ok(Uid::new(objects.len() as u64 - 1))
74 }
75 Value::Data(d) => {
76 objects.push(Value::Data(d));
77 Ok(Uid::new(objects.len() as u64 - 1))
78 }
79 Value::Uid(_) => {
80 Err(ConverterError::InvalidObjectEncoding(0))
82 }
83 _ => unimplemented!(),
84 }
85}
86
87fn encode_dictionary(dict: Dictionary, objects: &mut Vec<Value>) -> Result<Uid, ConverterError> {
89 let mut key_uids = Vec::new();
91 let mut value_uids = Vec::new();
92
93 for (key, value) in dict {
95 let key_uid = encode_object(Value::String(key), objects)?;
97 key_uids.push(Value::Uid(key_uid));
98
99 let value_uid = encode_object(value, objects)?;
101 value_uids.push(Value::Uid(value_uid));
102 }
103
104 let class_uid = create_class_reference("NSDictionary", objects)?;
106
107 let mut dict_structure = Dictionary::new();
109 dict_structure.insert("$class".to_string(), Value::Uid(class_uid));
110 dict_structure.insert("NS.keys".to_string(), Value::Array(key_uids));
111 dict_structure.insert("NS.objects".to_string(), Value::Array(value_uids));
112
113 objects.push(Value::Dictionary(dict_structure));
115 Ok(Uid::new(objects.len() as u64 - 1))
116}
117
118fn encode_array(array: Vec<Value>, objects: &mut Vec<Value>) -> Result<Uid, ConverterError> {
120 let mut object_uids = Vec::new();
122
123 for item in array {
124 let item_uid = encode_object(item, objects)?;
125 object_uids.push(Value::Uid(item_uid));
126 }
127
128 let class_uid = create_class_reference("NSArray", objects)?;
130
131 let mut array_structure = Dictionary::new();
133 array_structure.insert("$class".to_string(), Value::Uid(class_uid));
134 array_structure.insert("NS.objects".to_string(), Value::Array(object_uids));
135
136 objects.push(Value::Dictionary(array_structure));
138 Ok(Uid::new(objects.len() as u64 - 1))
139}
140
141fn create_class_reference(
143 class_name: &str,
144 objects: &mut Vec<Value>,
145) -> Result<Uid, ConverterError> {
146 for (i, obj) in objects.iter().enumerate() {
148 if let Some(dict) = obj.as_dictionary()
149 && let Some(classes) = dict.get("$classes").and_then(|c| c.as_array())
150 && let Some(name) = classes.first().and_then(|n| n.as_string())
151 && name == class_name
152 {
153 return Ok(Uid::new(i as u64));
154 }
155 }
156
157 let mut class_dict = Dictionary::new();
159 class_dict.insert(
160 "$classes".to_string(),
161 Value::Array(vec![Value::String(class_name.to_string())]),
162 );
163 class_dict.insert(
164 "$classname".to_string(),
165 Value::String(class_name.to_string()),
166 );
167
168 objects.push(Value::Dictionary(class_dict));
170 Ok(Uid::new(objects.len() as u64 - 1))
171}
172
173pub fn encode_to_file<P: AsRef<std::path::Path>>(
175 value: Value,
176 path: P,
177) -> Result<(), ConverterError> {
178 let encoded = encode(value)?;
179 encoded.to_file_binary(path)?;
180 Ok(())
181}
182
183pub fn encode_to_bytes(value: Value) -> Result<Vec<u8>, ConverterError> {
185 let encoded = encode(value)?;
186
187 let buf = Vec::new();
188 let mut writer = std::io::BufWriter::new(buf);
189 plist::to_writer_binary(&mut writer, &encoded).unwrap();
190
191 Ok(writer.into_inner().unwrap())
192}
193
194pub fn encode_to_writer<W: std::io::Write>(value: Value, writer: W) -> Result<(), ConverterError> {
196 let encoded = encode(value)?;
197 plist::to_writer_binary(writer, &encoded)?;
198 Ok(())
199}