Skip to content

Commit e67667b

Browse files
authored
Consistently support binary partition tables (#212)
* Move parsing either CSV or binary partition table into own associated function Since this is done in multiple places it makes sense for PartitionTable to just offer this as an associated function. * Make save-image able to use binary partition tables Fixes #211
1 parent 12f5a41 commit e67667b

File tree

2 files changed

+69
-30
lines changed

2 files changed

+69
-30
lines changed

espflash/src/cli/mod.rs

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,15 @@ pub fn save_elf_as_image(
178178
};
179179

180180
// If the '-T' option is provided, load the partition table from
181-
// the CSV at the specified path.
181+
// the CSV or binary file at the specified path.
182182
let partition_table = if let Some(partition_table_path) = partition_table_path {
183183
let path = fs::canonicalize(partition_table_path).into_diagnostic()?;
184-
let data = fs::read_to_string(path)
184+
let data = fs::read(path)
185185
.into_diagnostic()
186186
.wrap_err("Failed to open partition table")?;
187187

188188
let table =
189-
PartitionTable::try_from_str(data).wrap_err("Failed to parse partition table")?;
189+
PartitionTable::try_from(data).wrap_err("Failed to parse partition table")?;
190190

191191
Some(table)
192192
} else {
@@ -279,26 +279,14 @@ pub fn flash_elf_image(
279279
};
280280

281281
// If the '--partition-table' option is provided, load the partition table from
282-
// the CSV at the specified path.
282+
// the CSV or binary file at the specified path.
283283
let partition_table = if let Some(path) = partition_table {
284284
let path = fs::canonicalize(path).into_diagnostic()?;
285285

286-
// If a partition table was detected from ESP-IDF (eg. using `esp-idf-sys`) then
287-
// it will be passed in its _binary_ form. Otherwise, it will be provided as a
288-
// CSV.
289-
let table = if path.extension().map(|e| e.to_str().unwrap()) == Some("csv") {
290-
let data = fs::read_to_string(path)
291-
.into_diagnostic()
292-
.wrap_err("Failed to open partition table")?;
293-
294-
PartitionTable::try_from_str(data).wrap_err("Failed to parse partition table")?
295-
} else {
296-
let data = fs::read(path)
297-
.into_diagnostic()
298-
.wrap_err("Failed to open partition table")?;
299-
300-
PartitionTable::try_from_bytes(data).wrap_err("Failed to parse partition table")?
301-
};
286+
let data = fs::read(path)
287+
.into_diagnostic()
288+
.wrap_err("Failed to open partition table")?;
289+
let table = PartitionTable::try_from(data).wrap_err("Failed to parse partition table")?;
302290

303291
Some(table)
304292
} else {
@@ -350,13 +338,7 @@ pub fn partition_table(opts: PartitionTableOpts) -> Result<()> {
350338

351339
// Try getting the partition table from either the csv or the binary representation and
352340
// fail otherwise.
353-
let part_table = if let Ok(part_table) =
354-
PartitionTable::try_from_bytes(input.clone()).into_diagnostic()
355-
{
356-
part_table
357-
} else if let Ok(part_table) =
358-
PartitionTable::try_from_str(String::from_utf8(input).into_diagnostic()?)
359-
{
341+
let part_table = if let Ok(part_table) = PartitionTable::try_from(input).into_diagnostic() {
360342
part_table
361343
} else {
362344
return Err((InvalidPartitionTable {}).into());

espflash/src/partition_table.rs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ use strum::IntoEnumIterator;
1414
use strum_macros::EnumIter;
1515

1616
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,
2020
};
2121

2222
const MAX_PARTITION_LENGTH: usize = 0xC00;
@@ -219,6 +219,30 @@ impl PartitionTable {
219219
}
220220
}
221221

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+
222246
/// Attempt to parse a CSV partition table from the given string.
223247
///
224248
/// For more information on the partition table format see:
@@ -812,6 +836,39 @@ phy_init, data, phy, 0xf000, 0x1000,
812836
assert_eq!(expected, result.as_slice());
813837
}
814838

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+
815872
#[test]
816873
fn test_from_str() {
817874
let pt0 = PartitionTable::try_from_str(PTABLE_0);

0 commit comments

Comments
 (0)