/** @file
  Definitions for on-disk FAT structures.

Copyright (c) 2005 - 2017, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent


**/

#ifndef _FATFILESYSTEM_H_
#define _FATFILESYSTEM_H_

#pragma pack(1)
//
// FAT info signature
//
#define FAT_INFO_SIGNATURE        0x41615252
#define FAT_INFO_BEGIN_SIGNATURE  0x61417272
#define FAT_INFO_END_SIGNATURE    0xAA550000
//
// FAT entry values
//
#define FAT_CLUSTER_SPECIAL_EXT  (MAX_UINTN & (~0xF))
#define FAT_CLUSTER_SPECIAL      ((FAT_CLUSTER_SPECIAL_EXT) | 0x07)
#define FAT_CLUSTER_FREE         0
#define FAT_CLUSTER_RESERVED     (FAT_CLUSTER_SPECIAL)
#define FAT_CLUSTER_BAD          (FAT_CLUSTER_SPECIAL)
#define FAT_CLUSTER_LAST         (-1)
#define FAT_END_OF_FAT_CHAIN(Cluster)  ((Cluster) > (FAT_CLUSTER_SPECIAL))
#define FAT_MIN_CLUSTER            2
#define FAT_MAX_FAT12_CLUSTER      0xFF5
#define FAT_MAX_FAT16_CLUSTER      0xFFF5
#define FAT_CLUSTER_SPECIAL_FAT12  0xFF7
#define FAT_CLUSTER_SPECIAL_FAT16  0xFFF7
#define FAT_CLUSTER_SPECIAL_FAT32  0x0FFFFFF7
#define FAT_CLUSTER_MASK_FAT12     0xFFF
#define FAT_CLUSTER_UNMASK_FAT12   0xF000
#define FAT_CLUSTER_MASK_FAT32     0x0FFFFFFF
#define FAT_CLUSTER_UNMASK_FAT32   0xF0000000
#define FAT_POS_FAT12(a)          ((a) * 3 / 2)
#define FAT_POS_FAT16(a)          ((a) * 2)
#define FAT_POS_FAT32(a)          ((a) * 4)
#define FAT_ODD_CLUSTER_FAT12(a)  (((a) & 1) != 0)

//
// FAT attribute define
//
#define FAT_ATTRIBUTE_READ_ONLY  0x01
#define FAT_ATTRIBUTE_HIDDEN     0x02
#define FAT_ATTRIBUTE_SYSTEM     0x04
#define FAT_ATTRIBUTE_VOLUME_ID  0x08
#define FAT_ATTRIBUTE_DIRECTORY  0x10
#define FAT_ATTRIBUTE_ARCHIVE    0x20
#define FAT_ATTRIBUTE_DEVICE     0x40
#define FAT_ATTRIBUTE_LFN        0x0F
//
// Some Long File Name definitions
//
#define FAT_LFN_LAST     0x40         // Ordinal field
#define MAX_LFN_ENTRIES  20
#define LFN_CHAR1_LEN    5
#define LFN_CHAR2_LEN    6
#define LFN_CHAR3_LEN    2
#define LFN_CHAR_TOTAL   (LFN_CHAR1_LEN + LFN_CHAR2_LEN + LFN_CHAR3_LEN)
#define LFN_ENTRY_NUMBER(a)  (((a) + LFN_CHAR_TOTAL - 1) / LFN_CHAR_TOTAL)
//
// Some 8.3 File Name definitions
//
#define FAT_MAIN_NAME_LEN    8
#define FAT_EXTEND_NAME_LEN  3
#define FAT_NAME_LEN         (FAT_MAIN_NAME_LEN + FAT_EXTEND_NAME_LEN)
//
// Some directory entry information
//
#define FAT_ENTRY_INFO_OFFSET  13
#define DELETE_ENTRY_MARK      0xE5
#define EMPTY_ENTRY_MARK       0x00

//
// Volume dirty Mask
//
#define FAT16_DIRTY_MASK  0x7fff
#define FAT32_DIRTY_MASK  0xf7ffffff
//
// internal flag
//
#define FAT_CASE_MIXED       0x01
#define FAT_CASE_NAME_LOWER  0x08
#define FAT_CASE_EXT_LOWER   0x10

