#pragma once #include #include namespace FAT32 { using ClusterNr = uint32_t; using AbsOffset = uint32_t; using AbsPos = uint32_t; struct FSDesc { uint16_t bytesPerSector; uint8_t sectorsPerCluster; uint16_t numReservedSectors; uint8_t numberOfFATs; uint32_t sectorsPerFAT; ClusterNr rootDirFirstCluster; }; struct Precomputed { uint32_t bytesPerCluster; AbsPos startOfFAT; // absolute byte offset where the FAT begins AbsPos startOfFirstDataCluster; // absolute byte offset where the first cluster is AbsPos startOfFirstRootDirCluster; // absolute byte offset where the first root dir cluster is uint32_t dirEntriesPerSector; }; union Attributes { uint8_t raw; struct { uint8_t readOnly : 1; uint8_t hidden : 1; uint8_t system : 1; uint8_t volumeID : 1; uint8_t directory : 1; uint8_t archive : 1; uint8_t unused1 : 1; uint8_t unused2 : 1; } bits; } __attribute__((packed)); struct DirEntry { unsigned char name[8]; unsigned char ext[3]; Attributes attr; uint8_t dummy1[8]; uint16_t firstClusterHi; uint8_t dummy2[4]; uint16_t firstClusterLo; uint32_t size; // file size in bytes bool isUnused() const {return name[0] == 0xE5;} bool isDirectory() const {return attr.bits.directory;} bool isEndOfDirectory() const {return name[0] == 0x00;} bool isLongFileName() const {return (attr.raw & 0b1111) == 0b1111;} uint32_t getFirstCluster() const {return firstClusterHi<<16 | firstClusterLo<<0;} std::string getName() const { char buf[16]; uint8_t pos = 0; for (uint8_t i = 0; i < 8; ++i) {if (name[i] != ' ') {buf[pos++] = name[i];}} buf[pos++] = '.'; for (uint8_t i = 0; i < 8; ++i) {if ( ext[i] != ' ') {buf[pos++] = ext[i];}} buf[pos] = 0; return std::string(buf); } } __attribute__((packed)); static inline uint16_t getU8(const uint8_t* src) {return src[0];} static inline uint16_t getU16(const uint8_t* src) {return src[0]<<0 | src[1]<<8;} static inline uint32_t getU32(const uint8_t* src) {return src[0]<<0 | src[1]<<8 | src[2]<<16 | src[3]<<24;} }