@@ -14,9 +14,9 @@ use strum::IntoEnumIterator;
14
14
use strum_macros:: EnumIter ;
15
15
16
16
use crate :: error:: {
17
- CSVError , DuplicatePartitionsError , InvalidChecksum , InvalidSubTypeError ,
18
- LengthNotMultipleOf32 , NoAppError , NoEndMarker , OverlappingPartitionsError ,
19
- PartitionTableError , UnalignedPartitionError ,
17
+ CSVError , DuplicatePartitionsError , InvalidChecksum , InvalidPartitionTable ,
18
+ InvalidSubTypeError , LengthNotMultipleOf32 , NoAppError , NoEndMarker ,
19
+ OverlappingPartitionsError , PartitionTableError , UnalignedPartitionError ,
20
20
} ;
21
21
22
22
const MAX_PARTITION_LENGTH : usize = 0xC00 ;
@@ -219,6 +219,30 @@ impl PartitionTable {
219
219
}
220
220
}
221
221
222
+ /// Attempt to parse either a binary or CSV partition table from the given input.
223
+ ///
224
+ /// For more information on the partition table format see:
225
+ /// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/partition-tables.html
226
+ pub fn try_from < S > ( data : S ) -> Result < Self , PartitionTableError >
227
+ where
228
+ S : Into < Vec < u8 > > ,
229
+ {
230
+ let input: Vec < u8 > = data. into ( ) ;
231
+
232
+ // If a partition table was detected from ESP-IDF (eg. using `esp-idf-sys`) then
233
+ // it will be passed in its _binary_ form. Otherwise, it will be provided as a
234
+ // CSV.
235
+ if let Ok ( part_table) = Self :: try_from_bytes ( & * input) {
236
+ Ok ( part_table)
237
+ } else if let Ok ( part_table) =
238
+ Self :: try_from_str ( String :: from_utf8 ( input) . map_err ( |_| InvalidPartitionTable ) ?)
239
+ {
240
+ Ok ( part_table)
241
+ } else {
242
+ Err ( InvalidPartitionTable . into ( ) )
243
+ }
244
+ }
245
+
222
246
/// Attempt to parse a CSV partition table from the given string.
223
247
///
224
248
/// For more information on the partition table format see:
@@ -812,6 +836,39 @@ phy_init, data, phy, 0xf000, 0x1000,
812
836
assert_eq ! ( expected, result. as_slice( ) ) ;
813
837
}
814
838
839
+ #[ test]
840
+ fn test_from ( ) {
841
+ let pt0 = PartitionTable :: try_from ( PTABLE_0 ) ;
842
+ assert ! ( pt0. is_ok( ) ) ;
843
+
844
+ let pt0 = pt0. unwrap ( ) ;
845
+ let nvs = pt0. find ( "nvs" ) . unwrap ( ) ;
846
+ let fac = pt0. find ( "factory" ) . unwrap ( ) ;
847
+ assert_eq ! ( nvs. flags( ) , None ) ;
848
+ assert_eq ! ( fac. flags( ) , Some ( Flags :: Encrypted ) ) ;
849
+
850
+ let pt1 = PartitionTable :: try_from ( PTABLE_1 ) ;
851
+ assert ! ( pt1. is_ok( ) ) ;
852
+
853
+ let pt_spiffs = PartitionTable :: try_from ( PTABLE_SPIFFS ) ;
854
+ assert ! ( pt_spiffs. is_ok( ) ) ;
855
+
856
+ PartitionTable :: try_from ( PTABLE_NO_FACTORY )
857
+ . expect ( "Failed to parse partition table without factory partition" ) ;
858
+
859
+ PartitionTable :: try_from ( PTABLE_NO_APP )
860
+ . expect_err ( "Failed to reject partition table without factory or ota partition" ) ;
861
+
862
+ use std:: fs:: { read, read_to_string} ;
863
+ let binary_table = read ( "./tests/data/partitions.bin" ) . unwrap ( ) ;
864
+ let binary_parsed = PartitionTable :: try_from_bytes ( binary_table) . unwrap ( ) ;
865
+
866
+ let csv_table = read_to_string ( "./tests/data/partitions.csv" ) . unwrap ( ) ;
867
+ let csv_parsed = PartitionTable :: try_from ( csv_table) . unwrap ( ) ;
868
+
869
+ assert_eq ! ( binary_parsed, csv_parsed) ;
870
+ }
871
+
815
872
#[ test]
816
873
fn test_from_str ( ) {
817
874
let pt0 = PartitionTable :: try_from_str ( PTABLE_0 ) ;
0 commit comments