1use rpdfium_core::cfx_bitstream::BitReader;
16
17#[derive(Debug, Clone, Default)]
19pub struct PageHintEntry {
20 pub objects_delta: u32,
22 pub length_delta: u32,
24 pub shared_objects_count: u32,
26}
27
28#[derive(Debug, Clone)]
30pub struct PageOffsetHintTable {
31 pub min_objects: u32,
33 pub first_page_offset: u64,
35 pub min_page_length: u32,
37 pub bits_objects_delta: u8,
39 pub bits_length_delta: u8,
41 pub entries: Vec<PageHintEntry>,
43}
44
45#[derive(Debug, Clone, Default)]
47pub struct SharedHintEntry {
48 pub length: u32,
50}
51
52#[derive(Debug, Clone)]
54pub struct SharedObjectHintTable {
55 pub first_object: u32,
57 pub first_offset: u64,
59 pub count: u32,
61 pub entries: Vec<SharedHintEntry>,
63}
64
65#[derive(Debug, Clone)]
67pub struct HintTables {
68 pub page_offset: PageOffsetHintTable,
70 pub shared_objects: Option<SharedObjectHintTable>,
72}
73
74impl HintTables {
75 pub fn parse(data: &[u8], page_count: u32) -> Option<Self> {
81 if data.is_empty() || page_count == 0 {
82 return None;
83 }
84
85 let mut reader = BitReader::new(data);
86
87 let min_objects = reader.read_u32()?;
90 let first_page_offset_low = reader.read_u32()?;
92 let bits_objects_delta = reader.read_u16()? as u8;
94 let min_page_length = reader.read_u32()?;
96 let bits_length_delta = reader.read_u16()? as u8;
98 let _min_content_offset = reader.read_u32()?;
100 let _bits_content_offset_delta = reader.read_u16()?;
102 let _min_content_length = reader.read_u32()?;
104 let _bits_content_length_delta = reader.read_u16()?;
106 let bits_shared_count = reader.read_u16()? as u8;
108 let _bits_shared_id = reader.read_u16()?;
110 let _bits_numerator = reader.read_u16()?;
112 let _denominator = reader.read_u16()?;
114
115 if bits_objects_delta > 32 || bits_length_delta > 32 || bits_shared_count > 32 {
117 return None;
118 }
119
120 let n = page_count as usize;
122 let mut entries = Vec::with_capacity(n);
123
124 let mut objects_deltas = Vec::with_capacity(n);
126 for _ in 0..n {
127 objects_deltas.push(reader.read_bits(bits_objects_delta)?);
128 }
129
130 let mut length_deltas = Vec::with_capacity(n);
132 for _ in 0..n {
133 length_deltas.push(reader.read_bits(bits_length_delta)?);
134 }
135
136 let mut shared_counts = Vec::with_capacity(n);
138 for _ in 0..n {
139 shared_counts.push(reader.read_bits(bits_shared_count)?);
140 }
141
142 for i in 0..n {
144 entries.push(PageHintEntry {
145 objects_delta: objects_deltas[i],
146 length_delta: length_deltas[i],
147 shared_objects_count: shared_counts[i],
148 });
149 }
150
151 let page_offset = PageOffsetHintTable {
152 min_objects,
153 first_page_offset: u64::from(first_page_offset_low),
154 min_page_length,
155 bits_objects_delta,
156 bits_length_delta,
157 entries,
158 };
159
160 reader.byte_align();
162
163 let shared_objects = Self::parse_shared_objects(&mut reader);
165
166 Some(HintTables {
167 page_offset,
168 shared_objects,
169 })
170 }
171
172 fn parse_shared_objects(reader: &mut BitReader<'_>) -> Option<SharedObjectHintTable> {
174 if reader.bits_remaining() < 32 * 3 + 16 {
176 return None;
177 }
178
179 let first_object = reader.read_u32()?;
181 let first_offset_low = reader.read_u32()?;
183 let count = reader.read_u32()?;
185 let bits_length = reader.read_u16()? as u8;
187
188 if bits_length > 32 {
189 return None;
190 }
191
192 if count > rpdfium_core::fx_system::MAX_OBJECT_NUMBER {
194 return None;
195 }
196
197 let mut entries = Vec::with_capacity(count as usize);
198 for _ in 0..count {
199 let length = reader.read_bits(bits_length)?;
200 entries.push(SharedHintEntry { length });
201 }
202
203 Some(SharedObjectHintTable {
204 first_object,
205 first_offset: u64::from(first_offset_low),
206 count,
207 entries,
208 })
209 }
210
211 pub fn page_byte_range(&self, page: usize) -> Option<(u64, u32)> {
215 let entry = self.page_offset.entries.get(page)?;
216 let page_length = self.page_offset.min_page_length + entry.length_delta;
217
218 let mut offset = self.page_offset.first_page_offset;
220 for i in 0..page {
221 let prev = &self.page_offset.entries[i];
222 offset += u64::from(self.page_offset.min_page_length + prev.length_delta);
223 }
224
225 Some((offset, page_length))
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use super::*;
232
233 #[test]
234 fn test_hint_tables_parse_with_constructed_data() {
235 let mut bits = Vec::new();
237
238 push_u32(&mut bits, 3);
241 push_u32(&mut bits, 1000);
243 push_u16(&mut bits, 2);
245 push_u32(&mut bits, 500);
247 push_u16(&mut bits, 4);
249 push_u32(&mut bits, 100);
251 push_u16(&mut bits, 0);
253 push_u32(&mut bits, 200);
255 push_u16(&mut bits, 0);
257 push_u16(&mut bits, 1);
259 push_u16(&mut bits, 0);
261 push_u16(&mut bits, 0);
263 push_u16(&mut bits, 1);
265
266 push_bits(&mut bits, 1, 2); push_bits(&mut bits, 2, 2); push_bits(&mut bits, 5, 4); push_bits(&mut bits, 10, 4); push_bits(&mut bits, 0, 1); push_bits(&mut bits, 1, 1); let data = bits_to_bytes(&bits);
280 let tables = HintTables::parse(&data, 2).unwrap();
281
282 assert_eq!(tables.page_offset.min_objects, 3);
283 assert_eq!(tables.page_offset.first_page_offset, 1000);
284 assert_eq!(tables.page_offset.min_page_length, 500);
285 assert_eq!(tables.page_offset.bits_objects_delta, 2);
286 assert_eq!(tables.page_offset.bits_length_delta, 4);
287 assert_eq!(tables.page_offset.entries.len(), 2);
288
289 assert_eq!(tables.page_offset.entries[0].objects_delta, 1);
290 assert_eq!(tables.page_offset.entries[0].length_delta, 5);
291 assert_eq!(tables.page_offset.entries[0].shared_objects_count, 0);
292
293 assert_eq!(tables.page_offset.entries[1].objects_delta, 2);
294 assert_eq!(tables.page_offset.entries[1].length_delta, 10);
295 assert_eq!(tables.page_offset.entries[1].shared_objects_count, 1);
296 }
297
298 #[test]
299 fn test_page_byte_range_calculation() {
300 let tables = HintTables {
301 page_offset: PageOffsetHintTable {
302 min_objects: 3,
303 first_page_offset: 1000,
304 min_page_length: 500,
305 bits_objects_delta: 0,
306 bits_length_delta: 0,
307 entries: vec![
308 PageHintEntry {
309 objects_delta: 0,
310 length_delta: 100, shared_objects_count: 0,
312 },
313 PageHintEntry {
314 objects_delta: 0,
315 length_delta: 200, shared_objects_count: 0,
317 },
318 PageHintEntry {
319 objects_delta: 0,
320 length_delta: 0, shared_objects_count: 0,
322 },
323 ],
324 },
325 shared_objects: None,
326 };
327
328 let (offset, len) = tables.page_byte_range(0).unwrap();
330 assert_eq!(offset, 1000);
331 assert_eq!(len, 600);
332
333 let (offset, len) = tables.page_byte_range(1).unwrap();
335 assert_eq!(offset, 1600);
336 assert_eq!(len, 700);
337
338 let (offset, len) = tables.page_byte_range(2).unwrap();
340 assert_eq!(offset, 2300);
341 assert_eq!(len, 500);
342
343 assert!(tables.page_byte_range(3).is_none());
345 }
346
347 #[test]
348 fn test_empty_hint_stream_returns_none() {
349 assert!(HintTables::parse(&[], 1).is_none());
350 }
351
352 #[test]
353 fn test_zero_page_count_returns_none() {
354 let data = [0u8; 100];
355 assert!(HintTables::parse(&data, 0).is_none());
356 }
357
358 #[test]
359 fn test_truncated_hint_stream_returns_none() {
360 let data = [0u8; 10];
362 assert!(HintTables::parse(&data, 1).is_none());
363 }
364
365 fn push_u32(bits: &mut Vec<u8>, value: u32) {
370 for i in (0..32).rev() {
371 bits.push(((value >> i) & 1) as u8);
372 }
373 }
374
375 fn push_u16(bits: &mut Vec<u8>, value: u16) {
376 for i in (0..16).rev() {
377 bits.push(((value >> i) & 1) as u8);
378 }
379 }
380
381 fn push_bits(bits: &mut Vec<u8>, value: u32, count: u8) {
382 for i in (0..count).rev() {
383 bits.push(((value >> i) & 1) as u8);
384 }
385 }
386
387 fn bits_to_bytes(bits: &[u8]) -> Vec<u8> {
389 let mut bytes = Vec::new();
390 for chunk in bits.chunks(8) {
391 let mut byte = 0u8;
392 for (i, &bit) in chunk.iter().enumerate() {
393 byte |= bit << (7 - i);
394 }
395 bytes.push(byte);
396 }
397 bytes
398 }
399}