55use alloc:: boxed:: Box ;
66use alloc:: string:: { String , ToString } ;
77use alloc:: vec:: Vec ;
8+ use core:: iter:: Peekable ;
89use core:: slice;
910use core:: str:: { self , FromStr } ;
1011use uguid:: Guid ;
@@ -128,6 +129,7 @@ impl ConfigurationString {
128129 /// # Returns
129130 ///
130131 /// An iterator over bytes.
132+ #[ must_use]
131133 pub fn parse_bytes_from_hex ( hex : & str ) -> impl DoubleEndedIterator < Item = u8 > {
132134 hex. as_bytes ( ) . chunks ( 2 ) . map ( |chunk| {
133135 let chunk = str:: from_utf8 ( chunk) . unwrap_or_default ( ) ;
@@ -196,14 +198,11 @@ impl ConfigurationString {
196198 let v: Vec < _ > = Self :: parse_bytes_from_hex ( data) . collect ( ) ;
197199 Some ( Guid :: from_bytes ( v. try_into ( ) . ok ( ) ?) )
198200 }
199- }
200-
201- impl FromStr for ConfigurationString {
202- type Err = ParseError ;
203-
204- fn from_str ( bfr : & str ) -> Result < Self , Self :: Err > {
205- let mut splitter = ConfigurationStringIter :: new ( bfr) . peekable ( ) ;
206201
202+ /// Parse an instance of `Peekable<ConfigurationStringIter>` from the given kv-pair iterator.
203+ fn parse_from (
204+ splitter : & mut Peekable < ConfigurationStringIter < ' _ > > ,
205+ ) -> Result < Self , ParseError > {
207206 let guid = Self :: try_parse_with ( ParseError :: ConfigHdr ( ConfigHdrSection :: Guid ) , || {
208207 let v = splitter. next ( ) ?;
209208 let v = ( v. 0 == "GUID" ) . then_some ( v. 1 ) . flatten ( ) ?;
@@ -243,7 +242,7 @@ impl FromStr for ConfigurationString {
243242 } ;
244243
245244 while let Some ( next) = splitter. peek ( ) {
246- if next. 0 == "OFFSET" {
245+ if next. 0 == "OFFSET" || next . 0 == "GUID" {
247246 break ;
248247 }
249248 let _ = splitter. next ( ) ; // drop nvconfig entries for now
@@ -254,6 +253,10 @@ impl FromStr for ConfigurationString {
254253 width,
255254 value,
256255 } ) ;
256+ // Found start of a new `ConfigurationString`
257+ if let Some ( ( "GUID" , _) ) = splitter. peek ( ) {
258+ break ;
259+ }
257260 }
258261
259262 Ok ( Self {
@@ -265,12 +268,43 @@ impl FromStr for ConfigurationString {
265268 }
266269}
267270
271+ impl FromStr for ConfigurationString {
272+ type Err = ParseError ;
273+
274+ fn from_str ( bfr : & str ) -> Result < Self , Self :: Err > {
275+ Self :: parse_from ( & mut ConfigurationStringIter :: new ( bfr) . peekable ( ) )
276+ }
277+ }
278+
279+ /// Iterator over `ConfigurationString`'s in a multi configuration string buffer.
280+ #[ derive( Debug ) ]
281+ pub struct MultiConfigurationStringIter < ' a > {
282+ splitter : Peekable < ConfigurationStringIter < ' a > > ,
283+ }
284+ impl < ' a > MultiConfigurationStringIter < ' a > {
285+ /// Creates a new iterator instance for a given configuration string buffer.
286+ #[ must_use]
287+ pub fn new ( bfr : & ' a str ) -> Self {
288+ let splitter = ConfigurationStringIter :: new ( bfr) . peekable ( ) ;
289+ Self { splitter }
290+ }
291+ }
292+ impl < ' a > Iterator for MultiConfigurationStringIter < ' a > {
293+ type Item = Result < ConfigurationString , ParseError > ;
294+
295+ fn next ( & mut self ) -> Option < Self :: Item > {
296+ self . splitter . peek ( ) ?; // end of iterator?
297+ // try parsing the next full `ConfigurationString` from the splitter
298+ Some ( ConfigurationString :: parse_from ( & mut self . splitter ) )
299+ }
300+ }
301+
268302#[ cfg( test) ]
269303mod tests {
304+ use crate :: proto:: hii:: config_str:: { ConfigurationString , MultiConfigurationStringIter } ;
305+ use alloc:: vec:: Vec ;
270306 use core:: str:: FromStr ;
271307
272- use crate :: proto:: hii:: config_str:: ConfigurationString ;
273-
274308 #[ test]
275309 fn parse_single ( ) {
276310 // exemplary (shortened / manually constructed) UEFI configuration string
@@ -287,4 +321,38 @@ mod tests {
287321 assert_eq ! ( parsed. elements[ 10 ] . width, 1 ) ;
288322 assert_eq ! ( & parsed. elements[ 10 ] . value, & [ 0x00 ] ) ;
289323 }
324+
325+ #[ test]
326+ fn parse_multiple ( ) {
327+ // exemplary (shortened / manually constructed) UEFI configuration string
328+ let input = "GUID=16d6474bd6a852459d44ccad2e0f4cf9&NAME=00490053004300530049005f0043004f004e004600490047005f004900460052005f004e00560044004100540041&PATH=0104140016d6474bd6a852459d44ccad2e0f4cf97fff0400&OFFSET=01d8&WIDTH=0001&VALUE=00&GUID=16d6474bd6a852459d44ccad2e0f4cf9&NAME=00490053004300530049005f0043004f004e004600490047005f004900460052005f004e00560044004100540041&PATH=0104140016d6474bd6a852459d44ccad2e0f4cf97fff0400&OFFSET=01d8&WIDTH=0001&VALUE=00&OFFSET=1337&WIDTH=0005&VALUE=1122334455" ;
329+ let parsed: Vec < _ > = MultiConfigurationStringIter :: new ( input)
330+ . collect :: < Result < _ , _ > > ( )
331+ . unwrap ( ) ;
332+
333+ assert_eq ! ( parsed. len( ) , 2 ) ;
334+
335+ assert_eq ! (
336+ parsed[ 0 ] . guid,
337+ guid!( "4b47d616-a8d6-4552-9d44-ccad2e0f4cf9" )
338+ ) ;
339+ assert_eq ! ( parsed[ 0 ] . name, "ISCSI_CONFIG_IFR_NVDATA" ) ;
340+ assert_eq ! ( parsed[ 0 ] . elements. len( ) , 1 ) ;
341+ assert_eq ! ( parsed[ 0 ] . elements[ 0 ] . offset, 0x01d8 ) ;
342+ assert_eq ! ( parsed[ 0 ] . elements[ 0 ] . width, 1 ) ;
343+ assert_eq ! ( & parsed[ 0 ] . elements[ 0 ] . value, & [ 0x00 ] ) ;
344+
345+ assert_eq ! (
346+ parsed[ 1 ] . guid,
347+ guid!( "4b47d616-a8d6-4552-9d44-ccad2e0f4cf9" )
348+ ) ;
349+ assert_eq ! ( parsed[ 1 ] . name, "ISCSI_CONFIG_IFR_NVDATA" ) ;
350+ assert_eq ! ( parsed[ 1 ] . elements. len( ) , 2 ) ;
351+ assert_eq ! ( parsed[ 1 ] . elements[ 1 ] . offset, 0x1337 ) ;
352+ assert_eq ! ( parsed[ 1 ] . elements[ 1 ] . width, 5 ) ;
353+ assert_eq ! (
354+ & parsed[ 1 ] . elements[ 1 ] . value,
355+ & [ 0x55 , 0x44 , 0x33 , 0x22 , 0x11 ]
356+ ) ;
357+ }
290358}
0 commit comments