@@ -22,12 +22,7 @@ use serde::{Deserialize, Serialize};
2222use  zerocopy:: { AlignmentError ,  ConvertError ,  FromBytes ,  IntoBytes ,  Ref ,  SizeError } ; 
2323use  zerocopy_derive:: { FromBytes ,  Immutable ,  IntoBytes } ; 
2424
25- use  crate :: { 
26-     dir:: gen2:: Directory  as  Gen2Directory , 
27-     dir:: gen3:: CodePartitionDirectory , 
28-     fit:: { Fit ,  FitError } , 
29-     ver:: Version , 
30- } ; 
25+ use  crate :: ver:: Version ; 
3126
3227const  FPT_MAGIC :  & str  = "$FPT" ; 
3328
@@ -127,44 +122,65 @@ impl Display for FPTEntry {
127122
128123#[ derive( Serialize ,  Deserialize ,  Clone ,  Debug ) ]  
129124pub  struct  FPT  { 
125+     pub  offset :  usize , 
130126    pub  header :  FPTHeader , 
131127    pub  entries :  Vec < FPTEntry > , 
132128} 
133129
134- impl < ' a >  FPT  { 
135-     pub  fn  parse ( data :  & ' a  [ u8 ] )  -> Option < Result < Self ,  FptError < ' a > > >  { 
136-         let  m = & data[ ..4 ] ; 
130+ pub  const  FPT_SIZE :  usize  = size_of :: < FPT > ( ) ; 
131+ 
132+ // The FPT magic is either at the start or at a 16 bytes offset. 
133+ fn  determine_offset ( data :  & [ u8 ] )  -> Option < usize >  { 
134+     let  m = & data[ ..4 ] ; 
135+     if  m. eq ( FPT_MAGIC . as_bytes ( ) )  { 
136+         return  Some ( 0 ) ; 
137+     }  else  { 
138+         let  m = & data[ 16 ..20 ] ; 
137139        if  m. eq ( FPT_MAGIC . as_bytes ( ) )  { 
138-             let  header = match  FPTHeader :: read_from_prefix ( data)  { 
139-                 Ok ( ( h,  _) )  => h, 
140-                 Err ( e)  => return  Some ( Err ( FptError :: HeaderParseError ( e) ) ) , 
141-             } ; 
142-             // NOTE: Skip $FPT (header) itself 
143-             let  slice = & data[ FPT_HEADER_SIZE ..] ; 
144-             let  count = header. entries  as  usize ; 
145-             let  entries = match  Ref :: < _ ,  [ FPTEntry ] > :: from_prefix_with_elems ( slice,  count)  { 
146-                 Ok ( ( r,  _) )  => r, 
147-                 Err ( e)  => return  Some ( Err ( FptError :: EntryParseError ( e) ) ) , 
148-             } ; 
149- 
150-             Some ( Ok ( Self  { 
151-                 header, 
152-                 entries :  entries. to_vec ( ) , 
153-             } ) ) 
140+             return  Some ( 16 ) ; 
154141        }  else  { 
155-             None 
142+             return   None ; 
156143        } 
157144    } 
158145} 
159146
160- #[ allow( non_camel_case_types) ]  
161- #[ derive( Serialize ,  Deserialize ,  Clone ,  Debug ) ]  
162- pub  struct  ME_FW  { 
163-     pub  base :  usize , 
164-     pub  fpt :  FPT , 
165-     pub  gen3dirs :  Vec < CodePartitionDirectory > , 
166-     pub  gen2dirs :  Vec < Gen2Directory > , 
167-     pub  fit :  Result < Fit ,  FitError > , 
147+ impl < ' a >  FPT  { 
148+     pub  fn  parse ( data :  & ' a  [ u8 ] )  -> Option < Result < Self ,  FptError < ' a > > >  { 
149+         let  Some ( offset)  = determine_offset ( data)  else  { 
150+             return  None ; 
151+         } ; 
152+         let  d = & data[ offset..] ; 
153+         let  header = match  FPTHeader :: read_from_prefix ( d)  { 
154+             Ok ( ( h,  _) )  => h, 
155+             Err ( e)  => return  Some ( Err ( FptError :: HeaderParseError ( e) ) ) , 
156+         } ; 
157+         // NOTE: Skip $FPT (header) itself 
158+         let  slice = & d[ FPT_HEADER_SIZE ..] ; 
159+         let  count = header. entries  as  usize ; 
160+         let  entries = match  Ref :: < _ ,  [ FPTEntry ] > :: from_prefix_with_elems ( slice,  count)  { 
161+             Ok ( ( r,  _) )  => r, 
162+             Err ( e)  => return  Some ( Err ( FptError :: EntryParseError ( e) ) ) , 
163+         } ; 
164+ 
165+         Some ( Ok ( Self  { 
166+             offset, 
167+             header, 
168+             entries :  entries. to_vec ( ) , 
169+         } ) ) 
170+     } 
171+ 
172+     // Find an FPT in a given slice, and if the magic is detected, get the 
173+     // parse result and the offset. 
174+     pub  fn  scan ( data :  & ' a  [ u8 ] )  -> Option < ( Result < Self ,  FptError < ' a > > ,  usize ) >  { 
175+         let  mut  o = 0 ; 
176+         while  o + 16  + FPT_SIZE  <= data. len ( )  { 
177+             if  let  Some ( fpt)  = Self :: parse ( data)  { 
178+                 return  Some ( ( fpt,  o) ) ; 
179+             } 
180+             o += 16 ; 
181+         } 
182+         None 
183+     } 
168184} 
169185
170186#[ derive( Serialize ,  Deserialize ,  Clone ,  Debug ) ]  
@@ -218,7 +234,7 @@ static FPT_CLEANED: &[u8] = include_bytes!("../tests/me11_cleaned.fpt");
218234
219235#[ test]  
220236fn  parse_size_error ( )  { 
221-     let  parsed = FPT :: parse ( & DATA [ 16 ..70 ] ) ; 
237+     let  parsed = FPT :: parse ( & DATA [ ..70 ] ) ; 
222238    assert ! ( parsed. is_some( ) ) ; 
223239    let  fpt_res = parsed. unwrap ( ) ; 
224240    assert ! ( matches!( fpt_res,  Err ( FptError :: EntryParseError ( _) ) ) ) ; 
@@ -234,9 +250,19 @@ fn parse_okay_fpt() {
234250    assert_eq ! ( fpt. header. entries as  usize ,  fpt. entries. len( ) ) ; 
235251} 
236252
253+ #[ test]  
254+ fn  parse_okay_fpt_with_offset ( )  { 
255+     let  parsed = FPT :: parse ( & DATA ) ; 
256+     assert ! ( parsed. is_some( ) ) ; 
257+     let  fpt_res = parsed. unwrap ( ) ; 
258+     assert ! ( fpt_res. is_ok( ) ) ; 
259+     let  fpt = fpt_res. unwrap ( ) ; 
260+     assert_eq ! ( fpt. header. entries as  usize ,  fpt. entries. len( ) ) ; 
261+ } 
262+ 
237263#[ test]  
238264fn  checksum ( )  { 
239-     let  parsed = FPT :: parse ( & DATA [ 16 .. 12   *   32  +  16 ] ) ; 
265+     let  parsed = FPT :: parse ( & DATA ) ; 
240266    let  fpt = parsed. unwrap ( ) . unwrap ( ) ; 
241267    assert_eq ! ( fpt. header. checksum( ) ,  fpt. header. checksum) ; 
242268} 
0 commit comments