Microsoft OLE 2.0 Structured storage(DOCFILE.RFH):
Class: Text, Status: Partial, Last change: 27.05.2022 13:21:20

data

0x0000 ulong Signature
0x0004 ulong Signature1 //uinC: OLE version code

assert (Signature=0xE011CFD0)and(Signature1=0xE11AB1A1);

descr ('Microsoft OLE 2.0 Structured storage.',NL,
  'Info Src: The POI Project (http://www.sf.net/projects/poi)',NL)
//[MS-CFB]: Compound File Binary File Format
//https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/53989ce4-7b05-4f8d-829b-d08d6148375b

include GUID.RFI
include WinFTime.rfi

type

THeader0 struc
  TGUID CLSID //Header CLSID, Reserved CLSID_NULL
  word MinVer //Minor Version 0x3b or 0x3e
  int MajVer //Major Version 0x3 or 0x4
  word ByteOrd //Byte Order -2
  int SectShift //Sector Shift 0x9 for MajVer=3, 0xC for MajVer=4
  int MiniSectShift //Mini Sector Shift 0x6
  array[6]of Byte Reserved
ends

data

0x0008 THeader0 Hdr0

const

BIG_BLOCK_SIZE = 1 shl Hdr0.SectShift;//0x0200;
PROPERTY_SIZE  = 0x0080;
BIG_BLOCK_ITEMS = BIG_BLOCK_SIZE div 4;
BIG_BLOCK_PROPS = BIG_BLOCK_SIZE div PROPERTY_SIZE;
XBAT_ITEMS = BIG_BLOCK_ITEMS-1;

const

//BAT - Block Allocation Table

bat_array_offset      = 0x4c;
max_bats_in_header    = (BIG_BLOCK_SIZE - bat_array_offset)div 4;

type

TBAT_El enum long (
  IN_BAT   = -3,
  CHAIN_END   = -2,
  UNUSED = -1
)

TMiniBAT_El enum long (
  CHAIN_END   = -2,
  UNUSED = -1
)

TXBat(Base) forward

PXBat(Base) ^TXBat(@:Base) NIL:@<=0 near=TBAT_El, REF=(@+1)*BIG_BLOCK_SIZE;

PProperty ^TProperty NIL:@<=0 near=TBAT_El, REF=(@+1)*BIG_BLOCK_SIZE;

TBatBl(Base) forward

