(*
 * Copyright 2016, NICTA
 *
 * This software may be distributed and modified according to the terms of
 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
 * See "LICENSE_GPLv2.txt" for details.
 *
 * @TAG(NICTA_GPL)
 *)

theory SerialS
imports
  PleSle
begin  
type_synonym U8 = "8 word"
type_synonym U16 = "16 word"
type_synonym U32 = "32 word"
type_synonym U64 = "64 word"

lemma sle32_length:
  "length (sle32 x) = 4"
  by (simp add: sle32_def length_word_rsplit_exp_size' word_size)

lemma ple32_word_rcat_eq1:
  "ple32 (sle32 x @ xs) 0 = x"
  apply (simp only: ple32_def unat_0)
  apply (subst drop_0)
  apply (cut_tac x=x in sle32_length)
  apply (simp add: sle32_def word_rcat_rsplit)
  done
  
lemma ple32_word_rcat_eq2:
 "length ys = (unat n) \<Longrightarrow> ple32 (ys @ sle32 x @ xs) n = x"
  by (simp add: ple32_def ple32_word_rcat_eq1[simplified ple32_def, simplified])

lemmas ple32_word_rcat_eq = ple32_word_rcat_eq1 ple32_word_rcat_eq2

lemma sle64_length:
  "length (sle64 x) = 8"
  by (simp add: sle64_def length_word_rsplit_exp_size' word_size)
  
lemma ple64_word_rcat_eq1:
  "ple64 (sle64 x @ xs) 0 = x"
  apply (simp only: ple64_def unat_0)
  apply (subst drop_0)
  apply (cut_tac x=x in sle64_length)
  apply (simp add: sle64_def word_rcat_rsplit)
 done
  
lemma ple64_word_rcat_eq2:
 "length ys = (unat n) \<Longrightarrow> ple64 (ys @ sle64 x @ xs) n = x"
  by (simp add: ple64_def ple64_word_rcat_eq1[simplified ple64_def, simplified])

lemmas ple64_word_rcat_eq = ple64_word_rcat_eq1 ple64_word_rcat_eq2

definition pObjDel :: "U8 list \<Rightarrow> U32 \<Rightarrow> U64 ObjDel"
where
  "pObjDel data' offs' \<equiv> ObjDel.make (ple64 data' offs')  \<comment> \<open>id\<close>
   \<comment> \<open>End 4 bytes\<close>"
       
definition sObjDel :: "ObjDel\<^sub>T \<Rightarrow> U8 list"
where
  "sObjDel odel \<equiv> (sle64 $ ObjDel.id\<^sub>f odel) (* id *) (* End 8 bytes *)"

lemma objDel_inverse:
 "pObjDel (sObjDel odel) 0 = odel"
  apply(simp add: pObjDel_def sObjDel_def)
  apply(simp add: ObjDel.defs)
  using ple64_word_rcat_eq[where xs=Nil]
  by simp

definition pObjData :: "U8 list \<Rightarrow> U32 \<Rightarrow> U32 \<Rightarrow> ObjData\<^sub>T"
where
  "pObjData data offs olen \<equiv>
   ObjData.make (ple64 data offs) (* id *)
     (WordArrayT.make $ slice (unat (offs + 8)) (unat (offs + 8) + unat (olen - bilbyFsObjHeaderSize - bilbyFsObjDataHeaderSize)) data)"

definition sObjData :: "ObjData\<^sub>T \<Rightarrow> U32 \<Rightarrow> U8 list"
where
  "sObjData odata len \<equiv> (sle64 $ ObjData.id\<^sub>f odata) @ take (unat len) (\<alpha>wa (ObjData.odata\<^sub>f odata))"

lemma length_sle32: 
 "length ((sle32 (x::U32))::U8 list) = 4"
by (simp add: Word.length_word_rsplit_exp_size' Word.word_size sle32_def )

lemma length_sle64: 
 "length ((sle64 (x::U64))::U8 list) = 8"
by (simp add: Word.length_word_rsplit_exp_size' Word.word_size sle64_def )

lemma objData_inverse:
  "unat (len - bilbyFsObjHeaderSize - bilbyFsObjDataHeaderSize) = length (\<alpha>wa (odata\<^sub>f odata)) \<Longrightarrow>
  len - bilbyFsObjHeaderSize - bilbyFsObjDataHeaderSize < len \<Longrightarrow>
  pObjData (sObjData odata len) 0 len = odata"
  apply(simp add: pObjData_def)
  apply(simp add: sObjData_def)
  apply(simp add: ObjData.defs)
  apply(simp add: ple64_word_rcat_eq length_sle64 slice_def)
  apply (subgoal_tac "unat len \<ge> length (\<alpha>wa (odata\<^sub>f odata)) ")
   apply (simp add:  wordarray_make')
  apply unat_arith
 done

definition
 pu8 :: "U8 list \<Rightarrow> U32 \<Rightarrow> U8"
where
 "pu8 xs offs =  word_rcat (slice (unat offs) (unat offs+1) xs)"
 
definition pObjDentry :: "U8 list \<Rightarrow> U32 \<Rightarrow> ObjDentry\<^sub>T"
where
 "pObjDentry data offs \<equiv>
   let nlen = ple16 data (offs+6)
   in ObjDentry.make
    (ple32 data (offs+0)) (* ino *)
    (pu8 data (offs+4))  (* dtype *)
    (* 1 byte padding *)
    nlen  (* nlen *)
    (WordArrayT.make $ slice (unat (offs+ 8)) (unat (offs + 8) + unat nlen) data)  (* name *)"

definition pArrObjDentry :: "U8 list \<Rightarrow> U32 \<Rightarrow> U32 \<Rightarrow> (ObjDentry\<^sub>T Array \<times> 32 word \<times> 32 word list)"
where
 "pArrObjDentry data offs nb_dentry =
    (case (fold      
    (\<lambda>_ (xs,doffs,offslist).
      let dentry = pObjDentry data doffs ;
          newoffs = doffs +  8 + wordarray_length (ObjDentry.name\<^sub>f dentry)
      in (xs@[Option.Some dentry], newoffs, offslist@ [newoffs])) [0..<unat nb_dentry] ([], offs, []))
   of (xs, doffs, offslist) \<Rightarrow> (ArrayT.make (xs@ [Option.None ()]), doffs, offslist))"

definition pObjDentarr :: "U8 list \<Rightarrow> U32 \<Rightarrow> U32 \<Rightarrow> ObjDentarr\<^sub>T"
where
"pObjDentarr data offs olen \<equiv>
 let nb_dentry = ple32 data (offs+8)
 in ObjDentarr.make
     (ple64 data offs) (* id *)
     (nb_dentry) (* nb_dentry *)
     (prod.fst (pArrObjDentry (take (unat (offs+olen-bilbyFsObjHeaderSize)) data) (offs+bilbyFsObjDentarrHeaderSize) nb_dentry))
     "

definition pObjDentarrSize :: "U8 list \<Rightarrow> U32 \<Rightarrow> U32 \<Rightarrow> U32"
where
"pObjDentarrSize data offs olen \<equiv>
 let nb_dentry = ple32 data (offs+8)
 in (prod.fst (prod.snd (pArrObjDentry (take (unat (offs+olen-bilbyFsObjHeaderSize)) data) (offs+bilbyFsObjDentarrHeaderSize) nb_dentry)))
 "

definition pObjSuper :: "U8 list \<Rightarrow> U32 \<Rightarrow> ObjSuper\<^sub>T"
where
  "pObjSuper data offs \<equiv>
   ObjSuper.make
     (ple32 data offs) (* nb_eb *)
     (ple32 data (offs+4)) (* eb_size *)
     (ple32 data (offs+8)) (* io_size *)
     (ple32 data (offs+12)) (* nb_reserved_gc *)
     (ple32 data (offs+16)) (* nb_reserved_del *)
     (ple32 data (offs+20)) (* cur_eb *)
     (ple32 data (offs+24)) (* cur_offs *)
     (ple32 data (offs+28)) (* last_inum *)
     (ple64 data (offs+32)) (* next_sqnum *)
     "

(* TODO: we do not have pObjSumEntry . Probably we need it.*)
definition sObjSumEntry :: "ObjSumEntry\<^sub>T \<Rightarrow> U8 list"
where
 "sObjSumEntry ose \<equiv> 
   (sle64 $ ObjSumEntry.id\<^sub>f ose)
 @ (sle64 $ ObjSumEntry.sqnum\<^sub>f ose)
 @ (sle32 $ ObjSumEntry.len\<^sub>f ose)
 @ (sle32 $ ObjSumEntry.del_flags_and_offs\<^sub>f ose)
 @ (sle16 $ ObjSumEntry.count\<^sub>f ose)"

consts sObjSuper :: "ObjSuper\<^sub>T \<Rightarrow> U8 list" 

type_synonym Buffer\<^sub>T = "(U8 WordArray, U32) Buffer"

definition bounded :: "Buffer\<^sub>T \<Rightarrow> U8 list"
where
 "bounded buf = take (unat (bound\<^sub>f buf)) (WordArrayT.\<alpha>wa (data\<^sub>f buf))"

definition wellformed_buf :: "Buffer\<^sub>T \<Rightarrow> bool"
where
 "wellformed_buf buf \<equiv> unat (bound\<^sub>f buf) \<le> List.length (\<alpha>wa (Buffer.data\<^sub>f buf))"

lemma elem_take_n:
 "i<n \<Longrightarrow> (take n xs ! i) = xs ! i"
 by simp

lemma deserialise_le32_bounded_ret:
assumes bounded:
  "bbuf = bounded buf"
assumes valid_offs:
  "unat offs + 3 < length (bounded buf)"
shows
  "deserialise_le32 (buf, offs) = ple32 bbuf offs"
apply (simp add: bounded)
using valid_offs
  apply (subgoal_tac "(\<forall>i\<in>{0..3}. unat (offs+i) < length (bounded buf))")
   prefer 2
   apply unat_arith
  apply (simp add: bounded_def)
  apply (clarsimp simp: wordarray_get_ret[where arr="data\<^sub>f buf"] ple32_def 
                        deserialise_le32_def)
  apply (subgoal_tac "\<forall>j\<in>{1..3}. (unat (offs + j) > 0)")
   prefer 2
   apply clarsimp
   apply (drule_tac x=j in bspec, simp)
   apply unat_arith
  apply (subst take_drop_decomp, (simp+))+
  apply (subst unatSuc[symmetric], (simp add: unat_gt_0[symmetric] add.commute[where b=offs]))+
  apply simp
  apply (rule trans, rule word_rcat_rsplit[symmetric])
  apply (rule arg_cong[where f=word_rcat])
  apply (subst word_rsplit_upt[where n=4], simp add: word_size)
   apply simp
  apply (simp add: upt_rec shiftr_over_or_dist shiftl_shiftr1 shiftl_shiftr2 word_size)
  apply (safe intro!: word_eqI, simp_all add: word_size word_ops_nth_size nth_ucast
        nth_shiftr nth_shiftl add.commute[where b=offs] test_bit_out_of_bounds)
 done
 
lemma deserialise_le64_bounded_ret:
assumes bounded:
  "bbuf = bounded buf"
assumes valid_offs:
  "unat offs + 7 < length (bounded buf)"
shows
  "deserialise_le64 (buf, offs) = ple64 bbuf offs"
apply (simp add: bounded)
using valid_offs
  apply (subgoal_tac "(\<forall>i\<in>{0..7}. unat (offs+i) < length (bounded buf))")
   prefer 2
   apply unat_arith
  apply (simp add: bounded_def)
  apply (clarsimp simp: wordarray_get_ret[where arr="data\<^sub>f buf"] ple64_def 
                       deserialise_le64_def)
  apply (subgoal_tac "\<forall>j\<in>{1..7}. (unat (offs + j) > 0)")
   prefer 2
   apply clarsimp
   apply (drule_tac x=j in bspec, simp)
   apply unat_arith
  (* feel free to improve this apply script..*)
  apply (subst take_drop_decomp, (simp+))+
  apply (subst unatSuc[symmetric], (simp add: unat_gt_0[symmetric] add.commute[where b=offs]))+
  apply simp
  apply (rule trans, rule word_rcat_rsplit[symmetric])
  apply (rule arg_cong[where f=word_rcat])
  apply (subst word_rsplit_upt[where n=8], simp add: word_size)
   apply simp
  apply (simp add: upt_rec shiftr_over_or_dist shiftl_shiftr1 shiftl_shiftr2 word_size)
  apply (safe intro!: word_eqI, simp_all add: word_size word_ops_nth_size nth_ucast
        nth_shiftr nth_shiftl add.commute[where b=offs] test_bit_out_of_bounds)
  done


definition buf_unchanged :: "Buffer\<^sub>T \<Rightarrow> Buffer\<^sub>T \<Rightarrow> U32 \<Rightarrow> U32 \<Rightarrow> bool"
where
 "buf_unchanged newbuf oldbuf offs' l \<equiv> take (unat offs') (\<alpha>wa (data\<^sub>f newbuf)) = take (unat offs') (\<alpha>wa (data\<^sub>f oldbuf)) \<and>
  drop (unat offs' + unat l) (\<alpha>wa (data\<^sub>f newbuf)) = drop (unat offs' + unat l) (\<alpha>wa (data\<^sub>f oldbuf)) \<and>
  bound\<^sub>f newbuf = bound\<^sub>f oldbuf"

lemma bounded_le_length:
  "(length $ bounded  x) \<le> length (\<alpha>wa $ data\<^sub>f x)"
  by (simp add: bounded_def)

lemmas serialise_le64_simps = ArrA.make_def ElemA.make_def ElemAO.make_def ArrayUseValueP.defs
                              setu8_def[unfolded sanitizers] wordarray_make bounded_def
                             serialise_u8_def[unfolded tuple_simps sanitizers]
(*
lemma serialise_le64_ret:
assumes valid_offs:
  "unat offs + 7 < length (bounded buf)"
assumes ret:
  "P (buf\<lparr>data\<^sub>f := WordArrayT.make (\<alpha>wa (data\<^sub>f buf)[
      unat offs := u64_to_u8 v,
      unat (offs+1) := u64_to_u8 (v >> 8),
      unat (offs+2) := u64_to_u8 (v >> 16),
      unat (offs+3) := u64_to_u8 (v >> 24),
      unat (offs+4) := u64_to_u8 (v >> 32),
      unat (offs+5) := u64_to_u8 (v >> 40),
      unat (offs+6) := u64_to_u8 (v >> 48),
      unat (offs+7) := u64_to_u8 (v >> 56)])\<rparr>)"
notes  wa_modify_ret = wordarray_modify_ret[rotated - 1, simplified Let_def ArrayUseValueP.defs ArrA.defs]
shows
  "P (serialise_le64 (buf, offs, v))"
  unfolding serialise_le64_def[unfolded tuple_simps sanitizers]
  apply (simp add: serialise_le64_simps Let_def)
  apply (rule wa_modify_ret[where index="offs"], simp add: serialise_le64_simps)
    apply (rule wa_modify_ret[where index="offs+1"], simp add: serialise_le64_simps)
      apply (rule wa_modify_ret[where index="offs+2"], simp add: serialise_le64_simps)
        apply (rule wa_modify_ret[where index="offs+3"], simp add: serialise_le64_simps)
          apply (rule  wa_modify_ret[where index="offs+4"], simp add: serialise_le64_simps)
            apply (rule wa_modify_ret[where index="offs+5"], simp add: serialise_le64_simps)
              apply (rule wa_modify_ret[where index="offs+6"], simp add: serialise_le64_simps)
                apply (rule wa_modify_ret[where index="offs+7"], simp add: serialise_le64_simps)
                  using ret apply simp
                 using valid_offs 
                 apply ((simp add: serialise_le64_simps) , unat_arith?)+
 done
*)
lemma take_irrelevance:
  "P (xs!(unat (x + y))) \<Longrightarrow> unat (x + y) < unat z \<Longrightarrow>
   P ((take (unat z) xs)!(unat (x + y)))" 
   by auto

lemma unat_space:
assumes "unat (x + y) < z"
and "unat (x + y) > unat x"
and "y' \<le> y"
shows "unat (x + y') < z"
proof -
  have "\<And>x\<^sub>1. unat (x + y) \<le> x\<^sub>1 \<or> \<not> z \<le> x\<^sub>1"
  using assms(1)  by fastforce
  thus ?thesis using assms
  by (metis antisym_conv leI less_not_sym word_le_nat_alt word_plus_mono_right)
qed

lemma ple32_ret:
  assumes 1:"unat offs < unat (offs + 3)"
  assumes 2:"unat (offs + 3) < (length $ bounded buf)"
  assumes 3:"P(ple32 (bounded buf) offs)"
  shows "P (deserialise_le32 (buf, offs))"
  proof -
    from 1 2 have 4:"unat offs + 3 < (length $ bounded buf)" by (unat_arith, auto?)
    show ?thesis
    apply(subst deserialise_le32_bounded_ret)
       apply simp
      using 1 2 apply unat_arith
      apply auto[1]
     using 1 2 apply unat_arith
    using 3 apply auto
    done
  qed

lemma ple64_ret:
  assumes 1:"unat offs < unat (offs + 7)"
  assumes 2:"unat (offs + 7) < (length $ bounded buf)"
  assumes 3:"P (ple64 (bounded buf) offs)"
  shows "P (deserialise_le64 (buf, offs))"
  proof -
    from 1 2 have 4:"unat offs + 7 < (length $ bounded buf)" by (unat_arith, auto?)
    show ?thesis
    apply(subst deserialise_le64_bounded_ret)
       apply simp
      using 1 2 apply unat_arith
      apply auto[1]
     using 1 2 apply unat_arith
    using 3 apply auto
    done
  qed

lemma offs_le:
 assumes "offs < offs+n"
 assumes "unat (offs + n) \<le> ntake"
 shows   "unat offs < ntake"
 using assms by unat_arith

lemma word_add_eq_unat:
 assumes "(offs::('a::len word)) < offs + n"
 assumes "i < n"
 shows   "unat (offs + i) = unat offs  + unat i"
using assms by unat_arith

lemma ple16_eq_slice2:
 assumes "offs < offs + 2" 
 assumes "unat offs + 2 \<le> length xs"
 shows   "ple16 xs offs = ple16 (slice (unat offs) (unat offs + 2) xs) 0"
 using assms by (simp add:  slice_def ple16_def drop_take word_add_eq_unat)

lemma ple32_eq_slice4:
 assumes "offs < offs + 4" 
 assumes "unat offs + 4 \<le> length xs"
 shows   "ple32 xs offs = ple32 (slice (unat offs) (unat offs + 4) xs) 0"
 using assms by (simp add:  slice_def ple32_def drop_take word_add_eq_unat)

lemma ple64_eq_slice8:
 assumes "offs < offs + 8" 
 assumes "unat offs + 8 \<le> length xs"
 shows   "ple64 xs offs = ple64 (slice (unat offs) (unat offs + 8) xs) 0"
 using assms by (simp add:  slice_def ple64_def drop_take word_add_eq_unat)

definition pObjInode :: "U8 list \<Rightarrow> U32 \<Rightarrow> ObjInode\<^sub>T"
where
 "pObjInode data offs \<equiv>
     ObjInode.make
       (((ple64 data offs) AND (NOT (bilbyFsOidMaskAll OR ucast word32Max))) OR bilbyFsOidMaskInode) (* id *)
       (ple64 data (offs+8)) (* size *)
       (ple64 data (offs+16)) (* atime *)
       (ple64 data (offs+24)) (* ctime *)
       (ple64 data (offs+32)) (* mtime *)
       (ple32 data (offs+40)) (* nlink *)
       (ple32 data (offs+44)) (* uid *)
       (ple32 data (offs+48)) (* gid *)
       (ple32 data (offs+52)) (* mode *)
       (ple32 data (offs+56)) (* flags *)
       (* End 60 bytes *)"

definition sObjInode :: "ObjInode\<^sub>T \<Rightarrow> U8 list"
where
 "sObjInode odata \<equiv> 
   (sle64 $ ObjInode.id\<^sub>f odata) 
 @ (sle64 $ ObjInode.size\<^sub>f odata) 
 @ (sle64 $ ObjInode.atime_sec\<^sub>f odata)
 @ (sle64 $ ObjInode.ctime_sec\<^sub>f odata)
 @ (sle64 $ ObjInode.mtime_sec\<^sub>f odata)
 @ (sle32 $ ObjInode.nlink\<^sub>f odata)
 @ (sle32 $ ObjInode.uid\<^sub>f odata)
 @ (sle32 $ ObjInode.gid\<^sub>f odata)
 @ (sle32 $ ObjInode.mode\<^sub>f odata)
 @ (sle32 $ ObjInode.flags\<^sub>f odata)  (* End 60 bytes *)"

definition pObjHeader :: "U8 list \<Rightarrow> U32 \<Rightarrow> Obj\<^sub>T"
where
 "pObjHeader data offs \<equiv>
     Obj.make
       (ple32 data offs)      (* magic *)
       (ple32 data (offs+4))  (* crc *)
       (ple64 data (offs+8))  (* sqnum *)
       (offs)                    (* offs not stored on medium *) (* changed back to offs, otherwise this doesnt correspond to the code*)
       (ple32 data (offs+16)) (* len *)
       (* 2 padding bytes *)
       (data!unat (offs+22))  (* trans *)
       (data!unat (offs+23))  (* otype *)
       undefined               (* ounion *)
       (* End 24 bytes *)"

definition sObjHeader :: "Obj\<^sub>T \<Rightarrow> U8 list"
where
  "sObjHeader obj \<equiv>
   (sle32 $ Obj.magic\<^sub>f obj)
 @ (sle32 $ Obj.crc\<^sub>f obj)
 @ (sle64 $ Obj.sqnum\<^sub>f obj)
 @ (sle32 $ Obj.len\<^sub>f obj)
 @ [bilbyFsPadByte]
 @ [bilbyFsPadByte]
 @ [Obj.trans\<^sub>f obj]
 @ [Obj.otype\<^sub>f obj] (* End 24 bytes *)"

lemma ObjHeader_inverse:
  "pObjHeader (sObjHeader obj@xs) 0 = (obj\<lparr> Obj.ounion\<^sub>f := undefined, Obj.offs\<^sub>f := 0\<rparr>) "
   apply(clarsimp simp: pObjHeader_def sObjHeader_def)
   apply(clarsimp simp: Obj.defs)
   apply(clarsimp simp: ple32_word_rcat_eq length_sle32 length_sle64)
   apply(clarsimp simp: bilbyFsObjHeaderSize_def bilbyFsPadByte_def)
   proof -
     let ?magic = "sle32 (magic\<^sub>f obj)"
     let ?crc = "sle32 (crc\<^sub>f obj)"
     let ?sqnum = "sle64 (Obj.sqnum\<^sub>f obj)"
     let ?len = "sle32 (Obj.len\<^sub>f obj)"
     let ?tail = "0x42 # 0x42 # trans\<^sub>f obj # otype\<^sub>f obj # xs"

     have append_assoc_intro : "\<And>P ys1 ys2 xs. 
       P ((ys1 @ ys2) @ xs) \<Longrightarrow> P (ys1 @ (ys2 @ xs))" by auto

     have sqnum: "ple64 (?magic @ ?crc @ ?sqnum @ ?len @ ?tail) 8 = (Obj.sqnum\<^sub>f obj)"
     apply(rule append_assoc_intro)
     apply(rule ple64_word_rcat_eq)
     apply(subst List.length_append)
     using length_sle32 by auto

     have len: "ple32 (?magic @ ?crc @ ?sqnum @ ?len @ ?tail) 16 = Obj.len\<^sub>f obj"
     apply(rule append_assoc_intro[of _ "?magic"])
     apply(rule append_assoc_intro[of _ "?magic @ ?crc"])
     apply(rule append_assoc_intro[of _ "?magic @ ?crc @ ?sqnum"])
     apply(rule ple32_word_rcat_eq)
     using length_sle32 length_sle64 by auto

     have trans:"(?magic @ ?crc @ ?sqnum @ ?len @ ?tail) ! 22 = Obj.trans\<^sub>f obj"
     proof -
       have "length (?magic @ ?crc @ ?sqnum @ ?len @ (66::8 word) # [66::8 word]) = 22"
       using length_sle32 length_sle64 by simp
       from this show ?thesis
       by (metis (erased, hide_lams) append_Cons append_Nil append_assoc nth_append_length)
     qed

     have otype:"(?magic @ ?crc @ ?sqnum @ ?len @ ?tail) ! 23 = Obj.otype\<^sub>f obj"
     proof -
       have "length (?magic @ ?crc @ ?sqnum @ ?len @ (66::8 word) # (66::8 word) # [trans\<^sub>f obj]) = 23"
       using length_sle32 length_sle64 by simp
       from this show ?thesis
       by (metis (erased, hide_lams) append_Cons append_Nil append_assoc nth_append_length)
     qed

     from sqnum len trans otype
     show 
       "\<lparr>magic\<^sub>f = magic\<^sub>f obj, crc\<^sub>f = crc\<^sub>f obj,
         sqnum\<^sub>f = ple64 (?magic @ ?crc @ ?sqnum @ ?len @ ?tail) 8,
         offs\<^sub>f = 0,
         len\<^sub>f = ple32 (?magic @ ?crc @ ?sqnum @ ?len @ ?tail) 16,
         trans\<^sub>f = (?magic @ ?crc @ ?sqnum @ ?len @ ?tail) ! 22,
         otype\<^sub>f = (?magic @ ?crc @ ?sqnum @ ?len @ ?tail) ! 23,
         ounion\<^sub>f = undefined\<rparr> = obj\<lparr>ounion\<^sub>f := undefined, Obj.offs\<^sub>f := 0\<rparr>"
      by auto
   qed

lemmas pObjHeader_simp =
  pObjHeader_def Let_def Obj.make_def bilbyFsObjHeaderSize_def

definition is_valid_ObjHeader :: "Obj\<^sub>T \<Rightarrow> U8 list \<Rightarrow> bool"
where
 "is_valid_ObjHeader obj data \<equiv>
    magic\<^sub>f obj = bilbyFsMagic \<and>
    (unat $ Obj.len\<^sub>f obj) \<le> length data \<and>
    trans\<^sub>f obj \<in> {bilbyFsTransIn, bilbyFsTransCommit} \<and>
    is_len_and_type_ok (otype\<^sub>f obj, Obj.len\<^sub>f obj)"

lemma is_len_and_type_ok_hdr_szD:
  "is_len_and_type_ok (otype, olen) \<Longrightarrow> bilbyFsObjHeaderSize \<le> olen"
 by (auto simp add: 
         is_len_and_type_ok_def[unfolded sanitizers tuple_simps] 
        bilbyFsObjHeaderSize_def
        prod.case_eq_if split: if_splits)
  unat_arith+

lemma is_valid_ObjHeader_len_facts:
 "is_valid_ObjHeader obj data \<Longrightarrow> unat bilbyFsObjHeaderSize \<le> length data \<and>
   bilbyFsObjHeaderSize \<le> Obj.len\<^sub>f obj"
  apply (clarsimp simp: is_valid_ObjHeader_def)
  apply (drule is_len_and_type_ok_hdr_szD)
  apply unat_arith
 done


lemmas otype_simps =
  bilbyFsObjTypeInode_def
  bilbyFsObjTypeData_def
  bilbyFsObjTypeDentarr_def
  bilbyFsObjTypeDel_def
  bilbyFsObjTypePad_def
  bilbyFsObjTypeSuper_def
  bilbyFsObjTypeSum_def

lemma is_len_and_type_ok_otype_valD:
  "is_len_and_type_ok (otype, olen) \<Longrightarrow> otype \<in> {bilbyFsObjTypeInode,bilbyFsObjTypeData,bilbyFsObjTypeDentarr,bilbyFsObjTypeDel,bilbyFsObjTypePad,bilbyFsObjTypeSuper,bilbyFsObjTypeSum} "
 by (auto simp add: 
         is_len_and_type_ok_def[unfolded sanitizers tuple_simps] 
         otype_simps  split: if_splits)

definition is_valid_Obj :: "Obj\<^sub>T \<Rightarrow> bool"
where
 "is_valid_Obj obj \<equiv> 
    if otype\<^sub>f obj = bilbyFsObjTypePad then \<exists>v. ounion\<^sub>f obj = TObjPad v else
    if otype\<^sub>f obj = bilbyFsObjTypeInode then \<exists>v. ounion\<^sub>f obj = TObjInode v else
    if otype\<^sub>f obj = bilbyFsObjTypeData then \<exists>v. ounion\<^sub>f obj = TObjData v else
    if otype\<^sub>f obj = bilbyFsObjTypeDentarr then \<exists>v. ounion\<^sub>f obj = TObjDentarr v else
    if otype\<^sub>f obj = bilbyFsObjTypeDel then \<exists>v. ounion\<^sub>f obj = TObjDel v else
    True"


lemma is_valid_ObjHeader_len:
  "is_valid_ObjHeader obj data \<Longrightarrow> bilbyFsObjHeaderSize \<le> Obj.len\<^sub>f obj"
  apply (clarsimp simp add: is_valid_ObjHeader_def)
  apply (erule is_len_and_type_ok_hdr_szD)
 done

lemma is_valid_ObjHeader_len_unat:
  "is_valid_ObjHeader obj data \<Longrightarrow> unat bilbyFsObjHeaderSize \<le> unat (Obj.len\<^sub>f obj)"
 by (drule is_valid_ObjHeader_len) unat_arith

lemma is_valid_ObjHeader_buf_len:
  "is_valid_ObjHeader obj data \<Longrightarrow>
   (unat $ Obj.len\<^sub>f obj) \<le> length data \<and>
  unat bilbyFsObjHeaderSize \<le> length data"
  apply (clarsimp simp add: is_valid_ObjHeader_def)
  apply (drule is_len_and_type_ok_hdr_szD)
  apply unat_arith
 done

definition sObjPad :: "U32 \<Rightarrow> U8 list"
where
  "sObjPad olen \<equiv> replicate (unat (olen - bilbyFsObjHeaderSize)) bilbyFsPadByte"

consts pObjSummary :: "U8 list \<Rightarrow> U32 \<Rightarrow> ObjSummary\<^sub>T"
consts pObjPad :: "U8 list \<Rightarrow> U32 \<Rightarrow> unit"

definition pObjUnion :: "U8 list \<Rightarrow> U8 \<Rightarrow> U32 \<Rightarrow> U32 \<Rightarrow> ObjUnion\<^sub>T"
where
 "pObjUnion data otype olen offs  \<equiv>
   if otype = bilbyFsObjTypePad then
    TObjPad ()
   else if otype = bilbyFsObjTypeData then
    TObjData (pObjData data offs olen)
   else if otype = bilbyFsObjTypeInode then
    TObjInode (pObjInode data offs)
   else if otype = bilbyFsObjTypeDentarr then
    TObjDentarr (pObjDentarr data offs olen)
   else if otype = bilbyFsObjTypeDel then
    TObjDel (pObjDel data offs)
   else if otype = bilbyFsObjTypeSuper then
    TObjSuper (pObjSuper data offs)
   else (*if otype = bilbyFsObjTypeSum then
    TObjSummary (pObjSummary data offs) *) (* see comments in: serial.cogent for deserialise_ObjUnion:*)
    TObjPad ()"

definition pObj :: "U8 list \<Rightarrow> U32 \<Rightarrow> Obj\<^sub>T"
where
 "pObj data offs \<equiv>
   let obj = pObjHeader data offs
   in obj \<lparr>ounion\<^sub>f:= pObjUnion (take (unat offs + unat (Obj.len\<^sub>f obj)) data) (otype\<^sub>f  obj) (Obj.len\<^sub>f obj) (offs+bilbyFsObjHeaderSize)\<rparr>"

text {* This could be implemented in Cogent instead *}
definition serialise_size_summary_Obj :: "ObjSummary\<^sub>T \<Rightarrow> U32"
where
 "serialise_size_summary_Obj summary \<equiv>
   bilbyFsObjHeaderSize + serialise_size_ObjSummary (nb_sum_entry\<^sub>f summary)"

definition os_sum_sz :: "OstoreState\<^sub>T \<Rightarrow> U32"
where
 "os_sum_sz ostore_st \<equiv> serialise_size_summary_Obj (summary\<^sub>f ostore_st)"

definition bilbyFsMinObjSize :: U32
where
 "bilbyFsMinObjSize \<equiv> bilbyFsObjHeaderSize + 8"

lemma deserialise_u8_ret:
assumes wf: "wellformed_buf buf"
assumes valid_offs:
  "offs < bound\<^sub>f buf"
shows
  "deserialise_u8 (buf, offs) =  (\<alpha>wa $ data\<^sub>f buf) ! (unat offs)"
using valid_offs wordarray_get_ret[where arr="data\<^sub>f buf" and index=offs]
  wf[simplified wellformed_buf_def]
  apply  (simp add: deserialise_u8_def)
  apply (erule meta_impE)
   apply unat_arith
  apply simp
 done

lemmas objheaders_simps = bilbyFsMagic_def
    bilbyFsObjTypeInode_def bilbyFsObjTypeData_def
                  bilbyFsObjTypeDentarr_def bilbyFsObjTypeDel_def bilbyFsObjTypePad_def
                  bilbyFsObjTypeSuper_def bilbyFsObjTypeSum_def
    bilbyFsTransIn_def bilbyFsTransCommit_def is_valid_ObjHeader_def pObjHeader_def
    Obj.make_def  

lemma deserialise_ObjHeader_ret:
  assumes wf: "wellformed_buf buf"
  assumes bound: "offs + bilbyFsObjHeaderSize \<le> bound\<^sub>f buf"
  assumes no_of: "offs < offs + bilbyFsObjHeaderSize"
  assumes err: "\<And>obj. P (obj, Error eInval)"
  assumes suc:
  "\<And>obj offs'. \<lbrakk>  is_valid_ObjHeader (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs) (bounded buf) ;
    \<exists>v. obj\<lparr>ounion\<^sub>f:=v\<rparr> = pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs;
    offs' = offs + bilbyFsObjHeaderSize;
    offs + Obj.len\<^sub>f obj \<le> bound\<^sub>f buf;
    offs < offs + Obj.len\<^sub>f obj\<rbrakk> \<Longrightarrow> 
   P (obj, Success (offs'))"
 notes bilbyFsObjHeaderSize_def[simp]
  shows "P (deserialise_ObjHeader (buf, offs, obj))"
proof -
  have des_u8: 
    "deserialise_u8 (buf, offs + 23) =  (\<alpha>wa $ data\<^sub>f buf) ! unat (offs + 23)"  
    "deserialise_u8 (buf, offs + 22) =  (\<alpha>wa $ data\<^sub>f buf) ! unat (offs + 22)"
    using bound no_of
    by - ((subst deserialise_u8_ret[OF wf]), (unat_arith, simp+))+

  have des_le64:
    "deserialise_le64 (buf, offs + 8) = (ple64 (\<alpha>wa $ data\<^sub>f buf) (offs + 8))"
  apply (rule ple64_ret)
    using no_of
    apply (simp add: )
    apply (simp add: unat_arith_simps, unat_arith)
   using bound wf no_of
   apply (simp add: bounded_def wellformed_buf_def unat_arith_simps)
   apply unat_arith
  apply (simp add: bounded_def)
  apply (subst  ple64_take)
    using bound no_of
    apply (simp add: bounded_def unat_arith_simps)
    apply unat_arith
   using wf bound no_of
   apply (simp add: wellformed_buf_def unat_arith_simps)
  apply unat_arith
  apply simp
 done

 have des_le32:
    "deserialise_le32 (buf, offs) = (ple32 (\<alpha>wa $ data\<^sub>f buf) offs)"  
    "deserialise_le32 (buf, offs+4) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 4))"  
    "deserialise_le32 (buf, offs+16) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 16))"
ML_prf{*
fun solve_deserialise_le32 ctxt = 
  let 
  val add_simp = Simplifier.add_simp;
  fun add_simps ctxt [] = ctxt
   |  add_simps ctxt (thm::thms) = add_simps (add_simp thm ctxt) thms;
  val simp = Simplifier.asm_full_simp_tac;
  val unat = (unat_arith_tac ctxt 1);

  val ple32 = Method.rule_tac ctxt @{thms ple32_ret} [] 1;
  val wf_bounded_unat = @{thms wellformed_buf_def bounded_def unat_arith_simps};
  val simp_wf_bounded_unat = simp (add_simps ctxt wf_bounded_unat) 1;
  val simp_bounded = simp (add_simp @{thm bounded_def} ctxt) 1;
  val ple32_take = Method.rule_tac ctxt @{thms ple32_take} [] 1;
  val simp_unat_plus = REPEAT_DETERM_N 2 ( simp_wf_bounded_unat THEN unat);
  in
    DETERM (ple32 THEN  simp_unat_plus )
    THEN (simp_bounded THEN ple32_take THEN simp_unat_plus)
  end
*}
    using wf bound no_of
    by - (tactic {* solve_deserialise_le32  @{context} *})+
    
  show ?thesis
  unfolding deserialise_ObjHeader_def[unfolded tuple_simps sanitizers]
  apply (clarsimp simp:Let_def err[simplified eInval_def])
  apply (frule is_len_and_type_ok_hdr_szD)
  apply (rule suc)
       apply (clarsimp simp: objheaders_simps buf_simps des_le32 des_u8 )
       apply (subgoal_tac "\<exists>v. ple32 (\<alpha>wa (data\<^sub>f buf)) (offs + 0x10) = v")
        prefer 2
        apply clarsimp
       apply (erule exE, simp add: bounded_def)
       using bound no_of wf apply (simp add: wellformed_buf_def)
      apply (rule conjI)
       apply unat_arith
      apply (unat_arith)
     apply (rule_tac x=undefined in exI) 
     apply (simp add: pObjHeader_def Obj.defs buf_simps des_le32 des_u8 des_le64)
    apply (simp)
   apply (simp, unat_arith)+
 done
qed

definition
  sObjUnion :: "ObjUnion\<^sub>T \<Rightarrow> U8 \<Rightarrow> U32 \<Rightarrow> U8 list"
where
 "sObjUnion (ou::ObjUnion\<^sub>T) (otype::U8) (olen::U32) \<equiv> 
  case ou of
    TObjDentarr odent \<Rightarrow> undefined (* TODO: no dentarr support for now *)
  | TObjInode oinod \<Rightarrow> sObjInode oinod
  | TObjData odata \<Rightarrow> sObjData odata olen
  | TObjDel odel \<Rightarrow> sObjDel odel
  | TObjSuper osup \<Rightarrow> sObjSuper osup
  | TObjSummary g \<Rightarrow> undefined (* TODO: sObjSummary is undefined*)
  | TObjPad opad \<Rightarrow>  sObjPad olen"

lemmas bilbyFsObjTypes = 
  bilbyFsObjTypePad_def
  bilbyFsObjTypeInode_def
  bilbyFsObjTypeData_def
  bilbyFsObjTypeDentarr_def
  bilbyFsObjTypeDel_def
  bilbyFsObjTypeSuper_def
  bilbyFsObjTypeSum_def

lemma ObjUnion_inverse:
 "\<And>v. ounion = TObjPad v \<Longrightarrow> otype = bilbyFsObjTypePad \<Longrightarrow>
 pObjUnion (sObjUnion ounion otype olen @ xs) otype olen 0 = ounion"
 by (simp add: sObjUnion_def pObjUnion_def )

lemma length_sObjUnion:
 "\<And>v. ounion = TObjPad v \<Longrightarrow> otype = bilbyFsObjTypePad \<Longrightarrow>
  olen \<ge> bilbyFsObjHeaderSize  \<Longrightarrow>
    length (sObjUnion ounion otype olen) = unat olen - unat bilbyFsObjHeaderSize"
  apply (simp add: sObjUnion_def sObjPad_def )
  apply unat_arith
 done


definition sObj :: "Obj\<^sub>T \<Rightarrow> U8 list"
where
 "sObj obj \<equiv> sObjHeader obj @ sObjUnion (ounion\<^sub>f obj) (otype\<^sub>f obj) (Obj.len\<^sub>f obj)"

lemma length_sObjHeader:
 "length (sObjHeader obj) = unat bilbyFsObjHeaderSize"
 by (simp add: sObjHeader_def length_sle32 length_sle64 bilbyFsObjHeaderSize_def)
 
lemma length_sObj:
  "Obj.len\<^sub>f obj \<ge> bilbyFsObjHeaderSize \<Longrightarrow>
   otype\<^sub>f obj = bilbyFsObjTypePad \<Longrightarrow> 
   is_valid_Obj obj \<Longrightarrow>
   length (sObj obj) = unat (Obj.len\<^sub>f obj)"
  apply (clarsimp simp add: is_valid_Obj_def split:if_splits)
  apply (drule (2)  length_sObjUnion)
  apply (simp add: sObj_def length_sObjHeader word_le_nat_alt)
 done

lemma Obj_inverse:
 "otype\<^sub>f obj = bilbyFsObjTypePad \<Longrightarrow>
   is_valid_Obj obj \<Longrightarrow>
   Obj.offs\<^sub>f obj = 0 \<Longrightarrow>
   pObj (sObj obj @ xs) 0 = obj"
 unfolding pObj_def sObj_def Let_def
  apply (simp add: ObjHeader_inverse)
  apply (clarsimp simp: is_valid_Obj_def)
  apply (frule (1) ObjUnion_inverse)
  apply (simp add: pObjUnion_def sObjHeader_def word_le_nat_alt length_sObjHeader)
 done

lemma buf_sub_slice_len_simplified:
  "length v1 = unat j \<Longrightarrow> unat (offs :: 32 word) < length (\<alpha>wa (data\<^sub>f buf)) \<Longrightarrow>
    unat (offs + j) \<le> length (\<alpha>wa (data\<^sub>f buf)) \<Longrightarrow>
    unat offs < unat (offs + j) \<Longrightarrow>
     length (take (unat offs) (\<alpha>wa (data\<^sub>f buf)) @
              v1 @
              drop (unat (offs + j)) (\<alpha>wa (data\<^sub>f buf))) = length (\<alpha>wa (data\<^sub>f buf))"
    by simp unat_arith
 
lemma buf_sub_slice_absorb:
  assumes len1: "length v1 = unat j"
  and     len2: "length v2 = unat (k-j)"
  and   j_less: "j \<le> k"
  and     j_nz: "j > 0"
  and    no_of: "unat offs < unat (offs + k)"
  and   len_ge: "unat (offs + k) \<le> length (\<alpha>wa (data\<^sub>f buf))"
  shows "(buf_sub_slice (buf \<lparr>data\<^sub>f := WordArrayT.make
      (buf_sub_slice buf offs (offs + j) v1)\<rparr>)
                               (offs + j) (offs + k)
                               v2) =
             buf_sub_slice buf offs (offs + k) (v1 @ v2)"
  proof -
    have j_sub: "unat (offs + j) - unat offs = unat j"
      using no_of j_less by unat_arith
    have j_max: "unat (offs + j) \<ge> unat offs"
      using no_of j_less by unat_arith
    have k_j_sub: "unat (offs + k) - unat (offs + j) = unat (k - j)"
      using no_of j_less by unat_arith
    have k_sub: "(unat (offs + k) - unat offs) = unat k"
      using no_of by unat_arith
    have k_max: "(unat (offs + k)) \<ge> (unat offs)"
      using no_of by unat_arith
    have k_j_max: "(unat (offs + k)) \<ge> (unat (offs + j))"
      using no_of j_less by unat_arith
    have xx: "\<And>x v. data\<^sub>f (x\<lparr>data\<^sub>f := v\<rparr>) = v"
      by simp
    have len_ge': " unat offs < length (\<alpha>wa (data\<^sub>f buf))"
      using len_ge no_of by unat_arith
    have len_ge'': " unat (offs + j) \<le> length (\<alpha>wa (data\<^sub>f buf))"
      using len_ge no_of j_less by unat_arith
    have no_of': "unat offs < unat (offs + j)"
      using no_of j_less j_nz by unat_arith
    have len_app: "length (v1 @ v2) = unat k"
      using len1 len2 j_less by unat_arith
    have take_prefix: "(take (unat (offs + j))
           (take (unat offs) (\<alpha>wa (data\<^sub>f buf)) @
            v1 @ drop (unat (offs + j)) (\<alpha>wa (data\<^sub>f buf)))) 
         = take (unat offs) (\<alpha>wa (data\<^sub>f buf)) @
            v1" 
        using len1 no_of' len_ge' j_sub by simp
    have drop_prefix: "drop (unat (offs + k))
           (take (unat offs) (\<alpha>wa (data\<^sub>f buf)) @
            v1 @ drop (unat (offs + j)) (\<alpha>wa (data\<^sub>f buf))) 
             = drop (unat (offs + k))(\<alpha>wa (data\<^sub>f buf))"
        apply (subgoal_tac "(unat k - unat j + unat (offs + j)) = unat (offs + k)")
         prefer 2
         using no_of j_less apply unat_arith
        using len1 len_ge' k_sub j_less no_of apply simp
        by unat_arith
    thus ?thesis
      unfolding buf_sub_slice_def 
      using j_sub j_max k_j_sub k_sub k_max k_j_max apply (simp only: max_absorb1)
      using len1
      apply (subst take_append[where n="unat j"])+
      apply (simp only: diff_self_eq_0 take_0 append_Nil2)
      using len2 apply (subst take_append[where n="unat (k-j)"])+
      apply (simp only: diff_self_eq_0 take_0 append_Nil2)
      using len_app apply (subst take_append[where n="unat k"])
      apply (simp only: diff_self_eq_0 take_0 append_Nil2)
      using len1 k_j_sub apply (simp only:)
      apply (simp only:  xx wordarray_make fun_app_def)
      using len1 len2 len_app apply (simp only: take_all[where n="unat j"]
                                        take_all[where n="unat k"]
                                        take_all[where n="unat (k-j)"])
      using len1 len_ge len_ge' len_ge'' no_of' len_app no_of
      by (simp add: buf_sub_slice_len_simplified take_prefix drop_prefix)
   qed

lemma serialise_u8_ret':
    notes  wa_modify_ret = wordarray_modify_ret[rotated - 1, simplified Let_def]
    assumes no_of: "offs < offs + 1"
       and len_ge: "unat offs + 1 \<le> length (\<alpha>wa (data\<^sub>f buf))"
    shows "serialise_u8 (buf, offs, v) = 
      buf \<lparr>data\<^sub>f := WordArrayT.make (buf_sub_slice buf offs (offs + 1) [v])\<rparr>"
   proof -
    have offs_sub: "(unat (offs + 1) - unat offs) = 1" using no_of by unat_arith
    have no_of_unat: " unat offs < unat (offs + 1)" using no_of by (simp add: word_less_nat_alt)
    show ?thesis
    unfolding serialise_u8_def[unfolded sanitizers] Let_def
  using no_of len_ge
  apply simp
  apply (rule wa_modify_ret[where index="offs" and varr="(data\<^sub>f buf)"])
   prefer 2
   apply (unat_arith)
  apply (simp_all  add:ArrA.defs ElemAO.defs  ElemA.defs
                  setu8_def[unfolded tuple_simps sanitizers] wordarray_make buf_simps
                  min_absorb1 min_absorb2)
  apply (rule arg_cong[where f="\<lambda>v. Buffer.data\<^sub>f_update v buf"])
  apply (rule ext)
  apply (rule arg_cong[where f="WordArrayT.make"])
  apply (simp only: list_eq_iff_nth_eq)
  apply (clarsimp simp: buf_sub_slice_length)
  apply (simp add: buf_sub_slice_def min_absorb1 min_absorb2)
  apply (case_tac "i=unat offs")
   apply (simp only: append_assoc[symmetric] nth_append)
   apply (simp add: min_absorb1 min_absorb2)
   apply unat_arith
  apply (case_tac "i < unat offs")
   apply (simp add: min_absorb1 offs_sub max_absorb1 no_of no_of_unat nth_append)
  apply (simp add: min_absorb1 offs_sub max_absorb1)
  apply (subgoal_tac "(max (unat (offs + 1)) (unat offs)) = unat (offs + 1)")
   prefer 2
   using no_of_unat apply auto[1]
  apply (clarsimp simp add: nth_append nth_Cons split: nat.splits)
  apply (subst nth_drop)
   apply unat_arith
  apply (subgoal_tac "unat (offs + 1) = unat offs + 1")
   prefer 2
   using no_of_unat offs_sub apply simp
  apply simp
  apply (subgoal_tac "i = Suc (unat offs + x2)")
   apply simp
  apply unat_arith
 done
 qed

lemma serialise_ObjHeader_ret:
  assumes no_overflow: "offs \<le> offs + bilbyFsObjHeaderSize"
  and     is_valid_obj: "is_valid_ObjHeader obj (drop (unat offs) (\<alpha>wa (data\<^sub>f buf)))"
  and     suc: "\<And>buf' offs'. 
   offs' = offs + bilbyFsObjHeaderSize \<Longrightarrow>
   buf' = buf\<lparr>data\<^sub>f := WordArrayT.make (buf_sub_slice buf offs (offs +bilbyFsObjHeaderSize) (sObjHeader obj))\<rparr> \<Longrightarrow>
    P (buf', offs')"
  shows
   "P (serialise_ObjHeader (buf, offs, obj))" 
   proof -
    have offs_le_length: "unat offs \<le> length (\<alpha>wa (data\<^sub>f buf))"
      using is_valid_ObjHeader_len_facts[OF is_valid_obj]
      by (clarsimp simp: is_valid_ObjHeader_def bilbyFsObjHeaderSize_def) unat_arith
   have offs_sub_le: "(unat (offs + bilbyFsObjHeaderSize) - unat offs) \<le> (length (\<alpha>wa (data\<^sub>f buf)) - unat offs)"
      using is_valid_obj is_valid_ObjHeader_len_facts[OF is_valid_obj]
      by (clarsimp simp: is_valid_ObjHeader_def bilbyFsObjHeaderSize_def) unat_arith
   have offs_len_sub_eq: "unat (offs + bilbyFsObjHeaderSize) - unat offs = unat (bilbyFsObjHeaderSize)"
      using no_overflow by unat_arith
   have offs_obj_len_le_length: "unat (offs + bilbyFsObjHeaderSize) \<le> length (\<alpha>wa (data\<^sub>f buf))"
     using is_valid_obj offs_sub_le is_valid_ObjHeader_len_facts[OF is_valid_obj]
     by (clarsimp simp: is_valid_ObjHeader_def bilbyFsObjHeaderSize_def) unat_arith
   have offs_obj_len_le_length': "(unat (offs + bilbyFsObjHeaderSize) -
                (unat offs + unat bilbyFsObjHeaderSize)) \<le> (length (\<alpha>wa (data\<^sub>f buf)) -
                   (unat offs + unat bilbyFsObjHeaderSize))"
      using offs_obj_len_le_length by unat_arith   
   have offs_plus_eq: " (unat (offs + bilbyFsObjHeaderSize) = (unat offs + unat bilbyFsObjHeaderSize))"
      using no_overflow by unat_arith
   show ?thesis
  unfolding serialise_ObjHeader_def[unfolded sanitizers tuple_simps]
  apply (simp add: Let_def)
  apply (rule suc)
   apply (simp add: bilbyFsObjHeaderSize_def)
  apply (simp add: buf_sub_slice_def wordarray_make)
  apply (simp add:  min_absorb1 offs_le_length offs_sub_le)
  apply (simp add: offs_len_sub_eq length_sObjHeader
                    offs_obj_len_le_length' offs_plus_eq)
  using no_overflow apply (simp add: word_le_nat_alt max_absorb1 bilbyFsObjHeaderSize_def)
  using no_overflow offs_obj_len_le_length apply (simp add: bilbyFsObjHeaderSize_def)
  apply (subst serialise_le32_ret[where v="magic\<^sub>f obj"])
    apply ((unat_arith, auto)+)[2]
  apply (subst serialise_le32_ret[where v="crc\<^sub>f obj"])
     apply ((unat_arith, auto)+)[1]
    apply (simp add: buf_sub_slice_length wordarray_make)
    apply (unat_arith, auto)[1]
   apply (simp)
   apply (subst add.commute[where a=8])
   apply (subst buf_sub_slice_absorb[where offs=offs and j=4 and k=8, simplified])
       apply (simp add: length_sle32)+
     apply unat_arith 
     apply auto[1]
    apply unat_arith 
    apply auto[1]
   apply (subst serialise_le64_ret)
     apply (unat_arith, auto)[1]

    apply (simp add: buf_sub_slice_length wordarray_make)
    apply (unat_arith, auto)[1]
   apply simp
   apply (subst add.commute[where a="0x10"])
   apply (subst buf_sub_slice_absorb)
         apply (simp add: length_sle32 length_sle64)+
     apply ((unat_arith, auto)+)[2]
   apply (subst serialise_le32_ret)
     apply ((unat_arith, auto)+)[1]
    apply (simp add: buf_sub_slice_length wordarray_make)
    apply (unat_arith, auto)[1]
   apply (simp)
   apply (subst add.commute[where a="0x14"])
   apply (subst buf_sub_slice_absorb)
           apply (simp add: length_sle32 length_sle64)+
      apply ((unat_arith, auto)+)[2]
   apply (subst serialise_u8_ret'[where offs="offs + 0x14"])
     apply (unat_arith, auto)[1]
    apply (simp add: buf_sub_slice_length wordarray_make)
    apply (unat_arith, auto)[1]
   apply (simp)
   apply (subst add.commute[where a="0x15"])
   apply (subst buf_sub_slice_absorb)
         apply (simp add: length_sle32 length_sle64)+
     apply ((unat_arith, auto)+)[2]
    apply (subst serialise_u8_ret'[where offs="offs + 0x15"])
     apply (unat_arith, auto)[1]
    apply (simp add: buf_sub_slice_length wordarray_make)
    apply (unat_arith, auto)[1]
   apply (simp)
   apply (subst add.commute[where a="0x16"])
   apply (subst buf_sub_slice_absorb)
         apply (simp add: length_sle32 length_sle64)+
     apply ((unat_arith, auto)+)[2] 
   apply (subst serialise_u8_ret'[where offs="offs + 0x16"])
     apply (unat_arith, auto)[1]
    apply (simp add: buf_sub_slice_length wordarray_make)
    apply (unat_arith, auto)[1]
   apply (simp)
   apply (subst add.commute[where a="0x17"])
   apply (subst buf_sub_slice_absorb)
         apply (simp add: length_sle32 length_sle64)+
     apply ((unat_arith, auto)+)[2] 
   apply (subst serialise_u8_ret'[where offs="offs + 0x17"])
     apply (unat_arith, auto)[1]
    apply (simp add: buf_sub_slice_length wordarray_make)
    apply (unat_arith, auto)[1]
   apply (simp)
   apply (subst add.commute[where a="0x18"])
   apply (subst buf_sub_slice_absorb)
         apply (simp add: length_sle32 length_sle64)+
     apply ((unat_arith, auto)+)[2]
  
  apply (simp add: sObjHeader_def bilbyFsPadByte_def)
  apply (unfold buf_sub_slice_def)
  apply (simp add: offs_len_sub_eq[unfolded bilbyFsObjHeaderSize_def, simplified])
  apply (simp add: length_sle32 length_sle64)
  apply (subgoal_tac "(length (\<alpha>wa (data\<^sub>f buf)) - unat offs) \<ge> 24")
   prefer 2
   using offs_len_sub_eq bilbyFsObjHeaderSize_def apply (unat_arith, auto)[1]
  apply simp
  apply (subgoal_tac "(unat (offs + 0x18)) > (unat offs)")
   prefer 2
   using no_overflow apply (unat_arith, auto)[1]
  apply (simp add: max_absorb1)
  apply (rule arg_cong[where f="\<lambda>v. Buffer.data\<^sub>f_update v buf"])
  apply (rule ext)
  apply (rule arg_cong[where f="WordArrayT.make"])
   apply simp
  by (subst take_all, 
          ( simp add: length_sle32 length_sle64 | (unat_arith, auto)[1] )+
     )+
qed
  
lemmas ObjUnion_splits = ObjUnion.splits

lemma take_drop_decomp:"x \<ge> a \<Longrightarrow> take (x - a) (drop a xs) @ drop x xs = drop a xs"
  by (metis drop_take drop_take_drop)

lemma serialise_ObjPad_ret:
  assumes no_overflow: "offs \<le> offs + (olen - bilbyFsObjHeaderSize)"
  and     no_underflow: "olen - bilbyFsObjHeaderSize \<ge> 0"
  and     bound: "offs+ (olen - bilbyFsObjHeaderSize) \<le> bound\<^sub>f buf \<and> unat (bound\<^sub>f buf) \<le> length (\<alpha>wa (data\<^sub>f buf))" 
  and     suc: "\<And>buf' offs'. 
   offs' = offs + olen - bilbyFsObjHeaderSize \<Longrightarrow>
   buf' = buf\<lparr>data\<^sub>f := WordArrayT.make (buf_sub_slice buf offs (offs + (olen - bilbyFsObjHeaderSize)) (sObjPad olen))\<rparr> \<Longrightarrow>
    P (buf', offs')"
  shows
   "P (serialise_ObjPad (buf, offs, olen))"
   proof -
   
    have offs_le_bound: "offs \<le> bound\<^sub>f buf"
      using bound no_overflow by unat_arith
    have sub1: "(unat (olen - 0x18)) \<le> (unat (bound\<^sub>f buf) - unat offs)"
      using bound no_overflow no_underflow apply (clarsimp simp: bilbyFsObjHeaderSize_def)
      by unat_arith
    have sub2: "(unat (offs + (olen - 0x18)) - unat offs) = unat (olen - 0x18)"
      using bound no_overflow no_underflow apply (clarsimp simp: bilbyFsObjHeaderSize_def)
      by unat_arith (* takes ages *)
    have sub3: "unat (olen - 0x18) \<le> (length (\<alpha>wa (data\<^sub>f buf)) - unat offs)"
      using bound no_overflow no_underflow apply (clarsimp simp: bilbyFsObjHeaderSize_def)
      by unat_arith
    have sub4: "(unat (offs + (olen - 0x18)) - (unat offs + unat (olen - 0x18))) = 0"
      using bound no_overflow no_underflow apply (clarsimp simp: bilbyFsObjHeaderSize_def)
      by unat_arith
    have sub5: "(unat offs +
            (unat (olen - 0x18) + length (\<alpha>wa (data\<^sub>f buf))) -
            unat (offs + (olen - 0x18))) = length (\<alpha>wa (data\<^sub>f buf))"
      using bound no_overflow no_underflow apply (clarsimp simp: bilbyFsObjHeaderSize_def)
      by unat_arith
    have no_of_unat: "unat offs \<le> (unat (offs + (olen - 0x18)))"
      using no_overflow no_underflow by (simp add: bilbyFsObjHeaderSize_def word_le_nat_alt)
    have assoc: "(unat (offs + (olen - 0x18))) = unat offs + unat (olen - 0x18)"
      using no_overflow no_underflow by (simp add: bilbyFsObjHeaderSize_def) unat_arith
   show ?thesis
    unfolding serialise_ObjPad_def[unfolded sanitizers tuple_simps]
  apply (simp add: Let_def split: ObjUnion_splits)
  apply (rule suc)
   apply (simp add: bilbyFsObjHeaderSize_def)
  apply (subst buf_memset_eq)
    using bound apply simp
   using no_overflow  apply  (simp add: bilbyFsObjHeaderSize_def)
  apply (rule arg_cong[where f="\<lambda>v. Buffer.data\<^sub>f_update v buf"])
  apply (rule ext)
  apply (rule arg_cong[where f="WordArrayT.make"])
  using bound offs_le_bound apply (clarsimp simp: buf_sub_slice_def bilbyFsObjHeaderSize_def)
  apply (simp add: sObjPad_def bilbyFsPadByte_def buf_simps
                    min_absorb1 min_absorb2 word_le_nat_alt sub1 sub2 sub3 sub4 sub5
                    bilbyFsObjHeaderSize_def no_of_unat max_absorb1 assoc)
   
  apply (subst take_drop_decomp)
   using no_overflow no_underflow apply (clarsimp simp: bilbyFsObjHeaderSize_def)
  apply simp
 done
 qed
   
lemma serialise_ObjUnion_ret:
  assumes no_overflow: "offs \<le> offs + (olen - bilbyFsObjHeaderSize)"
  and     otype: "otype = bilbyFsObjTypePad"
  and     ounion: "\<And>v. ounion = TObjPad v"
  and     olen: " 0 \<le> olen - bilbyFsObjHeaderSize"
  and     bound: "offs + (olen - bilbyFsObjHeaderSize) \<le> bound\<^sub>f buf \<and> unat (bound\<^sub>f buf) \<le> length (\<alpha>wa (data\<^sub>f buf))" 
  and     suc: "\<And>buf' offs'. 
   offs' = offs + olen - bilbyFsObjHeaderSize \<Longrightarrow>
   buf' = buf\<lparr>data\<^sub>f := WordArrayT.make (buf_sub_slice buf offs (offs + (olen - bilbyFsObjHeaderSize)) (sObjUnion ounion otype olen))\<rparr> \<Longrightarrow>
    P (buf', offs')"
  shows
   "P (serialise_ObjUnion (buf, offs, ounion, olen))"
  unfolding serialise_ObjUnion_def[unfolded sanitizers tuple_simps]
  using ounion apply (simp add: Let_def split: ObjUnion_splits)
  apply (rule serialise_ObjPad_ret)
    using no_overflow apply simp
    using olen apply simp
    using bound apply simp
   apply (rule suc, simp)
  apply (simp add: sObjUnion_def)
 done

lemma data\<^sub>f_of_data\<^sub>f_update:
  "data\<^sub>f (x\<lparr>data\<^sub>f := v\<rparr>) = v"
 by simp

lemma serialise_Obj_ret:
  assumes no_overflow: "offs \<le> offs + Obj.len\<^sub>f obj"
  and     is_valid_obj: "is_valid_ObjHeader obj (drop (unat offs) (\<alpha>wa (data\<^sub>f buf)))"
  and     otype: "otype\<^sub>f obj = bilbyFsObjTypePad"
  and     ounion: "\<And>v. ounion\<^sub>f obj = TObjPad v"
  and     bound: " offs + Obj.len\<^sub>f obj \<le> bound\<^sub>f buf \<and>
           unat (bound\<^sub>f buf) \<le> length (\<alpha>wa (data\<^sub>f buf))"
  and     suc: "\<And>buf'. 
   buf' = buf\<lparr>data\<^sub>f := WordArrayT.make (buf_sub_slice buf offs (offs + Obj.len\<^sub>f obj) (sObj obj))\<rparr> \<Longrightarrow>
    P (buf', offs + Obj.len\<^sub>f obj)"
  shows
   "P (serialise_Obj (buf, offs, obj))"
   unfolding serialise_Obj_def[unfolded tuple_simps sanitizers]
  apply (simp add: Let_def)
  apply (rule serialise_ObjHeader_ret)
    using no_overflow is_valid_obj apply (clarsimp simp: is_valid_ObjHeader_def bilbyFsObjHeaderSize_def)
    apply (frule is_len_and_type_ok_hdr_szD, simp add: bilbyFsObjHeaderSize_def)
    apply unat_arith
   using is_valid_obj apply assumption
  apply simp
  apply (rule serialise_ObjUnion_ret)
       using is_valid_obj no_overflow apply (clarsimp simp: is_valid_ObjHeader_def bilbyFsObjHeaderSize_def )
       apply (frule  is_len_and_type_ok_hdr_szD)
       apply (simp add: bilbyFsObjHeaderSize_def)
       apply unat_arith
      apply (rule otype)
     using ounion apply simp
    using is_valid_obj no_overflow apply (clarsimp simp: is_valid_ObjHeader_def bilbyFsObjHeaderSize_def)
   using bound apply (simp add: wordarray_make buf_sub_slice_length)
  apply simp
 apply (rule suc)
    apply (rule arg_cong[where f="\<lambda>v. Buffer.data\<^sub>f_update v buf"])
   apply (rule ext)
   apply (rule arg_cong[where f="WordArrayT.make"])
   apply (thin_tac x for x)+
   apply (subst buf_sub_slice_absorb)
         apply (simp  add: length_sObjHeader)
        apply (subst length_sObjUnion[OF ounion otype])
        using is_valid_obj apply (clarsimp simp: is_valid_ObjHeader_def is_len_and_type_ok_hdr_szD)
       using is_valid_obj no_overflow apply (clarsimp simp: is_valid_ObjHeader_def  unat_plus_simple)
       apply (drule is_len_and_type_ok_hdr_szD)
       apply (unat_arith)
       apply (simp add: is_len_and_type_ok_hdr_szD)
      apply(simp add: bilbyFsObjHeaderSize_def)
     using no_overflow is_valid_obj apply (clarsimp simp: is_valid_ObjHeader_def  bilbyFsObjHeaderSize_def)
     apply (simp add:  is_len_and_type_ok_def otype otype_simps)
     apply (unat_arith)
    using bound is_valid_obj apply (clarsimp simp: is_valid_ObjHeader_def)
    apply unat_arith
   apply (simp add: sObj_def)
 done

lemma binNot_NOT: "binNot (x::64 word) = NOT x"
  unfolding  binNot_def[unfolded Let_def]
  by (rule subst[where s="-1"], fastforce, fastforce)

lemma deserialise_ObjDel_ret:
  assumes bound: "unat offs + 8 \<le> length (\<alpha>wa $ data\<^sub>f buf)"
  assumes err: "P (Error (eInval, ex))"
  assumes offs: "offs < offs + 8"
  assumes suc:
   "\<And>obj offs'. \<lbrakk> 
    obj = pObjDel (\<alpha>wa $ data\<^sub>f buf) offs;
    ObjDel.id\<^sub>f obj AND NOT bilbyFsOidMaskAll \<in> 
      { bilbyFsOidMaskData, bilbyFsOidMaskInode,bilbyFsOidMaskDentarr};
    offs' = offs + 8\<rbrakk> \<Longrightarrow> 
   P (Success (ex, obj, offs'))"
  shows "P (deserialise_ObjDel (ex, buf, offs))"
proof - 
  have des_le64: "deserialise_le64 (buf, offs) = ple64 (\<alpha>wa $ data\<^sub>f buf) offs"
   using bound offs
   by (fastforce intro!: deserialise_le64_ret simp: unat_arith_simps)
  show ?thesis
  unfolding deserialise_ObjDel_def[unfolded tuple_simps sanitizers] 
  apply (clarsimp simp: Let_def err[simplified eInval_def])
  by (fastforce
     intro: suc
     simp: Let_def binNot_NOT bilbyFsOidMaskData_def des_le64 bilbyFsOidMaskAll_def
      bilbyFsOidMaskInode_def bilbyFsOidMaskDentarr_def pObjDel_def ObjDel.make_def)
qed

lemma deserialise_ObjInode_ret:
  assumes bound: "unat offs + 60 \<le> length (\<alpha>wa $ data\<^sub>f buf)"
  assumes offs: "offs < offs + 60"
  assumes err: "\<And>ex e. e \<in> {eInval, eNoMem} \<Longrightarrow> P (Error (e, ex))"
  assumes suc:
   "\<And>ex oi offs'. \<lbrakk> 
    oi = pObjInode (\<alpha>wa (data\<^sub>f buf)) offs;
    offs' = offs + 60\<rbrakk> \<Longrightarrow> 
   P (Success (ex, oi, offs'))"
  shows "P (deserialise_ObjInode (ex, buf, offs))"
proof -
  have des_le64:
    "deserialise_le64 (buf, offs) = (ple64 (\<alpha>wa $ data\<^sub>f buf) offs)"
    "deserialise_le64 (buf, offs + 8) = (ple64 (\<alpha>wa $ data\<^sub>f buf) (offs + 8))"
    "deserialise_le64 (buf, offs + 16) = (ple64 (\<alpha>wa $ data\<^sub>f buf) (offs + 16))"
    "deserialise_le64 (buf, offs + 24) = (ple64 (\<alpha>wa $ data\<^sub>f buf) (offs + 24))"
    "deserialise_le64 (buf, offs + 32) = (ple64 (\<alpha>wa $ data\<^sub>f buf) (offs + 32))"
     using bound offs
     by - (simp,rule deserialise_le64_ret[simplified];
                  (simp add: unat_arith_simps, unat_arith?))+
  have des_le32:
   "deserialise_le32 (buf, offs + 40) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 40))"
   "deserialise_le32 (buf, offs + 44) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 44))"
   "deserialise_le32 (buf, offs + 48) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 48))"
   "deserialise_le32 (buf, offs + 52) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 52))"
   "deserialise_le32 (buf, offs + 56) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 56))"
     using bound offs
     by - (simp,rule deserialise_le32_ret[simplified];
                  (simp add: unat_arith_simps, unat_arith?))+

  show ?thesis
  unfolding deserialise_ObjInode_def[unfolded tuple_simps sanitizers] 
  by (fastforce 
     intro: suc err
     split: R.split
     simp: eInval_def eNoMem_def binNot_NOT Let_def bilbyFsOidMaskAll_def des_le32
      bilbyFsOidMaskInode_def word32Max_def pObjInode_def ObjInode.make_def des_le64)
qed

lemma deserialise_ObjSuper_ret:
  assumes bound: "unat offs + 40 \<le> length (\<alpha>wa $ data\<^sub>f buf)"
  assumes offs: "offs \<le> offs + 40" (* added by Yutaka on 11th.*)
  assumes err: "\<And>ex. P (Error (eNoMem, ex))"
  assumes suc:
   "\<And>ex osup offs'. \<lbrakk> 
    osup = pObjSuper (\<alpha>wa (data\<^sub>f buf)) offs;
    offs' = offs + 40\<rbrakk> \<Longrightarrow> 
   P (Success (ex, osup, offs'))"
  shows "P (deserialise_ObjSuper (ex, buf, offs))"
proof -
  have des_le64:
    "deserialise_le64 (buf, offs + 32) = (ple64 (\<alpha>wa $ data\<^sub>f buf) (offs + 32))"
     using bound offs
     by - (simp,rule deserialise_le64_ret[simplified];
                  (simp add: unat_arith_simps, unat_arith?))
  have des_le32:
   "deserialise_le32 (buf, offs) = (ple32 (\<alpha>wa $ data\<^sub>f buf) offs)"
   "deserialise_le32 (buf, offs + 4) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 4))"
   "deserialise_le32 (buf, offs + 8) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 8))"
   "deserialise_le32 (buf, offs + 12) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 12))"
   "deserialise_le32 (buf, offs + 16) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 16))"
   "deserialise_le32 (buf, offs + 20) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 20))"
   "deserialise_le32 (buf, offs + 24) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 24))"
   "deserialise_le32 (buf, offs + 28) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 28))"
     using bound offs
     by - (simp,rule deserialise_le32_ret[simplified];
                  (simp add: unat_arith_simps, unat_arith?))+

  show ?thesis
  unfolding deserialise_ObjSuper_def[unfolded tuple_simps sanitizers] 
  by (fastforce 
     intro: suc err[unfolded eNoMem_def] 
     split: R.split 
     simp: pObjSuper_def ObjSuper.make_def des_le32 des_le64)
qed

lemma slice_Cons_helper:
  "i < length xs \<Longrightarrow>
    xs \<noteq> [] \<Longrightarrow>
    drop i xs = 
    (xs !  i) # drop ( (i + 1)) xs" 
    apply (cases xs, simp_all)
    by (metis (no_types, hide_lams) drop_Suc_Cons Cons_nth_drop_Suc length_Cons)

lemma slice_singleton:
 "f < length xs \<Longrightarrow> slice f (Suc f) xs = [xs ! f]"
 unfolding slice_def by (simp add:drop_take list_eq_iff_nth_eq)

lemma take_n_minus_1_append:
  "0<n \<Longrightarrow> xs \<noteq> [] \<Longrightarrow> n \<le> length xs \<Longrightarrow>
 take (n - Suc 0) xs @ [xs ! (n - Suc 0)] = take n xs"
  apply (simp only: list_eq_iff_nth_eq)
  apply clarsimp
  apply (case_tac "(length xs) < (n - Suc 0)")
   apply (clarsimp simp add: min_absorb2)+
  by (metis One_nat_def Suc_pred' elem_take_n le0 le_less_trans diff_le_self
  less_not_refl linorder_neqE_nat diff_Suc_less take_Suc_conv_app_nth)

lemma take_n_minus_1_append_eq:
  "v = xs ! (unat (n - 1)) \<Longrightarrow> unat n  \<le> length xs \<Longrightarrow> n> 0 \<Longrightarrow>
  take (unat ((n::U32) - 1)) xs @ [v] = take (unat n) xs"
  apply (simp add: list_eq_iff_nth_eq min_absorb2 unat_arith_simps)
  apply clarsimp
  apply (subst take_n_minus_1_append)
     apply simp+
  apply (case_tac xs, simp_all)
 done

lemma slice_n_minus_1_append_last:
 "unat acc + unat n \<le> length xs \<Longrightarrow>
  (n::U32) > 0 \<Longrightarrow>
  acc \<le> acc + n \<Longrightarrow>
  slice (unat acc) (unat acc + unat (n - 1)) xs @
  [xs ! unat (acc + (n - 1))] =
  slice (unat acc) (unat acc + unat n) xs"
  apply (simp add:  slice_def list_eq_iff_nth_eq)
  apply (subgoal_tac "(length xs) \<ge> (unat acc + unat (n - 1))")
   prefer 2
   apply unat_arith
  apply (rule conjI)
   apply (simp add: min_absorb1 min_absorb2)
  apply (clarsimp simp: drop_take min_absorb1 min_absorb2 )
  apply (subst take_n_minus_1_append_eq)
     apply simp
     apply (rule arg_cong[where f="nth xs"]) 
     apply unat_arith (* takes long *)
    apply simp+
 done

lemma map_deserialise_waU8_map_eq_slice_apply:
  assumes nonempty: "xs \<noteq> []"
  assumes "length xs = unat (n:: 32 word)"
  assumes n_gr_0: "n > 0"
  assumes no_overflow: "acc \<le> acc + n"
  assumes bound: "unat acc + length xs \<le> length (\<alpha>wa d)"
  shows "
    (mapAccumObs 0 (length xs) deserialise_waU8_map xs acc d) =
 (FunBucket.slice (unat acc) (unat acc + (length xs)) (\<alpha>wa d), acc + n)"
  using assms
  apply (clarsimp simp: mapAccumObs_def ElemAO.make_def
        deserialise_waU8_map_def[unfolded tuple_simps sanitizers] slice_def[where frm=0])
  apply (induct "xs" arbitrary: n rule: rev_nonempty_induct)
   apply (drule sym, simp add: slice_singleton wordarray_get_ret unat_arith_simps)
  apply (drule_tac x="n - 1" in meta_spec)
  apply (erule meta_impE)
   apply unat_arith
  apply (erule meta_impE)
   apply (subgoal_tac "unat n \<ge> 2")
   apply unat_arith
   apply (case_tac xs, simp, simp)
  apply (erule meta_impE)
   apply unat_arith
  apply (erule meta_impE)
   apply unat_arith
  apply (simp add: prod.case_eq_if)
  apply (rule wordarray_get_ret')
   apply unat_arith (* takes a while *)
  apply (simp only: slice_n_minus_1_append_last)
 done

lemma map_deserialise_waU8_map_eq_slice:
  assumes n_gr_0: "n > 0"
  assumes no_overflow: "acc \<le> acc + n"
  assumes bound: "unat acc + unat n \<le> length (\<alpha>wa d)"
  assumes "length xs = unat (n:: 32 word)"
  shows "
    prod.fst (mapAccumObs 0 (unat n) deserialise_waU8_map xs acc d) =
     (FunBucket.slice (unat acc) (unat acc + unat n ) (\<alpha>wa d))"
  using map_deserialise_waU8_map_eq_slice_apply[THEN arg_cong[where f=prod.fst]]
        assms

 by (subgoal_tac "xs \<noteq> []") (fastforce simp: unat_arith_simps)+

lemma deserialise_wordarray_U8_ret:
  assumes err: "\<And>ex. P (Error (eNoMem, ex))"
  assumes suc:                       
   "\<And>ex wa. 
   offs \<le> offs + len \<longrightarrow> unat offs + unat len \<le> length (\<alpha>wa $ data\<^sub>f buf) \<longrightarrow> 
   wa = WordArrayT.make (slice (unat offs) (unat offs + unat len) (\<alpha>wa (data\<^sub>f buf))) \<Longrightarrow> 
   P (Success (ex, wa))"
  shows "P (deserialise_wordarray_U8 (ex, buf, offs, len))"
  unfolding deserialise_wordarray_U8_def[unfolded tuple_simps sanitizers] 
  apply (simp add: Let_def)
  apply (rule wordarray_create_ret)
   apply simp
   apply (simp add: err[unfolded eNoMem_def])
  apply (rename_tac ex' wa)
  apply  simp
  apply (rule wordarray_copy_ret)
  apply (simp add:Let_def prod.case_eq_if)
  apply (rule suc)
  apply clarsimp
 done

lemma deserialise_ObjData_ret:
  assumes offs_no_of: "offs \<le> offs + (olen - bilbyFsObjHeaderSize)"
  assumes buf_len: "unat (offs + (olen - bilbyFsObjHeaderSize)) \<le> length (\<alpha>wa (data\<^sub>f buf))"
  assumes olen: "is_len_and_type_ok (bilbyFsObjTypeData, olen)"
  assumes err: "\<And>ex e. e \<in> {eInval, eNoMem} \<Longrightarrow> P (Error (e, ex))"
  assumes suc:
   "\<And>ex od offs' . \<lbrakk>
   ObjData.id\<^sub>f od AND NOT bilbyFsOidMaskAll OR bilbyFsOidMaskData = ObjData.id\<^sub>f od;
     od = pObjData (\<alpha>wa (data\<^sub>f buf)) offs olen;
    offs' = offs + olen - bilbyFsObjHeaderSize\<rbrakk> \<Longrightarrow> 
   P (Success (ex, od, offs'))"
  shows "P (deserialise_ObjData (ex, buf, offs, olen))"
  proof -

   have hdr_le_olen: "bilbyFsObjDataHeaderSize \<le> (olen - bilbyFsObjHeaderSize)"
    using olen
    by (simp add: is_len_and_type_ok_def[unfolded sanitizers tuple_simps] otype_simps
      bilbyFsObjHeaderSize_def bilbyFsObjDataHeaderSize_def) unat_arith

  have offs_pl_hdr_le_offs_pl_olen:
  "offs + bilbyFsObjDataHeaderSize \<le> offs + (olen - bilbyFsObjHeaderSize)"
   using hdr_le_olen offs_no_of
   by (simp add: bilbyFsObjDataHeaderSize_def bilbyFsObjHeaderSize_def word_plus_mono_right)


  have offs_pl_hdr_no_of:
   "offs < offs + bilbyFsObjDataHeaderSize"
    using offs_no_of  hdr_le_olen
    by (simp add: bilbyFsObjDataHeaderSize_def bilbyFsObjHeaderSize_def)
       unat_arith

  have offs_pl_hdr_le_buf_len:
   "unat offs + unat bilbyFsObjDataHeaderSize \<le> length (\<alpha>wa (data\<^sub>f buf))"
   using  buf_len hdr_le_olen offs_pl_hdr_no_of offs_pl_hdr_le_offs_pl_olen
   by (simp add: bilbyFsObjHeaderSize_def bilbyFsObjDataHeaderSize_def)
      unat_arith

  have unat_offs_pl_olen_etc_eq: "unat (offs + (olen - bilbyFsObjHeaderSize)) = unat (offs + 8) + unat (0xFFFFFFE0 + olen)"
   using olen hdr_le_olen offs_pl_hdr_no_of offs_pl_hdr_le_offs_pl_olen
   apply (simp add: bilbyFsObjHeaderSize_def bilbyFsObjDataHeaderSize_def)
   apply (simp add: is_len_and_type_ok_def[unfolded sanitizers tuple_simps] otype_simps bilbyFsObjHeaderSize_def)
   apply (subgoal_tac "unat (offs + (olen - 0x18)) = unat (offs + 8) + unat (olen - 0x18 - 8)")
    apply unat_arith
   apply (simp add: unat_arith_simps)
   apply unat_arith
  done

  show ?thesis
  unfolding deserialise_ObjData_def[unfolded tuple_simps sanitizers] 
  apply (clarsimp simp: Let_def err[unfolded eNoMem_def eInval_def] binNot_NOT)
  apply (rule deserialise_wordarray_U8_ret)
    apply (simp add: err)
   apply (erule impE)
    using offs_pl_hdr_no_of apply (simp add: bilbyFsObjHeaderSize_def bilbyFsObjDataHeaderSize_def add.commute add.assoc)
    apply (subgoal_tac "olen + 0xFFFFFFE8 = olen - 0x18") (* Oh! Beloved words <3 *)
     prefer 2
     apply simp
   apply (simp only:)
   apply simp
   using offs_pl_hdr_le_offs_pl_olen apply (simp add: bilbyFsObjHeaderSize_def bilbyFsObjDataHeaderSize_def )
  apply simp
  apply (rule suc)
    apply simp
    apply (simp add: bilbyFsOidMaskAll_def bilbyFsOidMaskData_def
      pObjData_def ObjData.make_def bilbyFsObjHeaderSize_def)
   apply (simp add: Let_def  pObjData_def ObjData.make_def bilbyFsObjHeaderSize_def bilbyFsObjDataHeaderSize_def)
  apply (subst deserialise_le64_ret)
    using offs_pl_hdr_le_buf_len[simplified bilbyFsObjHeaderSize_def bilbyFsObjDataHeaderSize_def]
    apply (simp add:)
   using offs_pl_hdr_no_of
    apply (simp add: bilbyFsObjDataHeaderSize_def)
   apply (erule impE)
    using buf_len unat_offs_pl_olen_etc_eq
    apply simp
   apply simp
  apply (simp add: bilbyFsObjHeaderSize_def)
 done
qed

lemma deserialise_ObjPad_ret:
  assumes err: "P (Error (eInval, ex))"
  assumes suc: "\<And> out offs' .
    \<lbrakk> olen - bilbyFsObjHeaderSize \<le> olen ; 
      out=(); 
      offs' = offs + (olen - bilbyFsObjHeaderSize) \<rbrakk> \<Longrightarrow> 
    P (Success (ex, out, offs'))"
  shows "P (deserialise_ObjPad (ex, buf, offs, olen))"
  unfolding deserialise_ObjPad_def[unfolded tuple_simps sanitizers]
  by (auto simp: Let_def err[unfolded eInval_def] suc[unfolded bilbyFsObjHeaderSize_def] split: R.split)

lemma no_offs_overflow:
  assumes wellformed_buf: "wellformed_buf buf"
  assumes no_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes offs_bound: "offs \<le> (bound\<^sub>f buf)"
  assumes "n < bilbyFsMaxEbSize"
  assumes "m < bilbyFsMaxEbSize"
  shows "offs + n \<le> offs + n + m"
  using assms
  by (auto simp add: bilbyFsMaxEbSize_def wellformed_buf_def unat_arith_simps)

lemma no_offs_overflow_le:
  assumes wellformed_buf: "wellformed_buf buf"
  assumes no_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes offs_bound: "offs \<le> (bound\<^sub>f buf)"
  assumes "n < bilbyFsMaxEbSize"
  assumes "m < bilbyFsMaxEbSize"
  assumes "m > 0"
  shows "offs + n < offs + n + m"
  using assms
  by (auto simp add: bilbyFsMaxEbSize_def wellformed_buf_def unat_arith_simps)

lemma conc_offs_no_of:
  assumes wellformed_buf: "wellformed_buf buf"
  assumes no_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes offs_bound: "offs \<le> (bound\<^sub>f buf)"
  assumes "m < bilbyFsMaxEbSize"
  assumes "m > 0"
  shows "offs < offs + m"
  using assms
  by (auto simp add: bilbyFsMaxEbSize_def wellformed_buf_def unat_arith_simps)

lemma slice_take:
  "m \<le> l \<Longrightarrow> 
  slice n m (take l xs) = slice n m xs"
  by (simp add: slice_def)

lemma deserialise_pu8_ret:
assumes valid_offs:
  "unat offs + 1 < length (\<alpha>wa $ data\<^sub>f buf)"
assumes no_of:
  "offs < offs + 1"
shows
  "deserialise_u8 (buf, offs) = (pu8 (\<alpha>wa $ data\<^sub>f buf) offs)"
proof -
  from no_of have no_of': "offs \<le> offs + 1" by simp
  hence offs_pl_1: "unat (offs + 1) = unat offs + 1" by (simp add: unat_plus_simple)
  show ?thesis
using valid_offs
  apply (clarsimp simp:  wordarray_get_ret[where arr="data\<^sub>f buf"]
                        deserialise_u8_def pu8_def)
  apply (rule trans, rule word_rcat_rsplit[symmetric])
  apply (rule arg_cong[where f=word_rcat])
  apply (subst word_rsplit_upt[where n=1], simp add: word_size)
   apply (simp)
  apply (simp add: slice_def)
  apply (simp add: ucast_def)
  apply (subst Cons_nth_drop_Suc[symmetric])
   apply simp
  apply simp
 done
qed

lemma pu8_take:
 assumes offs:"offs < offs+1"
 assumes ntake:"unat (offs + 1) \<le> ntake"
 shows   "pu8 (take ntake ys) offs = pu8 ys offs"
  apply (simp add: pu8_def)
  apply (rule arg_cong[where f="word_rcat"])
  apply (rule slice_take)
 using ntake offs by unat_arith

lemma deserialise_ObjDentry_ret:
  assumes wellformed_buf: "wellformed_buf buf"
  assumes no_buf_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes bound: "end_offs \<le> bound\<^sub>f buf"
  assumes off_less_end_offs: "offs \<le> end_offs"
  assumes err:
    "\<And>ex e. e \<in> {eInval, eNoMem} \<Longrightarrow> P (Error (e, ex))"
  assumes suc:
    "\<And>ex dentry offs'. \<lbrakk>
      unat offs + 8 + unat (wordarray_length (name\<^sub>f dentry)) \<le> unat (bound\<^sub>f buf);
      wordarray_length (name\<^sub>f dentry) \<le> bilbyFsMaxNameLen + 1;
      offs + 8 + wordarray_length (name\<^sub>f dentry) \<le> end_offs ;
      dentry = pObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs ;
      offs' = offs + 8 + wordarray_length (name\<^sub>f dentry);
      offs' \<le> (bound\<^sub>f buf)
        \<rbrakk> \<Longrightarrow>
      P (Success (ex, dentry, offs'))"
  shows "P (deserialise_ObjDentry (ex, buf, offs, end_offs))"
proof -
  {
    fix ex' dentry offs'
    assume des_suc: "unat offs + 8 \<le> unat (bound\<^sub>f buf)"

    then have offs_ok:"\<forall>n\<in>{0..7}. unat (offs + n)  < length (\<alpha>wa $ data\<^sub>f buf)"
    proof -
      from wellformed_buf[unfolded wellformed_buf_def] des_suc
      have "unat offs + 8 \<le> length (\<alpha>wa $ data\<^sub>f buf)"
        by unat_arith

      thus ?thesis
        by unat_arith
    qed

    from des_suc have deserialises:
      "deserialise_le32 (buf, offs)     = (ple32 (\<alpha>wa $ data\<^sub>f buf) offs)"
      "deserialise_u8   (buf, offs + 4) = (pu8 (\<alpha>wa $ data\<^sub>f buf) (offs + 4))"
      "deserialise_le16 (buf, offs + 6) = (ple16 (\<alpha>wa $ data\<^sub>f buf) (offs + 6))"
        apply clarsimp
        apply(rule deserialise_le32_ret[simplified])
      using assms[simplified bilbyFsMaxEbSize_def wellformed_buf_def]
         apply unat_arith 
      using assms[simplified bilbyFsMaxEbSize_def ]
        apply unat_arith
       apply (subst deserialise_pu8_ret)
      using offs_ok des_suc wellformed_buf
         apply (simp add: wellformed_buf_def, unat_arith)
      using des_suc
        apply unat_arith
       apply simp+
      apply(rule deserialise_le16_ret[simplified])
      using offs_ok des_suc wellformed_buf apply (simp add: wellformed_buf_def, unat_arith)
      using des_suc
      apply unat_arith
      done
  }
  note deserialises = this

  have offs_le_bound: "offs  \<le> bound\<^sub>f buf"
    using off_less_end_offs bound by simp

  have const_offs_no_of: "\<And>n. n < bilbyFsMaxEbSize \<Longrightarrow> 0 < n \<Longrightarrow> offs < offs + n"
    apply (rule conc_offs_no_of[OF wellformed_buf no_buf_overflow, unfolded bilbyFsMaxEbSize_def, simplified])
    using offs_le_bound by (simp add:bilbyFsMaxEbSize_def)+
  note no_of_8 = no_offs_overflow[OF wellformed_buf no_buf_overflow offs_le_bound, where m=8 and n=0, unfolded bilbyFsMaxEbSize_def, simplified, simplified unat_plus_simple]
  show ?thesis
    unfolding deserialise_ObjDentry_def[simplified tuple_simps sanitizers]
    apply (clarsimp simp: Let_def err[unfolded eNoMem_def eInval_def])
    apply (subst (asm) not_less)+
    apply (rule deserialise_wordarray_U8_ret)
     apply (clarsimp simp add: err)
    apply(clarsimp simp add: err eNoMem_def Let_def prod.case_eq_if split: R.splits)
    apply (erule impE)
     apply (rule no_offs_overflow[OF wellformed_buf no_buf_overflow])
    using off_less_end_offs bound apply fastforce
      apply (simp add: bilbyFsMaxEbSize_def)+
     apply unat_arith
    apply (subgoal_tac "unat offs + unat (8::32word) + unat (ucast (deserialise_le16 (buf, offs + 6))) \<le> unat end_offs")
     prefer 2
     apply (subst add.assoc)
     apply (subst unat_plus_simple[THEN iffD1, symmetric])
      apply (simp add: unat_arith_simps)
     apply (subst unat_plus_simple[THEN iffD1, symmetric])
      apply (rule no_offs_overflow[OF wellformed_buf no_buf_overflow, where n=0, simplified])
    using off_less_end_offs bound apply fastforce
       apply (simp add: bilbyFsMaxEbSize_def)+
      apply (simp add: unat_arith_simps)
     apply (simp add: word_le_nat_alt[symmetric] add.assoc)
    apply (erule impE)
    using bound wellformed_buf[unfolded wellformed_buf_def] 
     apply (simp add: unat_arith_simps)
     apply unat_arith
    apply (subgoal_tac "unat offs + 8 \<le> unat (bound\<^sub>f buf)")
     prefer 2 
     apply (subst unat_plus_simple[THEN iffD1, symmetric, 
          where y="8::32word", simplified])
      apply (rule no_offs_overflow[OF wellformed_buf no_buf_overflow, 
          where n=0, simplified])
    using off_less_end_offs bound apply fastforce
       apply (simp add: bilbyFsMaxEbSize_def)+ 
     apply (subst word_le_nat_alt[symmetric])
     apply (cut_tac no_offs_overflow[OF wellformed_buf no_buf_overflow, 
          where offs=offs and n=8 and m="ucast (deserialise_le16 (buf, offs + 6))"])
    using off_less_end_offs bound apply (simp_all add: bilbyFsMaxEbSize_def)
     apply unat_arith
    apply (simp add: deserialises) 
    apply (subgoal_tac "wordarray_length (WordArrayT.make
         (FunBucket.slice (unat (offs + 8)) 
          (unat (offs + 8) + unat (ucast (ple16 (\<alpha>wa (data\<^sub>f buf)) (offs + 6)) :: 32 word))
          (\<alpha>wa (data\<^sub>f buf)))) \<le> ucast (ple16 (\<alpha>wa (data\<^sub>f buf)) (offs + 6))")
     prefer 2
     apply (subst wordarray_length_ofnat)
      apply (simp add: wordarray_length_ret)
     apply (subst wordarray_make)
     apply (simp add: slice_length)
     apply (subst min_absorb1)  
      prefer 3
    using wellformed_buf[unfolded wellformed_buf_def]  no_buf_overflow[unfolded bilbyFsMaxEbSize_def]
      apply (simp add: unat_arith_simps)
      apply (subgoal_tac 
        "unat (ucast (ple16 (\<alpha>wa (data\<^sub>f buf)) (offs + 6)) :: 32 word) = 
              unat (ple16 (\<alpha>wa (data\<^sub>f buf)) (offs + 6))")
       prefer 2 
       apply (fastforce intro: uint_up_ucast simp: eq_nat_nat_iff unat_def is_up) 
      apply (rule suc)  
           apply (simp_all add: Let_def pObjDentry_def ObjDentry.make_def bilbyFsMaxNameLen_def)
    using bound apply unat_arith
    using wellformed_buf[unfolded wellformed_buf_def]  no_buf_overflow[unfolded bilbyFsMaxEbSize_def]
        apply (simp add: unat_arith_simps)
       apply (simp add: ple16_take ple32_take const_offs_no_of bilbyFsMaxEbSize_def plus_no_overflow_unat_lift[OF const_offs_no_of[unfolded bilbyFsMaxEbSize_def, simplified]])
       apply (subst ple16_take)
         apply (rule no_offs_overflow_le[OF wellformed_buf no_buf_overflow offs_le_bound])
           apply (simp add: bilbyFsMaxEbSize_def)+
    using no_of_8
        apply (simp add: add.commute)
       apply (subst ple16_take)
         apply (rule no_offs_overflow_le[OF wellformed_buf no_buf_overflow offs_le_bound])
           apply (simp add: bilbyFsMaxEbSize_def)+
    using no_of_8
        apply (simp add: add.commute)
       apply (subst pu8_take)
    using no_offs_overflow[OF wellformed_buf no_buf_overflow offs_le_bound, where m=5 and n=0, unfolded bilbyFsMaxEbSize_def, simplified]
      no_offs_overflow[OF wellformed_buf no_buf_overflow offs_le_bound, where m=4 and n=0, unfolded bilbyFsMaxEbSize_def, simplified]
         apply (simp add: add.commute unat_plus_simple)
         apply unat_arith
    using no_of_8
      no_offs_overflow[OF wellformed_buf no_buf_overflow offs_le_bound, where m=5 and n=0, unfolded bilbyFsMaxEbSize_def, simplified]
        apply (fastforce simp add: unat_plus_simple add.commute)
       apply (subst ObjDentry.surjective, simp)
       apply (rule arg_cong[where f=WordArrayT.make])
       apply (rule slice_take[symmetric], simp)
      apply (rule word_unat.Rep_eqD)
      apply (simp add: wordarray_length_ret wordarray_make length_slice)
    using no_of_8 wellformed_buf
     apply (simp add: wellformed_buf_def)
     apply unat_arith
    using wellformed_buf[unfolded wellformed_buf_def]  no_buf_overflow[unfolded bilbyFsMaxEbSize_def]
    apply (simp add: unat_arith_simps)
    done
qed

lemma loop_deserialise_ObjDentry_ret:
  assumes wellformed_buf: "wellformed_buf buf"
  assumes no_buf_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes bound: "end_offs \<le> bound\<^sub>f buf"
  assumes off_less_end_offs: "offs  \<le> end_offs"
  assumes st_offs: "st_offs \<le> offs"
  shows "case loop_deserialise_ObjDentry (OptElemAO.make dentry (ex, offs) (buf, end_offs)) of
            Break (none, e, ex) \<Rightarrow> none= Option.None () \<and> e = eInval 
          | Iterate (optdentry, ex, offs') \<Rightarrow>
             \<exists>dentry. optdentry = Option.Some dentry \<and>
                unat offs + 8 + unat (wordarray_length (name\<^sub>f dentry)) \<le> unat (bound\<^sub>f buf)  \<and>
                wordarray_length (name\<^sub>f dentry) \<le> bilbyFsMaxNameLen + 1  \<and>
                offs + 8 + wordarray_length (name\<^sub>f dentry) \<le> end_offs  \<and>
                dentry = pObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs  \<and>
                offs' = offs + 8 + wordarray_length (name\<^sub>f dentry) \<and>
                offs' \<le> (bound\<^sub>f buf)"
  unfolding loop_deserialise_ObjDentry_def[unfolded tuple_simps sanitizers]
  apply (clarsimp simp: Let_def OptElemAO.make_def)
  apply (rule deserialise_ObjDentry_ret[OF assms(1-4)])
  by (clarsimp simp: eInval_def)+

lemma slice_Cons:
  "frm < length xs \<Longrightarrow> frm < to
    \<Longrightarrow> slice frm to xs = xs ! frm # slice (Suc frm) to xs"
  apply (simp add: slice_def)
  apply (subst slice_Cons_helper[where i=frm], simp_all)
  apply clarsimp
  done

lemma slice_list_update:
  "n < length xs
    \<Longrightarrow> slice i j (xs[n := x]) = (if n < i then slice i j xs
        else if n \<ge> j then slice i j xs
        else (slice i j xs)[n - i := x])"
  by (simp add: slice_def drop_list_update take_list_update)

lemma mapAccumObsOpt_step:
  assumes frm: "frm < to" "frm < length xs"
  shows "mapAccumObsOpt frm to fn xs vacc obs =
        (case fn (OptElemAO.make (xs ! frm) vacc obs)
         of Iterate (oelem, acc) \<Rightarrow> 
             mapAccumObsOpt (Suc frm) to fn (xs [frm := oelem]) acc obs
         | Break (oelem, d) \<Rightarrow> Break (xs [frm := oelem], d))"
proof -
  let ?folder = "(\<lambda>elem. case_LoopResult (\<lambda>(ys, d). Break (ys @ [elem], d))
                               (\<lambda>(ys, acc).
                                   case fn (OptElemAO.make elem acc obs) of
                                  Break (oelem, d) \<Rightarrow> Break (ys @ [oelem], d)
                                | Iterate (oelem, acc) \<Rightarrow> Iterate (ys @ [oelem], acc)))"

  { fix xs ys d
  have fold_break: "fold ?folder xs (Break (ys, d))
        = Break (ys @ xs, d)"
    by (induct xs arbitrary: ys d, simp_all)
  }
  note fold_break = this

  have fold_iterate_Cons: "\<And>xs. \<forall>y ys acc. fold ?folder xs (Iterate (y # ys, acc))
        = (case (fold ?folder xs (Iterate (ys, acc)))
            of Iterate (zs, acc) \<Rightarrow> Iterate (y # zs, acc)
          | Break (zs, d) \<Rightarrow> Break (y # zs, d))"
    apply (induct_tac xs, simp_all)
    apply clarsimp
    apply (case_tac "fn (OptElemAO.make a acc obs)")
     apply (clarsimp simp add: fold_break)
    apply clarsimp
    done

  from frm have drop_helper: "\<And>x xs. drop (to - frm) (x # xs) = drop (to - Suc frm) xs"
    apply (cases "to - frm", simp_all)
    apply (cases to, simp_all)
    apply (cases frm, simp_all)
    apply (metis Suc_diff_Suc Suc_inject)
    done

  show ?thesis using frm
    apply (simp add: mapAccumObsOpt_def)
    apply (simp add: slice_Cons)
    apply (cases "fn (OptElemAO.make (xs ! frm) vacc obs)")
     apply (clarsimp simp: fold_break)
     apply (simp add: slice_def upd_conv_take_nth_drop max_absorb2)
     apply (subst append_take_drop_id
                  [where xs="drop (Suc frm) xs" and n="to -frm - 1", 
                    simplified take_drop, symmetric])
     apply simp
    apply (clarsimp simp: mapAccumObsOpt_def slice_list_update take_list_update)
    apply (simp add: fold_iterate_Cons)
    apply (simp split: LoopResult.split)
    apply (clarsimp simp: slice_def upd_conv_take_nth_drop min_absorb2 max_absorb2
                          drop_helper)
    done
 qed

lemma mapAccumObsOpt_n_n:
  "mapAccumObsOpt n n fn xs vacc obs = Iterate (xs, vacc)"
  by (clarsimp simp: mapAccumObsOpt_def slice_n_n)

lemma mapAccumObsOpt_frm_eq_len:
  "frm = length xs \<Longrightarrow> mapAccumObsOpt frm to fn xs vacc obs = Iterate (xs @ [], vacc)"
  by (clarsimp simp: mapAccumObsOpt_def slice_def)

lemma snd_fold_simp:
 "prod.snd (fold (\<lambda>_ (a, b). (f a b, f' b)) xs (a,b)) =
  fold (\<lambda>_ b. f' b) xs b"
  by (induct xs arbitrary: a b, simp_all) 

lemma fst_fold_append_simp:
  "prod.fst (fold (\<lambda>_ (xs, n). (xs @ [f n], f' n)) ls (f n' # xs, f' n)) = 
   f n' # prod.fst (fold (\<lambda>_ (xs, n). (xs @ [f n], f' n)) ls (xs, f' n)) "
   by (induct ls arbitrary: n xs, simp_all)

lemma snd_snd_fold_simp:
  "(prod.snd (fold (\<lambda>_ (xs, doffs, offslist). (f xs doffs, f' doffs, f'' doffs offslist))  ls (xs, n, offslist))) =
    fold (\<lambda>_ (doffs, offslist).  (f' doffs, f'' doffs offslist)) ls (n, offslist)" 
  by (induct ls arbitrary: xs n offslist, simp_all) 

lemma snd_fold_append_gen_simp:
 "prod.snd (fold (\<lambda>_ (x, xs). (f' x, xs @ [f x])) ls (x, xs @ ys)) =
   xs @ prod.snd (fold (\<lambda>_ (x, xs). (f' x, xs @ [f x])) ls (x, ys))"
  by (induct ls arbitrary: x ys, simp_all)

lemma snd_fold_append_simp:
 "prod.snd (fold (\<lambda>_ (x, xs). (f' x, xs @ [f x])) ls (x, xs)) =
   xs @ prod.snd (fold (\<lambda>_ (x, xs). (f' x, xs @ [f x])) ls (x, []))"
 using snd_fold_append_gen_simp[where ys=Nil, simplified] .

lemma fst_fold_triple_simp:
 "prod.fst (fold (\<lambda>_ (a, b, c). (f a b, f' b, f'' b c)) ns (a, b, c)) =
  prod.fst (fold (\<lambda>_ (a, b). (f a b, f' b)) ns (a, b))"
  by (induct  ns arbitrary: a b c, simp_all)

lemma fst_snd_fold_triple_simp:
 "prod.fst (prod.snd (fold (\<lambda>_ (a, b, c). (f a b, f' b, f'' b c)) ns (a, b, c))) =
  prod.snd (fold (\<lambda>_ (a, b). (f a b, f' b)) ns (a, b))"
  by (induct  ns arbitrary: a b c, simp_all)

definition dentarr_offs_list_drop :: "U8 list \<Rightarrow> U32 \<Rightarrow> nat list \<Rightarrow> U32 \<Rightarrow> (32 word list)"
where
 "dentarr_offs_list_drop data ost entriesno offs =
    prod.snd (fold (\<lambda>_ (doffs, offslist).
      let dentry = pObjDentry (drop (unat offs) data) (doffs - offs);
          newoffs = doffs + 8 + wordarray_length (ObjDentry.name\<^sub>f dentry)
       in (newoffs, offslist @ [newoffs]))
      entriesno (ost, []))
"
definition
  dentarr_offs_list_drop_end_offs_pred
where
 "dentarr_offs_list_drop_end_offs_pred data ost entriesno offs end_offs \<equiv>
 \<forall>v\<in>set (dentarr_offs_list_drop data ost entriesno offs).
   v \<le> end_offs"

definition
 "dentarr_offs_list data ost entriesno \<equiv> 
  (prod.snd (fold (\<lambda>_ (doffs, offslist).
     let dentry = pObjDentry data doffs;
         newoffs = doffs + 8 + wordarray_length (ObjDentry.name\<^sub>f dentry)
     in (newoffs, offslist @ [newoffs]))
   entriesno (ost, [])))"

definition
  dentarr_offs_list_end_offs_pred
where
 "dentarr_offs_list_end_offs_pred data ost entriesno end_offs \<equiv>
 \<forall>v\<in>set (dentarr_offs_list data ost entriesno).
   v \<le> end_offs"

definition
  dentarr_otype_end_offs_pred
where
 "dentarr_otype_end_offs_pred otype data offs end_offs \<equiv>
 (otype = bilbyFsObjTypeDentarr \<longrightarrow>
 (let nbentry = ple32 data (offs + 8)
 in dentarr_offs_list_end_offs_pred data (offs+bilbyFsObjDentarrHeaderSize) [0..<unat nbentry] end_offs))"

lemmas dentarr_end_offs_simps = dentarr_offs_list_def dentarr_offs_list_end_offs_pred_def
  dentarr_otype_end_offs_pred_def

definition
  dentarr_otype_drop_end_offs_pred
where
 "dentarr_otype_drop_end_offs_pred otype data offs end_offs \<equiv>
 (otype = bilbyFsObjTypeDentarr \<longrightarrow>
  (let nbentry = ple32 data (offs+8)
  in dentarr_offs_list_drop_end_offs_pred data (offs+bilbyFsObjDentarrHeaderSize)
  [0..<unat nbentry] offs end_offs))
"
definition
  dentarr_otype_drop_end_offs_st_pred
where
 "dentarr_otype_drop_end_offs_st_pred otype data offs st_offs end_offs \<equiv>
 (otype = bilbyFsObjTypeDentarr \<longrightarrow>
  (let nbentry = ple32 data (offs+8)
  in dentarr_offs_list_drop_end_offs_pred data (offs+bilbyFsObjDentarrHeaderSize)
  [0..<unat nbentry] st_offs end_offs))
"

lemmas dentarr_drop_end_offs_simps = dentarr_offs_list_drop_def dentarr_offs_list_drop_end_offs_pred_def
  dentarr_otype_drop_end_offs_pred_def dentarr_otype_drop_end_offs_st_pred_def

lemma ple32_eq_slice:
 assumes "offs < offs + 4" 
 assumes "unat offs + 4 \<le> length xs"
 assumes "offs + 4 < end_offs"
 shows   "ple32 xs offs = ple32 (slice (unat offs) (unat end_offs) xs) 0"
 using assms 
  apply (simp add:  slice_def ple32_def drop_take word_add_eq_unat)
  apply (drule less_to_le, simp add: unat_plus_simple word_less_nat_alt)
 done

lemma split_upt_on_l_n:
  "n < m \<Longrightarrow> l \<le> n \<Longrightarrow> [l ..< m] = [l ..< n] @ [n] @ [Suc n ..< m]"
  apply (subst upt_add_eq_append')
  apply simp+
  apply (simp add: upt_conv_Cons)
  done

lemma unat_plus_simple_imp:
 "x \<le> (x::'a::len word) + y \<Longrightarrow> (unat (x + y) = unat x + unat y)"
 by (simp add: unat_plus_simple)

lemma pObjDentry_drop_eq:
 assumes offs_le_ost: "offs \<le> ost"
 and     ost_no_of8: " ost < ost + 8"
 and     ost_le_offs_olen: " ost \<le> end_offs"
 and     offs_olen_ys: "unat end_offs \<le> length ys"
 and     ys_le_max: " length ys \<le> unat bilbyFsMaxEbSize"
 and     end_offs: "end_offs_nat = unat end_offs"
 shows " pObjDentry (take end_offs_nat ys) ost = pObjDentry (drop (unat offs) (take end_offs_nat ys)) (ost - offs)"
proof -
 have ost_4_nat: "unat (ost + 4) = unat ost + 4"
   using ost_no_of8 by (simp add: unat_arith_simps) unat_arith

 have ost_le_max: "ost \<le> bilbyFsMaxEbSize" using ys_le_max offs_olen_ys ost_le_offs_olen
  by unat_arith

 hence offs_le_max: "offs \<le> bilbyFsMaxEbSize"
  using offs_le_ost by unat_arith


 have ost_minus_offs_bound: "ost - offs \<le> bilbyFsMaxEbSize"
  using  offs_le_ost ost_le_max
  by unat_arith

 have ost_no_ofs: "ost < ost + 4" "ost < ost + 6" using ost_no_of8
   by (clarsimp simp add: unat_arith_simps , unat_arith)+

 hence ost_offs_x: "unat (ost - offs + 4) = unat ost - unat offs + 4"
                   "unat (ost - offs + 6) = unat ost - unat offs + 6"
                   "unat (ost - offs + 8) = unat ost - unat offs + 8"
   using offs_le_ost offs_le_ost[simplified word_le_nat_alt] ost_4_nat 
   ost_minus_offs_bound
   apply (simp_all add: bilbyFsMaxEbSize_def)
   apply ((drule plus_no_overflow_unat_lift)+, 
      (subst unat_plus_simple_imp,
       simp only: word_le_nat_alt, unat_arith,subst unat_sub, simp+))

   apply ((drule plus_no_overflow_unat_lift)+, 
      (subst unat_plus_simple_imp,
       simp only: word_le_nat_alt, unat_arith,subst unat_sub, simp+))

   apply ((drule plus_no_overflow_unat_lift)+)
   apply (subst unat_plus_simple_imp)
   apply (simp only: word_le_nat_alt word_less_nat_alt)
   using offs_le_max[simplified bilbyFsMaxEbSize_def word_le_nat_alt]
   ost_no_of8

   apply (simp only:unat_arith_simps)
   apply unat_arith
  apply (subst unat_sub, simp+)
 done

 have offs_cancel: "(unat ost - unat offs + 4 + unat offs) = unat ost + 4" 
                   "(unat ost - unat offs + 6 + unat offs) = unat ost + 6"
                   "(unat ost - unat offs + 8 + unat offs) = unat ost + 8"
  using offs_le_ost[simplified word_less_nat_alt] by unat_arith+

 have ple16_eq: "ple16 (take end_offs_nat ys) (ost + 6) = ple16 (drop (unat offs) (take end_offs_nat ys)) (ost - offs + 6)"
   apply (simp add: ple16_def)
   apply (rule arg_cong[where f=word_rcat])
   apply (rule arg_cong[where f=rev])
   apply (rule arg_cong[where f="take 2"])
   apply (fastforce simp add: ost_offs_x offs_cancel less_to_le[OF ost_no_ofs(2), simplified unat_plus_simple])
  done

 have offs_cancel': "\<forall>v. unat ost - unat offs + 8 + unat v + unat offs = unat ost + 8 + unat v"
  using offs_le_ost[simplified word_less_nat_alt]
  by unat_arith

 show ?thesis
  apply (simp add: pObjDentry_def Let_def ObjDentry.make_def)
  apply (rule conjI)
   apply (simp add: ple32_def)
   apply (rule arg_cong[where f=word_rcat])
   apply (rule arg_cong[where f=rev])
   apply (rule arg_cong[where f="take 4"])
   apply (subst unat_sub[OF offs_le_ost])
   using offs_le_ost
   apply (subst add_diff_assoc2, fastforce simp: word_le_nat_alt)
   apply fastforce
  apply (rule conjI)
   apply (simp add: pu8_def )
   apply (rule arg_cong[where f=word_rcat])
   apply (simp only: slice_def drop_take fun_app_def)
   using ost_offs_x ost_4_nat
   apply simp
   apply (simp add: take_drop offs_cancel)
   apply (subst add.commute, fastforce simp only: offs_cancel)
  apply (simp add: ple16_eq )
  apply (rule arg_cong[where f=WordArrayT.make])
  apply (subgoal_tac "\<exists>v. ple16 (drop (unat offs) (take (unat offs + unat (Obj.len\<^sub>f obj)) ys)) (ost - offs + 6) = v")
   apply (erule exE)
   apply (simp only: ost_offs_x less_to_le[OF ost_no_of8, simplified unat_plus_simple])
   apply (simp add: slice_def take_drop )
   apply (simp add: offs_cancel offs_cancel')+
  done
qed

lemma wa_length_ObjDentry_name_le:
 "unat (wordarray_length (ObjDentry.name\<^sub>f (pObjDentry xs ost))) \<le> length xs"
 by (simp add: pObjDentry_def Let_def ObjDentry.make_def wordarray_make wordarray_length_ret slice_def)

lemma wa_length_ObjDentry_name_le_len:
 "unat (wordarray_length (ObjDentry.name\<^sub>f (pObjDentry xs ost))) \<le> unat (ple16 xs (ost + 6))"
 by (simp add: pObjDentry_def Let_def ObjDentry.make_def wordarray_make wordarray_length_ret slice_def)

lemma dentarr_end_offs_list_induct_helper:
 assumes diff: "Suc diff = unat to - frm"
 and     ih: "dentarr_offs_list_end_offs_pred (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) (offs + 8 +
     wordarray_length
      (ObjDentry.name\<^sub>f (pObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs)))
    [Suc frm..<unat to] end_offs"
 and cur: "   offs + 8 +
   wordarray_length (ObjDentry.name\<^sub>f (pObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs))
   \<le> end_offs"
 shows
 "dentarr_offs_list_end_offs_pred (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs [frm..<unat to] end_offs"
proof -
  have frm_lt_to: "frm < unat to" using diff by unat_arith
  show ?thesis
  apply (clarsimp simp: dentarr_end_offs_simps )
  apply (subst (asm) upt_rec, simp add: frm_lt_to Let_def) 
  apply (subst (asm) snd_fold_append_simp)
  apply clarsimp
  apply (erule disjE)
   using cur apply simp
  using ih apply (simp add: dentarr_end_offs_simps Let_def)
 done
qed

lemma offs_pl_8_name_of:
  " wellformed_buf buf \<Longrightarrow>
    length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize \<Longrightarrow>
    offs + 8 + wordarray_length (ObjDentry.name\<^sub>f (pObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs)) \<le> bound\<^sub>f buf \<Longrightarrow>
    offs \<le> bilbyFsMaxEbSize  \<Longrightarrow>
    offs < offs + 8"
 apply (simp add: bilbyFsMaxEbSize_def)
 using wa_length_ObjDentry_name_le[where xs="(take (unat end_offs) (\<alpha>wa (data\<^sub>f buf)))" and ost=offs]
 apply (clarsimp simp add: wellformed_buf_def)
 apply (simp add: unat_arith_simps)
done

lemma mapAccumObsOpt_loop_deserialise_ObjDentry_ret:
  assumes wellformed_buf: "wellformed_buf buf"
  assumes no_buf_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes bound: "end_offs \<le> bound\<^sub>f buf"
  assumes off_less_end_offs: "offs  \<le> end_offs"
  assumes frm: "frm \<le> unat (to::word32)" "unat to \<le> length ys" 
  assumes st_offs: "st_offs \<le> offs"
  shows 
  "let list_spec = 
      case (fold (\<lambda>_ (xs, doffs, offslist).
             let dentry = pObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) doffs ;
                 newoffs = doffs +  8 + wordarray_length (ObjDentry.name\<^sub>f dentry)
             in (xs@[Option.Some dentry], 
                newoffs, offslist @ [newoffs])) 
           [frm..<unat to] ([], offs, [])) 
         of (xs, offs) \<Rightarrow> ((take frm ys) @ xs @ (drop (unat to) ys), offs);
      data = take (unat end_offs) (\<alpha>wa (data\<^sub>f buf)) in
  (case mapAccumObsOpt frm (unat to) loop_deserialise_ObjDentry 
     ys (ex, offs) (buf, end_offs) of
       Break (ys, d, ex) \<Rightarrow> 
        d \<in> {eInval, eNoMem}
     | Iterate (ys, ex, offs') \<Rightarrow> 
        
        (ys, ex, offs') = (prod.fst list_spec, ex, prod.fst (prod.snd list_spec)) \<and>
        offs' \<le> end_offs \<and>
        dentarr_offs_list_end_offs_pred data offs [frm..<unat to] end_offs \<and>
        dentarr_offs_list_drop_end_offs_pred data offs [frm..<unat to] st_offs end_offs)"
  using assms
  proof (induct "unat to - frm" arbitrary: frm ys ex offs)
  case 0
  thus ?case
   by (simp add: dentarr_end_offs_simps mapAccumObsOpt_n_n dentarr_drop_end_offs_simps)
next   
  case (Suc diff) 
  note IH = this(1) and rest = this(2-)

  have offs_le_max: "offs \<le> bilbyFsMaxEbSize"
   using rest by (simp add: unat_arith_simps wellformed_buf_def) 

  hence offs_pl_8: "offs < offs + 8"
   by (simp add: bilbyFsMaxEbSize_def unat_arith_simps)

  have offs_pl_8_pl_name:
  "offs + 8 \<le> offs + 8 + wordarray_length (ObjDentry.name\<^sub>f (pObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs))"
   using wa_length_ObjDentry_name_le[where xs="take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))" and ost=offs] rest offs_le_max
     less_to_le[OF offs_pl_8]
   by (simp add: wellformed_buf_def bilbyFsMaxEbSize_def unat_arith_simps)

  have pObjDentry_eq: 
  "pObjDentry (drop (unat st_offs) (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf)))) (offs - st_offs) = pObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs"
      using rest offs_pl_8 by (fastforce intro: pObjDentry_drop_eq[symmetric,where end_offs=end_offs and offs=st_offs]
                                simp add: wellformed_buf_def word_le_nat_alt)
  
  from rest show ?case
  apply (subst mapAccumObsOpt_step, simp, simp)
  apply (clarsimp simp: Let_def split: LoopResult.split)
  apply (rule conjI)
   using loop_deserialise_ObjDentry_ret[OF wellformed_buf no_buf_overflow bound , 
    where dentry="ys ! frm" and  ex = ex and offs=offs]
   apply fastforce
  apply clarsimp
  apply (rename_tac elem ex' offs')
  apply (cut_tac 
            frm="Suc frm" and 
            ys= "ys[frm := elem]" and    
            ex =ex' and offs = offs' in IH[OF _ wellformed_buf no_buf_overflow bound], simp_all)
    apply(cut_tac loop_deserialise_ObjDentry_ret[OF wellformed_buf no_buf_overflow bound ,
          where dentry="ys ! frm" and  ex = ex and offs=offs and st_offs=st_offs], simp_all)
   apply(cut_tac loop_deserialise_ObjDentry_ret[OF wellformed_buf no_buf_overflow bound ,
      where dentry="ys ! frm" and  ex = ex and offs=offs and st_offs=st_offs], simp_all)
   apply clarsimp
   using  offs_pl_8_pl_name less_to_le[OF offs_pl_8]
   apply (fastforce simp add:  unat_plus_simple word_le_nat_alt)
  apply (clarsimp simp: Let_def)
  apply (rule conjI)
   apply fastforce
  apply (clarsimp simp: Let_def)
  apply (rename_tac ex'')
  apply (thin_tac "mapAccumObsOpt _ _ _ _ _ _ = _")
  apply(cut_tac loop_deserialise_ObjDentry_ret[OF wellformed_buf no_buf_overflow bound, 
      where dentry="ys ! frm" and  ex = ex and offs=offs], simp_all)

  apply (clarsimp simp: Let_def fst_fold_triple_simp fst_snd_fold_triple_simp prod.case_eq_if)
  apply (rule conjI)
   apply (simp add: upt_conv_Cons[where i = frm])
   apply (subst take_Suc_conv_app_nth, simp)
   apply (simp add: take_list_update prod.case_eq_if snd_fold_simp)
   apply (subst fst_fold_append_simp[where xs="[]", simplified, symmetric]) 
   apply fastforce

  apply (rule conjI)
   apply (simp add: snd_fold_simp)
    apply (case_tac "[frm..<unat to]")
     apply (fastforce+)
   apply (rename_tac l ls)
   apply (subgoal_tac "[Suc frm..<unat to] = ls")
    prefer 2
    apply (subst (asm) upt_rec[where i=frm], case_tac "frm = unat to"; fastforce)
   apply simp

  apply (rule conjI)
   apply (erule (2) dentarr_end_offs_list_induct_helper)

  apply (simp add: dentarr_offs_list_drop_end_offs_pred_def)
  apply clarsimp
  apply (rename_tac offs')
  apply (simp add:  snd_fold_simp)
  apply (case_tac "offs' = offs + 8 + wordarray_length (ObjDentry.name\<^sub>f (pObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs))")
   apply simp

  apply (simp add: dentarr_offs_list_drop_def)
  apply (subst (asm) split_upt_on_l_n[where l=frm and n=frm, simplified], fastforce)
  apply (simp add: Let_def)
  apply (subst (asm) snd_fold_append_simp[where xs="[_]"])
  apply (erule_tac x="offs' " in ballE, fastforce)
  apply (fastforce simp add: pObjDentry_eq)
  done
qed 

lemma replicate_simp:
  "replicate (unat to + 1 - unat to) (Option.None ()) = [Option.None ()]"
  by (simp add: unat_arith_simps)

lemma mapAccumObsOpt_loop_deserialise_ObjDentry_array_ret:
  assumes wellformed_buf: "wellformed_buf buf"
  assumes no_buf_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes bound: "end_offs \<le> bound\<^sub>f buf"
  assumes off_less_end_offs: "offs  \<le> end_offs"
  assumes st_offs: "st_offs \<le> offs"
  shows
  "let data = take (unat end_offs) (\<alpha>wa (data\<^sub>f buf));
       arr_spec = pArrObjDentry data offs to in 
   (case mapAccumObsOpt 0 (unat to) loop_deserialise_ObjDentry 
      (replicate (unat to + 1) (Option.None ())) (ex, offs) (buf, end_offs) of
        LoopResult.Break (ys, d, ex) \<Rightarrow> 
         d \<in> {eInval, eNoMem}
      | LoopResult.Iterate (ys, ex, offs') \<Rightarrow> 
         (ys, ex, offs') = (\<alpha>a (prod.fst arr_spec), ex, prod.fst (prod.snd arr_spec)) \<and> 
         offs' \<le> end_offs \<and>
        dentarr_offs_list_end_offs_pred data offs [0..<unat to] end_offs \<and>
        dentarr_offs_list_drop_end_offs_pred data offs [0..<unat to] st_offs end_offs)"
  unfolding pArrObjDentry_def Let_def
  apply (clarsimp simp: array_make split: LoopResult.splits prod.splits)
  using mapAccumObsOpt_loop_deserialise_ObjDentry_ret[OF assms(1-4), simplified Let_def, 
       where frm=0 and to=to and ex=ex  and st_offs=st_offs and
       ys="replicate (unat to + 1)(Option.None ())", simplified take_0 drop_replicate replicate_simp]
   st_offs
  apply (clarsimp split: LoopResult.splits) 
  done

lemma array_map_loop_deserialise_ObjDentry_ret:
  assumes wellformed_buf: "wellformed_buf buf"
  assumes no_buf_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes bound: "end_offs \<le> bound\<^sub>f buf"
  assumes off_less_end_offs: "offs  \<le> end_offs"
  assumes st_offs: "st_offs \<le> offs"
  shows "case array_map (ArrayMapP.make (ArrayT.make (replicate (unat to + 1) (Option.None ())))
                   0 to loop_deserialise_ObjDentry (ex, offs) (buf, end_offs)) of
         LoopResult.Break (arr, err, ex) \<Rightarrow> err \<in> {eInval, eNoMem}
       | LoopResult.Iterate (arr, ex', offs') \<Rightarrow>
                  let data = take (unat end_offs) (\<alpha>wa (data\<^sub>f buf));
                      (parr, poffs, poffslist) = pArrObjDentry data offs to;
                      ostlist = pArrObjDentry data offs to
                  in
                   arr = parr \<and> offs' = poffs \<and>
                  offs' \<le> end_offs \<and>
        dentarr_offs_list_end_offs_pred data offs [0..<unat to] end_offs \<and>
        dentarr_offs_list_drop_end_offs_pred data offs [0..<unat to] st_offs end_offs"
  apply (clarsimp simp: ArrayMapP.make_def array_make array_map_ret)
  using assms mapAccumObsOpt_loop_deserialise_ObjDentry_array_ret
  [unfolded Let_def, where to=to and buf=buf and ex=ex and offs=offs and end_offs=end_offs and st_offs=st_offs]
  by (clarsimp simp: array_make' Let_def split: LoopResult.splits)

lemma deserialise_Array_ObjDentry_ret:
  assumes wellformed_buf: "wellformed_buf buf"
  assumes no_buf_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes bound: "end_offs \<le> bound\<^sub>f buf"
  assumes off_less_end_offs: "offs  \<le> end_offs"
  assumes st_offs: "st_offs \<le> offs"
  assumes offs_pl_8_no_of: "offs \<le> offs + 8"
  assumes offs_pl_8_le_end_offs: "offs + 8 \<le> end_offs"
  assumes err: "\<And>ex e. e \<in> {eInval, eNoMem} \<Longrightarrow> P (Error (e, ex))"
  assumes suc:
   "\<And>ex arr offs' offslist data.
    \<lbrakk> (arr, offs',offslist) = (pArrObjDentry (take (unat end_offs) (\<alpha>wa (data\<^sub>f buf))) offs nb_dentry);
       offs' \<le>  end_offs;
       data = take (unat end_offs) (\<alpha>wa (data\<^sub>f buf));
        dentarr_offs_list_end_offs_pred data offs [0..<unat nb_dentry] end_offs;
        dentarr_offs_list_drop_end_offs_pred data offs [0..<unat nb_dentry] st_offs end_offs \<rbrakk> \<Longrightarrow>
      P (Success (ex, arr, offs'))"
  shows "P (deserialise_Array_ObjDentry (ex, buf, offs, nb_dentry, end_offs))"
  unfolding deserialise_Array_ObjDentry_def[unfolded tuple_simps sanitizers]
  apply (simp add: Let_def)
  apply (rule array_create_ret)
   apply (simp add: err[unfolded eNoMem_def])
  apply (rename_tac ex' arr a)
  apply (subgoal_tac "unat nb_dentry + 1 = unat (nb_dentry+1) ")
   apply (clarsimp simp: prod.case_eq_if id_def Let_def split: LoopResult.splits)
   apply (subgoal_tac "a = ArrayT.make (replicate (unat (nb_dentry + 1)) (Option.None ()))", simp)
    apply (cut_tac ex=ex' in array_map_loop_deserialise_ObjDentry_ret[OF assms(1-5), where to = nb_dentry])
    apply (clarsimp simp: Let_def err split: LoopResult.splits)
    apply (rename_tac offslist a ex'' offs')
    apply (rule suc)
     apply simp+
   apply (metis array_make')
  apply unat_arith
 done

lemma word_add_diff_assoc:
 "(a::'a:: len0 word) + b - c = a + (b - c)"
 by simp

method offs_olen_of_solver =
  (((drule less_to_le)?, simp add: word_add_diff_assoc unat_plus_simple),
   (simp only: unat_arith_simps)?, simp? ; unat_arith)

lemma deserialise_ObjDentarr_ret:
  assumes wf: "wellformed_buf buf"
  assumes buf_len: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes err: "\<And>ex e. e \<in> {eInval, eNoMem} \<Longrightarrow> P (Error (e, ex))"
  assumes offs_bound: "offs + olen - bilbyFsObjHeaderSize \<le> (bound\<^sub>f buf)"
  assumes offs_olen: "offs < offs + olen - bilbyFsObjHeaderSize"
  assumes olen: "bilbyFsObjHeaderSize + bilbyFsObjDentarrHeaderSize + bilbyFsObjDentryHeaderSize \<le> olen"
  assumes st_offs: "st_offs \<le> offs"
  assumes suc:
  "\<And>ex dentarr offs'. \<lbrakk>
  dentarr = pObjDentarr (\<alpha>wa (data\<^sub>f buf)) offs olen;
  offs' = pObjDentarrSize (\<alpha>wa (data\<^sub>f buf)) offs olen;
  let end_offs = offs + olen - bilbyFsObjHeaderSize;
  data = take (unat end_offs) (\<alpha>wa (data\<^sub>f buf));
  nb_dentry = ple32 (\<alpha>wa (data\<^sub>f buf)) (offs+8) in
  dentarr_offs_list_end_offs_pred data (offs+bilbyFsObjDentarrHeaderSize) [0..<unat nb_dentry] end_offs \<and>
  dentarr_offs_list_drop_end_offs_pred data (offs+bilbyFsObjDentarrHeaderSize) [0..<unat nb_dentry] st_offs end_offs;
  offs' \<le> offs + olen - bilbyFsObjHeaderSize
  \<rbrakk> \<Longrightarrow>
  P (Success (ex, dentarr, offs'))"
 notes bilbyFsObjDentarrHeaderSize_def[simp] bilbyFsObjHeaderSize_def[simp]
       bilbyFsObjDentryHeaderSize_def[simp]
  shows "P (deserialise_ObjDentarr (ex, buf, offs, olen))"
  proof -

  have offs_no_of: "offs < offs + bilbyFsObjDentarrHeaderSize"
    using olen and offs_olen by simp unat_arith

   have bound_max: "bound\<^sub>f buf \<le> bilbyFsMaxEbSize"
     using wf and buf_len by (simp add: wellformed_buf_def) unat_arith

   have offs_bound':  "offs < bilbyFsMaxEbSize"
     using offs_bound offs_olen bound_max offs_no_of by simp

   have offs_hdr_no_of: "offs < offs + bilbyFsObjDentarrHeaderSize"
     using offs_bound' by (simp add: bilbyFsMaxEbSize_def unat_arith_simps)

  have offs_pl_hdr_le_len: "unat offs + unat bilbyFsObjDentarrHeaderSize \<le> length (\<alpha>wa $ data\<^sub>f buf)"
   using offs_bound wf offs_no_of offs_olen olen
   by (simp add: wellformed_buf_def) unat_arith
  have deserialises:
    "deserialise_le32 (buf, offs + 8) = (ple32 (\<alpha>wa $ data\<^sub>f buf) (offs + 8))"
    "deserialise_le64 (buf, offs) = (ple64 (\<alpha>wa $ data\<^sub>f buf) offs)"
       using offs_pl_hdr_le_len apply (clarsimp simp:)
       apply (rule deserialise_le32_ret[simplified])
         using offs_hdr_no_of apply unat_arith
       using offs_hdr_no_of apply (simp add: unat_arith_simps)
       apply unat_arith

     using offs_pl_hdr_le_len apply (clarsimp)
     apply (rule deserialise_le64_ret[simplified])
    using offs_hdr_no_of  apply unat_arith
   using offs_hdr_no_of apply (simp add: unat_arith_simps)
   apply unat_arith
  done
  show ?thesis
  unfolding deserialise_ObjDentarr_def[unfolded tuple_simps sanitizers]
   apply (clarsimp simp: Let_def err[unfolded eInval_def])
   apply (subgoal_tac "\<exists>v. olen - bilbyFsObjHeaderSize = v \<and> bilbyFsObjDentarrHeaderSize + bilbyFsObjDentryHeaderSize \<le> v")
    apply (erule exE)
    apply (erule conjE)
    apply (rule deserialise_Array_ObjDentry_ret[OF assms(1,2), where st_offs=st_offs,
             simplified])
         using offs_bound apply simp
        subgoal using offs_olen olen by - offs_olen_of_solver
       subgoal for v
        using st_offs  offs_olen by - offs_olen_of_solver
      subgoal for v
       using offs_olen by - offs_olen_of_solver
     subgoal for v
      using offs_olen by (simp add: word_add_diff_assoc add.commute)
                         (rule word_plus_mono_right; simp)
    subgoal for v _ e by (fastforce intro: err)
   subgoal for v ex arr offs' offslist
    apply (case_tac "R.Success (ex, arr, offs')", simp_all)
    apply (clarsimp simp: Let_def err[unfolded eNoMem_def] split: R.split)
    apply (rule suc)
        subgoal
        apply (simp add: pObjDentarr_def Let_def)
        apply (subst ObjDentarr.surjective, simp add: ObjDentarr.make_def deserialises prod_eq_iff)
        done
       subgoal by (clarsimp simp add: prod_eq_iff pObjDentarrSize_def deserialises)
      subgoal by (simp add: Let_def deserialises)
     subgoal by simp
   done
  subgoal using olen by (simp) unat_arith
  done
qed

lemmas pObjUnion_def' = 
  pObjUnion_def[unfolded otype_simps, simplified]

lemmas len_otype_ok = is_len_and_type_ok_def[unfolded sanitizers tuple_simps]

lemma olen_bound_trivial:
 "   0x28 \<le> (olen::U32) \<Longrightarrow>
    offs + olen - 0x18 \<le> bound\<^sub>f buf \<Longrightarrow>
    offs \<le> offs + olen - 0x18 \<Longrightarrow> offs + 0x10 \<le> bound\<^sub>f buf"
  by unat_arith

lemma offs_trivial:
 "(offs::U32) \<le> offs + olen - 0x18 \<Longrightarrow>
    0x28 \<le> olen \<Longrightarrow>
    offs < offs + 0x10"
 by unat_arith

lemma unat_obj_len_minus_hdrsz:
  assumes len_otype_rel: "bilbyFsObjHeaderSize \<le> olen"
  assumes offs_no_of: "offs \<le> offs + olen - bilbyFsObjHeaderSize"
shows
 "unat (offs + olen - bilbyFsObjHeaderSize) = unat offs + unat olen - unat bilbyFsObjHeaderSize"
 using assms
 by (simp add: bilbyFsObjHeaderSize_def word_add_diff_assoc  unat_plus_simple) (simp add: unat_arith_simps)
 

lemma deserialise_ObjUnion_ret:
  assumes wf: "wellformed_buf buf"
  assumes no_buf_overflow: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes bound: "offs + olen - bilbyFsObjHeaderSize \<le> bound\<^sub>f buf"
  assumes len_otype_rel: "is_len_and_type_ok (otype, olen)"
  assumes offs_no_of: "offs \<le> offs + olen - bilbyFsObjHeaderSize"
  assumes offs_no_underflow: "offs - bilbyFsObjHeaderSize \<le> offs"
  assumes err:
  "\<And>ex e. e \<in> {eInval, eNoMem} \<Longrightarrow> P (Error (e, ex))"
  assumes suc:
  "\<And>ex ounion offs'. ounion = pObjUnion ((*take (unat (offs + olen))*) (\<alpha>wa (data\<^sub>f buf))) otype olen offs  \<Longrightarrow>
   offs' \<le> (offs + olen - bilbyFsObjHeaderSize) \<Longrightarrow>
  let end_offs = offs + olen - bilbyFsObjHeaderSize;
  data = take (unat end_offs) (\<alpha>wa (data\<^sub>f buf));
  nb_dentry = ple32 (\<alpha>wa (data\<^sub>f buf)) (offs+8) in
  dentarr_otype_end_offs_pred otype data offs end_offs \<and>
  dentarr_otype_drop_end_offs_st_pred otype data offs (offs - bilbyFsObjHeaderSize) end_offs 
  \<Longrightarrow>
   P (Success (ex, ounion, offs'))"
  notes suc_simps = len_otype_ok Let_def  pObjUnion_def' suc add.commute bilbyFsObjHeaderSize_def
          otype_simps dentarr_end_offs_simps  dentarr_drop_end_offs_simps
  shows "P (deserialise_ObjUnion (ex, buf, offs, (otype, olen)))"
  unfolding deserialise_ObjUnion_def[unfolded tuple_simps, simplified sanitizers]
  using is_len_and_type_ok_hdr_szD[OF len_otype_rel] 
  apply (clarsimp simp: Let_def)
  apply (rule conjI)
   apply clarsimp
   apply (rule deserialise_ObjSuper_ret, simp)
      using len_otype_rel offs_no_of bound wf
      apply (simp add: len_otype_ok Let_def prod.case_eq_if wellformed_buf_def bilbyFsObjHeaderSize_def)
      apply unat_arith
     using len_otype_rel offs_no_of bound wf
     apply (simp add: len_otype_ok Let_def prod.case_eq_if wellformed_buf_def bilbyFsObjHeaderSize_def)
     apply unat_arith
    apply (simp add: err)

   using len_otype_rel
   apply (simp add: suc_simps)
  apply clarsimp
  apply (rule conjI)
   apply clarsimp
   apply (rule deserialise_ObjDel_ret, simp)
      using len_otype_rel offs_no_of bound wf
      apply (simp add: len_otype_ok Let_def prod.case_eq_if wellformed_buf_def bilbyFsObjHeaderSize_def)
      apply unat_arith
     apply (simp add: err)
      using len_otype_rel offs_no_of bound wf
      apply (simp add: len_otype_ok Let_def prod.case_eq_if wellformed_buf_def bilbyFsObjHeaderSize_def)
      apply unat_arith
   using len_otype_rel
   apply (simp add: suc_simps)

  apply clarsimp
  apply (rule conjI)
   apply clarsimp
   apply (rule deserialise_ObjDentarr_ret[OF wf no_buf_overflow, where st_offs ="offs - bilbyFsObjHeaderSize"])
        apply (simp add: err)
       using bound  offs_no_of len_otype_rel 
       apply (simp add: len_otype_ok Let_def prod.case_eq_if wellformed_buf_def bilbyFsObjHeaderSize_def)
      using offs_no_of len_otype_rel 
      apply (simp add: len_otype_ok bilbyFsObjHeaderSize_def )
      apply (simp add: word_add_diff_assoc unat_plus_simple word_less_nat_alt )
      apply unat_arith
     using  len_otype_rel
     apply (simp add: len_otype_ok bilbyFsObjHeaderSize_def bilbyFsObjDentryHeaderSize_def bilbyFsObjDentarrHeaderSize_def)
     using offs_no_underflow apply simp
   apply (simp add: suc pObjUnion_def' )
   apply (rule suc)
      apply (clarsimp simp add: pObjUnion_def')+
   apply (simp add: dentarr_otype_drop_end_offs_st_pred_def dentarr_otype_end_offs_pred_def dentarr_otype_drop_end_offs_pred_def
        bilbyFsObjTypeDentarr_def Let_def)
   apply clarsimp
   apply (subgoal_tac "ple32 (take (unat (offs + olen - bilbyFsObjHeaderSize)) (\<alpha>wa (data\<^sub>f buf))) (offs + 8) = ple32 (\<alpha>wa (data\<^sub>f buf)) (offs + 8)")
    apply simp
   apply (subgoal_tac "\<exists>v. olen - bilbyFsObjHeaderSize = v")
    apply (erule exE)
    apply (subst ple32_take)
(* <automate?> *)
      using len_otype_rel 
      apply (simp add: len_otype_ok bilbyFsObjHeaderSize_def)
      using offs_no_of apply (simp add: word_add_diff_assoc  bilbyFsObjHeaderSize_def)
      apply (simp add: word_add_diff_assoc unat_plus_simple word_less_nat_alt word_le_nat_alt add.commute)
      apply (subst (asm) add.commute)
      using offs_no_of apply (simp add: bilbyFsObjHeaderSize_def) apply (simp add: word_add_diff_assoc word_le_nat_alt)
      apply (simp only: unat_arith_simps)
      apply unat_arith
    apply (simp add: bilbyFsObjHeaderSize_def word_add_diff_assoc)
     using offs_no_of 
     apply (simp add: bilbyFsObjHeaderSize_def word_add_diff_assoc word_less_nat_alt  add.commute)
     apply (subst (asm) add.commute, simp add: unat_plus_simple)
     using offs_no_of apply (simp add: bilbyFsObjHeaderSize_def)
     apply (simp add: word_add_diff_assoc)
     using len_otype_rel
      apply (simp add: len_otype_ok)
     apply (subgoal_tac "offs \<le> offs + 0xC")
      apply (simp add: unat_plus_simple add.commute, simp only: word_le_nat_alt)
      apply unat_arith
     apply (simp add: unat_plus_simple add.commute, simp only: word_le_nat_alt)
     apply unat_arith
(* </automate?> *)
    apply simp
   apply (fastforce)
  apply clarsimp
  apply (rule conjI)
   apply clarsimp
   apply (rule deserialise_ObjData_ret[OF ])
       using offs_no_of 
       apply (simp only: diff_conv_add_uminus)
       apply (simp only: add.assoc)
      using bound wf offs_no_of apply (simp add: bilbyFsObjHeaderSize_def
        wellformed_buf_def diff_conv_add_uminus add.assoc)
      apply unat_arith
     using len_otype_rel   apply (simp add: otype_simps)
    apply (simp add: err)
   apply simp
   apply (simp add: suc_simps)

  apply (clarsimp)
  apply (rule conjI)
   apply clarsimp
   apply (rule deserialise_ObjInode_ret)
      using len_otype_rel offs_no_of bound
         bound wf offs_no_of
       apply (simp add: bilbyFsObjHeaderSize_def wellformed_buf_def )
     using len_otype_rel  apply (simp add: otype_simps len_otype_ok)
       apply unat_arith
     using len_otype_rel  apply (simp add: otype_simps len_otype_ok)
       using  offs_no_of
       apply (simp add: bilbyFsObjHeaderSize_def)
       apply unat_arith
     apply (simp add: err)
     using len_otype_rel  apply (simp add: otype_simps len_otype_ok)
    apply (simp add: suc_simps)
  apply clarsimp
  apply (rule deserialise_ObjPad_ret)
   apply (simp add:err)  
  apply (simp add: suc_simps add_diff_eq)+
 done

lemma pObjDel_take:
 "is_valid_ObjHeader (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs) (bounded buf) \<Longrightarrow>
       offs + Obj.len\<^sub>f obj \<le> bound\<^sub>f buf \<Longrightarrow>
       is_len_and_type_ok (otype\<^sub>f obj, Obj.len\<^sub>f obj) \<Longrightarrow>
       offs < offs + Obj.len\<^sub>f obj \<Longrightarrow>
       otype\<^sub>f obj = 3 \<Longrightarrow>
       \<exists>v. obj\<lparr>ounion\<^sub>f := v\<rparr> = pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs \<Longrightarrow>
   pObjDel (\<alpha>wa (data\<^sub>f buf)) (offs + bilbyFsObjHeaderSize) =
      pObjDel (take (unat (offs + Obj.len\<^sub>f obj)) (\<alpha>wa (data\<^sub>f buf))) (offs + bilbyFsObjHeaderSize)"
  apply (simp add: pObjDel_def)
  apply (frule is_valid_ObjHeader_buf_len, clarify)
  apply (subst ple64_take, (simp add: otype_simps len_otype_ok bilbyFsObjHeaderSize_def, unat_arith)+)
  apply simp
done

lemma pObjSuper_take:
 "is_valid_ObjHeader (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs) (bounded buf) \<Longrightarrow>
       offs + Obj.len\<^sub>f obj \<le> bound\<^sub>f buf \<Longrightarrow>
       is_len_and_type_ok (otype\<^sub>f obj, Obj.len\<^sub>f obj) \<Longrightarrow>
       offs < offs + Obj.len\<^sub>f obj \<Longrightarrow>
       otype\<^sub>f obj = 4 \<Longrightarrow>
       \<exists>v. obj\<lparr>ounion\<^sub>f := v\<rparr> = pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs \<Longrightarrow>
    pObjSuper (\<alpha>wa (data\<^sub>f buf)) (offs + bilbyFsObjHeaderSize) =
     pObjSuper (take (unat (offs + Obj.len\<^sub>f obj)) (\<alpha>wa (data\<^sub>f buf))) (offs + bilbyFsObjHeaderSize)"
  apply (simp add: pObjSuper_def)
  apply (frule is_valid_ObjHeader_buf_len, clarify)
  apply (subst ple64_take, ((simp add: otype_simps len_otype_ok bilbyFsObjHeaderSize_def, unat_arith)+)[2])
  apply (subst ple32_take, ((simp add: otype_simps len_otype_ok bilbyFsObjHeaderSize_def, unat_arith)+)[2])+
  apply simp
 done

lemma pObjInode_take:
 "is_valid_ObjHeader (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs) (bounded buf) \<Longrightarrow>
       offs + Obj.len\<^sub>f obj \<le> bound\<^sub>f buf \<Longrightarrow>
       is_len_and_type_ok (otype\<^sub>f obj, Obj.len\<^sub>f obj) \<Longrightarrow>
       offs < offs + Obj.len\<^sub>f obj \<Longrightarrow>
       otype\<^sub>f obj = 0 \<Longrightarrow>
       \<exists>v. obj\<lparr>ounion\<^sub>f := v\<rparr> = pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs \<Longrightarrow>
    pObjInode (\<alpha>wa (data\<^sub>f buf)) (offs + bilbyFsObjHeaderSize) =
     pObjInode (take (unat (offs + Obj.len\<^sub>f obj)) (\<alpha>wa (data\<^sub>f buf))) (offs + bilbyFsObjHeaderSize)"
  apply (simp add: pObjInode_def)
  apply (frule is_valid_ObjHeader_buf_len, clarify)
  apply (subst ple64_take, ((simp add: otype_simps len_otype_ok bilbyFsObjHeaderSize_def, unat_arith)+)[2])+
  apply (subst ple32_take, ((simp add: otype_simps len_otype_ok bilbyFsObjHeaderSize_def, unat_arith)+)[2])+
  apply simp
 done

lemma pObjDentarr_take:
 "is_valid_ObjHeader (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs) (bounded buf) \<Longrightarrow>
       offs + Obj.len\<^sub>f obj \<le> bound\<^sub>f buf \<Longrightarrow>
       is_len_and_type_ok (otype\<^sub>f obj, Obj.len\<^sub>f obj) \<Longrightarrow>
       offs < offs + Obj.len\<^sub>f obj \<Longrightarrow>
       otype\<^sub>f obj = 2 \<Longrightarrow>
       \<exists>v. obj\<lparr>ounion\<^sub>f := v\<rparr> = pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs \<Longrightarrow>
    pObjDentarr (\<alpha>wa (data\<^sub>f buf)) (offs + bilbyFsObjHeaderSize) (Obj.len\<^sub>f obj) =
     pObjDentarr (take (unat (offs + Obj.len\<^sub>f obj)) (\<alpha>wa (data\<^sub>f buf))) (offs + bilbyFsObjHeaderSize) (Obj.len\<^sub>f obj)"
  apply (simp add: pObjDentarr_def)
  apply (frule is_valid_ObjHeader_buf_len, clarify)
  apply (subst ple64_take, ((simp add: otype_simps len_otype_ok bilbyFsObjHeaderSize_def, unat_arith)+)[2])+
  apply (subst ple32_take, ((simp add: otype_simps len_otype_ok bilbyFsObjHeaderSize_def, unat_arith)+)[2])+
  apply (simp add: Let_def) 
 done


lemma pObjData_take:
"is_valid_ObjHeader (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs) (bounded buf) \<Longrightarrow>
       offs + Obj.len\<^sub>f obj \<le> bound\<^sub>f buf \<Longrightarrow>
       is_len_and_type_ok (otype\<^sub>f obj, Obj.len\<^sub>f obj) \<Longrightarrow>
       offs < offs + Obj.len\<^sub>f obj \<Longrightarrow>
       otype\<^sub>f obj = 1 \<Longrightarrow>
       \<exists>v. obj\<lparr>ounion\<^sub>f := v\<rparr> = pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs \<Longrightarrow>
pObjData (\<alpha>wa (data\<^sub>f buf)) (offs + bilbyFsObjHeaderSize) (Obj.len\<^sub>f obj) =
    pObjData (take (unat (offs + Obj.len\<^sub>f obj)) (\<alpha>wa (data\<^sub>f buf))) (offs + bilbyFsObjHeaderSize)
     (Obj.len\<^sub>f obj)"
   apply (simp add: pObjData_def)
  apply (subst ple64_take, ((simp add: otype_simps len_otype_ok bilbyFsObjHeaderSize_def, unat_arith)+)[2])+
    apply (simp add: otype_simps len_otype_ok)
    apply (subst slice_take)
      apply (frule is_valid_ObjHeader_len)
      apply (subgoal_tac " unat (Obj.len\<^sub>f obj - bilbyFsObjHeaderSize - bilbyFsObjDataHeaderSize) =  unat (Obj.len\<^sub>f obj) - unat bilbyFsObjHeaderSize - unat bilbyFsObjDataHeaderSize")
       apply (subgoal_tac "unat (offs + Obj.len\<^sub>f obj) = unat offs + unat ( Obj.len\<^sub>f obj)")
         apply simp
         apply (simp add: bilbyFsObjHeaderSize_def bilbyFsObjDataHeaderSize_def)
         apply unat_arith
        apply (simp add: word_less_nat_alt unat_plus_simple[symmetric], unat_arith)
      apply (subst unat_sub, simp add: bilbyFsObjHeaderSize_def bilbyFsObjDataHeaderSize_def, unat_arith)+
    apply simp+
 done

lemma pObjUnion_take:
 "is_valid_ObjHeader (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs) (bounded buf) \<Longrightarrow>
       offs + Obj.len\<^sub>f obj \<le> bound\<^sub>f buf \<Longrightarrow>
       is_len_and_type_ok (otype\<^sub>f obj, Obj.len\<^sub>f obj) \<Longrightarrow>
       offs < offs + Obj.len\<^sub>f obj \<Longrightarrow>
       \<exists>v. obj\<lparr>ounion\<^sub>f := v\<rparr> = pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs \<Longrightarrow>
      pObjUnion (\<alpha>wa (data\<^sub>f buf)) (otype\<^sub>f obj) (Obj.len\<^sub>f obj) (offs + bilbyFsObjHeaderSize) = 
      pObjUnion (take (unat (offs + Obj.len\<^sub>f obj)) (\<alpha>wa (data\<^sub>f buf))) (otype\<^sub>f obj) (Obj.len\<^sub>f obj) (offs + bilbyFsObjHeaderSize)"
  apply (simp add: pObjUnion_def')
  apply (case_tac "otype\<^sub>f obj = 0")
   apply (simp add: pObjInode_take)
  apply (case_tac "otype\<^sub>f obj = 1")
   apply (simp add: pObjData_take)
  apply (case_tac "otype\<^sub>f obj = 2")
   apply (simp add: pObjDentarr_take)
  apply (case_tac "otype\<^sub>f obj = 3")
   apply (simp add: pObjDel_take)
  apply (case_tac "otype\<^sub>f obj = 4")
   apply (simp add: pObjSuper_take)
  apply simp
 done

lemmas Obj_ext_eq_expand = trans[OF _ Obj.ext_inject,
    OF arg_cong2[where f="(=)"], OF refl Obj.surjective]

lemma deserialise_Obj_ret:
  assumes wf: "wellformed_buf buf"
  assumes buf_len: "length (\<alpha>wa $ data\<^sub>f buf) \<le> unat bilbyFsMaxEbSize"
  assumes bound: "offs + bilbyFsObjHeaderSize \<le> bound\<^sub>f buf"
  assumes no_of: "offs < offs + bilbyFsObjHeaderSize"
  assumes err: "\<And>ex e. e \<in> {eInval, eNoMem} \<Longrightarrow> P (Error (e, ex))"
  assumes suc:
   "\<And>ex obj offs'. \<lbrakk> 
    is_valid_ObjHeader (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs) (\<alpha>wa (data\<^sub>f buf)) ;

    let end_offs = offs + (Obj.len\<^sub>f obj);
    data = take (unat end_offs) (\<alpha>wa (data\<^sub>f buf));
    nb_dentry = ple32 (\<alpha>wa (data\<^sub>f buf)) (offs+8) in
    dentarr_otype_end_offs_pred (Obj.otype\<^sub>f obj) data (offs + bilbyFsObjHeaderSize) end_offs \<and>
    dentarr_otype_drop_end_offs_st_pred (Obj.otype\<^sub>f obj) data (offs + bilbyFsObjHeaderSize) offs end_offs;
    obj = pObj (\<alpha>wa (data\<^sub>f buf)) offs;
    offs' \<le> offs + Obj.len\<^sub>f obj \<rbrakk> \<Longrightarrow> 

   P (Success (ex, obj, offs'))"
  notes bilbyFsObjHeaderSize_def[simp]
  shows "P (deserialise_Obj (ex, buf, offs))"
  unfolding deserialise_Obj_def[unfolded tuple_simps sanitizers]
  apply (clarsimp simp: err eNoMem_def split: R.split)
  apply (rule deserialise_ObjHeader_ret[OF wf bound no_of])
   apply (simp add: err)
  apply simp
  apply (rule deserialise_ObjUnion_ret[OF wf buf_len])
      apply (simp)
     apply (clarsimp, drule sym[where t="pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs"])
     apply (clarsimp simp  add: is_valid_ObjHeader_def)
    apply simp
    apply (drule is_valid_ObjHeader_len)
    apply (clarsimp, drule sym[where t="pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs"])
    apply (drule arg_cong[where f=Obj.len\<^sub>f])
    using no_of bound
    apply simp
    apply  (simp only: word_le_nat_alt plus_no_overflow_unat_lift)
   apply (drule is_valid_ObjHeader_len)
    apply (clarsimp, drule sym[where t="pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs"])
    apply (drule arg_cong[where f=Obj.len\<^sub>f])
   apply (clarsimp simp add: )
   apply unat_arith
   apply (simp add: err)

  apply simp
  apply (rule suc)
       apply (clarsimp simp add: is_valid_ObjHeader_def bounded_def)
      apply simp
   apply (clarsimp simp add: pObj_def Let_def)
   apply (drule sym[where t="pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs"])
   apply (subst pObjUnion_take[simplified], (fastforce simp add: is_valid_ObjHeader_def)+)
   apply (rename_tac obj offs' v)
   apply (subgoal_tac "pObjUnion (take (unat (offs + Obj.len\<^sub>f obj)) (\<alpha>wa (data\<^sub>f buf))) (otype\<^sub>f obj)
              (Obj.len\<^sub>f obj) (offs + 0x18) = pObjUnion
           (take (unat offs + unat (Obj.len\<^sub>f (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs))) (\<alpha>wa (data\<^sub>f buf)))
           (otype\<^sub>f (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs))
           (Obj.len\<^sub>f (pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs)) (offs + 0x18)")
    apply simp
   apply (case_tac "pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs", case_tac obj, simp)
   apply (case_tac "pObjHeader (\<alpha>wa (data\<^sub>f buf)) offs", case_tac obj, simp)
   apply (simp add: plus_no_overflow_unat_lift)+
 done

lemma pObjHeader_take:
 "is_valid_ObjHeader (pObjHeader xs (ObjAddr.offs\<^sub>f oaddr)) xs \<Longrightarrow>
is_obj_addr_consistent (pObj (take (unat (ObjAddr.offs\<^sub>f oaddr) + unat (ObjAddr.len\<^sub>f oaddr)) xs)
          (ObjAddr.offs\<^sub>f oaddr)) oaddr \<Longrightarrow>
  ObjAddr.offs\<^sub>f oaddr < ObjAddr.offs\<^sub>f oaddr + bilbyFsObjHeaderSize \<Longrightarrow>
  bilbyFsObjHeaderSize \<le> ObjAddr.len\<^sub>f oaddr \<Longrightarrow>
   pObjHeader xs (ObjAddr.offs\<^sub>f oaddr) = pObjHeader (take (unat (ObjAddr.offs\<^sub>f oaddr) + unat (ObjAddr.len\<^sub>f oaddr)) xs) (ObjAddr.offs\<^sub>f oaddr)"

  apply (simp add: pObjHeader_def)
  apply (subst ple32_take, ((simp add: bilbyFsObjHeaderSize_def, unat_arith, fastforce? )[2])+)+
  apply (subst ple64_take, ((simp add: bilbyFsObjHeaderSize_def, unat_arith, fastforce? )[2])+)+
  apply (subst nth_take,   (simp add: bilbyFsObjHeaderSize_def, unat_arith))+
  apply (rule refl)
done

end

