mobi/
lib.rs

1//! An implementation of [MOBI](https://wiki.mobileread.com/wiki/MOBI) format data parsing and manipulation, written in Rust.
2//!
3//! The code is available on [GitHub](https://github.com/vv9k/mobi-rs)
4//!
5//! License: [*MIT*](https://github.com/vv9k/mobi-rs/blob/master/license)
6//!
7//! ## Examples
8//! ### Access basic info
9//! ```no_run
10//! use mobi::{Mobi, MobiError};
11//! fn main() -> Result<(), MobiError> {
12//!     let book = vec![0, 0, 0];
13//!     // You can either create a Mobi struct from a slice
14//!     let m = Mobi::new(&book)?;
15//!     // Or from an instance of io::Read
16//!     let stdin = std::io::stdin();
17//!     let mut handle = stdin.lock();
18//!     let m = Mobi::from_read(&mut handle)?;
19//!     // Or from filesystem
20//!     let m = Mobi::from_path("/some/path/to/book.mobi")?;
21//!
22//!     // Access metadata
23//!     let title = m.title();
24//!     let author = m.author().unwrap_or_default();
25//!     let publisher = m.publisher().unwrap_or_default();
26//!     let desc = m.description().unwrap_or_default();
27//!     let isbn = m.isbn().unwrap_or_default();
28//!     let pub_date = m.publish_date().unwrap_or_default();
29//!     let contributor = m.contributor().unwrap_or_default();
30//!
31//!     // Access Headers
32//!     let metadata = &m.metadata;
33//!     let header = &metadata.header; // Normal Header
34//!     let pdheader = &metadata.palmdoc; // PalmDOC Header
35//!     let mheader = &metadata.mobi; // MOBI Header
36//!     let exth = &metadata.exth; // Extra Header
37//!
38//!     // Access content
39//!     let content = m.content_as_string();
40//!
41//!     Ok(())
42//! }
43//! ```
44
45/// Module with headers from book containg more extracted data not
46/// available through public API.
47pub mod headers;
48pub mod record;
49pub use crate::headers::MobiMetadata;
50pub(crate) mod book;
51pub(crate) mod compression;
52pub(crate) mod reader;
53pub(crate) mod writer;
54
55use compression::huff;
56use headers::{Compression, Encryption, Language, MobiType, TextEncoding};
57pub(crate) use reader::Reader;
58use record::{RawRecord, RawRecords};
59pub(crate) use writer::Writer;
60
61#[cfg(feature = "time")]
62use chrono::NaiveDateTime;
63use std::{fs::File, io, io::BufReader, ops::Range, path::Path};
64use thiserror::Error;
65
66pub type MobiResult<T> = std::result::Result<T, MobiError>;
67
68#[derive(Debug, Error)]
69pub enum MobiError {
70    #[error(transparent)]
71    IoError(#[from] std::io::Error),
72    #[error(transparent)]
73    MetadataParseError(#[from] headers::MetadataParseError),
74    #[error(transparent)]
75    DecodeError(#[from] record::DecodeError),
76    #[error(transparent)]
77    HuffmanError(#[from] huff::HuffmanError),
78}
79
80#[derive(Debug, Default)]
81/// Structure that holds parsed ebook information and contents
82pub struct Mobi {
83    pub content: Vec<u8>,
84    pub metadata: MobiMetadata,
85}
86
87impl Mobi {
88    /// Construct a Mobi object from a slice of bytes
89    pub fn new<B: AsRef<Vec<u8>>>(bytes: B) -> MobiResult<Mobi> {
90        Mobi::from_reader(&mut Reader::new(std::io::Cursor::new(bytes.as_ref())))
91    }
92
93    /// Construct a Mobi object from passed file path
94    pub fn from_path<P: AsRef<Path>>(file_path: P) -> MobiResult<Mobi> {
95        let mut reader = Reader::new(BufReader::new(File::open(file_path)?));
96        Mobi::from_reader(&mut reader)
97    }
98
99    /// Construct a Mobi object from an object that implements a Read trait
100    pub fn from_read<R: io::Read>(reader: R) -> MobiResult<Mobi> {
101        Mobi::from_reader(&mut Reader::new(reader))
102    }
103
104    fn from_reader<R: io::Read>(reader: &mut Reader<R>) -> MobiResult<Mobi> {
105        let metadata = MobiMetadata::from_reader(reader)?;
106        Ok(Mobi {
107            content: {
108                let mut buf = vec![0; reader.position()];
109                reader.read_to_end(&mut buf)?;
110                buf
111            },
112            metadata,
113        })
114    }
115
116    #[allow(dead_code)]
117    fn write(&self, writer: &mut impl io::Write) -> io::Result<()> {
118        let mut w = Writer::new(writer);
119
120        self.metadata.write_into(&mut w)?;
121
122        let first_offset = self.metadata.records.records[1].offset as usize;
123        let fill = first_offset - w.bytes_written();
124        w.write_be(vec![0; fill])?;
125        // TODO: Consider record compression and everything else.
126        w.write_be(&self.content[first_offset..])
127    }
128
129    /// Returns an author of this book
130    pub fn author(&self) -> Option<String> {
131        self.metadata.author()
132    }
133
134    /// Returns this books publisher
135    pub fn publisher(&self) -> Option<String> {
136        self.metadata.publisher()
137    }
138
139    /// Returns description record if such exists
140    pub fn description(&self) -> Option<String> {
141        self.metadata.description()
142    }
143
144    /// Returns isbn record if such exists
145    pub fn isbn(&self) -> Option<String> {
146        self.metadata.isbn()
147    }
148
149    /// Returns publish_date record if such exists
150    pub fn publish_date(&self) -> Option<String> {
151        self.metadata.publish_date()
152    }
153
154    /// Returns contributor record if such exists
155    pub fn contributor(&self) -> Option<String> {
156        self.metadata.contributor()
157    }
158
159    /// Returns title record if such exists
160    pub fn title(&self) -> String {
161        self.metadata.title()
162    }
163
164    /// Returns text encoding used in ebook
165    pub fn text_encoding(&self) -> TextEncoding {
166        self.metadata.text_encoding()
167    }
168
169    /// Returns type of this ebook
170    pub fn mobi_type(&self) -> MobiType {
171        self.metadata.mobi_type()
172    }
173
174    /// Returns language of the ebook
175    pub fn language(&self) -> Language {
176        self.metadata.language()
177    }
178
179    #[cfg(feature = "time")]
180    /// Returns creation datetime
181    /// This field is only available using `time` feature
182    pub fn created_datetime(&self) -> NaiveDateTime {
183        self.metadata.created_datetime()
184    }
185
186    #[cfg(feature = "time")]
187    /// Returns modification datetime
188    /// This field is only available using `time` feature
189    pub fn mod_datetime(&self) -> NaiveDateTime {
190        self.metadata.mod_datetime()
191    }
192
193    #[cfg(not(feature = "time"))]
194    /// Returns creation time as u32 timestamp
195    pub fn created_time(&self) -> u32 {
196        self.metadata.created_time()
197    }
198
199    #[cfg(not(feature = "time"))]
200    /// Returns last modification time as u32 timestamp
201    pub fn mod_time(&self) -> u32 {
202        self.metadata.mod_time()
203    }
204
205    /// Returns compression method used on this file
206    pub fn compression(&self) -> Compression {
207        self.metadata.compression()
208    }
209    /// Returns encryption method used on this file
210    pub fn encryption(&self) -> Encryption {
211        self.metadata.encryption()
212    }
213
214    /// Returns the readable reacord range - from first content record to first
215    /// non book index.
216    pub fn readable_records_range(&self) -> Range<usize> {
217        self.metadata.mobi.first_content_record as usize
218            ..self.metadata.mobi.first_non_book_index as usize
219    }
220
221    /// Returns raw records that contain compressed, encrypted and encoded content slices.
222    pub fn raw_records(&self) -> RawRecords {
223        self.metadata.records.parse(&self.content)
224    }
225
226    /// Returns all records classified as image records.
227    pub fn image_records(&self) -> Vec<RawRecord> {
228        self.raw_records()
229            .range(self.metadata.mobi.first_image_index as usize..)
230            .iter()
231            .copied()
232            .filter(|record| record.is_image_record())
233            .collect()
234    }
235
236    fn palmdoc_string_lossy(&self) -> String {
237        let encoding = self.text_encoding();
238        self.raw_records()
239            .range(self.readable_records_range())
240            .iter()
241            .map(|record| record.decompress_palmdoc().to_string_lossy(encoding))
242            .collect()
243    }
244
245    fn palmdoc_string(&self) -> MobiResult<String> {
246        let encoding = self.text_encoding();
247        let mut s = String::new();
248
249        for record in self.raw_records().range(self.readable_records_range()) {
250            let content = record.decompress_palmdoc().to_string(encoding)?;
251            s.push_str(&content);
252        }
253        Ok(s)
254    }
255
256    fn no_compression_string_lossy(&self) -> String {
257        let encoding = self.text_encoding();
258        self.raw_records()
259            .range(self.readable_records_range())
260            .iter()
261            .map(|r| record::content_to_string_lossy(r.content, encoding))
262            .collect()
263    }
264
265    fn no_compression_string(&self) -> MobiResult<String> {
266        let encoding = self.text_encoding();
267        let mut s = String::new();
268        for record in self.raw_records().range(self.readable_records_range()) {
269            let content = record::content_to_string(record.content, encoding)?;
270            s.push_str(&content);
271        }
272        Ok(s)
273    }
274
275    fn huff_data(&self) -> MobiResult<Vec<Vec<u8>>> {
276        let records = self.raw_records();
277        let huff_start = self.metadata.mobi.first_huff_record as usize;
278        let huff_count = self.metadata.mobi.huff_record_count as usize;
279        let huffs: Vec<_> = records
280            .range(huff_start..huff_start + huff_count)
281            .iter()
282            .map(|record| record.content)
283            .collect();
284
285        let sections: Vec<_> = records
286            .range(self.readable_records_range())
287            .iter()
288            .map(|record| record.content)
289            .collect();
290
291        Ok(huff::decompress(&huffs, &sections)?)
292    }
293
294    fn huff_string_lossy(&self) -> MobiResult<String> {
295        let encoding = self.text_encoding();
296        let mut s = String::new();
297        let data = self.huff_data()?;
298
299        for section in data {
300            let content = record::content_to_string_lossy(&section, encoding);
301            s.push_str(&content);
302        }
303        Ok(s)
304    }
305
306    fn huff_string(&self) -> MobiResult<String> {
307        let encoding = self.text_encoding();
308        let mut s = String::new();
309        let data = self.huff_data()?;
310
311        for section in data {
312            let content = record::content_to_string(&section, encoding)?;
313            s.push_str(&content);
314        }
315        Ok(s)
316    }
317
318    /// Returns all readable records content decompressed as a String.
319    /// There are only two supported encodings in mobi format (UTF8, WIN1252)
320    /// and both are losely converted by this function
321    pub fn content_as_string_lossy(&self) -> String {
322        match self.compression() {
323            Compression::No => self.no_compression_string_lossy(),
324            Compression::PalmDoc => self.palmdoc_string_lossy(),
325            Compression::Huff => self.huff_string_lossy().unwrap_or_default(),
326        }
327    }
328
329    /// Returns all readable records content decompressed as a String.
330    /// This function is a strict version returning error on first encountered
331    /// decoding error.
332    pub fn content_as_string(&self) -> MobiResult<String> {
333        match self.compression() {
334            Compression::No => self.no_compression_string(),
335            Compression::PalmDoc => self.palmdoc_string(),
336            Compression::Huff => self.huff_string(),
337        }
338    }
339}
340
341#[cfg(test)]
342mod test {
343    use super::*;
344    #[test]
345    fn test_no_records() {
346        let bytes = [
347            173, 21, 58, 173, 252, 173, 173, 173, 173, 173, 173, 173, 165, 173, 173, 173, 0, 0, 0,
348            255, 255, 255, 255, 255, 255, 255, 139, 0, 0, 0, 0, 0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0,
349            0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0,
350            0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
351            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
352            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
353            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
354            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
355            255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
356            0, 0, 0, 0, 0, 0, 0, 231, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 173, 0, 0, 0, 0,
357            0, 0, 0, 173, 173, 173, 33, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 0,
358            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
359            0, 0, 0, 0, 0, 70, 70, 70, 70, 70, 70, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
360            173, 162, 162, 162, 173, 173, 84, 255,
361        ];
362        assert!(Mobi::new(bytes.to_vec()).is_err());
363    }
364
365    #[test]
366    fn test_backwards_cursor_1() {
367        let bytes = [
368            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 173, 21, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
369            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
370            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
371            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
372            0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 236, 0, 0, 3, 0, 173, 173, 173,
373            173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 162, 162, 162, 173, 162,
374            255, 255, 255, 5, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0,
375            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 121, 121, 121, 121, 121, 121, 121,
376            121, 121, 121, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
377            244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 3, 0, 0, 0, 0, 0,
378            0, 0, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244,
379            244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 121, 121, 0, 193,
380            0, 0, 0, 0, 0, 65, 0, 0, 64, 0, 0, 0, 0, 0, 0, 10,
381        ];
382        assert!(Mobi::new(bytes.to_vec()).is_err());
383    }
384
385    #[test]
386    fn test_backwards_cursor_2() {
387        let bytes = [
388            0, 0, 0, 0, 0, 0, 0, 198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
389            0, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 3,
390            0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
391            0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 2, 0, 0, 0, 0, 0,
392            0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0,
393            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
394            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
395            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
396            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
397            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
398            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
399            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0,
400            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 2, 0, 0, 0, 0, 193, 2, 0, 0, 0,
401            0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
402        ];
403        assert!(Mobi::new(bytes.to_vec()).is_err());
404    }
405
406    #[test]
407    fn test_offset_mismatch() {
408        let bytes = [
409            0, 0, 0, 0, 0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0,
410            0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
411            0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
412            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
413            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0,
414            0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
415            0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
416            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 231, 0,
417            2, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
418            0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
419            255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 3, 0, 0,
420            0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
421            0, 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0, 65, 0, 0, 0, 62, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0,
422            0, 0, 0, 10,
423        ];
424        assert!(Mobi::new(bytes.to_vec()).is_err());
425    }
426
427    #[test]
428    fn test_offset_overflow() {
429        let bytes = [
430            0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255,
431            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
432            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
433            255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0,
434            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151, 0, 0, 0, 0, 0, 0, 0, 0, 0,
435            0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
436            255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
437            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255,
438            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 65, 0,
439            0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
440            0, 193, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
441            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
442            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
443            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
444            255, 255, 255, 255, 255, 255, 251, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
445            255, 255, 255, 255, 255, 255, 255, 255, 245, 255, 255, 255, 255, 255, 255, 255, 255,
446            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
447            255, 255, 255, 255, 255, 255, 255, 255, 255, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10,
448        ];
449        assert!(Mobi::new(bytes.to_vec()).is_err());
450    }
451
452    #[test]
453    fn test_small_record() {
454        let bytes = [
455            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
456            50, 3, 128, 0, 0, 0, 0, 0, 0, 0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 3, 0, 0,
457            0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
458            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 231, 0, 2, 0, 0, 0, 0, 0, 0,
459            0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 65, 65, 65, 65, 65, 65, 65,
460            65, 0, 0, 0, 0, 0, 0, 50, 3, 128, 0, 0, 0, 0, 0, 0, 0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0,
461            0, 0, 0, 50, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 65, 65, 65, 65, 65, 65, 65,
462            65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
463            65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
464            65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
465            65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 0,
466            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, 0, 0, 231, 0, 2, 0, 0, 0, 0,
467            193, 0, 0, 0, 254, 255, 0, 173, 173, 173, 173, 0, 0, 0, 0, 0, 0, 0, 173, 173, 173, 33,
468            173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 0, 0, 0, 0, 0, 0, 0, 48, 48, 48,
469            48, 48, 48, 48, 48, 48, 48, 49, 0, 10,
470        ];
471        assert!(Mobi::new(bytes.to_vec()).is_err());
472    }
473
474    #[test]
475    fn test_subtract_overflow() {
476        let bytes = [
477            211, 147, 90, 255, 64, 255, 211, 211, 211, 88, 84, 77, 79, 66, 73, 77, 79, 66, 73, 10,
478            1, 23, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 211, 10, 211, 61, 45, 84, 69, 88,
479            84, 77, 79, 66, 73, 10, 20, 0, 0, 0, 0, 0, 0, 0, 10, 211, 61, 45, 84, 69, 88, 84, 77,
480            79, 66, 73, 77, 79, 66, 73, 10, 1, 23, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255,
481            211, 10, 211, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
482            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
483            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
484            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
485            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 20, 0, 0, 248, 255,
486            255, 255, 23, 0, 0, 0, 0, 0, 0, 0, 211, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73, 79, 66,
487            73, 10, 1, 23, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 211, 10, 211, 61, 45, 84,
488            69, 88, 84, 77, 79, 66, 73, 10, 20, 0, 0, 77, 79, 66, 73, 211, 147, 90, 255, 64, 255,
489            211, 211, 9, 0, 0, 0, 0, 0, 0, 0, 211, 10, 211, 211, 10, 1, 255, 0, 188, 255, 211, 1,
490            23, 0, 0, 0, 0, 0, 0, 10, 20, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
491            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
492            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
493            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
494            255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 10, 211, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73,
495            77, 79, 66, 73, 10, 1, 23, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 211, 0, 255,
496            255, 255, 255, 255, 211, 10, 211, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73, 10, 20, 0, 0,
497            248, 255, 255, 255, 211, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73, 77, 79, 66, 73, 10, 1,
498            255, 0, 188, 255, 211, 10, 211, 61, 45, 84, 69, 10, 211, 61, 45, 84, 69, 79, 75,
499        ];
500        assert!(Mobi::new(bytes.to_vec()).is_err());
501    }
502
503    #[test]
504    fn test_read_out_of_bounds() {
505        let bytes = [
506            211, 147, 90, 255, 64, 255, 211, 211, 211, 10, 211, 211, 211, 255, 255, 255, 255, 255,
507            211, 10, 211, 61, 45, 84, 69, 88, 84, 1, 0, 0, 0, 188, 128, 255, 42, 0, 211, 207, 147,
508            90, 255, 64, 255, 211, 211, 211, 10, 211, 211, 108, 255, 255, 255, 255, 255, 211, 10,
509            211, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73, 77, 79, 66, 73, 10, 1, 23, 0, 0, 0, 0, 0,
510            0, 0, 255, 255, 0, 0, 0, 159, 10, 211, 61, 211, 255, 69, 88, 84, 77, 79, 66, 73, 0, 0,
511            0, 232, 10, 20, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 211, 147, 90, 255,
512            64, 255, 211, 211, 211, 88, 84, 77, 79, 66, 73, 77, 79, 66, 73, 10, 1, 23, 0, 0, 0, 0,
513            0, 0, 0, 255, 255, 255, 255, 255, 211, 10, 211, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73,
514            10, 20, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
515            255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 66, 73, 10, 1, 255, 0,
516            211, 1, 23, 84, 69, 88, 84, 0, 0, 0, 0, 0, 0, 10, 20, 0, 255, 255, 255, 255, 255, 255,
517            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
518            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
519            255, 255, 255, 35, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
520            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
521            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 255, 0,
522            0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
523            255, 255, 255, 255, 255, 255, 255, 248, 255, 255, 255, 211, 61, 45, 84, 69, 88, 84, 77,
524            1, 0, 0, 0, 0, 0, 0, 1, 79, 66, 73, 77, 79, 66, 255, 255, 255, 255, 211, 0, 255, 255,
525            255, 255, 0, 188, 73, 10, 1, 255, 0, 188, 255, 211, 1, 23, 0, 0, 0, 0, 0, 0, 0, 255,
526            255, 255, 255, 255, 211, 10, 211, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73, 10, 20, 0, 0,
527            248, 255, 255, 255, 211, 61, 255, 211, 10, 211, 61, 45, 84, 69, 10, 211, 45, 84, 69,
528            88, 84, 77, 79, 66, 73, 77, 79, 66, 61, 45, 84, 73, 10, 1, 255, 0, 188, 255, 211, 10,
529            69, 211, 61, 45, 84, 69, 10, 211, 61, 45, 84, 69, 79, 79, 75, 75,
530        ];
531        assert!(Mobi::new(bytes.to_vec()).is_err());
532    }
533
534    #[test]
535    fn test_overflowing_record() {
536        let bytes = [
537            211, 147, 90, 255, 64, 255, 211, 211, 211, 88, 84, 77, 79, 66, 73, 77, 79, 66, 2, 0, 0,
538            0, 73, 10, 1, 23, 0, 0, 0, 0, 0, 0, 77, 79, 66, 2, 0, 0, 0, 73, 10, 1, 23, 0, 0, 0,
539            255, 255, 255, 22, 255, 255, 255, 255, 255, 211, 10, 211, 61, 45, 84, 69, 88, 84, 77,
540            79, 66, 73, 10, 20, 0, 0, 0, 0, 0, 0, 0, 10, 211, 61, 45, 84, 69, 88, 93, 77, 79, 66,
541            73, 77, 79, 66, 73, 10, 1, 23, 0, 11, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 211, 10, 211,
542            61, 45, 255, 211, 10, 211, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73, 10, 20, 0, 0, 0, 0,
543            0, 0, 0, 10, 211, 61, 45, 84, 69, 88, 84, 93, 79, 66, 73, 77, 79, 66, 73, 84, 77, 79,
544            66, 2, 0, 0, 0, 73, 10, 1, 0, 10, 20, 0, 255, 255, 255, 255, 45, 84, 69, 88, 84, 77,
545            79, 66, 73, 0, 0, 0, 255, 255, 255, 22, 255, 255, 255, 255, 255, 211, 10, 211, 61, 45,
546            84, 69, 88, 84, 77, 79, 66, 73, 10, 20, 0, 0, 0, 0, 0, 0, 0, 10, 211, 61, 45, 84, 69,
547            88, 93, 77, 79, 66, 73, 77, 79, 66, 73, 10, 1, 23, 0, 11, 0, 0, 0, 0, 0, 0, 0, 255,
548            255, 211, 61, 45, 255, 211, 10, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
549            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
550            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
551            0, 0, 0, 0, 0, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73, 10, 20, 0, 0, 0, 0, 0, 0, 0, 10,
552            211, 61, 45, 84, 69, 88, 84, 93, 79, 66, 73, 77, 79, 66, 73, 84, 77, 79, 66, 2, 0, 0,
553            0, 73, 10, 1, 0, 10, 20, 0, 255, 255, 255, 255, 45, 84, 69, 88, 84, 77, 79, 66, 73,
554            179, 176, 189, 182, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
555            255, 75, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
556            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
557            255, 255, 255, 255, 255, 255, 255, 255, 10, 1, 255, 0, 230, 230, 230, 230, 230, 230,
558            230, 0, 0, 255, 255, 255, 255, 255, 211, 10, 211, 61, 45, 255, 211, 10, 211, 0, 0, 0,
559            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
560            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0,
561            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61, 45, 84, 69, 88, 84, 77,
562            79, 66, 73, 10, 20, 0, 0, 0, 0, 0, 0, 0, 10, 211, 61, 45, 84, 69, 88, 84, 93, 79, 66,
563            73, 77, 79, 66, 73, 84, 77, 79, 66, 2, 0, 0, 0, 73, 10, 1, 0, 10, 20, 0, 255, 255, 255,
564            255, 45, 84, 69, 88, 84, 77, 79, 66, 73, 179, 176, 189, 182, 255, 255, 255, 255, 255,
565            255, 255, 255, 255, 255, 255, 255, 255, 255, 75, 255, 255, 255, 255, 255, 255, 255,
566            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
567            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 179, 176, 189, 182, 255, 255,
568            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
569            255, 255, 79, 66, 0, 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
570            0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
571            230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
572            230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
573            230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 240, 230, 230, 230, 230,
574            230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
575            230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 255, 255, 255, 255, 255, 211,
576            10, 211, 61, 45, 255, 211, 10, 211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
577            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
578            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
579            0, 0, 0, 0, 0, 61, 45, 84, 69, 88, 84, 77, 79, 66, 73, 10, 20, 0, 0, 0, 0, 0, 0, 0, 10,
580            211, 61, 45, 84, 69, 88, 84, 93, 79, 66, 73, 77, 79, 66, 73, 84, 77, 79, 66, 2, 0, 0,
581            0, 73, 10, 1, 0, 10, 20, 0, 255, 255, 255, 255, 45, 84, 69, 88, 84, 77, 79, 66, 73,
582            179, 176, 189, 182, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
583            255, 75, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
584            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
585            255, 255, 255, 255, 255, 255, 255, 255, 10, 1, 255, 0, 188, 255, 61, 45, 84, 69, 0, 0,
586            0, 0, 0, 0, 0, 0, 0, 39, 0, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
587            230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 79, 75,
588        ];
589        assert!(Mobi::new(bytes.to_vec()).is_err());
590    }
591
592    #[test]
593    fn test_set_position_oom() {
594        let bytes = [
595            242, 242, 242, 242, 242, 242, 84, 80, 90, 55, 242, 242, 242, 242, 242, 242, 242, 242,
596            242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 130, 62, 178, 126, 126, 126, 126,
597            130, 9, 68, 82, 77, 73, 79, 78, 238, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126,
598            126, 126, 126, 126, 126, 126, 84, 69, 88, 84, 82, 69, 65, 68, 126, 126, 126, 126, 242,
599            136, 126, 1, 0, 8, 242, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
600            15, 15, 15, 15, 15, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 84, 69,
601            255, 255, 255, 255, 9, 0, 0, 0, 0, 0, 0, 0, 255, 126, 126, 126, 126, 126, 126, 126,
602            126, 242, 0, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 84, 69, 88, 84, 82, 69,
603            65, 68, 82, 175, 130, 129, 129, 77, 79, 66, 73, 0, 0, 0, 232, 122, 126, 255, 255, 255,
604            255, 255, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
605            15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
606            15, 15, 1, 69, 88, 84, 15, 15, 15, 15, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
607            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
608            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
609            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
610            0, 0, 0, 0, 0, 0, 0, 0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
611            15, 15, 15, 15, 15, 15, 15, 15, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
612            255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
613            255, 255, 255, 48, 126, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
614            163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
615            163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 247,
616            247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247,
617            84, 69, 255, 255, 255, 255, 255, 255, 40, 255, 255, 255, 255, 255, 255, 126, 126, 126,
618            126, 126, 93, 92, 92, 92, 92, 92, 92, 92, 163, 163, 163, 163, 163, 212, 163, 163, 163,
619            163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
620            163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
621        ];
622        assert!(Mobi::new(bytes.to_vec()).is_err());
623    }
624
625    #[test]
626    fn test_records_ascending() {
627        let bytes = [
628            242, 242, 242, 242, 242, 242, 84, 80, 90, 51, 242, 242, 242, 242, 242, 242, 242, 242,
629            242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 130, 62, 178, 126, 126, 126, 126,
630            130, 9, 68, 82, 77, 73, 79, 248, 2, 0, 0, 0, 0, 0, 0, 126, 126, 126, 126, 126, 126,
631            126, 126, 126, 126, 84, 69, 88, 84, 82, 69, 65, 68, 126, 126, 250, 126, 242, 136, 126,
632            1, 0, 8, 0, 0, 0, 0, 0, 0, 0, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247,
633            247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 84, 69,
634            255, 255, 255, 255, 255, 255, 255, 255, 127, 255, 255, 255, 255, 126, 126, 126, 126,
635            126, 126, 126, 126, 242, 0, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 84, 69,
636            88, 84, 82, 69, 65, 68, 82, 175, 130, 129, 129, 77, 79, 66, 73, 0, 0, 0, 232, 122, 0,
637            0, 4, 228, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
638            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 0, 0,
639            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
640            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
641            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
642            96, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
643            255, 255, 255, 255, 255, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 146, 3,
644            3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
645            3, 3, 3, 3, 3, 3, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163,
646        ];
647        assert!(Mobi::new(bytes.to_vec()).is_err());
648    }
649
650    #[test]
651    fn test_backwards_name_offset() {
652        let bytes = [
653            242, 242, 242, 242, 242, 242, 84, 80, 90, 51, 242, 242, 242, 242, 242, 242, 242, 242,
654            242, 242, 242, 242, 242, 250, 242, 118, 178, 242, 242, 242, 62, 131, 126, 126, 126,
655            130, 15, 68, 82, 77, 73, 79, 76, 238, 126, 126, 126, 126, 126, 126, 126, 103, 126, 126,
656            126, 126, 126, 126, 126, 126, 84, 69, 88, 84, 77, 79, 66, 73, 126, 147, 126, 127, 242,
657            136, 41, 126, 0, 1, 0, 0, 0, 0, 0, 0, 4, 126, 84, 69, 88, 84, 82, 242, 242, 84, 80, 90,
658            51, 242, 242, 242, 242, 242, 129, 129, 77, 79, 66, 73, 0, 0, 0, 242, 242, 242, 242,
659            127, 126, 126, 58, 242, 242, 84, 80, 90, 50, 242, 242, 242, 242, 242, 242, 242, 242,
660            242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 130, 62, 178, 126, 126, 126, 126,
661            130, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
662            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
663            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
664            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 68, 82, 77, 73, 79,
665            78, 238, 126, 126, 126, 126, 126, 126, 126, 127, 126, 126, 126, 126, 242, 242, 242,
666            242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
667            242, 242, 242, 242, 242, 242, 242, 242, 178, 130, 126, 126, 126, 126, 126, 126, 126,
668            126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 242, 126, 126,
669            126, 126, 126, 126, 126, 126, 84, 69, 88, 84, 82, 69, 65, 68, 82, 126, 126, 126, 242,
670            242, 242, 84, 80, 90, 50, 242, 242, 242, 242, 130, 62, 178, 126, 126, 126, 126, 130,
671            15, 68, 82, 77, 73, 79, 78, 238, 126, 109, 109, 109, 133, 133, 122, 126, 48, 234, 68,
672            82, 77, 73, 79, 78, 238, 65, 68, 126, 126, 126, 126, 242, 136, 126, 1, 0, 1, 0, 242, 0,
673            126, 126, 126, 126, 126, 126, 88, 88, 88, 88, 88, 88, 88, 88, 48, 88, 88, 88, 88, 88,
674            88, 40, 39, 73, 68, 82, 175, 41, 130, 129, 129, 77, 79, 66, 73, 122, 126, 48, 126, 163,
675            163, 44, 163, 163, 163, 163, 163, 40, 39, 40, 172,
676        ];
677        assert!(Mobi::new(bytes.to_vec()).is_err());
678    }
679}