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.