5
5
use alloc:: boxed:: Box ;
6
6
use alloc:: string:: { String , ToString } ;
7
7
use alloc:: vec:: Vec ;
8
+ use core:: iter:: Peekable ;
8
9
use core:: slice;
9
10
use core:: str:: { self , FromStr } ;
10
11
use uguid:: Guid ;
@@ -128,6 +129,7 @@ impl ConfigurationString {
128
129
/// # Returns
129
130
///
130
131
/// An iterator over bytes.
132
+ #[ must_use]
131
133
pub fn parse_bytes_from_hex ( hex : & str ) -> impl DoubleEndedIterator < Item = u8 > {
132
134
hex. as_bytes ( ) . chunks ( 2 ) . map ( |chunk| {
133
135
let chunk = str:: from_utf8 ( chunk) . unwrap_or_default ( ) ;
@@ -196,14 +198,11 @@ impl ConfigurationString {
196
198
let v: Vec < _ > = Self :: parse_bytes_from_hex ( data) . collect ( ) ;
197
199
Some ( Guid :: from_bytes ( v. try_into ( ) . ok ( ) ?) )
198
200
}
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 ( ) ;
206
201
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 > {
207
206
let guid = Self :: try_parse_with ( ParseError :: ConfigHdr ( ConfigHdrSection :: Guid ) , || {
208
207
let v = splitter. next ( ) ?;
209
208
let v = ( v. 0 == "GUID" ) . then_some ( v. 1 ) . flatten ( ) ?;
@@ -246,7 +245,7 @@ impl FromStr for ConfigurationString {
246
245
} ;
247
246
248
247
while let Some ( next) = splitter. peek ( ) {
249
- if next. 0 == "OFFSET" {
248
+ if next. 0 == "OFFSET" || next . 0 == "GUID" {
250
249
break ;
251
250
}
252
251
let _ = splitter. next ( ) ; // drop nvconfig entries for now
@@ -257,6 +256,10 @@ impl FromStr for ConfigurationString {
257
256
width,
258
257
value,
259
258
} ) ;
259
+ // Found start of a new `ConfigurationString`
260
+ if let Some ( ( "GUID" , _) ) = splitter. peek ( ) {
261
+ break ;
262
+ }
260
263
}
261
264
262
265
Ok ( Self {
@@ -268,12 +271,43 @@ impl FromStr for ConfigurationString {
268
271
}
269
272
}
270
273
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 buffer.
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 buffer.
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
+
271
305
#[ cfg( test) ]
272
306
mod tests {
307
+ use crate :: proto:: hii:: config_str:: { ConfigurationString , MultiConfigurationStringIter } ;
308
+ use alloc:: vec:: Vec ;
273
309
use core:: str:: FromStr ;
274
310
275
- use crate :: proto:: hii:: config_str:: ConfigurationString ;
276
-
277
311
#[ test]
278
312
fn parse_single ( ) {
279
313
// exemplary (shortened / manually constructed) UEFI configuration string
@@ -290,4 +324,38 @@ mod tests {
290
324
assert_eq ! ( parsed. elements[ 10 ] . width, 1 ) ;
291
325
assert_eq ! ( & parsed. elements[ 10 ] . value, & [ 0x00 ] ) ;
292
326
}
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
+ }
293
361
}
0 commit comments