bin_file/
lib.rs

1#![warn(missing_docs)]
2
3//! # BinFile
4//!
5//! Mangling of various file formats that conveys binary information
6//! (Motorola S-Record, Intel HEX, TI-TXT and binary files).
7//!
8//! ## Supported Formats
9//! - [Intel Hex Format](https://en.wikipedia.org/wiki/Intel_HEX)
10//! - [SREC](https://en.wikipedia.org/wiki/SREC_(file_format))
11//! - [TI-TXT](https://software-dl.ti.com/codegen/docs/tiarmclang/compiler_tools_user_guide/compiler_manual/hex_utility_description/description-of-the-object-formats-stdz0792390.html)
12//! - [VERILOG VMEM](https://linux.die.net/man/5/srec_vmem)
13//! - [Extended Tektronix Object Format](https://en.wikipedia.org/wiki/Tektronix_hex_format)
14
15use ansic::ansi;
16pub use records::Record;
17#[cfg(feature = "serde")]
18use serde::{Deserialize, Serialize};
19use std::cmp::{max, min};
20use std::collections::BTreeMap;
21use std::fmt::Display;
22use std::fs::{metadata, File};
23use std::io::{BufRead, BufReader, Read, Write};
24use std::ops::{Add, AddAssign, Range, RangeBounds};
25use std::path::{Path, PathBuf};
26use std::str::FromStr;
27
28use bytesize::ByteSize;
29pub use error::Error;
30pub use records::ext_tek_hex::ExtTekHexRecord;
31pub use records::ihex::IHexRecord;
32pub use records::srec::SRecord;
33use records::srec::{Address16, Address24, Address32, Count16, Count24, Data};
34use regex::Captures;
35use regex::Regex;
36pub use segments::Segment;
37use segments::Segments;
38
39mod checksums;
40mod error;
41mod records;
42mod segments;
43
44const TI_TXT_BYTES_PER_LINE: usize = 16;
45const EXT_TEK_HEX_BYTES_PER_LINE: u8 = 16;
46const VERILOG_VMEM_BYTES_PER_LINE: usize = 16;
47
48const PRINTABLE: &str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+, -./:;<=>?@[\\]^_`{|}~ ";
49
50const R: &str = ansi!(reset);
51const YELLOW: &str = ansi!(yellow);
52const MAGENTA: &str = ansi!(magenta);
53
54#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, Default, PartialOrd, Ord)]
55/// Enum defining the Address Length of SRec
56/// Default value can be created with `SRecordAddressLength::default()`
57pub enum SRecordAddressLength {
58    /// 16-bit Address Length
59    Length16,
60    /// 24-bit Address Length
61    Length24,
62    /// 32-bit Address Length
63    #[default]
64    Length32,
65}
66
67impl Display for SRecordAddressLength {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        match self {
70            SRecordAddressLength::Length16 => write!(f, "16 Byte Length"),
71            SRecordAddressLength::Length24 => write!(f, "24 Byte Length"),
72            SRecordAddressLength::Length32 => write!(f, "32 Byte Length"),
73        }
74    }
75}
76
77#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, Default, PartialOrd, Ord)]
78/// Enum defining the intel hex format
79/// Default value can be created with `IHexFormat::default()`
80pub enum IHexFormat {
81    /// IHex8 Format
82    IHex8,
83    /// IHex16 Format
84    IHex16,
85    /// IHex32 Format
86    #[default]
87    IHex32,
88}
89
90impl Display for IHexFormat {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        match self {
93            IHexFormat::IHex8 => write!(f, "Intel Hex 8"),
94            IHexFormat::IHex16 => write!(f, "Intel Hex 16"),
95            IHexFormat::IHex32 => write!(f, "Intel Hex 32"),
96        }
97    }
98}
99
100/// Struct representing a binary file
101#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
102#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
103pub struct BinFile {
104    header: Option<Vec<u8>>,
105    execution_start_address: Option<usize>,
106    segments: Segments,
107    #[cfg_attr(feature = "serde", serde(skip_serializing))]
108    cursor: usize,
109}
110
111impl BinFile {
112    /// Creates a `BinFile` struct representing a binary file.
113    /// ```rust
114    /// use bin_file::BinFile;
115    ///
116    /// let binfile = BinFile::new();
117    /// ```
118    pub fn new() -> Self {
119        BinFile {
120            header: None,
121            execution_start_address: None,
122            segments: Segments::new(),
123            cursor: 0,
124        }
125    }
126
127    /// Creates a `BinFile` struct representing a binary file
128    /// from a given file. It tries to guess the correct file
129    /// format and reads it in.
130    ///
131    /// # Parameters
132    ///
133    /// - `file_name`: Reference to a [`Path`](std::path::Path)
134    ///
135    /// # Errors
136    ///
137    /// - `Error::UnsupportedFileFormat`: If file format can't
138    ///   be determined
139    pub fn from_file<P>(file_name: P) -> Result<Self, Error>
140    where
141        P: AsRef<Path>,
142    {
143        let mut binfile = BinFile {
144            header: None,
145            execution_start_address: None,
146            segments: Segments::new(),
147            cursor: 0,
148        };
149        binfile.add_file(file_name, false)?;
150        Ok(binfile)
151    }
152
153    /// Creates a `BinFile` struct representing a binary file
154    /// from multiple files. It tries to guess the currect file
155    /// format for each file and reads it in.
156    ///
157    /// # Parameters
158    ///
159    /// - `file_names` Array of file names
160    ///
161    /// # Errors
162    ///
163    /// - `Error::UnsupportedFileFormat`: If file format can't
164    ///   be determined
165    /// - `Error::AddDataError`: If datas overlap in files, but `overwrite` was not set
166    pub fn from_files<P, T>(file_names: P, overwrite: bool) -> Result<Self, Error>
167    where
168        P: AsRef<[T]>,
169        T: AsRef<Path>,
170    {
171        let mut binfile = BinFile::new();
172        for file_name in file_names.as_ref() {
173            binfile.add_file(file_name, overwrite)?;
174        }
175        Ok(binfile)
176    }
177
178    /// Returns the header string
179    pub fn header(&self) -> Option<&Vec<u8>> {
180        self.header.as_ref()
181    }
182
183    /// Sets the header string
184    ///
185    /// # Parameters
186    ///
187    /// - `header`: Header to be set
188    pub fn set_header_string<S>(&mut self, header: S)
189    where
190        S: Into<String>,
191    {
192        let str: String = header.into();
193        self.header = Some(str.into());
194    }
195
196    /// Returns the execution start address
197    pub fn execution_start_address(&self) -> Option<usize> {
198        self.execution_start_address
199    }
200
201    /// Sets the execution start address
202    ///
203    /// # Parameters
204    ///
205    /// - `address`: Start address to be set
206    pub fn set_exexution_start_address(&mut self, address: usize) {
207        self.execution_start_address = Some(address);
208    }
209
210    /// The segments object. Can be used to iterate over all segments in
211    /// the binary.
212    ///
213    /// Below is an example iterating over all segments, two in this
214    /// case, and printing them.
215    ///
216    /// ```
217    /// use bin_file::BinFile;
218    /// use std::error::Error;
219    ///
220    /// fn main() -> Result<(), Box<dyn Error>> {
221    ///     let mut binfile = BinFile::new();
222    ///
223    ///     binfile.add_bytes([0,1,2], Some(0), false)?;
224    ///     binfile.add_bytes([3,4,5], Some(10), false)?;
225    ///
226    ///     for segment in binfile.segments() {
227    ///         println!("{}", segment);
228    ///     }
229    ///     Ok(())
230    /// }
231    /// ```
232    ///
233    /// ```console
234    /// Segment(address=0, data=[0, 1, 2])
235    /// Segment(address=10, data=[3, 4, 5])
236    /// ```
237    ///
238    /// All segment can be split into smaller pieces using the
239    /// `chunks` function on segments.
240    ///
241    /// ```rust
242    /// use bin_file::BinFile;
243    /// use std::error::Error;
244    ///
245    /// fn main() -> Result<(), Box<dyn Error>> {
246    ///     let mut binfile = BinFile::new();
247    ///
248    ///     binfile.add_bytes([0,1,2], Some(0), false)?;
249    ///     binfile.add_bytes([3,4,5], Some(10), false)?;
250    ///
251    ///     for (address, data) in binfile.segments().chunks(Some(2), None)? {
252    ///         println!("Address: {} Data: {:?}", address, data);
253    ///     }
254    ///     Ok(())
255    /// }
256    /// ```
257    ///
258    /// ```console
259    /// Address: 0 Data: [0, 1]
260    /// Address: 2 Data: [2]
261    /// Address: 10 Data: [3, 4]
262    /// Address: 12 Data: [5]
263    /// ```
264    ///
265    /// Each segment can be split into smaller pieces using the
266    /// `chunks()` function on a single segment.
267    ///
268    /// ```rust
269    /// use bin_file::BinFile;
270    /// use std::error::Error;
271    ///
272    /// fn main() -> Result<(), Box<dyn Error>> {
273    ///     let mut binfile = BinFile::new();
274    ///
275    ///     binfile.add_bytes([0,1,2], Some(0), false)?;
276    ///     binfile.add_bytes([3,4,5], Some(10), false)?;
277    ///
278    ///     for segment in binfile.segments() {
279    ///         println!("{}", segment);
280    ///         for (address, data) in segment.chunks(Some(2), None)? {
281    ///             println!("Address: {} Data: {:?}", address, data);
282    ///         }
283    ///     }
284    ///     Ok(())
285    /// }
286    /// ```
287    ///
288    /// ```console
289    /// Segment(address=0, data=[0, 1, 2])
290    /// Address: 0 Data: [0, 1]
291    /// Address: 2 Data: [2]
292    /// Segment(address=10, data=[3, 4, 5])
293    /// Address: 10 Data: [3, 4]
294    /// Address: 12 Data: [5]
295    /// ```
296    pub fn segments(&self) -> &Segments {
297        &self.segments
298    }
299
300    /// Returns the list of Segments
301    pub fn segments_list(&self) -> Vec<(usize, Vec<u8>)> {
302        let mut list = Vec::new();
303        for segment in self.segments() {
304            let (address, data) = segment.get_tuple().to_owned();
305            list.push((address, data.to_vec()));
306        }
307        list
308    }
309
310    /// Returns the overall minimum address
311    pub fn minimum_address(&self) -> Option<usize> {
312        self.segments.get_minimum_address()
313    }
314
315    /// Returns the overall maximum address
316    pub fn maximum_address(&self) -> Option<usize> {
317        self.segments.get_maximum_address()
318    }
319
320    /// Retruns chunks for all datas.
321    /// See [`BinFile.segments()`](#method.segments) for examples.
322    ///
323    /// # Parameters
324    ///
325    /// - `size`: Size of a chunk
326    /// - `alignment`: Alignment of the chunk to minimum address
327    pub fn chunks(
328        &self,
329        size: Option<usize>,
330        alignment: Option<usize>,
331    ) -> Result<BTreeMap<usize, Vec<u8>>, Error> {
332        self.segments.chunks(size, alignment)
333    }
334
335    /// Returns the value at a particular address
336    /// and None if address is not present.
337    ///
338    /// # Parameters
339    ///
340    /// - `address`: Address which should be read out
341    pub fn get_value_by_address(&self, address: usize) -> Option<u8> {
342        self.segments.get_value_by_address(address)
343    }
344
345    /// Returns the values at a particular address range, range must be within a segment
346    /// Returns None if value is not present or range is not within one segment
347    ///
348    /// # Parameters
349    ///
350    /// - `address`: Address Range
351    ///
352    /// # Examples
353    ///
354    /// ```rust
355    /// use bin_file::BinFile;
356    ///
357    /// let mut binfile = BinFile::new();
358    /// // First add some values
359    /// assert!(binfile.add_bytes([0x01, 0x02, 0x03, 0x04], Some(1), false).is_ok());
360    /// assert!(binfile.add_bytes([0x01, 0x02, 0x03, 0x04], Some(11), false).is_ok());
361    ///
362    /// // Read out values
363    /// assert_eq!(binfile.get_values_by_address_range(3..5),Some(vec![0x03, 0x04]));
364    /// assert!(binfile.get_values_by_address_range(3..6).is_none());
365    /// assert!(binfile.get_values_by_address_range(0..3).is_none());
366    /// ```
367    pub fn get_values_by_address_range<R>(&self, address: R) -> Option<Vec<u8>>
368    where
369        R: RangeBounds<usize>,
370    {
371        self.segments.get_values_by_address_range(&address)
372    }
373
374    /// Add given data string array by guessing its format. The format must be
375    /// Motorola S-Records, Intel HEX or TI-TXT. Set `overwrite` to
376    /// `true` to allow already added data to be overwritten.
377    ///
378    /// # Parameters
379    ///
380    /// - `data`: String array of records to be read in
381    /// - `overwrite`: flag to activate overwrite mode
382    pub fn add_strings<T, S>(&mut self, data: T, overwrite: bool) -> Result<(), Error>
383    where
384        T: AsRef<[S]>,
385        S: AsRef<str>,
386    {
387        if let Some(first_line) = data.as_ref().first() {
388            let data = data.as_ref();
389            if SRecord::is_record_str_correct(first_line) {
390                self.add_srec(data, overwrite)
391            } else if IHexRecord::is_record_str_correct(first_line) {
392                self.add_ihex(data, overwrite)
393            } else if ExtTekHexRecord::is_record_str_correct(first_line) {
394                self.add_ext_tek_hex(data, overwrite)
395            } else if is_ti_txt(data) {
396                self.add_ti_txt(data, overwrite)
397            } else if is_verilog_vmem(data) {
398                self.add_verilog_vmem(data, overwrite)
399            } else {
400                Err(Error::UnsupportedFileFormat)
401            }
402        } else {
403            Ok(())
404        }
405    }
406
407    /// Add given Motorola S-Records string array. Set `overwrite` to `true` to
408    /// allow already added data to be overwritten.
409    /// See [`BinFile.to_srec()`](#method.to_srec) for examples.
410    ///
411    /// # Parameters
412    ///
413    /// - `data`: String array of records to be read in
414    /// - `overwrite`: flag to activate overwrite mode
415    ///
416    /// # Errors
417    ///
418    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
419    pub fn add_srec<T, S>(&mut self, records: T, overwrite: bool) -> Result<(), Error>
420    where
421        T: AsRef<[S]>,
422        S: AsRef<str>,
423    {
424        for record_str in records.as_ref() {
425            match SRecord::from_record_string(record_str) {
426                Ok(record) => match record {
427                    SRecord::Address16(address) => {
428                        self.execution_start_address = Some(address.0 as usize)
429                    }
430                    SRecord::Header(header) => self.header = Some(header),
431                    SRecord::Data16(data) => {
432                        let address = data.address.0 as usize;
433                        self.segments
434                            .add_segment(Segment::new(address, data.data), overwrite)?
435                    }
436                    SRecord::Data24(data) => {
437                        let address = data.address.0 as usize;
438                        self.segments
439                            .add_segment(Segment::new(address, data.data), overwrite)?
440                    }
441                    SRecord::Data32(data) => {
442                        let address = data.address.0 as usize;
443                        self.segments
444                            .add_segment(Segment::new(address, data.data), overwrite)?
445                    }
446                    SRecord::Count16(_) => (),
447                    SRecord::Count24(_) => (),
448                    SRecord::Address32(address) => {
449                        self.execution_start_address = Some(address.0 as usize)
450                    }
451                    SRecord::Address24(address) => {
452                        self.execution_start_address = Some(address.0 as usize)
453                    }
454                },
455                Err(err) => return Err(err),
456            }
457        }
458        Ok(())
459    }
460
461    /// Add given Intel HEX records string array. Set `overwrite` to `true` to
462    /// allow already added data to be overwritten.
463    /// See [`BinFile.to_ihex()`](#method.to_ihex) for examples.
464    ///
465    /// # Parameters
466    ///
467    /// - `data`: String array of records to be read in
468    /// - `overwrite`: flag to activate overwrite mode
469    ///
470    /// # Errors
471    ///
472    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
473    pub fn add_ihex<T, S>(&mut self, data: T, overwrite: bool) -> Result<(), Error>
474    where
475        T: AsRef<[S]>,
476        S: AsRef<str>,
477    {
478        let mut extended_segment_address = 0;
479        let mut extended_linear_address = 0;
480        for record_str in data.as_ref() {
481            match IHexRecord::from_record_string(record_str) {
482                Ok(record) => match record {
483                    IHexRecord::Data { offset, value } => {
484                        let address =
485                            offset as usize + extended_segment_address + extended_linear_address;
486                        self.segments
487                            .add_segment(Segment::new(address, value), overwrite)?;
488                    }
489                    IHexRecord::EndOfFile => break,
490                    IHexRecord::ExtendedSegmentAddress(address) => {
491                        extended_segment_address = address as usize * 16
492                    }
493                    IHexRecord::StartSegmentAddress(address) => {
494                        self.execution_start_address = Some(address as usize)
495                    }
496                    IHexRecord::ExtendedLinearAddress(address) => {
497                        extended_linear_address = (address as usize) << 16
498                    }
499                    IHexRecord::StartLinearAddress(address) => {
500                        self.execution_start_address = Some(address as usize)
501                    }
502                },
503                Err(err) => return Err(err),
504            }
505        }
506        Ok(())
507    }
508
509    /// Add given Extended Tektronix Hex records string array. Set `overwrite` to `true` to
510    /// allow already added data to be overwritten.
511    /// See [`BinFile.to_ext_tek_hex()`](#method.to_ext_tek_hex) for examples.
512    ///
513    /// # Parameters
514    ///
515    /// - `data`: String array of records to be read in
516    /// - `overwrite`: flag to activate overwrite mode
517    ///
518    /// # Errors
519    ///
520    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
521    pub fn add_ext_tek_hex<T, S>(&mut self, data: T, overwrite: bool) -> Result<(), Error>
522    where
523        T: AsRef<[S]>,
524        S: AsRef<str>,
525    {
526        for record_str in data.as_ref() {
527            match ExtTekHexRecord::from_record_string(record_str)? {
528                ExtTekHexRecord::Data { address, value } => {
529                    self.segments
530                        .add_segment(Segment::new(address, value), overwrite)?;
531                }
532                ExtTekHexRecord::Termination { start_address } => {
533                    self.execution_start_address = Some(start_address);
534                    break;
535                }
536                ExtTekHexRecord::Symbol(_) => (),
537            }
538        }
539        Ok(())
540    }
541
542    /// Add given TI-TXT string `lines` as array. Set `overwrite` to `true` to
543    /// allow already added data to be overwritten.
544    /// See [`BinFile.to_ti_tex()`](#method.to_ti_tex) for examples.
545    ///
546    /// # Parameters
547    ///
548    /// - `data`: String array of records to be read in
549    /// - `overwrite`: flag to activate overwrite mode
550    ///
551    /// # Errors
552    ///
553    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
554    pub fn add_ti_txt<T, S>(&mut self, data: T, overwrite: bool) -> Result<(), Error>
555    where
556        T: AsRef<[S]>,
557        S: AsRef<str>,
558    {
559        let mut address = None;
560        let mut eof_found = false;
561
562        for line in data.as_ref() {
563            if eof_found {
564                return Err(Error::UnsupportedFileFormat);
565            }
566            let line = line.as_ref().trim();
567
568            if line.is_empty() {
569                return Err(Error::RecordTooShort);
570            }
571            if line.starts_with('q') {
572                eof_found = true;
573            } else if line.starts_with('@') {
574                if let Ok(add) = u32::from_str_radix(line.trim_start_matches('@'), 16) {
575                    address = Some(add as usize);
576                } else {
577                    return Err(Error::ContainsInvalidCharacters);
578                }
579            } else {
580                let mut data_bytes = Vec::new();
581                // Convert the character stream to bytes.
582                for byte_str in line
583                    .replace(' ', "")
584                    .as_bytes()
585                    .chunks(2)
586                    .map(|chunk| std::str::from_utf8(chunk))
587                {
588                    if let Ok(value) = u8::from_str_radix(byte_str?, 16) {
589                        data_bytes.push(value);
590                    } else {
591                        return Err(Error::ContainsInvalidCharacters);
592                    }
593                }
594                let size = data_bytes.len();
595
596                if size > TI_TXT_BYTES_PER_LINE {
597                    return Err(Error::RecordTooLong);
598                }
599                if let Some(addr) = address {
600                    self.segments
601                        .add_segment(Segment::new(addr, data_bytes), overwrite)?;
602                    if size == TI_TXT_BYTES_PER_LINE {
603                        address = Some(addr + size);
604                    } else {
605                        address = None;
606                    }
607                } else {
608                    return Err(Error::MissingStartCode);
609                }
610            }
611        }
612        if !eof_found {
613            return Err(Error::UnsupportedFileFormat);
614        }
615        Ok(())
616    }
617
618    /// Add given Verlog-Vmem string `lines` array. Set `overwrite` to `true` to
619    /// allow already added data to be overwritten.
620    /// See [`BinFile.to_verilog_vmem()`](#method.to_verilog_vmem) for examples.
621    ///
622    /// # Parameters
623    ///
624    /// - `data`: String array of records to be read in
625    /// - `overwrite`: flag to activate overwrite mode
626    ///
627    /// # Errors
628    ///
629    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
630    pub fn add_verilog_vmem<T, S>(&mut self, data: T, overwrite: bool) -> Result<(), Error>
631    where
632        T: AsRef<[S]>,
633        S: AsRef<str>,
634    {
635        let mut address = None;
636        let regex = Regex::new(r"\s+")?;
637        let mut chunk = Vec::new();
638        let data: Vec<&str> = data.as_ref().iter().map(|val| val.as_ref()).collect();
639        let data = data.join("\n\r");
640        let comment_removed_string = comment_remover(&data);
641        let words = regex.split(comment_removed_string.trim());
642        let mut word_size_bytes = None;
643        let words: Vec<&str> = words.into_iter().collect();
644
645        for word in &words {
646            if !word.starts_with('@') {
647                let mut length = word.len();
648
649                if length % 2 != 0 {
650                    return Err(Error::UnsupportedFileFormat);
651                }
652                length /= 2;
653                if let Some(wsl) = word_size_bytes {
654                    if wsl != length {
655                        return Err(Error::UnsupportedFileFormat);
656                    }
657                } else {
658                    word_size_bytes = Some(length);
659                }
660            }
661        }
662        for word in words {
663            if word.starts_with('@') {
664                if let Some(addr) = address {
665                    self.segments
666                        .add_segment(Segment::new(addr, chunk), overwrite)?;
667                }
668                address = usize::from_str_radix(word.trim_start_matches('@'), 16).ok();
669                chunk = Vec::new();
670            } else {
671                let data_bytes: Result<Vec<u8>, Error> = word
672                    .replace(' ', "")
673                    .as_bytes()
674                    .chunks(2)
675                    .map(|chunk| {
676                        let byte_str = std::str::from_utf8(chunk).map_err(Error::from)?;
677                        u8::from_str_radix(byte_str, 16)
678                            .map_err(|_| Error::ContainsInvalidCharacters)
679                    })
680                    //.map(|byte_str| u8::from_str_radix(byte_str, 16))
681                    .collect();
682                chunk.append(&mut data_bytes?);
683            }
684        }
685        if let Some(addr) = address {
686            if !chunk.is_empty() {
687                self.segments
688                    .add_segment(Segment::new(addr, chunk), overwrite)?;
689            }
690        }
691        Ok(())
692    }
693
694    /// Add given data at given address. Set `overwrite` to `true` to
695    /// allow already added data to be overwritten.
696    /// See [`BinFile.to_bytes()`](#method.to_bytes) for examples.
697    ///
698    /// # Parameters
699    ///
700    /// - `data`: String array of records to be read in
701    /// - `address`: Address were the data shall be inserted
702    /// - `overwrite`: flag to activate overwrite mode
703    ///
704    /// # Errors
705    ///
706    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
707    pub fn add_bytes<T>(
708        &mut self,
709        data: T,
710        address: Option<usize>,
711        overwrite: bool,
712    ) -> Result<(), Error>
713    where
714        T: AsRef<[u8]>,
715    {
716        let address = address.unwrap_or(0);
717        self.segments
718            .add_segment(Segment::new(address, data), overwrite)
719    }
720
721    /// Open given file and add its data by guessing its format. The format
722    /// must be Motorola S-Records, Intel HEX, TI-TXT. Set `overwrite`
723    /// to `true` to allow already added data to be overwritten.
724    ///
725    /// # Parameters
726    ///
727    /// - `file_name`: File name of the file
728    /// - `overwrite`: flag to activate overwrite mode
729    ///
730    /// # Errors
731    ///
732    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
733    /// - `Error::IoError`: Any other error occurred while loading the input data
734    pub fn add_file<P>(&mut self, file_name: P, overwrite: bool) -> Result<(), Error>
735    where
736        P: AsRef<Path>,
737    {
738        self.add_strings(self._open_input(file_name)?.as_slice(), overwrite)?;
739        Ok(())
740    }
741
742    /// Open given Motorola S-Records file and add its records. Set
743    /// `overwrite` to `true` to allow already added data to be
744    /// overwritten.
745    ///
746    /// # Parameters
747    ///
748    /// - `file_name`: File name of the file
749    /// - `overwrite`: flag to activate overwrite mode
750    ///
751    /// # Errors
752    ///
753    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
754    /// - `Error::IoError`: Any other error occurred while loading the input data
755    pub fn add_srec_file<P>(&mut self, file_name: P, overwrite: bool) -> Result<(), Error>
756    where
757        P: AsRef<Path>,
758    {
759        self.add_srec(self._open_input(file_name)?.as_slice(), overwrite)?;
760        Ok(())
761    }
762
763    /// Open given Intel HEX file and add its records. Set `overwrite` to
764    /// `true` to allow already added data to be overwritten.
765    ///
766    /// # Parameters
767    ///
768    /// - `file_name`: File name of the file
769    /// - `overwrite`: flag to activate overwrite mode
770    ///
771    /// # Errors
772    ///
773    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
774    /// - `Error::IoError`: Any other error occurred while loading the input data
775    pub fn add_ihex_file<P>(&mut self, file_name: P, overwrite: bool) -> Result<(), Error>
776    where
777        P: AsRef<Path>,
778    {
779        self.add_ihex(self._open_input(file_name)?.as_slice(), overwrite)?;
780        Ok(())
781    }
782
783    /// Open given Extended Tektronix Hex file and add its records. Set `overwrite` to
784    /// `true` to allow already added data to be overwritten.
785    ///
786    /// # Parameters
787    ///
788    /// - `file_name`: File name of the file
789    /// - `overwrite`: flag to activate overwrite mode
790    ///
791    /// # Errors
792    ///
793    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
794    /// - `Error::IoError`: Any other error occurred while loading the input data
795    pub fn add_ext_tek_hex_file<P>(&mut self, file_name: P, overwrite: bool) -> Result<(), Error>
796    where
797        P: AsRef<Path>,
798    {
799        self.add_ext_tek_hex(self._open_input(file_name)?.as_slice(), overwrite)?;
800        Ok(())
801    }
802
803    /// Open given TI-TXT file and add its contents. Set `overwrite` to
804    /// `true` to allow already added data to be overwritten.
805    ///
806    /// # Parameters
807    ///
808    /// - `file_name`: File name of the file
809    /// - `overwrite`: flag to activate overwrite mode
810    ///
811    /// # Errors
812    ///
813    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
814    /// - `Error::IoError`: Any other error occurred while loading the input data
815    pub fn add_ti_txt_file<P>(&mut self, file_name: P, overwrite: bool) -> Result<(), Error>
816    where
817        P: AsRef<Path>,
818    {
819        self.add_ti_txt(self._open_input(file_name)?.as_slice(), overwrite)?;
820        Ok(())
821    }
822
823    /// Open given Verilog VMEM file and add its contents. Set `overwrite` to
824    /// `true` to allow already added data to be overwritten.
825    ///
826    /// # Parameters
827    ///
828    /// - `file_name`: File name of the file
829    /// - `overwrite`: flag to activate overwrite mode
830    ///
831    /// # Errors
832    ///
833    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
834    /// - `Error::IoError`: Any other error occurred while loading the input data
835    pub fn add_verilog_vmem_file<P>(&mut self, file_name: P, overwrite: bool) -> Result<(), Error>
836    where
837        P: AsRef<Path>,
838    {
839        self.add_verilog_vmem(self._open_input(file_name)?.as_slice(), overwrite)?;
840        Ok(())
841    }
842
843    /// Private method which reads in a given text file and returns the content as `Vec<String>`
844    ///
845    /// # Parameters
846    ///
847    /// - `file_name`: File name of the file
848    ///
849    /// # Errors
850    ///
851    /// - `Error::IoError`: Error while reading the file
852    fn _open_input<P>(&self, file_name: P) -> Result<Vec<String>, Error>
853    where
854        P: AsRef<Path>,
855    {
856        if let Ok(file) = File::open(file_name) {
857            let reader = BufReader::new(file);
858            let data: Vec<String> = reader.lines().map_while(Result::ok).collect();
859            Ok(data)
860        } else {
861            Err(Error::IoError)
862        }
863    }
864
865    /// Open given binary file and add its contents add the given address.
866    /// Set `overwrite` to `true` to allow already added data to be overwritten.
867    ///
868    /// # Parameters
869    ///
870    /// - `file_name`: File name of the file
871    /// - `address`: Address where datas will be written
872    /// - `overwrite`: flag to activate overwrite mode
873    ///
874    /// # Errors
875    ///
876    /// - `Error::AddDataError`: If already present datas shall be overwritten, but `overwrite` was not set
877    /// - `Error::IoError`: Any other error occurred while loading the input data
878    pub fn add_binary_file<P>(
879        &mut self,
880        file_name: P,
881        address: Option<usize>,
882        overwrite: bool,
883    ) -> Result<(), Error>
884    where
885        P: AsRef<Path>,
886    {
887        if let Ok(mut file) = File::open(&file_name) {
888            let metadata_len = metadata(&file_name).map(|md| md.len()).unwrap_or(0) as usize;
889            let mut data: Vec<u8> = Vec::with_capacity(metadata_len);
890            if let Ok(n) = file.read_to_end(&mut data) {
891                self.add_bytes(&data[..n], address, overwrite)?;
892            } else {
893                return Err(Error::IoError);
894            }
895            return Ok(());
896        }
897        Err(Error::IoError)
898    }
899
900    fn to_srec_int(
901        &self,
902        number_of_data_bytes: Option<usize>,
903        address_length_bits: SRecordAddressLength,
904        pretty: bool,
905    ) -> Result<Vec<String>, Error> {
906        if let Some(maximum_address) = self.maximum_address() {
907            match address_length_bits {
908                SRecordAddressLength::Length16 => {
909                    if maximum_address > 0xFFFF {
910                        return Err(Error::AddressTooBig);
911                    }
912                }
913                SRecordAddressLength::Length24 => {
914                    if maximum_address > 0xFFFFFF {
915                        return Err(Error::AddressTooBig);
916                    }
917                }
918                SRecordAddressLength::Length32 => {
919                    if maximum_address > 0xFFFFFFFF {
920                        return Err(Error::AddressTooBig);
921                    }
922                }
923            }
924        }
925        let number_of_data_bytes = number_of_data_bytes.unwrap_or(32);
926        let mut lines = Vec::new();
927        if let Some(header) = &self.header {
928            let record = SRecord::Header(header.to_owned());
929            if pretty {
930                lines.push(record.to_pretty_record_string()?)
931            } else {
932                lines.push(record.to_record_string()?)
933            }
934        }
935        let mut number_of_records = 0;
936        let data = self.segments.chunks(Some(number_of_data_bytes), None)?;
937        for (address, datas) in data {
938            let record = match address_length_bits {
939                SRecordAddressLength::Length16 => SRecord::Data16(Data {
940                    address: Address16(address as u16),
941                    data: datas,
942                }),
943                SRecordAddressLength::Length24 => SRecord::Data24(Data {
944                    address: Address24(address as u32),
945                    data: datas,
946                }),
947                SRecordAddressLength::Length32 => SRecord::Data32(Data {
948                    address: Address32(address as u32),
949                    data: datas,
950                }),
951            };
952            if pretty {
953                lines.push(record.to_pretty_record_string()?)
954            } else {
955                lines.push(record.to_record_string()?)
956            }
957            number_of_records += 1;
958        }
959        let record = if number_of_records <= 0xFFFF {
960            SRecord::Count16(Count16(number_of_records as u16))
961        } else {
962            SRecord::Count24(Count24(number_of_records))
963        };
964        if pretty {
965            lines.push(record.to_pretty_record_string()?)
966        } else {
967            lines.push(record.to_record_string()?)
968        }
969
970        // Add the execution start address
971        if let Some(execution_start_address) = self.execution_start_address {
972            let record = match address_length_bits {
973                SRecordAddressLength::Length16 => {
974                    SRecord::Address16(Address16(execution_start_address as u16))
975                }
976                SRecordAddressLength::Length24 => {
977                    SRecord::Address24(Address24(execution_start_address as u32))
978                }
979                SRecordAddressLength::Length32 => {
980                    SRecord::Address32(Address32(execution_start_address as u32))
981                }
982            };
983            if pretty {
984                lines.push(record.to_pretty_record_string()?)
985            } else {
986                lines.push(record.to_record_string()?)
987            }
988        }
989        Ok(lines)
990    }
991
992    /// Format the binary file as Motorola S-Records records and return
993    /// them as a string.
994    ///
995    /// # Parameters
996    ///
997    /// - `number_of_data_bytes` is the number of data bytes in each
998    ///   record.
999    /// - `address_length_bits` is the number of address bits in each
1000    ///   record. If you're not sure what to take use `SRecordAddressLength::default()`
1001    ///
1002    /// # Errors
1003    ///
1004    /// - `Error::AlignmentToSizeError`: Should not occure, only if someone chaged alignment default value
1005    /// - `Error::AddressTooBig`: If maximum address doesn't fit in the selected file format. Choose bigger
1006    ///   `address_length_bits` if possible
1007    ///
1008    /// # Examples
1009    ///
1010    /// ```rust
1011    /// use bin_file::BinFile;
1012    /// use bin_file::SRecordAddressLength;
1013    /// use bin_file::Error;
1014    ///
1015    /// fn main() -> Result<(), Error> {
1016    ///     let mut binfile = BinFile::new();
1017    ///     assert!(binfile.add_srec(
1018    ///         [
1019    ///             "S32500000100214601360121470136007EFE09D219012146017E17C20001FF5F16002148011973",
1020    ///             "S32500000120194E79234623965778239EDA3F01B2CA3F0156702B5E712B722B73214601342199",
1021    ///             "S5030002FA",
1022    ///         ], false).is_ok());
1023    ///     print!("{}", binfile.to_srec(None, SRecordAddressLength::default())?.join("\n\r"));
1024    ///     Ok(())
1025    /// }
1026    /// ```
1027    ///
1028    /// ```console
1029    /// S32500000100214601360121470136007EFE09D219012146017E17C20001FF5F16002148011973
1030    /// S32500000120194E79234623965778239EDA3F01B2CA3F0156702B5E712B722B73214601342199
1031    /// S5030002FA
1032    /// ```
1033    pub fn to_srec(
1034        &self,
1035        number_of_data_bytes: Option<usize>,
1036        address_length_bits: SRecordAddressLength,
1037    ) -> Result<Vec<String>, Error> {
1038        self.to_srec_int(number_of_data_bytes, address_length_bits, false)
1039    }
1040
1041    /// Format the binary file as Motorola S-Records records and return
1042    /// them as a string with added coloring and comments
1043    ///
1044    /// Important: File is not readable afterwards
1045    ///
1046    /// # Parameters
1047    ///
1048    /// - `number_of_data_bytes` is the number of data bytes in each
1049    ///   record.
1050    /// - `address_length_bits` is the number of address bits in each
1051    ///   record. If you're not sure what to take use `SRecordAddressLength::default()`
1052    ///
1053    /// # Errors
1054    ///
1055    /// - `Error::AlignmentToSizeError`: Should not occure, only if someone chaged alignment default value
1056    /// - `Error::AddressTooBig`: If maximum address doesn't fit in the selected file format. Choose bigger
1057    ///   `address_length_bits` if possible
1058    ///
1059    /// # Examples
1060    ///
1061    /// ```rust
1062    /// use bin_file::BinFile;
1063    /// use bin_file::SRecordAddressLength;
1064    /// use bin_file::Error;
1065    ///
1066    /// fn main() -> Result<(), Error> {
1067    ///     let mut binfile = BinFile::new();
1068    ///     assert!(binfile.add_srec(
1069    ///         [
1070    ///             "S32500000100214601360121470136007EFE09D219012146017E17C20001FF5F16002148011973",
1071    ///             "S32500000120194E79234623965778239EDA3F01B2CA3F0156702B5E712B722B73214601342199",
1072    ///             "S5030002FA",
1073    ///         ], false).is_ok());
1074    ///     print!("{}", binfile.to_srec_pretty(None, SRecordAddressLength::default())?.join("\n\r"));
1075    ///     Ok(())
1076    /// }
1077    /// ```
1078    pub fn to_srec_pretty(
1079        &self,
1080        number_of_data_bytes: Option<usize>,
1081        address_length_bits: SRecordAddressLength,
1082    ) -> Result<Vec<String>, Error> {
1083        self.to_srec_int(number_of_data_bytes, address_length_bits, true)
1084    }
1085
1086    fn to_ihex_int(
1087        &self,
1088        number_of_bytes: Option<usize>,
1089        ihex_format: IHexFormat,
1090        pretty: bool,
1091    ) -> Result<Vec<String>, Error> {
1092        let i32hex = |address: usize,
1093                      extended_linear_address: u32,
1094                      lines: &mut Vec<String>|
1095         -> Result<(usize, u32), Error> {
1096            if address > 0xffffffff {
1097                return Err(Error::AddressTooBig);
1098            }
1099            let mut extended_linear_address = extended_linear_address;
1100            let address_upper_16_bits = (address >> 16) & 0xffff;
1101            if address_upper_16_bits > extended_linear_address as usize {
1102                extended_linear_address = address_upper_16_bits as u32;
1103                let record = IHexRecord::ExtendedLinearAddress(address_upper_16_bits as u16);
1104                lines.push(record.to_record_string().unwrap());
1105            }
1106            Ok((address, extended_linear_address))
1107        };
1108        let i16hex = |address: usize,
1109                      extended_segment_address: u32,
1110                      lines: &mut Vec<String>|
1111         -> Result<(usize, u32), Error> {
1112            if address > 16 * 0xffff + 0xffff {
1113                return Err(Error::AddressTooBig);
1114            }
1115            let mut extended_segment_address = extended_segment_address;
1116            let mut address_lower = address - 16 * extended_segment_address as usize;
1117
1118            if address_lower > 0xffff {
1119                extended_segment_address = 4096 * (address >> 16) as u32;
1120                if extended_segment_address > 0xffff {
1121                    extended_segment_address = 0xffff;
1122                }
1123                address_lower = address - 16 * extended_segment_address as usize;
1124                let record = IHexRecord::ExtendedSegmentAddress(extended_segment_address as u16);
1125                lines.push(record.to_record_string().unwrap());
1126            }
1127            Ok((address_lower, extended_segment_address))
1128        };
1129        let i8hex = |address: usize| -> Result<(), Error> {
1130            if address > 0xffff {
1131                return Err(Error::AddressTooBig);
1132            }
1133            Ok(())
1134        };
1135
1136        let mut lines = Vec::new();
1137        let mut extended_segment_address = 0;
1138        let mut extended_linear_address = 0;
1139        let number_of_data_words = number_of_bytes.unwrap_or(32);
1140
1141        for (address, data) in self.segments.chunks(Some(number_of_data_words), None)? {
1142            let mut address = address;
1143            match ihex_format {
1144                IHexFormat::IHex8 => i8hex(address)?,
1145                IHexFormat::IHex16 => {
1146                    (address, extended_segment_address) =
1147                        i16hex(address, extended_segment_address, &mut lines)?
1148                }
1149                IHexFormat::IHex32 => {
1150                    (address, extended_linear_address) =
1151                        i32hex(address, extended_linear_address, &mut lines)?
1152                }
1153            }
1154            let record = IHexRecord::Data {
1155                offset: address as u16,
1156                value: data,
1157            };
1158            if pretty {
1159                lines.push(record.to_pretty_record_string()?)
1160            } else {
1161                lines.push(record.to_record_string()?)
1162            }
1163        }
1164        if let Some(start_address) = self.execution_start_address {
1165            match ihex_format {
1166                IHexFormat::IHex8 => (),
1167                IHexFormat::IHex16 => {
1168                    let record = IHexRecord::StartSegmentAddress(start_address as u32);
1169                    if pretty {
1170                        lines.push(record.to_pretty_record_string()?)
1171                    } else {
1172                        lines.push(record.to_record_string()?)
1173                    }
1174                }
1175                IHexFormat::IHex32 => {
1176                    let record = IHexRecord::StartLinearAddress(start_address as u32);
1177                    if pretty {
1178                        lines.push(record.to_pretty_record_string()?)
1179                    } else {
1180                        lines.push(record.to_record_string()?)
1181                    }
1182                }
1183            }
1184        }
1185        if pretty {
1186            lines.push(IHexRecord::EndOfFile.to_pretty_record_string()?)
1187        } else {
1188            lines.push(IHexRecord::EndOfFile.to_record_string()?)
1189        }
1190        Ok(lines)
1191    }
1192
1193    /// Format the binary file as Intel HEX records and return them as a
1194    /// string.
1195    ///
1196    /// # Parameters
1197    /// - `number_of_data_bytes` is the number of data bytes in each
1198    ///   record.
1199    /// - `ihex_format` is the number of address bits in each
1200    ///   record. If you're not sure what to take use `IHexFormat::default()`
1201    ///
1202    /// # Examples
1203    ///
1204    /// ```rust
1205    /// use bin_file::BinFile;
1206    /// use bin_file::IHexFormat;
1207    /// use bin_file::Error;
1208    ///
1209    /// fn main() -> Result<(), Error> {
1210    ///     let mut binfile = BinFile::new();
1211    ///
1212    ///     assert!(binfile.add_ihex(
1213    ///         [
1214    ///         ":20010000214601360121470136007EFE09D219012146017E17C20001FF5F16002148011979",
1215    ///         ":20012000194E79234623965778239EDA3F01B2CA3F0156702B5E712B722B7321460134219F",
1216    ///         ":00000001FF"
1217    ///         ], false).is_ok());
1218    ///     print!("{}", binfile.to_ihex(None, IHexFormat::default())?.join("\n\r"));
1219    ///     Ok(())
1220    /// }
1221    /// ```
1222    ///
1223    /// ```console
1224    /// :20010000214601360121470136007EFE09D219012146017E17C20001FF5F16002148011979
1225    /// :20012000194E79234623965778239EDA3F01B2CA3F0156702B5E712B722B7321460134219F
1226    /// :00000001FF
1227    /// ```
1228    pub fn to_ihex(
1229        &self,
1230        number_of_bytes: Option<usize>,
1231        ihex_format: IHexFormat,
1232    ) -> Result<Vec<String>, Error> {
1233        self.to_ihex_int(number_of_bytes, ihex_format, false)
1234    }
1235
1236    /// Format the binary file as Intel HEX records and return them as a
1237    /// string with added coloring and comments
1238    ///
1239    /// Important: File is not readable afterwards
1240    ///
1241    /// # Parameters
1242    /// - `number_of_data_bytes` is the number of data bytes in each
1243    ///   record.
1244    /// - `ihex_format` is the number of address bits in each
1245    ///   record. If you're not sure what to take use `IHexFormat::default()`
1246    ///
1247    /// # Examples
1248    ///
1249    /// ```rust
1250    /// use bin_file::BinFile;
1251    /// use bin_file::IHexFormat;
1252    /// use bin_file::Error;
1253    ///
1254    /// fn main() -> Result<(), Error> {
1255    ///     let mut binfile = BinFile::new();
1256    ///
1257    ///     assert!(binfile.add_ihex(
1258    ///         [
1259    ///         ":20010000214601360121470136007EFE09D219012146017E17C20001FF5F16002148011979",
1260    ///         ":20012000194E79234623965778239EDA3F01B2CA3F0156702B5E712B722B7321460134219F",
1261    ///         ":00000001FF"
1262    ///         ], false).is_ok());
1263    ///     print!("{}", binfile.to_ihex_pretty(None, IHexFormat::default())?.join("\n\r"));
1264    ///     Ok(())
1265    /// }
1266    /// ```
1267    pub fn to_ihex_pretty(
1268        &self,
1269        number_of_bytes: Option<usize>,
1270        ihex_format: IHexFormat,
1271    ) -> Result<Vec<String>, Error> {
1272        self.to_ihex_int(number_of_bytes, ihex_format, true)
1273    }
1274
1275    fn to_ext_tek_hex_int(
1276        &self,
1277        number_of_bytes_per_line: Option<u8>,
1278        pretty: bool,
1279    ) -> Result<Vec<String>, Error> {
1280        let mut lines = Vec::new();
1281        let number_of_data_words =
1282            number_of_bytes_per_line.unwrap_or(EXT_TEK_HEX_BYTES_PER_LINE) as usize;
1283        if number_of_data_words > 255 - 6 {
1284            Err(Error::RecordTooLong)
1285        } else {
1286            for segment in self.segments.segments() {
1287                for (address, data) in segment.chunks(Some(number_of_data_words), None)? {
1288                    let record = ExtTekHexRecord::Data {
1289                        address,
1290                        value: data,
1291                    };
1292                    if pretty {
1293                        lines.push(record.to_pretty_record_string()?);
1294                    } else {
1295                        lines.push(record.to_record_string()?);
1296                    }
1297                }
1298            }
1299            Ok(lines)
1300        }
1301    }
1302
1303    /// Format the binary file as a Extended Tektronix Hex
1304    /// file and return it as a string.
1305    ///
1306    /// # Parameters
1307    ///
1308    /// - `number_of_bytes_per_line`: Number of bytes printed per line.
1309    ///   If set to None 16 Bytes will be printed
1310    ///
1311    /// # Examples
1312    ///
1313    /// ```rust
1314    /// use bin_file::BinFile;
1315    /// use bin_file::Error;
1316    ///
1317    /// fn main() -> Result<(), Error> {
1318    ///     let mut binfile = BinFile::new();
1319    ///
1320    ///     assert!(binfile.add_ext_tek_hex(
1321    ///         ["%1A626810000000202020202020"], false).is_ok());
1322    ///     print!("{}", binfile.to_ext_tek_hex(None)?.join("\n\r"));
1323    ///     Ok(())
1324    /// }
1325    /// ```
1326    ///
1327    /// ```console
1328    /// %1A626810000000202020202020
1329    /// ```
1330    pub fn to_ext_tek_hex(
1331        &self,
1332        number_of_bytes_per_line: Option<u8>,
1333    ) -> Result<Vec<String>, Error> {
1334        self.to_ext_tek_hex_int(number_of_bytes_per_line, false)
1335    }
1336
1337    /// Format the binary file as a Extended Tektronix Hex
1338    /// file and return it as a string with added coloring and comments
1339    ///
1340    /// Important: File is not readable afterwards
1341    ///
1342    /// # Parameters
1343    ///
1344    /// - `number_of_bytes_per_line`: Number of bytes printed per line.
1345    ///   If set to None 16 Bytes will be printed
1346    ///
1347    /// # Examples
1348    ///
1349    /// ```rust
1350    /// use bin_file::BinFile;
1351    /// use bin_file::Error;
1352    ///
1353    /// fn main() -> Result<(), Error> {
1354    ///     let mut binfile = BinFile::new();
1355    ///
1356    ///     assert!(binfile.add_ext_tek_hex(
1357    ///         ["%1A626810000000202020202020"], false).is_ok());
1358    ///     print!("{}", binfile.to_ext_tek_hex_pretty(None)?.join("\n\r"));
1359    ///     Ok(())
1360    /// }
1361    pub fn to_ext_tek_hex_pretty(
1362        &self,
1363        number_of_bytes_per_line: Option<u8>,
1364    ) -> Result<Vec<String>, Error> {
1365        self.to_ext_tek_hex_int(number_of_bytes_per_line, true)
1366    }
1367
1368    fn to_ti_txt_int(&self, pretty: bool) -> Result<Vec<String>, Error> {
1369        let mut lines = Vec::new();
1370        let number_of_data_words = TI_TXT_BYTES_PER_LINE;
1371
1372        for segment in self.segments.segments() {
1373            lines.push(if pretty {
1374                format!(
1375                    "{YELLOW}@{:04X}{R} (segment address)",
1376                    segment.minimum_address()
1377                )
1378            } else {
1379                format!("@{:04X}", segment.minimum_address())
1380            });
1381            for (_, data) in segment.chunks(Some(number_of_data_words), None)? {
1382                let mut string = String::new();
1383                for value in data {
1384                    string += format!("{:02X} ", value).as_str();
1385                }
1386                lines.push(if pretty {
1387                    format!("{} (data)", string.trim_end())
1388                } else {
1389                    string.trim_end().to_string()
1390                });
1391            }
1392        }
1393        if pretty {
1394            lines.push(format!("{MAGENTA}q{R} (end of file)"))
1395        } else {
1396            lines.push("q".into());
1397        }
1398        Ok(lines)
1399    }
1400
1401    /// Format the binary file as a TI-TXT file and return it as a string array.
1402    ///
1403    /// # Examples
1404    ///
1405    /// ```rust
1406    /// use bin_file::BinFile;
1407    /// use bin_file::Error;
1408    ///
1409    /// fn main() -> Result<(), Error> {
1410    ///     let mut binfile = BinFile::new();
1411    ///
1412    ///     assert!(binfile.add_ti_txt(
1413    ///         [
1414    ///         "@0100",
1415    ///         "21 46 01 36 01 21 47 01 36 00 7E FE 09 D2 19 01",
1416    ///         "21 46 01 7E 17 C2 00 01 FF 5F 16 00 21 48 01 19",
1417    ///         "19 4E 79 23 46 23 96 57 78 23 9E DA 3F 01 B2 CA",
1418    ///         "3F 01 56 70 2B 5E 71 2B 72 2B 73 21 46 01 34 21",
1419    ///         "q",
1420    ///         ], false).is_ok());
1421    ///     print!("{}", binfile.to_ti_txt()?.join("\n\r"));
1422    ///     Ok(())
1423    /// }
1424    /// ```
1425    ///
1426    /// ```console
1427    /// @0100
1428    /// 21 46 01 36 01 21 47 01 36 00 7E FE 09 D2 19 01
1429    /// 21 46 01 7E 17 C2 00 01 FF 5F 16 00 21 48 01 19
1430    /// 19 4E 79 23 46 23 96 57 78 23 9E DA 3F 01 B2 CA
1431    /// 3F 01 56 70 2B 5E 71 2B 72 2B 73 21 46 01 34 21
1432    /// q
1433    /// ```
1434    pub fn to_ti_txt(&self) -> Result<Vec<String>, Error> {
1435        self.to_ti_txt_int(false)
1436    }
1437
1438    /// Format the binary file as a TI-TXT file and return it as a string array
1439    ///  with added coloring and comments
1440    ///
1441    /// Important: File is not readable afterwards
1442    ///
1443    /// # Examples
1444    ///
1445    /// ```rust
1446    /// use bin_file::BinFile;
1447    /// use bin_file::Error;
1448    ///
1449    /// fn main() -> Result<(), Error> {
1450    ///     let mut binfile = BinFile::new();
1451    ///
1452    ///     assert!(binfile.add_ti_txt(
1453    ///         [
1454    ///         "@0100",
1455    ///         "21 46 01 36 01 21 47 01 36 00 7E FE 09 D2 19 01",
1456    ///         "21 46 01 7E 17 C2 00 01 FF 5F 16 00 21 48 01 19",
1457    ///         "19 4E 79 23 46 23 96 57 78 23 9E DA 3F 01 B2 CA",
1458    ///         "3F 01 56 70 2B 5E 71 2B 72 2B 73 21 46 01 34 21",
1459    ///         "q",
1460    ///         ], false).is_ok());
1461    ///     print!("{}", binfile.to_ti_txt_pretty()?.join("\n\r"));
1462    ///     Ok(())
1463    /// }
1464    /// ```
1465    ///
1466    /// ```console
1467    /// \033[0;33m@0100\033[0m (segment address)
1468    /// 21 46 01 36 01 21 47 01 36 00 7E FE 09 D2 19 01 (data)
1469    /// 21 46 01 7E 17 C2 00 01 FF 5F 16 00 21 48 01 19 (data)
1470    /// 19 4E 79 23 46 23 96 57 78 23 9E DA 3F 01 B2 CA (data)
1471    /// 3F 01 56 70 2B 5E 71 2B 72 2B 73 21 46 01 34 21 (data)
1472    /// 033[0;35mq\033[0m (end of file)
1473    /// ```
1474    pub fn to_ti_txt_pretty(&self) -> Result<Vec<String>, Error> {
1475        self.to_ti_txt_int(true)
1476    }
1477
1478    /// Format the binary file as a Verilog VMEM file and return it as a string.
1479    ///
1480    /// # Examples
1481    ///
1482    /// ```rust
1483    /// use bin_file::BinFile;
1484    /// use bin_file::Error;
1485    ///
1486    /// fn main() -> Result<(), Error> {
1487    ///     let mut binfile = BinFile::new();
1488    ///
1489    ///     assert!(binfile.add_verilog_vmem(
1490    ///         [
1491    ///         "@00000100 21 46 01 36 01 21 47 01 36 00 7E FE 09 D2 19 01 21 46 01 7E 17 C2 00 01 FF 5F 16 00 21 48 01 19",
1492    ///         "@00000120 19 4E 79 23 46 23 96 57 78 23 9E DA 3F 01 B2 CA 3F 01 56 70 2B 5E 71 2B 72 2B 73 21 46 01 34 21",
1493    ///         ], false).is_ok());
1494    ///     print!("{}", binfile.to_verilog_vmem()?.join("\n\r"));
1495    ///     Ok(())
1496    /// }
1497    /// ```
1498    ///
1499    /// ```console
1500    /// @00000100 21 46 01 36 01 21 47 01 36 00 7E FE 09 D2 19 01 21 46 01 7E 17 C2 00 01 FF 5F 16 00 21 48 01 19
1501    /// @00000120 19 4E 79 23 46 23 96 57 78 23 9E DA 3F 01 B2 CA 3F 01 56 70 2B 5E 71 2B 72 2B 73 21 46 01 34 21
1502    /// ```
1503    pub fn to_verilog_vmem(&self) -> Result<Vec<String>, Error> {
1504        let mut lines = Vec::new();
1505        if let Some(header) = self.header.clone() {
1506            lines.push(format!("/* {} */", String::from_utf8(header).unwrap()));
1507        }
1508        for segment in self.segments.segments() {
1509            for (address, data) in segment.chunks(Some(VERILOG_VMEM_BYTES_PER_LINE), None)? {
1510                let mut string = format!("@{:08X}", address);
1511                for value in data {
1512                    string += format!(" {:02x}", value).as_str();
1513                }
1514            }
1515        }
1516        Ok(lines)
1517    }
1518
1519    /// Return a `Vec<u8>` of all data within given address range.
1520    ///
1521    /// # Parameters
1522    ///
1523    /// - `range`: the address range which shall be exported
1524    /// - `padding`: is the word value of the padding between
1525    ///   non-adjacent segments. If not provided `0xFF`will be used
1526    ///
1527    /// # Examples
1528    ///
1529    /// ```rust
1530    /// use bin_file::BinFile;
1531    /// use bin_file::Error;
1532    ///
1533    /// fn main() -> Result<(), Error> {
1534    ///     let mut binfile = BinFile::new();
1535    ///     let data = [0x21, 0x46, 0x01, 0x36, 0x01, 0x21, 0x47, 0x01, 0x36, 0x00, 0x7E, 0xFE, 0x09, 0xD2, 0x19, 0x01,
1536    ///                 0x21, 0x46, 0x01, 0x7E, 0x17, 0xC2, 0x00, 0x01, 0xFF, 0x5F, 0x16, 0x00, 0x21, 0x48, 0x01, 0x19,
1537    ///                 0x19, 0x4E, 0x79, 0x23, 0x46, 0x23, 0x96, 0x57, 0x78, 0x23, 0x9E, 0xDA, 0x3F, 0x01, 0xB2, 0xCA,
1538    ///                 0x3F, 0x01, 0x56, 0x70, 0x2B, 0x5E, 0x71, 0x2B, 0x72, 0x2B, 0x73, 0x21, 0x46, 0x01, 0x34, 0x21];
1539    ///
1540    ///     assert!(binfile.add_bytes(data, Some(0x100), false).is_ok());
1541    ///     assert_eq!(binfile.to_bytes(.., None), Ok(data.to_vec()));
1542    ///     Ok(())
1543    /// }
1544    /// ```
1545    pub fn to_bytes<R>(&self, range: R, padding: Option<u8>) -> Result<Vec<u8>, Error>
1546    where
1547        R: RangeBounds<usize>,
1548    {
1549        if self.segments.segments().is_empty() {
1550            return Ok(Vec::new());
1551        }
1552        let mut current_maximum_address = match range.start_bound() {
1553            std::ops::Bound::Included(val) => *val,
1554            std::ops::Bound::Excluded(val) => *val + 1,
1555            std::ops::Bound::Unbounded => self.minimum_address().unwrap(),
1556        };
1557        let maximum_address = match range.end_bound() {
1558            std::ops::Bound::Included(val) => *val + 1,
1559            std::ops::Bound::Excluded(val) => *val,
1560            std::ops::Bound::Unbounded => self.maximum_address().unwrap(),
1561        };
1562
1563        if current_maximum_address >= maximum_address {
1564            // Asked address is upper of data
1565            return Ok(Vec::new());
1566        }
1567        let padding = padding.unwrap_or(0xFF);
1568        let mut binary = Vec::new();
1569
1570        for segment in self.segments.segments() {
1571            let (mut address, data) = segment.get_tuple();
1572            let mut data = data.to_vec();
1573            let mut length = data.len();
1574
1575            // Discard data below the minimum
1576            if address < current_maximum_address {
1577                if address + length <= current_maximum_address {
1578                    continue;
1579                }
1580                let offset = current_maximum_address - address;
1581                data = data[offset..].to_vec();
1582                length = data.len();
1583                address = current_maximum_address;
1584            }
1585
1586            // Discard data above the maximum address
1587            if address + length > maximum_address {
1588                if address < maximum_address {
1589                    let size = maximum_address - address;
1590                    data = data[..size].to_vec();
1591                } else if maximum_address > current_maximum_address {
1592                    let mut pad_vec = vec![padding; maximum_address - current_maximum_address];
1593                    binary.append(&mut pad_vec);
1594                }
1595            }
1596            if current_maximum_address < address {
1597                let mut pad_vec = vec![padding; address - current_maximum_address];
1598                binary.append(&mut pad_vec);
1599            }
1600            binary.append(&mut data);
1601            current_maximum_address = address + length;
1602        }
1603        Ok(binary)
1604    }
1605
1606    /// Format the binary file as a string values separated by given
1607    /// separator `separator`. This function can be used to generate
1608    /// array initialization code for C and other languages.
1609    ///
1610    /// # Parameters
1611    ///
1612    /// - `range`: the address range which shall be exported
1613    /// - `padding`: is the word value of the padding between
1614    ///   non-adjacent segments. If not provided `0xFF`will be used
1615    /// - `seperator`: connecting string between two bytes
1616    ///
1617    /// # Examples
1618    ///
1619    /// ```rust
1620    /// use bin_file::BinFile;
1621    /// use bin_file::Error;
1622    ///
1623    /// fn main() -> Result<(), Error> {
1624    ///     let mut binfile = BinFile::new();
1625    ///     let data = [0x21, 0x46, 0x01, 0x36, 0x01, 0x21, 0x47, 0x01, 0x36, 0x00, 0x7E, 0xFE, 0x09, 0xD2, 0x19, 0x01,
1626    ///                 0x21, 0x46, 0x01, 0x7E, 0x17, 0xC2, 0x00, 0x01, 0xFF, 0x5F, 0x16, 0x00, 0x21, 0x48, 0x01, 0x19,
1627    ///                 0x19, 0x4E, 0x79, 0x23, 0x46, 0x23, 0x96, 0x57, 0x78, 0x23, 0x9E, 0xDA, 0x3F, 0x01, 0xB2, 0xCA,
1628    ///                 0x3F, 0x01, 0x56, 0x70, 0x2B, 0x5E, 0x71, 0x2B, 0x72, 0x2B, 0x73, 0x21, 0x46, 0x01, 0x34, 0x21];
1629    ///
1630    ///     assert!(binfile.add_bytes(data, Some(0x100), false).is_ok());
1631    ///     println!("{}", binfile.to_array_str(.., None, None)?);
1632    ///     Ok(())
1633    /// }
1634    /// ```
1635    ///
1636    /// ```console
1637    ///  0x21, 0x46, 0x01, 0x36, 0x01, 0x21, 0x47, 0x01, 0x36, 0x00, 0x7e, 0xfe, 0x09, 0xd2, 0x19, 0x01, 0x21, 0x46, 0x01, 0x7e, 0x17, 0xc2, 0x00, 0x01, 0xff, 0x5f, 0x16, 0x00, 0x21, 0x48, 0x01, 0x19, 0x19, 0x4e, 0x79, 0x23, 0x46, 0x23, 0x96, 0x57, 0x78, 0x23, 0x9e, 0xda, 0x3f, 0x01, 0xb2, 0xca, 0x3f, 0x01, 0x56, 0x70, 0x2b, 0x5e, 0x71, 0x2b, 0x72, 0x2b, 0x73, 0x21, 0x46, 0x01, 0x34, 0x21
1638    /// ```
1639    pub fn to_array_str<R>(
1640        &self,
1641        range: R,
1642        padding: Option<u8>,
1643        separator: Option<&str>,
1644    ) -> Result<String, Error>
1645    where
1646        R: RangeBounds<usize>,
1647    {
1648        let binary_data = self.to_bytes(range, padding)?;
1649        let separator = separator.unwrap_or(", ");
1650        let mut string = String::new();
1651        for value in binary_data {
1652            string += format!("0x{:02x}{}", value, separator).as_str();
1653        }
1654        Ok(string.trim_end_matches(separator).to_string())
1655    }
1656
1657    /// Format the binary file as a hexdump and return it as a string array.
1658    ///
1659    /// # Examples
1660    ///
1661    /// ```rust
1662    /// use bin_file::BinFile;
1663    /// use bin_file::Error;
1664    ///
1665    /// fn main() -> Result<(), Error> {
1666    ///     let mut binfile = BinFile::new();
1667    ///     let data = [0x21, 0x46, 0x01, 0x36, 0x01, 0x21, 0x47, 0x01, 0x36, 0x00, 0x7E, 0xFE, 0x09, 0xD2, 0x19, 0x01,
1668    ///                 0x21, 0x46, 0x01, 0x7E, 0x17, 0xC2, 0x00, 0x01, 0xFF, 0x5F, 0x16, 0x00, 0x21, 0x48, 0x01, 0x19,
1669    ///                 0x19, 0x4E, 0x79, 0x23, 0x46, 0x23, 0x96, 0x57, 0x78, 0x23, 0x9E, 0xDA, 0x3F, 0x01, 0xB2, 0xCA,
1670    ///                 0x3F, 0x01, 0x56, 0x70, 0x2B, 0x5E, 0x71, 0x2B, 0x72, 0x2B, 0x73, 0x21, 0x46, 0x01, 0x34, 0x21];
1671    ///
1672    ///     assert!(binfile.add_bytes(data, Some(0x100), false).is_ok());
1673    ///     println!("{}", binfile.to_hexdump()?.join("\n"));
1674    ///     Ok(())
1675    /// }
1676    /// ```
1677    ///
1678    /// ```console
1679    /// 00000100  21 46 01 36 01 21 47 01  36 00 7e fe 09 d2 19 01  |!F.6.!G.6.~.....|
1680    /// 00000110  21 46 01 7e 17 c2 00 01  ff 5f 16 00 21 48 01 19  |!F.~....._..!H..|
1681    /// 00000120  19 4e 79 23 46 23 96 57  78 23 9e da 3f 01 b2 ca  |.Ny#F#.Wx#..?...|
1682    /// 00000130  3f 01 56 70 2b 5e 71 2b  72 2b 73 21 46 01 34 21  |?.Vp+^q+r+s!F.4!|
1683    /// ```
1684    pub fn to_hexdump(&self) -> Result<Vec<String>, Error> {
1685        if self.is_empty() {
1686            Ok(Vec::new())
1687        } else {
1688            let not_dot_characters = PRINTABLE;
1689            let align_to_line = |address: usize| address - (address % 16);
1690            let padding = |length: usize| -> Vec<Option<u8>> { vec![None; length] };
1691            let format_line = |address: usize, data: &Vec<Option<u8>>| -> String {
1692                let mut data = data.clone();
1693                let mut padding = padding(16 - data.len());
1694                data.append(&mut padding);
1695
1696                let mut hexdata = Vec::new();
1697                for byte in &data {
1698                    let elem = if let Some(byte) = byte {
1699                        format!("{:02x}", byte)
1700                    } else {
1701                        "  ".to_string()
1702                    };
1703                    hexdata.push(elem);
1704                }
1705                let first_half = hexdata[..8].join(" ");
1706                let second_half = hexdata[8..].join(" ");
1707                let mut text = String::new();
1708
1709                for byte in data {
1710                    if let Some(byte) = byte {
1711                        if not_dot_characters.contains(byte as char) {
1712                            text += format!("{}", byte as char).as_str();
1713                        } else {
1714                            text += "."
1715                        }
1716                    } else {
1717                        text += " "
1718                    }
1719                }
1720                format!(
1721                    "{:08x}  {:23}  {:23}  |{:16}|",
1722                    address, first_half, second_half, text
1723                )
1724            };
1725            let mut lines = Vec::new();
1726            let mut line_address = align_to_line(self.minimum_address().unwrap());
1727            let mut line_data = Vec::new();
1728
1729            for (address, data) in self.segments.chunks(Some(16), Some(16))? {
1730                let aligned_chunk_address = align_to_line(address);
1731                if aligned_chunk_address > line_address {
1732                    lines.push(format_line(line_address, &line_data));
1733                    if aligned_chunk_address > line_address + 16 {
1734                        lines.push("...".to_string());
1735                    }
1736                    line_address = aligned_chunk_address;
1737                    line_data.clear();
1738                }
1739                let mut padding = padding(address - line_address - line_data.len());
1740                line_data.append(&mut padding);
1741                for value in data {
1742                    line_data.push(Some(value));
1743                }
1744            }
1745            lines.push(format_line(line_address, &line_data));
1746            Ok(lines)
1747        }
1748    }
1749
1750    /// Fill empty space between segments.
1751    ///
1752    /// # Parameters
1753    ///
1754    /// - `value`: is the value which is used to fill the empty space. By
1755    ///   default the value is `0xff`.
1756    /// - `max_words` is the maximum number of words to fill between the
1757    ///   segments. Empty space which larger than this is not
1758    ///   touched. If `None`, all empty space is filled.
1759    pub fn fill(&mut self, value: Option<u8>, max_words: Option<usize>) -> Result<(), Error> {
1760        let value = value.unwrap_or(0xff);
1761        let mut previous_segment_maximum_address = None;
1762        let mut fill_segments = Vec::new();
1763
1764        for segment in self.segments.segments() {
1765            let address = segment.minimum_address();
1766            let maximum_address = address + segment.len();
1767
1768            if let Some(previous_segment_maximum_address) = previous_segment_maximum_address {
1769                let fill_size = address - previous_segment_maximum_address;
1770
1771                if max_words.is_none() || fill_size <= max_words.unwrap() {
1772                    fill_segments.push(Segment::new(
1773                        previous_segment_maximum_address,
1774                        vec![value; fill_size],
1775                    ));
1776                }
1777            }
1778            previous_segment_maximum_address = Some(maximum_address);
1779        }
1780        for segment in fill_segments {
1781            self.segments.add_segment(segment, false)?;
1782        }
1783        Ok(())
1784    }
1785
1786    /// Exclude given range and keep the rest.
1787    ///
1788    /// # Parameters
1789    ///
1790    /// - `range`: Range, which should be excluded
1791    pub fn exclude(&mut self, range: Range<usize>) -> Result<(), Error> {
1792        if range.end < range.start {
1793            Err(Error::InvalidAddressRange)
1794        } else {
1795            self.segments.remove(range);
1796            Ok(())
1797        }
1798    }
1799
1800    /// Keep given range and discard the rest.
1801    ///
1802    /// # Parameters
1803    ///
1804    /// - `range`: Range, which shall be kept
1805    pub fn crop(&mut self, range: Range<usize>) -> Result<(), Error> {
1806        let maximum_address = self.segments.get_maximum_address().unwrap();
1807        self.segments.remove(0..range.start);
1808        self.segments.remove(range.end..maximum_address);
1809        Ok(())
1810    }
1811
1812    /// Length of all bytes in all segments
1813    pub fn len(&self) -> usize {
1814        let mut len = 0;
1815        for segment in self.segments.segments() {
1816            len += segment.len()
1817        }
1818        len
1819    }
1820
1821    /// Returns true if datas are empty
1822    pub fn is_empty(&self) -> bool {
1823        self.segments.segments().is_empty()
1824    }
1825
1826    /// Return a string of human readable information about the binary
1827    /// file.
1828    ///
1829    /// # Examples
1830    ///
1831    /// ```rust
1832    /// use bin_file::BinFile;
1833    /// use bin_file::Error;
1834    ///
1835    /// fn main() -> Result<(), Error> {
1836    ///     let mut binfile = BinFile::new();
1837    ///     let data = [0x21, 0x46, 0x01, 0x36, 0x01, 0x21, 0x47, 0x01, 0x36, 0x00, 0x7E, 0xFE, 0x09, 0xD2, 0x19, 0x01,
1838    ///                 0x21, 0x46, 0x01, 0x7E, 0x17, 0xC2, 0x00, 0x01, 0xFF, 0x5F, 0x16, 0x00, 0x21, 0x48, 0x01, 0x19,
1839    ///                 0x19, 0x4E, 0x79, 0x23, 0x46, 0x23, 0x96, 0x57, 0x78, 0x23, 0x9E, 0xDA, 0x3F, 0x01, 0xB2, 0xCA,
1840    ///                 0x3F, 0x01, 0x56, 0x70, 0x2B, 0x5E, 0x71, 0x2B, 0x72, 0x2B, 0x73, 0x21, 0x46, 0x01, 0x34, 0x21];
1841    ///
1842    ///     assert!(binfile.add_bytes(data, Some(0x100), false).is_ok());
1843    ///     println!("{}", binfile.info());
1844    ///     Ok(())
1845    /// }
1846    /// ```
1847    pub fn info(&self) -> String {
1848        let mut info = String::new();
1849        if let Some(header) = self.header.as_ref() {
1850            info += format!(
1851                "Header:                  \"{}\"\n",
1852                String::from_utf8(header.to_vec()).unwrap()
1853            )
1854            .as_str()
1855        }
1856        if let Some(execution_start_address) = self.execution_start_address {
1857            info += format!(
1858                "Execution start address: 0x{:08x}\n",
1859                execution_start_address
1860            )
1861            .as_str()
1862        }
1863        info += "Data ranges:\n\n";
1864        for segment in self.segments() {
1865            let minimum_address = segment.minimum_address();
1866            let size = segment.len();
1867            let maximum_address = minimum_address + size;
1868            info += format!(
1869                "    0x{:08x} - 0x{:08x} ({})\n",
1870                minimum_address,
1871                maximum_address,
1872                ByteSize(size as u64)
1873            )
1874            .as_str();
1875        }
1876        info
1877    }
1878
1879    /// Return the memory layout as a string.
1880    ///
1881    /// # Examples
1882    ///
1883    /// ```rust
1884    /// use bin_file::BinFile;
1885    /// use bin_file::Error;
1886    ///
1887    /// fn main() -> Result<(), Error> {
1888    ///     let mut binfile = BinFile::new();
1889    ///     let data = [0x21, 0x46, 0x01, 0x36, 0x01, 0x21, 0x47, 0x01, 0x36, 0x00, 0x7E, 0xFE, 0x09, 0xD2, 0x19, 0x01,
1890    ///                 0x21, 0x46, 0x01, 0x7E, 0x17, 0xC2, 0x00, 0x01, 0xFF, 0x5F, 0x16, 0x00, 0x21, 0x48, 0x01, 0x19,
1891    ///                 0x19, 0x4E, 0x79, 0x23, 0x46, 0x23, 0x96, 0x57, 0x78, 0x23, 0x9E, 0xDA, 0x3F, 0x01, 0xB2, 0xCA,
1892    ///                 0x3F, 0x01, 0x56, 0x70, 0x2B, 0x5E, 0x71, 0x2B, 0x72, 0x2B, 0x73, 0x21, 0x46, 0x01, 0x34, 0x21];
1893    ///
1894    ///     assert!(binfile.add_bytes(data, Some(0x100), false).is_ok());
1895    ///     println!("{}", binfile.layout()?);
1896    ///     Ok(())
1897    /// }
1898    /// ```
1899    ///
1900    /// ```console
1901    /// 0x100                                                      0x140
1902    /// ================================================================
1903    /// ```
1904    pub fn layout(&self) -> Result<String, Error> {
1905        if let (Some(minimum_address), Some(maximum_address)) =
1906            (self.minimum_address(), self.maximum_address())
1907        {
1908            let size = maximum_address - minimum_address;
1909            let width = min(80, size);
1910            let mut chunk_address = minimum_address;
1911            let chunk_size = size / width;
1912            let minimum_address = format!("0x{:x}", minimum_address);
1913            let maximum_address = format!("0x{:x}", maximum_address);
1914            let padding = " ".repeat(width - minimum_address.len() - maximum_address.len());
1915            let mut output = format!("{}{}{}\n", minimum_address, padding, maximum_address);
1916            for i in 0..width {
1917                let mut chunk = BinFile::try_from(self)?;
1918
1919                let maximum_address = if i < width - 1 {
1920                    chunk_address + chunk_size
1921                } else {
1922                    chunk.maximum_address().unwrap()
1923                };
1924                chunk.crop(chunk_address..maximum_address)?;
1925
1926                if chunk.is_empty() {
1927                    output += " ";
1928                } else if chunk.len() != maximum_address - chunk_address {
1929                    output += "-";
1930                } else {
1931                    output += "=";
1932                }
1933                chunk_address += chunk_size;
1934            }
1935            Ok(output)
1936        } else {
1937            Ok("Empty File".into())
1938        }
1939    }
1940}
1941
1942impl Default for BinFile {
1943    fn default() -> Self {
1944        Self::new()
1945    }
1946}
1947
1948impl TryFrom<PathBuf> for BinFile {
1949    type Error = Error;
1950
1951    fn try_from(file_name: PathBuf) -> Result<Self, Self::Error> {
1952        Self::from_file(file_name)
1953    }
1954}
1955
1956impl TryFrom<&PathBuf> for BinFile {
1957    type Error = Error;
1958
1959    fn try_from(file_name: &PathBuf) -> Result<Self, Self::Error> {
1960        Self::from_file(file_name)
1961    }
1962}
1963
1964impl TryFrom<&Path> for BinFile {
1965    type Error = Error;
1966
1967    fn try_from(file_name: &Path) -> Result<Self, Self::Error> {
1968        Self::from_file(file_name)
1969    }
1970}
1971
1972impl TryFrom<&BinFile> for BinFile {
1973    type Error = Error;
1974    fn try_from(value: &BinFile) -> Result<Self, Self::Error> {
1975        let mut binfile = BinFile::new();
1976        binfile.add_srec(value.to_srec(None, SRecordAddressLength::default())?, false)?;
1977        Ok(binfile)
1978    }
1979}
1980
1981impl Add for BinFile {
1982    type Output = Self;
1983
1984    fn add(self, rhs: Self) -> Self::Output {
1985        let mut binfile = self;
1986        let _ = binfile.add_srec(
1987            rhs.to_srec(None, SRecordAddressLength::default()).unwrap(),
1988            false,
1989        );
1990        binfile
1991    }
1992}
1993
1994impl AddAssign for BinFile {
1995    fn add_assign(&mut self, rhs: Self) {
1996        let _ = self.add_srec(
1997            rhs.to_srec(None, SRecordAddressLength::default()).unwrap(),
1998            false,
1999        );
2000    }
2001}
2002
2003impl Add<&[String]> for BinFile {
2004    type Output = Self;
2005
2006    fn add(self, rhs: &[String]) -> Self::Output {
2007        let mut binfile = self;
2008        let _ = binfile.add_strings(rhs, false);
2009        binfile
2010    }
2011}
2012
2013impl AddAssign<&[String]> for BinFile {
2014    fn add_assign(&mut self, rhs: &[String]) {
2015        let _ = self.add_strings(rhs, false);
2016    }
2017}
2018
2019impl Display for BinFile {
2020    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2021        write!(f, "{}", self.segments)
2022    }
2023}
2024
2025impl Read for BinFile {
2026    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
2027        if self.is_empty() {
2028            Ok(0)
2029        } else {
2030            let minimum_address = max(self.minimum_address().unwrap(), self.cursor);
2031            let max_buffer_address = minimum_address + buf.len();
2032            if max_buffer_address < self.maximum_address().unwrap() {
2033                self.cursor = max_buffer_address;
2034            } else {
2035                self.cursor = 0;
2036            }
2037            let maximum_address = min(max_buffer_address, self.maximum_address().unwrap());
2038            match self.to_bytes(minimum_address..maximum_address, None) {
2039                Ok(values) => {
2040                    for (pos, val) in values.iter().enumerate() {
2041                        buf[pos] = *val;
2042                    }
2043                    Ok(maximum_address - minimum_address)
2044                }
2045                Err(err) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, err)),
2046            }
2047        }
2048    }
2049}
2050
2051impl Write for BinFile {
2052    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
2053        match self.add_bytes(buf, None, false) {
2054            Ok(_) => Ok(buf.len()),
2055            Err(err) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, err)),
2056        }
2057    }
2058
2059    fn flush(&mut self) -> std::io::Result<()> {
2060        Ok(())
2061    }
2062}
2063
2064impl FromStr for BinFile {
2065    type Err = Error;
2066
2067    fn from_str(s: &str) -> Result<Self, Self::Err> {
2068        let mut binfile = BinFile {
2069            header: None,
2070            execution_start_address: None,
2071            segments: Segments::new(),
2072            cursor: 0,
2073        };
2074        let lines: Vec<&str> = s.lines().collect();
2075        binfile.add_strings(lines, false)?;
2076        Ok(binfile)
2077    }
2078}
2079
2080fn comment_remover(data: &str) -> String {
2081    let regex =
2082        regex::RegexBuilder::new(r#"//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*""#)
2083            .dot_matches_new_line(true)
2084            .multi_line(true)
2085            .build()
2086            .unwrap();
2087    let replacer = |caps: &Captures| -> String {
2088        let s = caps.get(0).unwrap();
2089        if s.as_str().starts_with('/') {
2090            " ".to_string()
2091        } else {
2092            s.as_str().to_string()
2093        }
2094    };
2095    regex.replace_all(data, &replacer).to_string()
2096}
2097
2098fn is_verilog_vmem<T, S>(data: T) -> bool
2099where
2100    T: AsRef<[S]>,
2101    S: AsRef<str>,
2102{
2103    BinFile {
2104        header: None,
2105        execution_start_address: None,
2106        segments: Segments::new(),
2107        cursor: 0,
2108    }
2109    .add_verilog_vmem(data, false)
2110    .is_ok()
2111}
2112
2113fn is_ti_txt<T, S>(data: T) -> bool
2114where
2115    T: AsRef<[S]>,
2116    S: AsRef<str>,
2117{
2118    BinFile {
2119        header: None,
2120        execution_start_address: None,
2121        segments: Segments::new(),
2122        cursor: 0,
2123    }
2124    .add_ti_txt(data, false)
2125    .is_ok()
2126}
2127
2128#[cfg(test)]
2129mod tests {
2130
2131    use super::*;
2132
2133    fn open_text_file(file_name: &str) -> Vec<String> {
2134        let file = File::open(file_name).unwrap();
2135        let reader = BufReader::new(file);
2136        let data: Vec<String> = reader.lines().map_while(Result::ok).collect();
2137        data
2138    }
2139
2140    fn open_binary_file(file_name: &str) -> Vec<u8> {
2141        let mut file = File::open(file_name).unwrap();
2142        let metadata = metadata(file_name).unwrap();
2143        let mut data: Vec<u8> = vec![0; metadata.len() as usize];
2144        let n = file.read(&mut data);
2145        data[..n.unwrap()].to_vec()
2146    }
2147
2148    #[test]
2149    fn it_works() {
2150        let binfile = BinFile::new();
2151        print!("{}", binfile.info())
2152    }
2153
2154    #[test]
2155    fn it_fails_with_report() {
2156        let mut binfile = BinFile::new();
2157        assert!(binfile
2158            .add_binary_file("/dev/this surely doesnt exist", None, false)
2159            .is_err())
2160    }
2161
2162    #[test]
2163    fn test_srec() {
2164        let data = open_text_file("tests/in.s19");
2165        let mut binfile = BinFile::new();
2166        assert!(binfile.add_srec(&data, false).is_ok());
2167        assert_eq!(
2168            binfile
2169                .to_srec(Some(28), SRecordAddressLength::Length16)
2170                .unwrap(),
2171            data
2172        );
2173
2174        let data = open_binary_file("tests/empty_main.bin");
2175        let mut binfile = BinFile::new();
2176        assert!(binfile.add_srec_file("tests/empty_main.s19", false).is_ok());
2177        let mut binfile2 = BinFile::new();
2178        assert!(binfile2
2179            .add_srec_file("tests/empty_main.s19", false)
2180            .is_ok());
2181        assert!(binfile2
2182            .add_srec_file("tests/empty_main_rearranged.s19", true)
2183            .is_ok());
2184        assert_eq!(binfile.to_bytes(.., Some(0x00)).unwrap().len(), data.len());
2185        assert_eq!(binfile.to_bytes(.., Some(0x00)).unwrap(), data);
2186        assert_eq!(binfile2.to_bytes(.., Some(0x00)).unwrap().len(), data.len());
2187        assert_eq!(binfile2.to_bytes(.., Some(0x00)).unwrap(), data);
2188
2189        let mut binfile = BinFile::new();
2190        let res = binfile.add_srec_file("tests/bad_crc.s19", false);
2191        assert!(res.is_err());
2192        assert_eq!(res, Err(Error::ChecksumMismatch(0x22, 0x25)));
2193    }
2194
2195    #[test]
2196    fn test_ti_txt() {
2197        let data = open_text_file("tests/in.s19.txt");
2198        let mut binfile = BinFile::new();
2199        assert!(binfile.add_ti_txt(&data, false).is_ok());
2200        assert_eq!(binfile.to_ti_txt().unwrap(), data);
2201
2202        let data = open_binary_file("tests/empty_main.bin");
2203        let mut binfile = BinFile::new();
2204        assert!(binfile
2205            .add_ti_txt_file("tests/empty_main.s19.txt", false)
2206            .is_ok());
2207        let mut binfile2 = BinFile::new();
2208        assert!(binfile2
2209            .add_ti_txt_file("tests/empty_main.s19.txt", false)
2210            .is_ok());
2211        assert!(binfile2
2212            .add_ti_txt_file("tests/empty_main_rearranged.s19.txt", true)
2213            .is_ok());
2214        assert_eq!(binfile.to_bytes(.., Some(0x00)).unwrap().len(), data.len());
2215        assert_eq!(binfile.to_bytes(.., Some(0x00)).unwrap(), data);
2216        assert_eq!(binfile2.to_bytes(.., Some(0x00)).unwrap().len(), data.len());
2217        assert_eq!(binfile2.to_bytes(.., Some(0x00)).unwrap(), data);
2218
2219        let empty = BinFile::new();
2220        let mut binfile = BinFile::new();
2221        assert!(binfile.add_ti_txt_file("tests/empty.txt", false).is_ok());
2222        assert_eq!(empty.to_ti_txt(), binfile.to_ti_txt());
2223    }
2224
2225    #[test]
2226    fn test_bad_ti_txt() {
2227        let datas = [
2228            (
2229                "bad_ti_txt_address_value.txt",
2230                Error::ContainsInvalidCharacters,
2231            ),
2232            ("bad_ti_txt_bad_q.txt", Error::UnsupportedFileFormat),
2233            (
2234                "bad_ti_txt_data_value.txt",
2235                Error::ContainsInvalidCharacters,
2236            ),
2237            ("bad_ti_txt_record_short.txt", Error::MissingStartCode),
2238            ("bad_ti_txt_record_long.txt", Error::RecordTooLong),
2239            ("bad_ti_txt_no_offset.txt", Error::MissingStartCode),
2240            ("bad_ti_txt_no_q.txt", Error::UnsupportedFileFormat),
2241            ("bad_ti_txt_blank_line.txt", Error::RecordTooShort),
2242        ];
2243        for (filename, error) in datas {
2244            let mut binfile = BinFile::new();
2245            let res = binfile.add_ti_txt_file(format!("tests/{}", filename), false);
2246            assert_eq!(res, Err(error), "Testing: {}", filename);
2247        }
2248    }
2249
2250    #[test]
2251    fn test_compare_ti_txt() {
2252        let filenames = [
2253            "in.s19",
2254            "empty_main.s19",
2255            "convert.s19",
2256            "out.s19",
2257            //            "non_sorted_segments.s19",
2258            "non_sorted_segments_merged_and_sorted.s19",
2259            "in.hex",
2260            "empty_main.hex",
2261            "convert.hex",
2262            "out.hex",
2263        ];
2264
2265        for file_1 in filenames {
2266            let file_2 = format!("{}.txt", file_1);
2267            let mut binfile1 = BinFile::new();
2268            let mut binfile2 = BinFile::new();
2269            let res1 = binfile1.add_file(format!("tests/{}", file_1), false);
2270
2271            assert_eq!(
2272                res1.is_ok(),
2273                binfile2
2274                    .add_file(format!("tests/{}", file_2), false)
2275                    .is_ok(),
2276                "Testing: {}",
2277                file_1
2278            );
2279            assert_eq!(
2280                binfile1.to_ti_txt(),
2281                binfile2.to_ti_txt(),
2282                "Testing: {}",
2283                file_1
2284            )
2285        }
2286    }
2287
2288    #[test]
2289    fn test_hex() {
2290        let data = open_text_file("tests/in.hex");
2291        let mut binfile = BinFile::new();
2292        assert!(binfile.add_ihex(&data, false).is_ok());
2293        assert_eq!(binfile.to_ihex(None, IHexFormat::default()).unwrap(), data);
2294
2295        let mut binfile = BinFile::new();
2296        assert!(binfile.add_ihex_file("tests/in.hex", false).is_ok());
2297        assert!(binfile.add_ihex_file("tests/in.hex", true).is_ok());
2298        assert_eq!(binfile.to_ihex(None, IHexFormat::default()).unwrap(), data);
2299    }
2300
2301    #[test]
2302    fn test_i8hex() {
2303        let mut binfile = BinFile::new();
2304
2305        let data = [
2306            ":0100000001FE".to_string(),
2307            ":0101000002FC".to_string(),
2308            ":01FFFF0003FE".to_string(),
2309            // Will not be part of I8HEX output.
2310            ":0400000300000000F9".to_string(),
2311            ":00000001FF".to_string(),
2312        ];
2313        assert!(binfile.add_ihex(&data, false).is_ok());
2314        assert_eq!(binfile.segments().len(), 3);
2315        assert_eq!(binfile.segments()[0].get_tuple(), (0, &vec![0x01]));
2316        assert_eq!(binfile.segments()[1].get_tuple(), (0x100, &vec![0x02]));
2317        assert_eq!(binfile.segments()[2].get_tuple(), (0xffff, &vec![0x03]));
2318        let data_exp = [
2319            ":0100000001FE".to_string(),
2320            ":0101000002FC".to_string(),
2321            ":01FFFF0003FE".to_string(),
2322            ":00000001FF".to_string(),
2323        ];
2324        assert_eq!(
2325            binfile.to_ihex(None, IHexFormat::IHex8),
2326            Ok(data_exp.to_vec())
2327        );
2328    }
2329
2330    #[test]
2331    fn test_i8hex_address_above_64k() {
2332        let mut binfile = BinFile::new();
2333
2334        assert!(binfile.add_bytes([0x00], Some(65536), false).is_ok());
2335        let res = binfile.to_ihex(None, IHexFormat::IHex8);
2336        assert_eq!(res, Err(Error::AddressTooBig));
2337    }
2338
2339    #[test]
2340    fn test_i16hex() {
2341        let mut binfile = BinFile::new();
2342
2343        let data = [
2344            ":0100000001FE".to_string(),
2345            ":01F00000020D".to_string(),
2346            ":01FFFF0003FE".to_string(),
2347            ":02000002C0003C".to_string(),
2348            ":0110000005EA".to_string(),
2349            ":02000002FFFFFE".to_string(),
2350            ":0100000006F9".to_string(),
2351            ":01FFFF0007FA".to_string(),
2352            ":020000021000EC".to_string(),
2353            ":0100000004FB".to_string(),
2354            // Coverted to 03 in I16HEX output
2355            ":0400000500000000F7".to_string(),
2356            ":00000001FF".to_string(),
2357        ];
2358        assert!(binfile.add_ihex(&data, false).is_ok());
2359        assert_eq!(binfile.segments().len(), 6);
2360        assert_eq!(binfile.segments()[0].get_tuple(), (0, &vec![0x01]));
2361        assert_eq!(binfile.segments()[1].get_tuple(), (0xf000, &vec![0x02]));
2362        assert_eq!(
2363            binfile.segments()[2].get_tuple(),
2364            (0xffff, &vec![0x03, 0x04])
2365        );
2366        assert_eq!(
2367            binfile.segments()[3].get_tuple(),
2368            (16 * 0xc000 + 0x1000, &vec![0x05])
2369        );
2370        assert_eq!(
2371            binfile.segments()[4].get_tuple(),
2372            (16 * 0xffff, &vec![0x06])
2373        );
2374        assert_eq!(
2375            binfile.segments()[5].get_tuple(),
2376            (17 * 0xffff, &vec![0x07])
2377        );
2378        let data_exp = [
2379            ":0100000001FE".to_string(),
2380            ":01F00000020D".to_string(),
2381            ":02FFFF000304F9".to_string(),
2382            ":02000002C0003C".to_string(),
2383            ":0110000005EA".to_string(),
2384            ":02000002F0000C".to_string(),
2385            ":01FFF000060A".to_string(),
2386            ":02000002FFFFFE".to_string(),
2387            ":01FFFF0007FA".to_string(),
2388            ":0400000300000000F9".to_string(),
2389            ":00000001FF".to_string(),
2390        ];
2391        assert_eq!(
2392            binfile.to_ihex(None, IHexFormat::IHex16),
2393            Ok(data_exp.to_vec())
2394        );
2395    }
2396
2397    #[test]
2398    fn test_i16hex_address_above_1meg() {
2399        let mut binfile = BinFile::new();
2400
2401        assert!(binfile
2402            .add_bytes([0x00], Some(17 * 65535 + 1), false)
2403            .is_ok());
2404        let res = binfile.to_ihex(None, IHexFormat::IHex16);
2405        assert_eq!(res, Err(Error::AddressTooBig));
2406    }
2407
2408    #[test]
2409    fn test_i32hex() {
2410        let mut binfile = BinFile::new();
2411
2412        let data = [
2413            ":0100000001FE".to_string(),
2414            ":01FFFF0002FF".to_string(),
2415            ":02000004FFFFFC".to_string(),
2416            ":0100000004FB".to_string(),
2417            ":01FFFF0005FC".to_string(),
2418            ":020000040001F9".to_string(),
2419            ":0100000003FC".to_string(),
2420            ":0400000500000000F7".to_string(),
2421            ":00000001FF".to_string(),
2422        ];
2423        assert!(binfile.add_ihex(&data, false).is_ok());
2424        let data_exp = [
2425            ":0100000001FE".to_string(),
2426            ":02FFFF000203FB".to_string(),
2427            ":02000004FFFFFC".to_string(),
2428            ":0100000004FB".to_string(),
2429            ":01FFFF0005FC".to_string(),
2430            ":0400000500000000F7".to_string(),
2431            ":00000001FF".to_string(),
2432        ];
2433        assert_eq!(
2434            binfile.to_ihex(None, IHexFormat::IHex32),
2435            Ok(data_exp.to_vec())
2436        );
2437        assert_eq!(binfile.minimum_address(), Some(0));
2438        assert_eq!(binfile.maximum_address(), Some(0x100000000));
2439        assert_eq!(binfile.execution_start_address(), Some(0));
2440        assert_eq!(binfile.get_value_by_address(0), Some(1));
2441        assert_eq!(binfile.get_value_by_address(0xffff), Some(2));
2442        assert_eq!(binfile.get_value_by_address(0x10000), Some(3));
2443        assert_eq!(binfile.get_value_by_address(0xffff0000), Some(4));
2444        assert_eq!(binfile.get_value_by_address(0xffff0002), None);
2445        assert_eq!(binfile.get_value_by_address(0xffff0004), None);
2446        assert_eq!(binfile.get_value_by_address(0xffffffff), Some(0x05));
2447    }
2448
2449    #[test]
2450    fn test_i32hex_address_above_4gig() {
2451        let mut binfile = BinFile::new();
2452
2453        assert!(binfile.add_bytes([0x00], Some(0x100000000), false).is_ok());
2454        let res = binfile.to_ihex(None, IHexFormat::IHex32);
2455        assert_eq!(res, Err(Error::AddressTooBig));
2456    }
2457
2458    #[test]
2459    fn test_binary() {
2460        let data = open_binary_file("tests/binary1.bin");
2461        let mut binfile = BinFile::new();
2462        assert!(binfile.add_bytes(&data, None, false).is_ok());
2463        assert_eq!(binfile.to_bytes(.., None), Ok(data));
2464
2465        // Add and overwrite data to 15..179
2466        let mut binfile = BinFile::new();
2467        assert!(binfile
2468            .add_binary_file("tests/binary2.bin", Some(15), false)
2469            .is_ok());
2470        assert!(binfile
2471            .add_binary_file("tests/binary2.bin", Some(15), true)
2472            .is_ok());
2473        let data = open_binary_file("tests/binary2.bin");
2474        assert_eq!(
2475            binfile.add_bytes(&data, Some(20), false),
2476            Err(Error::AddDataError),
2477        );
2478
2479        // Exclude the overlapping part and add
2480        assert!(binfile.exclude(20..1024).is_ok());
2481        assert!(binfile.add_bytes(&data, Some(20), false).is_ok());
2482
2483        let mut data = open_binary_file("tests/binary3.bin");
2484        assert_eq!(binfile.to_bytes(0.., Some(0x00)), Ok(data.clone()));
2485
2486        // Exclude first byte and read it to test adjecent add before
2487        assert!(binfile.exclude(0..1).is_ok());
2488        assert!(binfile.add_bytes([1], None, false).is_ok());
2489        let first = data.first_mut().unwrap();
2490        *first = 1;
2491        assert_eq!(binfile.to_bytes(0.., Some(0x00)), Ok(data.clone()));
2492
2493        // Basic checks
2494        assert_eq!(binfile.minimum_address(), Some(0));
2495        assert_eq!(binfile.maximum_address(), Some(184));
2496        assert_eq!(binfile.len(), 170);
2497
2498        // Dump with start address beyond end of binary
2499        assert_eq!(binfile.to_bytes(512.., None), Ok(vec![]));
2500
2501        // Dump with start address at maximum address
2502        assert_eq!(binfile.to_bytes(184.., None), Ok(vec![]));
2503
2504        // Dump with start address one before maximum address
2505        assert_eq!(binfile.to_bytes(183.., None), Ok(vec![10]));
2506
2507        // Dump with start address one after minimum address
2508        assert_eq!(binfile.to_bytes(1.., Some(0)), Ok(data[1..].to_vec()));
2509
2510        // Dump with start address 16 and end address 18
2511        assert_eq!(binfile.to_bytes(16..18, None), Ok(vec![0x32, 0x30]));
2512
2513        // Dump with start address and end address 16
2514        assert_eq!(binfile.to_bytes(16..16, None), Ok(vec![]));
2515
2516        // Dump with end beyond end of binary
2517        assert_eq!(binfile.to_bytes(..1024, Some(0)), Ok(data));
2518
2519        // Dump with end before start
2520        assert_eq!(binfile.to_bytes(2..0, None), Ok(vec![]));
2521    }
2522
2523    #[test]
2524    fn test_add() {
2525        let mut binfile = BinFile::new();
2526        let data = open_text_file("tests/in.s19");
2527        let binfile_2 = binfile.clone() + data.as_slice();
2528        binfile += data.as_slice();
2529        assert_eq!(
2530            binfile.to_srec(Some(28), SRecordAddressLength::Length16),
2531            Ok(data.clone())
2532        );
2533        assert_eq!(
2534            binfile_2.to_srec(Some(28), SRecordAddressLength::Length16),
2535            Ok(data)
2536        );
2537
2538        let mut binfile = BinFile::new();
2539        let data = open_text_file("tests/in.hex");
2540        binfile += data.as_slice();
2541        assert_eq!(binfile.to_ihex(None, IHexFormat::default()), Ok(data));
2542    }
2543
2544    #[test]
2545    fn test_add_strings() {
2546        let mut binfile = BinFile::new();
2547        let data = open_text_file("tests/in.s19");
2548        assert!(binfile.add_strings(data.as_slice(), false).is_ok());
2549        assert_eq!(
2550            binfile.to_srec(Some(28), SRecordAddressLength::Length16),
2551            Ok(data)
2552        );
2553
2554        let mut binfile = BinFile::new();
2555        let data = open_text_file("tests/in.hex");
2556        assert!(binfile.add_strings(data.as_slice(), false).is_ok());
2557        assert_eq!(binfile.to_ihex(None, IHexFormat::default()), Ok(data));
2558
2559        let mut binfile = BinFile::new();
2560        let res = binfile.add_strings(["invalid data"], false);
2561        assert_eq!(res, Err(Error::UnsupportedFileFormat));
2562
2563        let mut binfile = BinFile::new();
2564        let res = binfile.add_strings(
2565            [
2566                "S214400420ED044000E8B7FFFFFFF4660F1F440000EE",
2567                "invalid data",
2568            ],
2569            false,
2570        );
2571        assert_eq!(res, Err(Error::MissingStartCode));
2572
2573        let mut binfile = BinFile::new();
2574        let res = binfile.add_strings([":020000040040BA", "invalid data"], false);
2575        assert_eq!(res, Err(Error::MissingStartCode));
2576    }
2577
2578    #[test]
2579    fn test_add_file() {
2580        let mut binfile = BinFile::new();
2581        assert!(binfile
2582            .add_file("tests/empty_main_rearranged.s19", false)
2583            .is_ok());
2584        let data = open_binary_file("tests/empty_main.bin");
2585        assert_eq!(binfile.to_bytes(.., Some(0x00)), Ok(data));
2586
2587        let mut binfile = BinFile::new();
2588        assert!(binfile.add_file("tests/in.hex", false).is_ok());
2589        let data = open_text_file("tests/in.hex");
2590        assert_eq!(binfile.to_ihex(None, IHexFormat::default()), Ok(data));
2591
2592        let mut binfile = BinFile::new();
2593        assert_eq!(
2594            binfile.add_file("tests/hexdump.txt", false),
2595            Err(Error::UnsupportedFileFormat)
2596        );
2597    }
2598
2599    #[test]
2600    fn test_from_file() {
2601        let binfile = BinFile::from_file("tests/empty_main_rearranged.s19").unwrap();
2602        let data = open_binary_file("tests/empty_main.bin");
2603        assert_eq!(binfile.to_bytes(.., Some(0x00)), Ok(data));
2604
2605        assert_eq!(
2606            BinFile::from_file("tests/hexdump.txt").err(),
2607            Some(Error::UnsupportedFileFormat)
2608        );
2609
2610        let binfile =
2611            BinFile::try_from(PathBuf::from("tests/empty_main_rearranged.s19").as_path()).unwrap();
2612        let data = open_binary_file("tests/empty_main.bin");
2613        assert_eq!(binfile.to_bytes(.., Some(0x00)), Ok(data));
2614
2615        assert_eq!(
2616            BinFile::from_file("tests/hexdump.txt").err(),
2617            Some(Error::UnsupportedFileFormat)
2618        );
2619    }
2620
2621    #[test]
2622    fn test_from_files() {
2623        let binfile = BinFile::from_files(["tests/in.hex", "tests/in.hex"], true).unwrap();
2624        let data = open_text_file("tests/in.hex");
2625        assert_eq!(binfile.to_ihex(None, IHexFormat::default()), Ok(data));
2626    }
2627
2628    #[test]
2629    fn test_array() {
2630        let mut binfile = BinFile::new();
2631        assert!(binfile.add_ihex_file("tests/in.hex", false).is_ok());
2632        let data = open_text_file("tests/in.i");
2633        assert_eq!(binfile.to_array_str(.., None, None), Ok(data[0].to_owned()));
2634    }
2635
2636    #[test]
2637    fn test_hexdump_1() {
2638        let mut binfile = BinFile::new();
2639        assert!(binfile.add_bytes("12".as_bytes(), Some(17), false).is_ok());
2640        assert!(binfile.add_bytes("34".as_bytes(), Some(26), false).is_ok());
2641        assert!(binfile
2642            .add_bytes("5678".as_bytes(), Some(30), false)
2643            .is_ok());
2644        assert!(binfile.add_bytes("9".as_bytes(), Some(47), false).is_ok());
2645        let data = open_text_file("tests/hexdump.txt");
2646        assert_eq!(binfile.to_hexdump(), Ok(data));
2647    }
2648
2649    #[test]
2650    fn test_hexdump_2() {
2651        let mut binfile = BinFile::new();
2652        assert!(binfile
2653            .add_bytes("34".as_bytes(), Some(0x150), false)
2654            .is_ok());
2655        assert!(binfile
2656            .add_bytes("3".as_bytes(), Some(0x163), false)
2657            .is_ok());
2658        assert!(binfile.add_bytes([0x01], Some(0x260), false).is_ok());
2659        assert!(binfile
2660            .add_bytes("3".as_bytes(), Some(0x263), false)
2661            .is_ok());
2662        let data = open_text_file("tests/hexdump2.txt");
2663        assert_eq!(binfile.to_hexdump(), Ok(data));
2664    }
2665
2666    #[test]
2667    fn test_hexdump_gaps() {
2668        let mut binfile = BinFile::new();
2669        assert!(binfile.add_bytes("1".as_bytes(), Some(0), false).is_ok());
2670        assert!(binfile.add_bytes("3".as_bytes(), Some(32), false).is_ok());
2671        assert!(binfile.add_bytes("6".as_bytes(), Some(80), false).is_ok());
2672        let data = open_text_file("tests/hexdump3.txt");
2673        assert_eq!(binfile.to_hexdump(), Ok(data));
2674    }
2675
2676    #[test]
2677    fn test_hexdump_empty() {
2678        let binfile = BinFile::new();
2679        assert_eq!(binfile.to_hexdump(), Ok(vec![]));
2680    }
2681
2682    #[test]
2683    fn test_srec_ihex_binary() {
2684        let mut binfile = BinFile::new();
2685        let data = open_text_file("tests/in.hex");
2686        assert!(binfile.add_ihex(data, false).is_ok());
2687        let data = open_text_file("tests/in.s19");
2688        assert!(binfile.add_srec(data, false).is_ok());
2689        let data = open_binary_file("tests/binary1.bin");
2690        assert!(binfile.add_bytes(data, Some(1024), false).is_ok());
2691        let data = open_text_file("tests/out.hex");
2692        assert_eq!(binfile.to_ihex(None, IHexFormat::default()), Ok(data));
2693        let data = open_text_file("tests/out.s19");
2694        assert_eq!(
2695            binfile.to_srec(None, SRecordAddressLength::Length16),
2696            Ok(data)
2697        );
2698        assert!(binfile.fill(Some(0x00), None).is_ok());
2699        let data = open_binary_file("tests/out.bin");
2700        assert_eq!(binfile.to_bytes(.., None), Ok(data));
2701    }
2702
2703    #[test]
2704    fn test_exclude() {
2705        let mut binfile = BinFile::new();
2706        assert!(binfile.add_file("tests/in.s19", false).is_ok());
2707        assert!(binfile.exclude(2..4).is_ok());
2708        let data = open_text_file("tests/in_exclude_2_4.s19");
2709        assert_eq!(
2710            binfile.to_srec(Some(32), SRecordAddressLength::Length16),
2711            Ok(data)
2712        );
2713
2714        let mut binfile = BinFile::new();
2715        assert!(binfile.add_file("tests/in.s19", false).is_ok());
2716        assert!(binfile.exclude(3..1024).is_ok());
2717        let data = open_text_file("tests/in_exclude_3_1024.s19");
2718        assert_eq!(
2719            binfile.to_srec(Some(32), SRecordAddressLength::Length16),
2720            Ok(data)
2721        );
2722
2723        let mut binfile = BinFile::new();
2724        assert!(binfile.add_file("tests/in.s19", false).is_ok());
2725        assert!(binfile.exclude(0..9).is_ok());
2726        let data = open_text_file("tests/in_exclude_0_9.s19");
2727        assert_eq!(
2728            binfile.to_srec(Some(32), SRecordAddressLength::Length16),
2729            Ok(data)
2730        );
2731
2732        let mut binfile = BinFile::new();
2733        assert!(binfile.add_file("tests/empty_main.s19", false).is_ok());
2734        assert!(binfile.exclude(0x400240..0x400600).is_ok());
2735        let data = open_binary_file("tests/empty_main_mod.bin");
2736        assert_eq!(binfile.to_bytes(.., Some(0x00)), Ok(data));
2737
2738        let mut binfile = BinFile::new();
2739        assert!(binfile
2740            .add_bytes("111111".as_bytes(), Some(8), false)
2741            .is_ok());
2742        assert!(binfile
2743            .add_bytes("222222".as_bytes(), Some(16), false)
2744            .is_ok());
2745        assert!(binfile
2746            .add_bytes("333333".as_bytes(), Some(24), false)
2747            .is_ok());
2748        assert!(binfile.exclude(7..8).is_ok());
2749        assert!(binfile.exclude(15..16).is_ok());
2750        assert!(binfile.exclude(23..24).is_ok());
2751        let data = vec![
2752            "111111".as_bytes().to_owned(),
2753            vec![0xff; 2],
2754            "222222".as_bytes().to_owned(),
2755            vec![0xff; 2],
2756            "333333".as_bytes().to_owned(),
2757        ]
2758        .into_iter()
2759        .flatten()
2760        .collect();
2761        assert_eq!(binfile.to_bytes(.., None), Ok(data));
2762        assert_eq!(binfile.segments().len(), 3);
2763
2764        assert!(binfile.exclude(20..24).is_ok());
2765        let data = vec![
2766            "111111".as_bytes().to_owned(),
2767            vec![0xff; 2],
2768            "2222".as_bytes().to_owned(),
2769            vec![0xff; 4],
2770            "333333".as_bytes().to_owned(),
2771        ]
2772        .into_iter()
2773        .flatten()
2774        .collect();
2775        assert_eq!(binfile.to_bytes(.., None), Ok(data));
2776        assert_eq!(binfile.segments().len(), 3);
2777
2778        assert!(binfile.exclude(12..24).is_ok());
2779        let data = vec![
2780            "1111".as_bytes().to_owned(),
2781            vec![0xff; 12],
2782            "333333".as_bytes().to_owned(),
2783        ]
2784        .into_iter()
2785        .flatten()
2786        .collect();
2787        assert_eq!(binfile.to_bytes(.., None), Ok(data));
2788        assert_eq!(binfile.segments().len(), 2);
2789
2790        assert!(binfile.exclude(11..26).is_ok());
2791        let data = vec![
2792            "111".as_bytes().to_owned(),
2793            vec![0xff; 15],
2794            "3333".as_bytes().to_owned(),
2795        ]
2796        .into_iter()
2797        .flatten()
2798        .collect();
2799        assert_eq!(binfile.to_bytes(.., None), Ok(data));
2800        assert_eq!(binfile.segments().len(), 2);
2801
2802        assert!(binfile.exclude(27..29).is_ok());
2803        let data = vec![
2804            "111".as_bytes().to_owned(),
2805            vec![0xff; 15],
2806            "3".as_bytes().to_owned(),
2807            vec![0xff; 2],
2808            "3".as_bytes().to_owned(),
2809        ]
2810        .into_iter()
2811        .flatten()
2812        .collect();
2813        assert_eq!(binfile.to_bytes(.., None), Ok(data));
2814        assert_eq!(binfile.segments().len(), 3);
2815
2816        let mut binfile = BinFile::new();
2817        assert!(binfile
2818            .add_bytes("111111".as_bytes(), Some(8), false)
2819            .is_ok());
2820        assert_eq!(binfile.exclude(4..2), Err(Error::InvalidAddressRange));
2821
2822        assert!(binfile.exclude(2..2).is_ok());
2823        assert_eq!(
2824            binfile.to_bytes(.., None),
2825            Ok("111111".as_bytes().to_owned())
2826        );
2827    }
2828
2829    #[test]
2830    fn test_crop() {
2831        let mut binfile = BinFile::new();
2832        assert!(binfile.add_file("tests/in.s19", false).is_ok());
2833        assert!(binfile.crop(2..4).is_ok());
2834        let data = open_text_file("tests/in_crop_2_4.s19");
2835        assert_eq!(
2836            binfile.to_srec(Some(32), SRecordAddressLength::Length16),
2837            Ok(data)
2838        );
2839        assert!(binfile.exclude(2..4).is_ok());
2840        assert_eq!(binfile.to_bytes(.., Some(0x00)), Ok(vec![]));
2841    }
2842
2843    #[test]
2844    fn text_minimum_maximum_length() {
2845        let mut binfile = BinFile::new();
2846
2847        // Get values of an empty file
2848        assert_eq!(binfile.minimum_address(), None);
2849        assert_eq!(binfile.maximum_address(), None);
2850        assert_eq!(binfile.len(), 0);
2851        assert!(binfile.is_empty());
2852
2853        // Read in small file
2854        assert!(binfile.add_file("tests/in.s19", false).is_ok());
2855
2856        assert_eq!(binfile.minimum_address(), Some(0));
2857        assert_eq!(binfile.maximum_address(), Some(70));
2858        assert_eq!(binfile.len(), 70);
2859        assert!(!binfile.is_empty());
2860
2861        // Add second segment
2862        assert!(binfile.add_bytes([0x01; 9], Some(80), false).is_ok());
2863
2864        assert_eq!(binfile.minimum_address(), Some(0));
2865        assert_eq!(binfile.maximum_address(), Some(89));
2866        assert_eq!(binfile.len(), 79);
2867        assert!(!binfile.is_empty());
2868    }
2869
2870    #[test]
2871    fn test_iterate_segments() {
2872        let binfile = BinFile::from_file("tests/in.s19").unwrap();
2873
2874        let mut i = 0;
2875        for _segment in binfile.segments() {
2876            i += 1;
2877        }
2878        assert_eq!(i, 1);
2879        assert_eq!(binfile.segments().len(), 1);
2880    }
2881
2882    #[test]
2883    fn test_segments_list() {
2884        let mut binfile = BinFile::new();
2885
2886        assert!(binfile.add_bytes([0x00], Some(0), false).is_ok());
2887        assert!(binfile.add_bytes([0x01, 0x02], Some(10), false).is_ok());
2888        assert!(binfile.add_bytes([0x03], Some(12), false).is_ok());
2889        assert!(binfile.add_bytes([0x04], Some(1000), false).is_ok());
2890
2891        assert_eq!(
2892            binfile.segments_list(),
2893            vec![
2894                (0, vec![0x00]),
2895                (10, vec![0x01, 0x02, 0x03]),
2896                (1000, vec![0x04]),
2897            ]
2898        )
2899    }
2900
2901    #[test]
2902    fn test_chunks_list() {
2903        let mut binfile = BinFile::new();
2904
2905        assert!(binfile
2906            .add_bytes([0x00, 0x00, 0x01, 0x01, 0x02], Some(0), false)
2907            .is_ok());
2908        assert!(binfile
2909            .add_bytes([0x04, 0x05, 0x05, 0x06, 0x06, 0x07], Some(9), false)
2910            .is_ok());
2911        assert!(binfile.add_bytes([0x09], Some(19), false).is_ok());
2912        assert!(binfile.add_bytes([0x0a], Some(21), false).is_ok());
2913
2914        assert_eq!(
2915            binfile.to_bytes(.., None),
2916            Ok(vec![
2917                0x00, 0x00, 0x01, 0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0x04, 0x05, 0x05, 0x06, 0x06,
2918                0x07, 0xff, 0xff, 0xff, 0xff, 0x09, 0xff, 0x0a
2919            ])
2920        );
2921
2922        // Size 8, alignment 1
2923        let mut data = BTreeMap::new();
2924        data.insert(0, vec![0x00, 0x00, 0x01, 0x01, 0x02]);
2925        data.insert(9, vec![0x04, 0x05, 0x05, 0x06, 0x06, 0x07]);
2926        data.insert(19, vec![0x09]);
2927        data.insert(21, vec![0x0a]);
2928        assert_eq!(binfile.segments().chunks(Some(8), None), Ok(data));
2929
2930        // Size 8, alignment 2
2931        let mut data = BTreeMap::new();
2932        data.insert(0, vec![0x00, 0x00, 0x01, 0x01, 0x02]);
2933        data.insert(9, vec![0x04]);
2934        data.insert(10, vec![0x05, 0x05, 0x06, 0x06, 0x07]);
2935        data.insert(19, vec![0x09]);
2936        data.insert(21, vec![0x0a]);
2937        assert_eq!(binfile.segments().chunks(Some(8), Some(2)), Ok(data));
2938
2939        // Size 8, alignment 4
2940        let mut data = BTreeMap::new();
2941        data.insert(0, vec![0x00, 0x00, 0x01, 0x01, 0x02]);
2942        data.insert(9, vec![0x04, 0x05, 0x05]);
2943        data.insert(12, vec![0x06, 0x06, 0x07]);
2944        data.insert(19, vec![0x09]);
2945        data.insert(21, vec![0x0a]);
2946        assert_eq!(binfile.segments().chunks(Some(8), Some(4)), Ok(data));
2947
2948        // Size 8, alignment 8
2949        let mut data = BTreeMap::new();
2950        data.insert(0, vec![0x00, 0x00, 0x01, 0x01, 0x02]);
2951        data.insert(9, vec![0x04, 0x05, 0x05, 0x06, 0x06, 0x07]);
2952        data.insert(19, vec![0x09]);
2953        data.insert(21, vec![0x0a]);
2954        assert_eq!(binfile.segments().chunks(Some(8), Some(8)), Ok(data));
2955
2956        // Size 4, alignment 1
2957        let mut data = BTreeMap::new();
2958        data.insert(0, vec![0x00, 0x00, 0x01, 0x01]);
2959        data.insert(4, vec![0x02]);
2960        data.insert(9, vec![0x04, 0x05, 0x05, 0x06]);
2961        data.insert(13, vec![0x06, 0x07]);
2962        data.insert(19, vec![0x09]);
2963        data.insert(21, vec![0x0a]);
2964        assert_eq!(binfile.segments().chunks(Some(4), None), Ok(data));
2965
2966        // Size 4, alignment 2
2967        let mut data = BTreeMap::new();
2968        data.insert(0, vec![0x00, 0x00, 0x01, 0x01]);
2969        data.insert(4, vec![0x02]);
2970        data.insert(9, vec![0x04]);
2971        data.insert(10, vec![0x05, 0x05, 0x06, 0x06]);
2972        data.insert(14, vec![0x07]);
2973        data.insert(19, vec![0x09]);
2974        data.insert(21, vec![0x0a]);
2975        assert_eq!(binfile.segments().chunks(Some(4), Some(2)), Ok(data));
2976
2977        // Size 4, alignment 4
2978        let mut data = BTreeMap::new();
2979        data.insert(0, vec![0x00, 0x00, 0x01, 0x01]);
2980        data.insert(4, vec![0x02]);
2981        data.insert(9, vec![0x04, 0x05, 0x05]);
2982        data.insert(12, vec![0x06, 0x06, 0x07]);
2983        data.insert(19, vec![0x09]);
2984        data.insert(21, vec![0x0a]);
2985        assert_eq!(binfile.segments().chunks(Some(4), Some(4)), Ok(data));
2986    }
2987
2988    #[test]
2989    fn test_segment() {
2990        let mut binfile = BinFile::new();
2991        assert!(binfile
2992            .add_bytes([0x00, 0x01, 0x02, 0x03, 0x04], Some(2), false)
2993            .is_ok());
2994
2995        // size 4, alignment 4
2996        let mut data = BTreeMap::new();
2997        data.insert(2, vec![0x00, 0x01]);
2998        data.insert(4, vec![0x02, 0x03, 0x04]);
2999        assert_eq!(binfile.segments()[0].chunks(Some(4), Some(4)), Ok(data));
3000
3001        // Bad argument
3002        assert_eq!(
3003            binfile.segments()[0].chunks(Some(4), Some(8)),
3004            Err(Error::AlignmentToSizeError {
3005                size: 4,
3006                alignment: 8
3007            })
3008        );
3009
3010        // Missing segment
3011        assert!(
3012            std::panic::catch_unwind(|| binfile.segments()[1].chunks(Some(4), Some(4))).is_err()
3013        );
3014    }
3015
3016    #[test]
3017    fn test_add_files() {
3018        let mut binfile = BinFile::new();
3019        assert!(binfile.add_bytes([0], None, false).is_ok());
3020
3021        let mut binfile_1_2 = BinFile::new();
3022        assert!(binfile_1_2.add_bytes([1], Some(1), false).is_ok());
3023
3024        binfile += binfile_1_2;
3025        assert_eq!(binfile.to_bytes(.., None), Ok(vec![0, 1]));
3026    }
3027
3028    #[test]
3029    fn test_info() {
3030        let binfile = BinFile::try_from(PathBuf::from("tests/empty_main.s19")).unwrap();
3031        let data = r#"Header:                  "bincopy/empty_main.s19"
3032Execution start address: 0x00400400
3033Data ranges:
3034
3035    0x00400238 - 0x004002b4 (124 B)
3036    0x004002b8 - 0x0040033e (134 B)
3037    0x00400340 - 0x004003c2 (130 B)
3038    0x004003d0 - 0x00400572 (418 B)
3039    0x00400574 - 0x0040057d (9 B)
3040    0x00400580 - 0x004006ac (300 B)
3041    0x00600e10 - 0x00601038 (552 B)
3042"#;
3043        assert_eq!(binfile.info(), data);
3044    }
3045
3046    #[test]
3047    fn test_layout_empty_main() {
3048        let binfile = BinFile::try_from(PathBuf::from("tests/empty_main.s19")).unwrap();
3049        let data = r###"0x400238                                                                0x601038
3050-                                                                              -"###;
3051        assert_eq!(binfile.layout(), Ok(data.to_string()));
3052    }
3053
3054    #[test]
3055    fn test_layout_out() {
3056        let binfile = BinFile::try_from(PathBuf::from("tests/out.hex")).unwrap();
3057        let data = r###"0x0                                                                        0x403
3058=====-               -====-                                                    -"###;
3059        assert_eq!(binfile.layout(), Ok(data.to_string()));
3060    }
3061
3062    #[test]
3063    fn test_layout_in_exclude_2_4() {
3064        let binfile = BinFile::try_from(PathBuf::from("tests/in_exclude_2_4.s19")).unwrap();
3065        let data = r###"0x0                                                               0x46
3066==  =================================================================="###;
3067        assert_eq!(binfile.layout(), Ok(data.to_string()));
3068    }
3069
3070    #[test]
3071    fn test_execution_start_address() {
3072        let mut binfile = BinFile::try_from(PathBuf::from("tests/empty_main.s19")).unwrap();
3073        assert_eq!(binfile.execution_start_address(), Some(0x00400400));
3074        binfile.set_exexution_start_address(0x00400401);
3075        assert_eq!(binfile.execution_start_address(), Some(0x00400401));
3076    }
3077
3078    #[test]
3079    fn test_add_ihex_record_type_3() {
3080        let mut binfile = BinFile::new();
3081        assert!(binfile.add_ihex([":0400000302030405EB"], false).is_ok());
3082        assert_eq!(binfile.execution_start_address(), Some(0x02030405));
3083    }
3084
3085    #[test]
3086    fn test_add_ihex_record_type_5() {
3087        let mut binfile = BinFile::new();
3088        assert!(binfile.add_ihex([":0400000501020304ED"], false).is_ok());
3089        assert_eq!(binfile.execution_start_address(), Some(0x01020304));
3090    }
3091
3092    #[test]
3093    fn test_add_ihex_record_type_6() {
3094        let mut binfile = BinFile::new();
3095        assert_eq!(
3096            binfile.add_ihex([":00000006FA"], false),
3097            Err(Error::UnsupportedRecordType {
3098                record: ":00000006FA".into(),
3099                record_type: 6
3100            })
3101        );
3102    }
3103
3104    #[test]
3105    fn test_add_to_srec_record_5() {
3106        let mut binfile = BinFile::new();
3107        assert!(binfile.add_bytes([0x00; 65535], None, false).is_ok());
3108        let records = binfile.to_srec(Some(1), SRecordAddressLength::default());
3109        assert!(records.is_ok());
3110        assert_eq!(records.clone().unwrap().len(), 65536);
3111        assert_eq!(records.unwrap().last(), Some(&"S503FFFFFE".to_string()));
3112    }
3113
3114    #[test]
3115    fn test_add_to_srec_record_6() {
3116        let mut binfile = BinFile::new();
3117        assert!(binfile.add_bytes([0x00; 65536], None, false).is_ok());
3118        let records = binfile.to_srec(Some(1), SRecordAddressLength::default());
3119        assert!(records.is_ok());
3120        assert_eq!(records.clone().unwrap().len(), 65537);
3121        assert_eq!(records.unwrap().last(), Some(&"S604010000FA".to_string()));
3122    }
3123
3124    #[test]
3125    fn test_add_to_srec_record_8() {
3126        let mut binfile = BinFile::new();
3127        assert!(binfile.add_bytes([0x00], None, false).is_ok());
3128        binfile.set_exexution_start_address(0x123456);
3129        assert_eq!(
3130            binfile.to_srec(Some(1), SRecordAddressLength::Length24),
3131            Ok(vec![
3132                "S20500000000FA".to_string(),
3133                "S5030001FB".to_string(),
3134                "S8041234565F".to_string()
3135            ])
3136        );
3137    }
3138
3139    #[test]
3140    fn test_issue_4_1() {
3141        let mut binfile = BinFile::new();
3142        assert!(binfile.add_ihex_file("tests/issue_4_in.hex", false).is_ok());
3143        let data = open_text_file("tests/issue_4_out.hex");
3144        assert_eq!(binfile.to_ihex(None, IHexFormat::default()), Ok(data));
3145    }
3146
3147    #[test]
3148    fn test_issue_4_2() {
3149        let mut binfile = BinFile::new();
3150        assert!(binfile.add_srec_file("tests/empty_main.s19", false).is_ok());
3151        let data = open_text_file("tests/empty_main.hex");
3152        assert_eq!(binfile.to_ihex(None, IHexFormat::default()), Ok(data));
3153    }
3154
3155    #[test]
3156    fn test_overwrite() {
3157        let mut binfile = BinFile::new();
3158
3159        // Overwrite in empty file
3160        assert!(binfile
3161            .add_bytes("1234".as_bytes(), Some(512), true)
3162            .is_ok());
3163        assert_eq!(
3164            binfile.to_bytes(512.., None),
3165            Ok("1234".as_bytes().to_vec())
3166        );
3167
3168        // Test setting data with multiple existing segments.
3169        assert!(binfile
3170            .add_bytes("123456".as_bytes(), Some(1024), false)
3171            .is_ok());
3172        assert!(binfile.add_bytes("99".as_bytes(), Some(1026), true).is_ok());
3173        let data = vec![
3174            "1234".as_bytes().to_owned(),
3175            vec![0xff; 508],
3176            "129956".as_bytes().to_owned(),
3177        ]
3178        .into_iter()
3179        .flatten()
3180        .collect();
3181        assert_eq!(binfile.to_bytes(512.., None), Ok(data));
3182
3183        // Test setting data crossing the original segment limits.
3184        assert!(binfile
3185            .add_bytes("abc".as_bytes(), Some(1022), true)
3186            .is_ok());
3187        assert!(binfile
3188            .add_bytes("def".as_bytes(), Some(1029), true)
3189            .is_ok());
3190        let data = vec![
3191            "1234".as_bytes().to_owned(),
3192            vec![0xff; 506],
3193            "abc2995def".as_bytes().to_owned(),
3194        ]
3195        .into_iter()
3196        .flatten()
3197        .collect();
3198        assert_eq!(binfile.to_bytes(512.., None), Ok(data));
3199
3200        // Overwrite a segment and write outside it.
3201        assert!(binfile
3202            .add_bytes("111111111111".as_bytes(), Some(1021), true)
3203            .is_ok());
3204        let data = vec![
3205            "1234".as_bytes().to_owned(),
3206            vec![0xff; 505],
3207            "111111111111".as_bytes().to_owned(),
3208        ]
3209        .into_iter()
3210        .flatten()
3211        .collect();
3212        assert_eq!(binfile.to_bytes(512.., None), Ok(data));
3213
3214        // Overwrite multiple segments (all segments in this test).
3215        assert!(binfile
3216            .add_bytes(["1".as_bytes()[0]; 1204], Some(256), true)
3217            .is_ok());
3218        assert_eq!(
3219            binfile.to_bytes(256.., None),
3220            Ok(vec!["1".as_bytes()[0]; 1204])
3221        );
3222    }
3223
3224    #[test]
3225    fn test_non_sorted_segments() {
3226        let mut binfile = BinFile::new();
3227        assert!(binfile
3228            .add_srec_file("tests/non_sorted_segments.s19", false)
3229            .is_ok());
3230        let data = open_text_file("tests/non_sorted_segments_merged_and_sorted.s19");
3231        assert_eq!(
3232            binfile.to_srec(None, SRecordAddressLength::default()),
3233            Ok(data)
3234        );
3235    }
3236
3237    #[test]
3238    fn test_fill() {
3239        let mut binfile = BinFile::new();
3240
3241        // Fill empty file
3242        assert!(binfile.fill(None, None).is_ok());
3243        assert!(binfile.is_empty());
3244
3245        // Add some data and fill again
3246        assert!(binfile
3247            .add_bytes([0x01, 0x02, 0x03, 0x04], Some(0), false)
3248            .is_ok());
3249        assert!(binfile
3250            .add_bytes([0x01, 0x02, 0x03, 0x04], Some(8), false)
3251            .is_ok());
3252        assert!(binfile.fill(None, None).is_ok());
3253        assert_eq!(
3254            binfile.to_bytes(.., None),
3255            Ok(vec![
3256                0x01, 0x02, 0x03, 0x04, 0xff, 0xff, 0xff, 0xff, 0x01, 0x02, 0x03, 0x04
3257            ])
3258        );
3259    }
3260
3261    #[test]
3262    fn test_fill_max_words() {
3263        let mut binfile = BinFile::new();
3264
3265        // Add some data and fill again
3266        assert!(binfile.add_bytes([0x01], Some(0), false).is_ok());
3267        assert!(binfile.add_bytes([0x02], Some(2), false).is_ok());
3268        assert!(binfile.add_bytes([0x03], Some(5), false).is_ok());
3269        assert!(binfile.add_bytes([0x04], Some(9), false).is_ok());
3270        assert!(binfile.fill(Some(0xaa), Some(2)).is_ok());
3271        assert_eq!(binfile.segments().len(), 2);
3272        assert_eq!(binfile.segments()[0].minimum_address(), 0);
3273        assert_eq!(
3274            binfile.segments()[0].data(),
3275            &[0x01, 0xaa, 0x02, 0xaa, 0xaa, 0x03]
3276        );
3277        assert_eq!(binfile.segments()[1].minimum_address(), 9);
3278        assert_eq!(binfile.segments()[1].data(), &[0x04]);
3279    }
3280
3281    #[test]
3282    fn test_get_value_by_address() {
3283        let mut binfile = BinFile::new();
3284        assert!(binfile
3285            .add_bytes([0x01, 0x02, 0x03, 0x04], Some(1), false)
3286            .is_ok());
3287        assert!(binfile.get_value_by_address(0).is_none());
3288        assert_eq!(binfile.get_value_by_address(1), Some(1));
3289        assert_eq!(binfile.get_value_by_address(2), Some(2));
3290        assert_eq!(binfile.get_value_by_address(3), Some(3));
3291        assert_eq!(binfile.get_value_by_address(4), Some(4));
3292        assert!(binfile.get_value_by_address(5).is_none());
3293    }
3294
3295    #[test]
3296    fn test_get_values_by_address_ranges() {
3297        let mut binfile = BinFile::new();
3298        assert!(binfile
3299            .add_bytes([0x01, 0x02, 0x03, 0x04], Some(1), false)
3300            .is_ok());
3301        assert!(binfile
3302            .add_bytes([0x01, 0x02, 0x03, 0x04], Some(11), false)
3303            .is_ok());
3304        assert_eq!(
3305            binfile.get_values_by_address_range(3..5),
3306            Some(vec![0x03, 0x04])
3307        );
3308        assert!(binfile.get_values_by_address_range(3..6).is_none());
3309        assert!(binfile.get_values_by_address_range(0..3).is_none());
3310        assert_eq!(
3311            binfile.get_values_by_address_range(3..),
3312            Some(vec![0x03, 0x04])
3313        );
3314        assert_eq!(
3315            binfile.get_values_by_address_range(..3),
3316            Some(vec![0x01, 0x02])
3317        );
3318        assert_eq!(
3319            binfile.get_values_by_address_range(11..15),
3320            Some(vec![0x01, 0x02, 0x03, 0x04])
3321        );
3322
3323        assert_eq!(
3324            binfile.get_values_by_address_range(13..15),
3325            Some(vec![0x03, 0x04])
3326        );
3327        assert!(binfile.get_values_by_address_range(13..16).is_none());
3328        assert!(binfile.get_values_by_address_range(10..13).is_none());
3329        assert_eq!(
3330            binfile.get_values_by_address_range(13..),
3331            Some(vec![0x03, 0x04])
3332        );
3333        assert_eq!(
3334            binfile.get_values_by_address_range(..13),
3335            Some(vec![0x01, 0x02])
3336        );
3337        assert_eq!(
3338            binfile.get_values_by_address_range(11..15),
3339            Some(vec![0x01, 0x02, 0x03, 0x04])
3340        );
3341    }
3342
3343    #[test]
3344    fn test_performance() {
3345        let mut binfile = BinFile::new();
3346
3347        // add a 1MB consecuitive binary
3348        let chunk = vec!["1".as_bytes()[0]; 1024];
3349        for i in 0..1024 {
3350            assert!(binfile
3351                .add_bytes(chunk.clone(), Some(1024 * i), false)
3352                .is_ok());
3353        }
3354        assert_eq!(binfile.minimum_address(), Some(0));
3355        assert_eq!(binfile.maximum_address(), Some(1024 * 1024));
3356
3357        let ihex = binfile.to_ihex(None, IHexFormat::default()).unwrap();
3358        let srec = binfile
3359            .to_srec(None, SRecordAddressLength::default())
3360            .unwrap();
3361
3362        binfile = BinFile::new();
3363        assert!(binfile.add_ihex(ihex, false).is_ok());
3364
3365        binfile = BinFile::new();
3366        assert!(binfile.add_srec(srec, false).is_ok());
3367    }
3368
3369    #[test]
3370    fn test_print() {
3371        let mut binfile = BinFile::new();
3372
3373        assert!(binfile.add_bytes([0, 1, 2], Some(0), false).is_ok());
3374        assert!(binfile.add_bytes([3, 4, 5], Some(10), false).is_ok());
3375
3376        for segment in binfile.segments() {
3377            println!("{}", segment);
3378            for (address, data) in segment.chunks(Some(2), None).unwrap() {
3379                println!("Adress: {} Data: {:?}", address, data);
3380            }
3381        }
3382    }
3383
3384    #[test]
3385    fn test_verilog_vmem() {
3386        let mut binfile = BinFile::new();
3387
3388        assert!(binfile.add_verilog_vmem(
3389             [
3390             "@00000100 21 46 01 36 01 21 47 01 36 00 7E FE 09 D2 19 01 21 46 01 7E 17 C2 00 01 FF 5F 16 00 21 48 01 19",
3391             "@00000120 19 4E 79 23 46 23 96 57 78 23 9E DA 3F 01 B2 CA 3F 01 56 70 2B 5E 71 2B 72 2B 73 21 46 01 34 21",
3392             ], false).is_ok());
3393    }
3394}