typedef struct {
  UINT8     Ia32Jump[3];
  CHAR8     OemId[8];
  UINT16    SectorSize;
  UINT8     SectorsPerCluster;
  UINT16    ReservedSectors;
  UINT8     NumFats;
  UINT16    RootEntries;        // < FAT32, root dir is fixed size
  UINT16    Sectors;
  UINT8     Media;
  UINT16    SectorsPerFat;      // < FAT32
  UINT16    SectorsPerTrack;    // (ignored)
  UINT16    Heads;              // (ignored)
  UINT32    HiddenSectors;      // (ignored)
  UINT32    LargeSectors;       // Used if Sectors==0
} FAT_BOOT_SECTOR_BASIC;

typedef struct {
  UINT8    PhysicalDriveNumber; // (ignored)
  UINT8    CurrentHead;         // holds boot_sector_dirty bit
  UINT8    Signature;           // (ignored)
  CHAR8    Id[4];
  CHAR8    FatLabel[11];
  CHAR8    SystemId[8];
} FAT_BOOT_SECTOR_EXT;

typedef struct {
  UINT32    LargeSectorsPerFat;  // FAT32
  UINT16    ExtendedFlags;       // FAT32 (ignored)
  UINT16    FsVersion;           // FAT32 (ignored)
  UINT32    RootDirFirstCluster; // FAT32
  UINT16    FsInfoSector;        // FAT32
  UINT16    BackupBootSector;    // FAT32
  UINT8     Reserved[12];        // FAT32 (ignored)
  UINT8     PhysicalDriveNumber; // (ignored)
  UINT8     CurrentHead;         // holds boot_sector_dirty bit
  UINT8     Signature;           // (ignored)
  CHAR8     Id[4];
  CHAR8     FatLabel[11];
  CHAR8     SystemId[8];
} FAT32_BOOT_SECTOR_EXT;

typedef union {
  FAT_BOOT_SECTOR_EXT      FatBse;
  FAT32_BOOT_SECTOR_EXT    Fat32Bse;
} FAT_BSE;

typedef struct {
  FAT_BOOT_SECTOR_BASIC    FatBsb;
  FAT_BSE                  FatBse;
} FAT_BOOT_SECTOR;

//
// FAT Info Structure
//
typedef struct {
  UINT32    ClusterCount;
  UINT32    NextCluster;
} FAT_FREE_INFO;

typedef struct {
  UINT32           Signature;
  UINT8            ExtraBootCode[480];
  UINT32           InfoBeginSignature;
  FAT_FREE_INFO    FreeInfo;
  UINT8            Reserved[12];
  UINT32           InfoEndSignature;
} FAT_INFO_SECTOR;

//
// Directory Entry
//
#define FAT_MAX_YEAR_FROM_1980  0x7f
typedef struct {
  UINT16    Day   : 5;
  UINT16    Month : 4;
  UINT16    Year  : 7;              // From 1980
} FAT_DATE;

typedef struct {
  UINT16    DoubleSecond : 5;
  UINT16    Minute       : 6;
  UINT16    Hour         : 5;
} FAT_TIME;

typedef struct {
  FAT_TIME    Time;
  FAT_DATE    Date;
} FAT_DATE_TIME;

typedef struct {
  CHAR8            FileName[11];    // 8.3 filename
  UINT8            Attributes;
  UINT8            CaseFlag;
  UINT8            CreateMillisecond; // (creation milliseconds - ignored)
  FAT_DATE_TIME    FileCreateTime;
  FAT_DATE         FileLastAccess;
  UINT16           FileClusterHigh; // >= FAT32
  FAT_DATE_TIME    FileModificationTime;
  UINT16           FileCluster;
  UINT32           FileSize;
} FAT_DIRECTORY_ENTRY;

typedef struct {
  UINT8     Ordinal;
  CHAR8     Name1[10];              // (Really 5 chars, but not WCHAR aligned)
  UINT8     Attributes;
  UINT8     Type;
  UINT8     Checksum;
  CHAR16    Name2[6];
  UINT16    MustBeZero;
  CHAR16    Name3[2];
} FAT_DIRECTORY_LFN;

#pragma pack()

#endif
