lopdf_bugfix_19072017/
processor.rs

1use std::collections::BTreeMap;
2use super::{Document, Object, ObjectId, StringFormat};
3
4impl Document {
5	/// Change producer of document information dictionary.
6	pub fn change_producer(&mut self, producer: &str) {
7		if let Some(info) = self.trailer.get_mut("Info") {
8			if let Some(dict) = match *info {
9				Object::Dictionary(ref mut dict) => Some(dict),
10				Object::Reference(ref id) => self.objects.get_mut(id).and_then(|obj|obj.as_dict_mut()),
11				_ => None,
12			} {
13				dict.set("Producer", Object::String(producer.as_bytes().to_vec(), StringFormat::Literal));
14			}
15		}
16	}
17
18	/// Compress PDF stream objects.
19	pub fn compress(&mut self) {
20		for (_, object) in self.objects.iter_mut() {
21			match *object {
22				Object::Stream(ref mut stream) => {
23                    if stream.allows_compression {
24                        stream.compress()
25                    }
26                },
27				_ => ()
28			}
29		}
30	}
31
32	/// Decompress PDF stream objects.
33	pub fn decompress(&mut self) {
34		for (_, object) in self.objects.iter_mut() {
35			match *object {
36				Object::Stream(ref mut stream) => stream.decompress(),
37				_ => ()
38			}
39		}
40	}
41
42	/// Delete pages.
43	pub fn delete_pages(&mut self, page_numbers: &[u32]) {
44		let pages = self.get_pages();
45		for page_number in page_numbers {
46			if let Some(page) = pages.get(&page_number).and_then(|page_id|self.delete_object(page_id)) {
47				let mut page_tree_ref = page.as_dict().and_then(|dict|dict.get("Parent")).and_then(|obj|obj.as_reference());
48				while let Some(page_tree_id) = page_tree_ref {
49					if let Some(page_tree) = self.objects.get_mut(&page_tree_id).and_then(|obj|obj.as_dict_mut()) {
50						page_tree.get("Count").and_then(|obj|obj.as_i64()).map(|count|{
51							page_tree.set("Count", count - 1);
52						});
53						page_tree_ref = page_tree.get("Parent").and_then(|obj|obj.as_reference());
54					} else {
55						break;
56					}
57				}
58			}
59		}
60	}
61
62	/// Prune all unused objects.
63	pub fn prune_objects(&mut self) -> Vec<ObjectId> {
64		let mut ids = vec![];
65		let refs = self.traverse_objects(|_|{});
66		for id in self.objects.keys().cloned().collect::<Vec<ObjectId>>() {
67			if !refs.contains(&id) {
68				self.objects.remove(&id);
69				ids.push(id);
70			}
71		}
72		ids
73	}
74
75	/// Delete object by object ID.
76	pub fn delete_object(&mut self, id: &ObjectId) -> Option<Object> {
77		let action = |object: &mut Object| {
78			match *object {
79				Object::Array(ref mut array) => {
80					if let Some(index) = array.iter().position(|item: &Object| {
81						match *item {
82							Object::Reference(ref_id) => ref_id == *id,
83							_ => false
84						}
85					}) {
86						array.remove(index);
87					}
88				},
89				Object::Dictionary(ref mut dict) => {
90					let keys: Vec<String> = dict.iter().filter(|&(_, item): &(&String, &Object)| {
91						match *item {
92							Object::Reference(ref_id) => ref_id == *id,
93							_ => false
94						}
95					}).map(|(k, _)| k.clone()).collect();
96					for key in keys {
97						dict.remove(key.as_str());
98					}
99				},
100				_ => {}
101			}
102		};
103		self.traverse_objects(action);
104		self.objects.remove(id)
105	}
106
107	/// Delete zero length stream objects.
108	pub fn delete_zero_length_streams(&mut self) -> Vec<ObjectId> {
109		let mut ids = vec![];
110		for id in self.objects.keys().cloned().collect::<Vec<ObjectId>>() {
111			if self.objects.get(&id).and_then(|obj|obj.as_stream()).map(|stream|stream.content.len()==0) == Some(true) {
112				self.delete_object(&id);
113				ids.push(id);
114			}
115		}
116		ids
117	}
118
119	/// Renumber objects, normally called after delete_unused_objects.
120	pub fn renumber_objects(&mut self) {
121		let mut replace = BTreeMap::new();
122		let mut new_id = 1;
123		let mut ids = self.objects.keys().cloned().collect::<Vec<ObjectId>>();
124		ids.sort();
125
126		for id in ids {
127			if id.0 != new_id {
128				replace.insert(id, (new_id, id.1));
129			}
130			new_id += 1;
131		}
132
133		// replace order is from small to big
134		for (old, new) in replace.iter() {
135			if let Some(object) = self.objects.remove(old) {
136				self.objects.insert(new.clone(), object);
137			}
138		}
139
140		let action = |object: &mut Object| {
141			match *object {
142				Object::Reference(ref mut id) => {
143					if replace.contains_key(&id) {
144						*id = replace.get(id).unwrap().clone();
145					}
146				},
147				_ => {}
148			}
149		};
150		
151		self.traverse_objects(action);
152		self.max_id = new_id - 1;
153	}
154}