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 ( ) ?;
@@ -246,7 +245,7 @@ impl FromStr for ConfigurationString {
246245 } ;
247246
248247 while let Some ( next) = splitter. peek ( ) {
249- if next. 0 == "OFFSET" {
248+ if next. 0 == "OFFSET" || next . 0 == "GUID" {
250249 break ;
251250 }
252251 let _ = splitter. next ( ) ; // drop nvconfig entries for now
@@ -257,6 +256,10 @@ impl FromStr for ConfigurationString {
257256 width,
258257 value,
259258 } ) ;
259+ // Found start of a new [ConfigurationString]
260+ if let Some ( ( "GUID" , _) ) = splitter. peek ( ) {
261+ break ;
262+ }
260263 }
261264
262265 Ok ( Self {
@@ -268,12 +271,43 @@ impl FromStr for ConfigurationString {
268271 }
269272}
270273
274+ impl FromStr for ConfigurationString {
275+ type Err = ParseError ;
276+
277+ fn from_str ( bfr : & str ) -> Result < Self , Self :: Err > {
278+ Self :: parse_from ( & mut ConfigurationStringIter :: new ( bfr) . peekable ( ) )
279+ }
280+ }
281+
282+ /// Iterator over [ConfigurationString]'s in a multi configuration string.
283+ #[ derive( Debug ) ]
284+ pub struct MultiConfigurationStringIter < ' a > {
285+ splitter : Peekable < ConfigurationStringIter < ' a > > ,
286+ }
287+ impl < ' a > MultiConfigurationStringIter < ' a > {
288+ /// Creates a new iterator instance for a given configuration string.
289+ #[ must_use]
290+ pub fn new ( bfr : & ' a str ) -> Self {
291+ let splitter = ConfigurationStringIter :: new ( bfr) . peekable ( ) ;
292+ Self { splitter }
293+ }
294+ }
295+ impl < ' a > Iterator for MultiConfigurationStringIter < ' a > {
296+ type Item = Result < ConfigurationString , ParseError > ;
297+
298+ fn next ( & mut self ) -> Option < Self :: Item > {
299+ self . splitter . peek ( ) ?; // end of iterator?
300+ // try parsing the next full [ConfigurationString] from the splitter
301+ Some ( ConfigurationString :: parse_from ( & mut self . splitter ) )
302+ }
303+ }
304+
271305#[ cfg( test) ]
272306mod tests {
307+ use crate :: proto:: hii:: config_str:: { ConfigurationString , MultiConfigurationStringIter } ;
308+ use alloc:: vec:: Vec ;
273309 use core:: str:: FromStr ;
274310
275- use crate :: proto:: hii:: config_str:: ConfigurationString ;
276-
277311 #[ test]
278312 fn parse_single ( ) {
279313 // exemplary (shortened / manually constructed) UEFI configuration string
@@ -290,4 +324,38 @@ mod tests {
290324 assert_eq ! ( parsed. elements[ 10 ] . width, 1 ) ;
291325 assert_eq ! ( & parsed. elements[ 10 ] . value, & [ 0x00 ] ) ;
292326 }
327+
328+ #[ test]
329+ fn parse_multiple ( ) {
330+ // exemplary (shortened / manually constructed) UEFI configuration string
331+ 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" ;
332+ let parsed: Vec < _ > = MultiConfigurationStringIter :: new ( input)
333+ . collect :: < Result < _ , _ > > ( )
334+ . unwrap ( ) ;
335+
336+ assert_eq ! ( parsed. len( ) , 2 ) ;
337+
338+ assert_eq ! (
339+ parsed[ 0 ] . guid,
340+ guid!( "4b47d616-a8d6-4552-9d44-ccad2e0f4cf9" )
341+ ) ;
342+ assert_eq ! ( parsed[ 0 ] . name, "ISCSI_CONFIG_IFR_NVDATA" ) ;
343+ assert_eq ! ( parsed[ 0 ] . elements. len( ) , 1 ) ;
344+ assert_eq ! ( parsed[ 0 ] . elements[ 0 ] . offset, 0x01d8 ) ;
345+ assert_eq ! ( parsed[ 0 ] . elements[ 0 ] . width, 1 ) ;
346+ assert_eq ! ( & parsed[ 0 ] . elements[ 0 ] . value, & [ 0x00 ] ) ;
347+
348+ assert_eq ! (
349+ parsed[ 1 ] . guid,
350+ guid!( "4b47d616-a8d6-4552-9d44-ccad2e0f4cf9" )
351+ ) ;
352+ assert_eq ! ( parsed[ 1 ] . name, "ISCSI_CONFIG_IFR_NVDATA" ) ;
353+ assert_eq ! ( parsed[ 1 ] . elements. len( ) , 2 ) ;
354+ assert_eq ! ( parsed[ 1 ] . elements[ 1 ] . offset, 0x1337 ) ;
355+ assert_eq ! ( parsed[ 1 ] . elements[ 1 ] . width, 5 ) ;
356+ assert_eq ! (
357+ & parsed[ 1 ] . elements[ 1 ] . value,
358+ & [ 0x55 , 0x44 , 0x33 , 0x22 , 0x11 ]
359+ ) ;
360+ }
293361}
0 commit comments