PBatBl(Base) ^TBatBl((@:Base+@:#)*BIG_BLOCK_ITEMS) NIL:@<0 near=TBAT_El,
  REF=(@+1)*BIG_BLOCK_SIZE;
 
TBlockKind enum byte of (bkMiniBAT,bkDirectory,bkSmallBlocks,bkData)

//TBlockData(Kind) forward

TBlock(Kind,SeqIndex) forward
PBlocks(Kind) ^TBlock(@:Kind,0) NIL:@<=0 near=TBAT_El,
  REF=(@+1)*BIG_BLOCK_SIZE;

PBatBl0 struc //To make Q.#=0
  PBatBl(0) P
ends:displ=(@.P)

THeader struc
 /*
  TGUID CLSID //Header CLSID, Reserved CLSID_NULL
  word MinVer //Minor Version 0x3b or 0x3e
  int MajVer //Major Version 0x3 or 0x4
  word ByteOrd //Byte Order -2
  int SectShift //Sector Shift 0x9 for MajVer=3, 0xC for MajVer=4
  int MiniSectShift //Mini Sector Shift 0x6
  array[6]of Byte Reserved
 */ 
  ulong NDirSect //Number of Directory Sectors
  ulong NFatSects //Number of FAT Sectors
  PBlocks(TBlockKind.bkDirectory)/*PProperty*/ property_start //First Directory Sector Location
  long NTransaction //Transaction Signature Number, usually 0
  ulong MiniStreamCutoffSize //Mini Stream Cutoff Size 0x1000
  PBlocks(TBlockKind.bkMiniBAT) min_bat/*PBatBl0 sbat_start*/ //First Mini FAT Sector Location
  long NMiniFATSects //Number of Mini FAT Sectors
  PXBat(max_bats_in_header) /*(@.NFatSects-max_bats_in_header)*/ xbat_start //First DIFAT Sector Location
  ulong NDiFatSects //Number of DIFAT Sectors
  array[(@.NFatSects when (@.NFatSects<=max_bats_in_header))exc
    max_bats_in_header] of PBatBl(0) bat_array
  raw[]nodup at 0; rest
ends:[@:Size=BIG_BLOCK_SIZE-8-Hdr0:Size]

TXBat(Base) struc
  array[XBAT_ITEMS/*(@:Cnt when (@:Cnt<=0x7F))exc 0x7F*/] of PBatBl(@@:Base) bat_array
  PXBat(@:Base+XBAT_ITEMS) Next
ends:[@:Size=BIG_BLOCK_SIZE]

TBatBl(Base) array[BIG_BLOCK_ITEMS] of TBAT_El:displ=(ShowArray(@,
  (INT(@:#+(@:@ as TBatBl):Base),'->',@),','))

const

NO_INDEX=-1;

type

//The data types make it possible to change their displ in MSI.rfh
//TPropNameChar WChar()//:displ=('#',HEX(@,4)) 
//TPropNameStr(Sz) array/*[@:Cnt]*/of TPropNameChar:[@:Size=@:Sz]
TPropNameStr(Sz) array/*[@:Cnt]*/of WChar,0;:[@:Size=@:Sz]

TPropName(Cnt) struc
  //array/*[@:Cnt]*/of TPropNameChar N
  TPropNameStr(@:Cnt) N
  raw[] nodup rest
ends:[@:Size=0x40/*,@.N:Size=@:Cnt*/]

TPropType enum byte (
  UNKNOWN = 0,
  DIRECTORY = 1, //Storage Object
  DOCUMENT = 2, //Stream Object
  LOCK_BYTES = 3, //uinC
  ROOT = 5 //Root Storage Object
)

TPropNodeColor enum byte (
  BLACK = 1,
  RED = 0
)

TStreamId enum long (NOSTREAM=-1)

data

0x0008+Hdr0:Size; THeader Hdr

type

TPropDataRef(PropType,IsSmall) case @:PropType*2+@:IsSmall of
 TPropType.DOCUMENT*2: PBlocks(TBlockKind.bkData)
 TPropType.ROOT*2: PBlocks(TBlockKind.bkSmallBlocks)
else ulong
endc
 
TProperty struc
  TPropName Name
  int name_size
  TPropType property_type
  TPropNodeColor node_color
  TStreamId previous_property
  TStreamId next_property
  TStreamId child_property
  TGUID CLSID 
  ulong StateBits //State Bits (user-defined flags)
  TFileTime Created //Creation Time
  TFileTime Modified //Modified Time
  TPropDataRef(@.property_type) start_block //Starting Sector Location
  uint64 size //Stream Size
ends:[@:Size=PROPERTY_SIZE, @.Name:Cnt=@.name_size, 
  @.start_block:IsSmall = @.size<Hdr.MiniStreamCutoffSize]:autoname=(@.Name.N)


function GetXBatBlock(PXBat & XBat,hBl): PBatBl = XBat^.bat_array[hBl] when (hBl<XBAT_ITEMS)
  exc GetXBatBlock(XBat^.Next,hBl-XBAT_ITEMS);
     
function GetNextBlockIndex(hBl,Index)=-1 when ((hBl<0)or(hBl>=Hdr.NFatSects)) 
  exc Hdr.bat_array[hBl]^[Index] when (hBl<max_bats_in_header) 
  exc (GetXBatBlock(Hdr.xbat_start,hBl-max_bats_in_header)^[Index] exc -1);
  
function NextBlockIndex(n) = GetNextBlockIndex(n div BIG_BLOCK_ITEMS,n mod BIG_BLOCK_ITEMS);  
  
function BlockAddr(hBl)=(hBl+1)*BIG_BLOCK_SIZE when (hBl>=0) exc -1; 
 
type
PNextBatBl(Kind,SeqIndex) ^TBlock(@:Kind,@:SeqIndex+1) near=void nil-, 
  REF=(BlockAddr(NextBlockIndex(&@ div BIG_BLOCK_SIZE - 1)));:
  displ=(cond((&@^ exc -1)>0,(ADDR(&@^)),('nil'))):hide[0];

TBlock(Kind,SeqIndex) struc
  PNextBatBl(@:Kind,@:SeqIndex) Next
  case TBlockKind @:Kind of
   bkMiniBAT: array[BIG_BLOCK_ITEMS] of TMiniBAT_El:displ=(
     ShowArray(@,(INT(@:#+OwnerOfType(@,TBlock):SeqIndex*BIG_BLOCK_ITEMS),'->',@),','))
   bkDirectory: array[BIG_BLOCK_PROPS] of TProperty:displ=(
     ShowArray(@,(NL,INT(@:#+OwnerOfType(@,TBlock):SeqIndex*BIG_BLOCK_PROPS),':',@),','))
  endc Data
  raw[] at &@-OwnerOfType(@,TBlock):SeqIndex*BIG_BLOCK_SIZE; Rest 
  //TBlockData(@:Kind) Data
ends:[@:Size=BIG_BLOCK_SIZE]

  


Other specifications.


FlexT home page, Author`s home page.