1 use std;
2 use std::ffi::CStr;
3 use std::marker::PhantomData;
4 use std::os::raw::c_char;
5 use super::ChunkRef;
6 use crate::rustimpl;
7 
8 pub struct TextKeysCStrIter<'a> {
9     pub(crate) k: *mut *mut c_char,
10     pub(crate) v: *mut *mut c_char,
11     pub(crate) n: usize,
12     pub(crate) _p: PhantomData<&'a CStr>,
13 }
14 
15 impl<'a> Iterator for TextKeysCStrIter<'a> {
16     type Item = (&'a CStr, &'a CStr);
next(&mut self) -> Option<Self::Item>17     fn next(&mut self) -> Option<Self::Item> {
18         if self.n > 0 {
19             unsafe {
20                 debug_assert!(!(*self.k).is_null()); let k = CStr::from_ptr(*self.k);
21                 debug_assert!(!(*self.v).is_null()); let v = CStr::from_ptr(*self.v);
22                 self.n -= 1;
23                 self.k = self.k.offset(1);
24                 self.v = self.v.offset(1);
25                 Some((k, v))
26             }
27         } else {
28             None
29         }
30     }
31 }
32 
33 pub struct ITextKeysIter<'a> {
34     pub(crate) k: *mut *mut c_char,
35     pub(crate) l: *mut *mut c_char,
36     pub(crate) t: *mut *mut c_char,
37     pub(crate) s: *mut *mut c_char,
38     pub(crate) n: usize,
39     pub(crate) _p: PhantomData<&'a str>,
40 }
41 
42 /// Invalid encoding truncates the strings
43 impl<'a> Iterator for ITextKeysIter<'a> {
44     type Item = (&'a str, &'a str, &'a str, &'a str);
next(&mut self) -> Option<Self::Item>45     fn next(&mut self) -> Option<Self::Item> {
46         if self.n > 0 {
47             unsafe {
48                 debug_assert!(!(*self.k).is_null()); let k = CStr::from_ptr(*self.k);
49                 debug_assert!(!(*self.l).is_null()); let l = CStr::from_ptr(*self.l);
50                 debug_assert!(!(*self.t).is_null()); let t = CStr::from_ptr(*self.t);
51                 debug_assert!(!(*self.s).is_null()); let s = CStr::from_ptr(*self.s);
52                 self.n -= 1;
53                 self.k = self.k.offset(1);
54                 self.l = self.l.offset(1);
55                 self.t = self.t.offset(1);
56                 self.s = self.s.offset(1);
57                 Some((
58                     cstr_to_str(k),
59                     cstr_to_str(l),
60                     cstr_to_str(t),
61                     cstr_to_str(s)))
62             }
63         } else {
64             None
65         }
66     }
67 }
68 
cstr_to_str(s: &CStr) -> &str69 fn cstr_to_str(s: &CStr) -> &str {
70     match s.to_str() {
71         Ok(s) => s,
72         Err(e) => {
73             std::str::from_utf8(&s.to_bytes()[0..e.valid_up_to()]).unwrap()
74         }
75     }
76 }
77 
78 pub struct ChunksIter<'a> {
79     pub(crate) data: &'a [u8],
80 }
81 
82 impl<'a> Iterator for ChunksIter<'a> {
83     type Item = ChunkRef<'a>;
next(&mut self) -> Option<Self::Item>84     fn next(&mut self) -> Option<Self::Item> {
85         let header_len = 12;
86         if self.data.len() < header_len {
87             return None;
88         }
89 
90         let len = rustimpl::lodepng_chunk_length(self.data);
91         if self.data.len() < len + header_len {
92             return None;
93         }
94         let c = ChunkRef::new(&self.data[0..len + header_len]);
95         self.data = rustimpl::lodepng_chunk_next(self.data);
96         Some(c)
97     }
98 }
99