github.com/shakinm/xlsReader@v0.9.12/cfb/header.go (about)

     1  package cfb
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"github.com/shakinm/xlsReader/helpers"
     7  )
     8  
     9  //HeaderSignature Identification signature for the compound file structure, and MUST be
    10  //set to the value ...
    11  var HeaderSignature = []byte{0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1}
    12  
    13  //MajorVersion3 - Version number sign fot version 3
    14  var MajorVersion3 = []byte{0x03, 0x00}
    15  
    16  //MajorVersion4 - Version number sign fot version 4
    17  var MajorVersion4 = []byte{0x04, 0x00}
    18  
    19  //MajorVersion -Version number for breaking changes. This field MUST be set to either
    20  //0x0003 (version 3) or 0x0004 (version 4).
    21  var MajorVersion = [][]byte{MajorVersion3, MajorVersion4}
    22  
    23  //ByteOrder - This field MUST be set to 0xFFFE. This field is a byte order mark for all integer
    24  //fields, specifying little-endian byte order.
    25  var ByteOrder = []byte{0xFE, 0xFF}
    26  
    27  //SectorShiftForMajorVersion3 - If Major Version is 3, the Sector Shift MUST be 0x0009, specifying a sector size of 512 bytes.
    28  var SectorShiftForMajorVersion3 = []byte{0x09, 0x00}
    29  
    30  //SectorShiftForMajorVersion4 - If Major Version is 4, the Sector Shift MUST be 0x000C, specifying a sector size of 4096 bytes.
    31  var SectorShiftForMajorVersion4 = []byte{0x0C, 0x00}
    32  
    33  //MiniSectorShift - This field MUST be set to 0x0009, or 0x000c, depending on the Major
    34  //Version field. This field specifies the sector size of the compound file as a power of 2.
    35  var MiniSectorShift = []byte{0x06, 0x00}
    36  
    37  //Reserved - This field MUST be set to all zeroes.
    38  var Reserved = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
    39  
    40  //NumberDirectorySectorsForMajorVersion3 - If Major Version is 3, the Number of Directory Sectors MUST be zero.
    41  var NumberDirectorySectorsForMajorVersion3 = []byte{0x00, 0x00, 0x00, 0x00}
    42  
    43  //MiniStreamCutoffSize - This integer field MUST be set to 0x00001000. This field
    44  //specifies the maximum size of a user-defined data stream that is allocated from the mini FAT
    45  //and mini stream, and that cutoff is 4,096 bytes. Any user-defined data stream that is greater than
    46  //or equal to this cutoff size must be allocated as normal sectors from the FAT.
    47  var MiniStreamCutoffSize = []byte{0x00, 0x10, 0x00, 0x00}
    48  
    49  // Header - The Compound File Header structure
    50  type Header struct {
    51  	HeaderSignature              [8]byte
    52  	HeaderCLSID                  [16]byte
    53  	MinorVersion                 [2]byte
    54  	MajorVersion                 [2]byte
    55  	ByteOrder                    [2]byte
    56  	SectorShift                  [2]byte
    57  	MiniSectorShift              [2]byte
    58  	Reserved                     [6]byte
    59  	NumberDirectorySectors       [4]byte
    60  	NumberFATSectors             [4]byte
    61  	FirstDirectorySectorLocation [4]byte
    62  	TransactionSignatureNumber   [4]byte
    63  	MiniStreamCutoffSize         [4]byte
    64  	FirstMiniFATSectorLocation   [4]byte
    65  	NumberMiniFATSectors         [4]byte
    66  	FirstDIFATSectorLocation     [4]byte
    67  	NumberDIFATSectors           [4]byte
    68  	DIFAT                        [3584]byte
    69  }
    70  
    71  func (h *Header) getDIFATEntry(i uint32) []byte {
    72  	return h.DIFAT[i*4:(i*4)+4]
    73  }
    74  
    75  func (h *Header) sectorSize() (size uint32) {
    76  	if bytes.Compare(h.MajorVersion[:], MajorVersion3) == 0 {
    77  		size = 512
    78  	}
    79  	if bytes.Compare(h.MajorVersion[:], MajorVersion4) == 0 {
    80  		size = 4096
    81  	}
    82  
    83  	return size
    84  }
    85  
    86  func (h *Header) validate() (err error) { // nolint: gocyclo
    87  
    88  	if bytes.Compare(h.HeaderSignature[:], HeaderSignature) != 0 {
    89  		return errors.New(`Identification signature for the compound file structure, and MUST be set to the value 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1`)
    90  	}
    91  
    92  	if !helpers.BytesInSlice(h.MajorVersion[:], MajorVersion) {
    93  		return errors.New(`Version number for breaking changes. This structure MUST be set to either 0x0003 (version 3) or 0x0004 (version 4)`)
    94  	}
    95  
    96  	if bytes.Compare(h.ByteOrder[:], ByteOrder) != 0 {
    97  		return errors.New(`Byte Order MUST be set to 0xFFFE. This structure is a byte order mark for all integer fields, specifying little-endian byte order`)
    98  	}
    99  
   100  	if bytes.Compare(h.MajorVersion[:], MajorVersion3) == 0 && bytes.Compare(h.SectorShift[:], SectorShiftForMajorVersion3) != 0 {
   101  		return errors.New(`If Major Version is 3, the Sector Shift MUST be 0x0009, specifying a sector size of 512 bytes`)
   102  	}
   103  
   104  	if bytes.Compare(h.MajorVersion[:], MajorVersion4) == 0 && bytes.Compare(h.SectorShift[:], SectorShiftForMajorVersion4) != 0 {
   105  		return errors.New(`If Major Version is 4, the Sector Shift MUST be 0x000C, specifying a sector size of 4,096 bytes`)
   106  	}
   107  
   108  	if bytes.Compare(h.MiniSectorShift[:], MiniSectorShift) != 0 {
   109  		return errors.New(`Mini Sector Shift MUST be set to 0x0006. This structure specifies the sector size of the Mini Stream as a power of 2. The sector size of the Mini Stream MUST be 64 bytes`)
   110  	}
   111  
   112  	if bytes.Compare(h.Reserved[:], Reserved) != 0 {
   113  		return errors.New(`Reserved MUST be set to all zeroes`)
   114  	}
   115  
   116  	if bytes.Compare(h.MiniStreamCutoffSize[:], MiniStreamCutoffSize) != 0 {
   117  		return errors.New(`Mini Stream Cutoff Size structure MUST be set to 0x00001000`)
   118  	}
   119  
   120  	if bytes.Compare(h.MajorVersion[:], MajorVersion3) == 0 && bytes.Compare(h.NumberDirectorySectors[:], NumberDirectorySectorsForMajorVersion3) != 0 {
   121  		return errors.New(`if Major Version is 3, the Number of Directory Sectors MUST be zero`)
   122  	}
   123  
   124  	if bytes.Compare(h.MajorVersion[:], MajorVersion4) == 0 {
   125  		for i := 513; i <= 4096; i++ {
   126  			if h.DIFAT[i] != 0x00 {
   127  				return errors.New(`For version 4 compound files, the header size (512 bytes) is less than the sector size (4,096 bytes), so the remaining part of the header (3,584 bytes) MUST be filled with all zeroes`)
   128  			}
   129  		}
   130  
   131  	}
   132  
   133  	return
   134  }
   135