This page hosts a formal specification of vfat using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
All parsing code for C++11/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.
For C++, the easiest way is to clone the runtime library sources and build them along with your project.
Using Kaitai Struct in C++/STL usually consists of 3 steps.
std::istream
). One can open local file for that, or use existing std::string
or char*
buffer.
#include <fstream>
std::ifstream is("path/to/local/file.bin", std::ifstream::binary);
#include <sstream>
std::istringstream is(str);
#include <sstream>
const char buf[] = { ... };
std::string str(buf, sizeof buf);
std::istringstream is(str);
#include "kaitai/kaitaistream.h"
kaitai::kstream ks(&is);
vfat_t data(&ks);
After that, one can get various attributes from the structure by invoking getter methods like:
data.boot_sector() // => get boot sector
#pragma once
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include "dos_datetime.h"
#include <vector>
#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif
class dos_datetime_t;
/**
* \sa https://download.microsoft.com/download/0/8/4/084c452b-b772-4fe5-89bb-a0cbf082286a/fatgen103.doc Source
*/
class vfat_t : public kaitai::kstruct {
public:
class ext_bios_param_block_fat32_t;
class boot_sector_t;
class bios_param_block_t;
class root_directory_rec_t;
class root_directory_t;
class ext_bios_param_block_fat16_t;
vfat_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, vfat_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~vfat_t();
/**
* Extended BIOS Parameter Block for FAT32
*/
class ext_bios_param_block_fat32_t : public kaitai::kstruct {
public:
ext_bios_param_block_fat32_t(kaitai::kstream* p__io, vfat_t::boot_sector_t* p__parent = nullptr, vfat_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~ext_bios_param_block_fat32_t();
private:
uint32_t m_ls_per_fat;
bool m_has_active_fat;
uint64_t m_reserved1;
uint64_t m_active_fat_id;
std::string m_reserved2;
uint16_t m_fat_version;
uint32_t m_root_dir_start_clus;
uint16_t m_ls_fs_info;
uint16_t m_boot_sectors_copy_start_ls;
std::string m_reserved3;
uint8_t m_phys_drive_num;
uint8_t m_reserved4;
uint8_t m_ext_boot_sign;
std::string m_volume_id;
std::string m_partition_volume_label;
std::string m_fs_type_str;
vfat_t* m__root;
vfat_t::boot_sector_t* m__parent;
public:
/**
* Logical sectors per file allocation table (corresponds with
* the old entry `ls_per_fat` in the DOS 2.0 BPB).
*/
uint32_t ls_per_fat() const { return m_ls_per_fat; }
/**
* If true, then there is "active" FAT, which is designated in
* `active_fat` attribute. If false, all FATs are mirrored as
* usual.
*/
bool has_active_fat() const { return m_has_active_fat; }
uint64_t reserved1() const { return m_reserved1; }
/**
* Zero-based number of active FAT, if `has_active_fat`
* attribute is true.
*/
uint64_t active_fat_id() const { return m_active_fat_id; }
std::string reserved2() const { return m_reserved2; }
uint16_t fat_version() const { return m_fat_version; }
/**
* Cluster number of root directory start, typically 2 if it
* contains no bad sector. (Microsoft's FAT32 implementation
* imposes an artificial limit of 65,535 entries per directory,
* whilst many third-party implementations do not.)
*/
uint32_t root_dir_start_clus() const { return m_root_dir_start_clus; }
/**
* Logical sector number of FS Information Sector, typically 1,
* i.e., the second of the three FAT32 boot sectors. Values
* like 0 and 0xFFFF are used by some FAT32 implementations to
* designate abscence of FS Information Sector.
*/
uint16_t ls_fs_info() const { return m_ls_fs_info; }
/**
* First logical sector number of a copy of the three FAT32
* boot sectors, typically 6.
*/
uint16_t boot_sectors_copy_start_ls() const { return m_boot_sectors_copy_start_ls; }
std::string reserved3() const { return m_reserved3; }
/**
* Physical drive number (0x00 for (first) removable media,
* 0x80 for (first) fixed disk as per INT 13h).
*/
uint8_t phys_drive_num() const { return m_phys_drive_num; }
uint8_t reserved4() const { return m_reserved4; }
/**
* Should be 0x29 to indicate that an EBPB with the following 3
* entries exists.
*/
uint8_t ext_boot_sign() const { return m_ext_boot_sign; }
/**
* Volume ID (serial number).
*
* Typically the serial number "xxxx-xxxx" is created by a
* 16-bit addition of both DX values returned by INT 21h/AH=2Ah
* (get system date) and INT 21h/AH=2Ch (get system time) for
* the high word and another 16-bit addition of both CX values
* for the low word of the serial number. Alternatively, some
* DR-DOS disk utilities provide a /# option to generate a
* human-readable time stamp "mmdd-hhmm" build from BCD-encoded
* 8-bit values for the month, day, hour and minute instead of
* a serial number.
*/
std::string volume_id() const { return m_volume_id; }
std::string partition_volume_label() const { return m_partition_volume_label; }
std::string fs_type_str() const { return m_fs_type_str; }
vfat_t* _root() const { return m__root; }
vfat_t::boot_sector_t* _parent() const { return m__parent; }
};
class boot_sector_t : public kaitai::kstruct {
public:
boot_sector_t(kaitai::kstream* p__io, vfat_t* p__parent = nullptr, vfat_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~boot_sector_t();
private:
bool f_pos_fats;
int32_t m_pos_fats;
public:
/**
* Offset of FATs in bytes from start of filesystem
*/
int32_t pos_fats();
private:
bool f_ls_per_fat;
uint32_t m_ls_per_fat;
public:
uint32_t ls_per_fat();
private:
bool f_ls_per_root_dir;
int32_t m_ls_per_root_dir;
public:
/**
* Size of root directory in logical sectors
* \sa FAT: General Overview of On-Disk Format, section "FAT Data Structure"
*/
int32_t ls_per_root_dir();
private:
bool f_is_fat32;
bool m_is_fat32;
public:
/**
* Determines if filesystem is FAT32 (true) or FAT12/16 (false)
* by analyzing some preliminary conditions in BPB. Used to
* determine whether we should parse post-BPB data as
* `ext_bios_param_block_fat16` or `ext_bios_param_block_fat32`.
*/
bool is_fat32();
private:
bool f_size_fat;
int32_t m_size_fat;
public:
/**
* Size of one FAT in bytes
*/
int32_t size_fat();
private:
bool f_pos_root_dir;
int32_t m_pos_root_dir;
public:
/**
* Offset of root directory in bytes from start of filesystem
*/
int32_t pos_root_dir();
private:
bool f_size_root_dir;
int32_t m_size_root_dir;
public:
/**
* Size of root directory in bytes
*/
int32_t size_root_dir();
private:
std::string m_jmp_instruction;
std::string m_oem_name;
std::unique_ptr<bios_param_block_t> m_bpb;
std::unique_ptr<ext_bios_param_block_fat16_t> m_ebpb_fat16;
bool n_ebpb_fat16;
public:
bool _is_null_ebpb_fat16() { ebpb_fat16(); return n_ebpb_fat16; };
private:
std::unique_ptr<ext_bios_param_block_fat32_t> m_ebpb_fat32;
bool n_ebpb_fat32;
public:
bool _is_null_ebpb_fat32() { ebpb_fat32(); return n_ebpb_fat32; };
private:
vfat_t* m__root;
vfat_t* m__parent;
public:
std::string jmp_instruction() const { return m_jmp_instruction; }
std::string oem_name() const { return m_oem_name; }
/**
* Basic BIOS parameter block, present in all versions of FAT
*/
bios_param_block_t* bpb() const { return m_bpb.get(); }
/**
* FAT12/16-specific extended BIOS parameter block
*/
ext_bios_param_block_fat16_t* ebpb_fat16() const { return m_ebpb_fat16.get(); }
/**
* FAT32-specific extended BIOS parameter block
*/
ext_bios_param_block_fat32_t* ebpb_fat32() const { return m_ebpb_fat32.get(); }
vfat_t* _root() const { return m__root; }
vfat_t* _parent() const { return m__parent; }
};
class bios_param_block_t : public kaitai::kstruct {
public:
bios_param_block_t(kaitai::kstream* p__io, vfat_t::boot_sector_t* p__parent = nullptr, vfat_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~bios_param_block_t();
private:
uint16_t m_bytes_per_ls;
uint8_t m_ls_per_clus;
uint16_t m_num_reserved_ls;
uint8_t m_num_fats;
uint16_t m_max_root_dir_rec;
uint16_t m_total_ls_2;
uint8_t m_media_code;
uint16_t m_ls_per_fat;
uint16_t m_ps_per_track;
uint16_t m_num_heads;
uint32_t m_num_hidden_sectors;
uint32_t m_total_ls_4;
vfat_t* m__root;
vfat_t::boot_sector_t* m__parent;
public:
/**
* Bytes per logical sector
*/
uint16_t bytes_per_ls() const { return m_bytes_per_ls; }
/**
* Logical sectors per cluster
*/
uint8_t ls_per_clus() const { return m_ls_per_clus; }
/**
* Count of reserved logical sectors. The number of logical
* sectors before the first FAT in the file system image.
*/
uint16_t num_reserved_ls() const { return m_num_reserved_ls; }
/**
* Number of File Allocation Tables
*/
uint8_t num_fats() const { return m_num_fats; }
/**
* Maximum number of FAT12 or FAT16 root directory entries. 0
* for FAT32, where the root directory is stored in ordinary
* data clusters.
*/
uint16_t max_root_dir_rec() const { return m_max_root_dir_rec; }
/**
* Total logical sectors (if zero, use total_ls_4)
*/
uint16_t total_ls_2() const { return m_total_ls_2; }
/**
* Media descriptor
*/
uint8_t media_code() const { return m_media_code; }
/**
* Logical sectors per File Allocation Table for
* FAT12/FAT16. FAT32 sets this to 0 and uses the 32-bit value
* at offset 0x024 instead.
*/
uint16_t ls_per_fat() const { return m_ls_per_fat; }
/**
* Physical sectors per track for disks with INT 13h CHS
* geometry, e.g., 15 for a "1.20 MB" (1200 KB) floppy. A zero
* entry indicates that this entry is reserved, but not used.
*/
uint16_t ps_per_track() const { return m_ps_per_track; }
/**
* Number of heads for disks with INT 13h CHS geometry,[9]
* e.g., 2 for a double sided floppy.
*/
uint16_t num_heads() const { return m_num_heads; }
/**
* Number of hidden sectors preceding the partition that
* contains this FAT volume. This field should always be zero
* on media that are not partitioned. This DOS 3.0 entry is
* incompatible with a similar entry at offset 0x01C in BPBs
* since DOS 3.31. It must not be used if the logical sectors
* entry at offset 0x013 is zero.
*/
uint32_t num_hidden_sectors() const { return m_num_hidden_sectors; }
/**
* Total logical sectors including hidden sectors. This DOS 3.2
* entry is incompatible with a similar entry at offset 0x020
* in BPBs since DOS 3.31. It must not be used if the logical
* sectors entry at offset 0x013 is zero.
*/
uint32_t total_ls_4() const { return m_total_ls_4; }
vfat_t* _root() const { return m__root; }
vfat_t::boot_sector_t* _parent() const { return m__parent; }
};
class root_directory_rec_t : public kaitai::kstruct {
public:
class attr_flags_t;
root_directory_rec_t(kaitai::kstream* p__io, vfat_t::root_directory_t* p__parent = nullptr, vfat_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~root_directory_rec_t();
class attr_flags_t : public kaitai::kstruct {
public:
attr_flags_t(kaitai::kstream* p__io, vfat_t::root_directory_rec_t* p__parent = nullptr, vfat_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~attr_flags_t();
private:
bool f_long_name;
bool m_long_name;
public:
bool long_name();
private:
bool m_read_only;
bool m_hidden;
bool m_system;
bool m_volume_id;
bool m_is_directory;
bool m_archive;
uint64_t m_reserved;
vfat_t* m__root;
vfat_t::root_directory_rec_t* m__parent;
public:
bool read_only() const { return m_read_only; }
bool hidden() const { return m_hidden; }
bool system() const { return m_system; }
bool volume_id() const { return m_volume_id; }
bool is_directory() const { return m_is_directory; }
bool archive() const { return m_archive; }
uint64_t reserved() const { return m_reserved; }
vfat_t* _root() const { return m__root; }
vfat_t::root_directory_rec_t* _parent() const { return m__parent; }
};
private:
std::string m_file_name;
std::unique_ptr<attr_flags_t> m_attrs;
std::string m_reserved;
std::unique_ptr<dos_datetime_t> m_last_write_time;
uint16_t m_start_clus;
uint32_t m_file_size;
vfat_t* m__root;
vfat_t::root_directory_t* m__parent;
std::string m__raw_attrs;
std::unique_ptr<kaitai::kstream> m__io__raw_attrs;
std::string m__raw_last_write_time;
std::unique_ptr<kaitai::kstream> m__io__raw_last_write_time;
public:
std::string file_name() const { return m_file_name; }
attr_flags_t* attrs() const { return m_attrs.get(); }
std::string reserved() const { return m_reserved; }
dos_datetime_t* last_write_time() const { return m_last_write_time.get(); }
uint16_t start_clus() const { return m_start_clus; }
uint32_t file_size() const { return m_file_size; }
vfat_t* _root() const { return m__root; }
vfat_t::root_directory_t* _parent() const { return m__parent; }
std::string _raw_attrs() const { return m__raw_attrs; }
kaitai::kstream* _io__raw_attrs() const { return m__io__raw_attrs.get(); }
std::string _raw_last_write_time() const { return m__raw_last_write_time; }
kaitai::kstream* _io__raw_last_write_time() const { return m__io__raw_last_write_time.get(); }
};
class root_directory_t : public kaitai::kstruct {
public:
root_directory_t(kaitai::kstream* p__io, vfat_t* p__parent = nullptr, vfat_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~root_directory_t();
private:
std::unique_ptr<std::vector<std::unique_ptr<root_directory_rec_t>>> m_records;
vfat_t* m__root;
vfat_t* m__parent;
public:
std::vector<std::unique_ptr<root_directory_rec_t>>* records() const { return m_records.get(); }
vfat_t* _root() const { return m__root; }
vfat_t* _parent() const { return m__parent; }
};
/**
* Extended BIOS Parameter Block (DOS 4.0+, OS/2 1.0+). Used only
* for FAT12 and FAT16.
*/
class ext_bios_param_block_fat16_t : public kaitai::kstruct {
public:
ext_bios_param_block_fat16_t(kaitai::kstream* p__io, vfat_t::boot_sector_t* p__parent = nullptr, vfat_t* p__root = nullptr);
private:
void _read();
void _clean_up();
public:
~ext_bios_param_block_fat16_t();
private:
uint8_t m_phys_drive_num;
uint8_t m_reserved1;
uint8_t m_ext_boot_sign;
std::string m_volume_id;
std::string m_partition_volume_label;
std::string m_fs_type_str;
vfat_t* m__root;
vfat_t::boot_sector_t* m__parent;
public:
/**
* Physical drive number (0x00 for (first) removable media,
* 0x80 for (first) fixed disk as per INT 13h).
*/
uint8_t phys_drive_num() const { return m_phys_drive_num; }
uint8_t reserved1() const { return m_reserved1; }
/**
* Should be 0x29 to indicate that an EBPB with the following 3
* entries exists.
*/
uint8_t ext_boot_sign() const { return m_ext_boot_sign; }
/**
* Volume ID (serial number).
*
* Typically the serial number "xxxx-xxxx" is created by a
* 16-bit addition of both DX values returned by INT 21h/AH=2Ah
* (get system date) and INT 21h/AH=2Ch (get system time) for
* the high word and another 16-bit addition of both CX values
* for the low word of the serial number. Alternatively, some
* DR-DOS disk utilities provide a /# option to generate a
* human-readable time stamp "mmdd-hhmm" build from BCD-encoded
* 8-bit values for the month, day, hour and minute instead of
* a serial number.
*/
std::string volume_id() const { return m_volume_id; }
std::string partition_volume_label() const { return m_partition_volume_label; }
std::string fs_type_str() const { return m_fs_type_str; }
vfat_t* _root() const { return m__root; }
vfat_t::boot_sector_t* _parent() const { return m__parent; }
};
private:
bool f_fats;
std::unique_ptr<std::vector<std::string>> m_fats;
public:
std::vector<std::string>* fats();
private:
bool f_root_dir;
std::unique_ptr<root_directory_t> m_root_dir;
public:
root_directory_t* root_dir();
private:
std::unique_ptr<boot_sector_t> m_boot_sector;
vfat_t* m__root;
kaitai::kstruct* m__parent;
std::string m__raw_root_dir;
std::unique_ptr<kaitai::kstream> m__io__raw_root_dir;
public:
boot_sector_t* boot_sector() const { return m_boot_sector.get(); }
vfat_t* _root() const { return m__root; }
kaitai::kstruct* _parent() const { return m__parent; }
std::string _raw_root_dir() const { return m__raw_root_dir; }
kaitai::kstream* _io__raw_root_dir() const { return m__io__raw_root_dir.get(); }
};
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
#include "vfat.h"
#include "kaitai/exceptions.h"
vfat_t::vfat_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, vfat_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = this;
m_boot_sector = nullptr;
m_fats = nullptr;
m_root_dir = nullptr;
m__io__raw_root_dir = nullptr;
f_fats = false;
f_root_dir = false;
_read();
}
void vfat_t::_read() {
m_boot_sector = std::unique_ptr<boot_sector_t>(new boot_sector_t(m__io, this, m__root));
}
vfat_t::~vfat_t() {
_clean_up();
}
void vfat_t::_clean_up() {
if (f_fats) {
}
if (f_root_dir) {
}
}
vfat_t::ext_bios_param_block_fat32_t::ext_bios_param_block_fat32_t(kaitai::kstream* p__io, vfat_t::boot_sector_t* p__parent, vfat_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
_read();
}
void vfat_t::ext_bios_param_block_fat32_t::_read() {
m_ls_per_fat = m__io->read_u4le();
m_has_active_fat = m__io->read_bits_int_le(1);
m_reserved1 = m__io->read_bits_int_le(3);
m_active_fat_id = m__io->read_bits_int_le(4);
m__io->align_to_byte();
m_reserved2 = m__io->read_bytes(1);
if (!(reserved2() == std::string("\x00", 1))) {
throw kaitai::validation_not_equal_error<std::string>(std::string("\x00", 1), reserved2(), _io(), std::string("/types/ext_bios_param_block_fat32/seq/4"));
}
m_fat_version = m__io->read_u2le();
m_root_dir_start_clus = m__io->read_u4le();
m_ls_fs_info = m__io->read_u2le();
m_boot_sectors_copy_start_ls = m__io->read_u2le();
m_reserved3 = m__io->read_bytes(12);
m_phys_drive_num = m__io->read_u1();
m_reserved4 = m__io->read_u1();
m_ext_boot_sign = m__io->read_u1();
m_volume_id = m__io->read_bytes(4);
m_partition_volume_label = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(11), 32), std::string("ASCII"));
m_fs_type_str = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 32), std::string("ASCII"));
}
vfat_t::ext_bios_param_block_fat32_t::~ext_bios_param_block_fat32_t() {
_clean_up();
}
void vfat_t::ext_bios_param_block_fat32_t::_clean_up() {
}
vfat_t::boot_sector_t::boot_sector_t(kaitai::kstream* p__io, vfat_t* p__parent, vfat_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_bpb = nullptr;
m_ebpb_fat16 = nullptr;
m_ebpb_fat32 = nullptr;
f_pos_fats = false;
f_ls_per_fat = false;
f_ls_per_root_dir = false;
f_is_fat32 = false;
f_size_fat = false;
f_pos_root_dir = false;
f_size_root_dir = false;
_read();
}
void vfat_t::boot_sector_t::_read() {
m_jmp_instruction = m__io->read_bytes(3);
m_oem_name = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 32), std::string("ASCII"));
m_bpb = std::unique_ptr<bios_param_block_t>(new bios_param_block_t(m__io, this, m__root));
n_ebpb_fat16 = true;
if (!(is_fat32())) {
n_ebpb_fat16 = false;
m_ebpb_fat16 = std::unique_ptr<ext_bios_param_block_fat16_t>(new ext_bios_param_block_fat16_t(m__io, this, m__root));
}
n_ebpb_fat32 = true;
if (is_fat32()) {
n_ebpb_fat32 = false;
m_ebpb_fat32 = std::unique_ptr<ext_bios_param_block_fat32_t>(new ext_bios_param_block_fat32_t(m__io, this, m__root));
}
}
vfat_t::boot_sector_t::~boot_sector_t() {
_clean_up();
}
void vfat_t::boot_sector_t::_clean_up() {
if (!n_ebpb_fat16) {
}
if (!n_ebpb_fat32) {
}
}
int32_t vfat_t::boot_sector_t::pos_fats() {
if (f_pos_fats)
return m_pos_fats;
m_pos_fats = (bpb()->bytes_per_ls() * bpb()->num_reserved_ls());
f_pos_fats = true;
return m_pos_fats;
}
uint32_t vfat_t::boot_sector_t::ls_per_fat() {
if (f_ls_per_fat)
return m_ls_per_fat;
m_ls_per_fat = ((is_fat32()) ? (ebpb_fat32()->ls_per_fat()) : (bpb()->ls_per_fat()));
f_ls_per_fat = true;
return m_ls_per_fat;
}
int32_t vfat_t::boot_sector_t::ls_per_root_dir() {
if (f_ls_per_root_dir)
return m_ls_per_root_dir;
m_ls_per_root_dir = ((((bpb()->max_root_dir_rec() * 32) + bpb()->bytes_per_ls()) - 1) / bpb()->bytes_per_ls());
f_ls_per_root_dir = true;
return m_ls_per_root_dir;
}
bool vfat_t::boot_sector_t::is_fat32() {
if (f_is_fat32)
return m_is_fat32;
m_is_fat32 = bpb()->max_root_dir_rec() == 0;
f_is_fat32 = true;
return m_is_fat32;
}
int32_t vfat_t::boot_sector_t::size_fat() {
if (f_size_fat)
return m_size_fat;
m_size_fat = (bpb()->bytes_per_ls() * ls_per_fat());
f_size_fat = true;
return m_size_fat;
}
int32_t vfat_t::boot_sector_t::pos_root_dir() {
if (f_pos_root_dir)
return m_pos_root_dir;
m_pos_root_dir = (bpb()->bytes_per_ls() * (bpb()->num_reserved_ls() + (ls_per_fat() * bpb()->num_fats())));
f_pos_root_dir = true;
return m_pos_root_dir;
}
int32_t vfat_t::boot_sector_t::size_root_dir() {
if (f_size_root_dir)
return m_size_root_dir;
m_size_root_dir = (ls_per_root_dir() * bpb()->bytes_per_ls());
f_size_root_dir = true;
return m_size_root_dir;
}
vfat_t::bios_param_block_t::bios_param_block_t(kaitai::kstream* p__io, vfat_t::boot_sector_t* p__parent, vfat_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
_read();
}
void vfat_t::bios_param_block_t::_read() {
m_bytes_per_ls = m__io->read_u2le();
m_ls_per_clus = m__io->read_u1();
m_num_reserved_ls = m__io->read_u2le();
m_num_fats = m__io->read_u1();
m_max_root_dir_rec = m__io->read_u2le();
m_total_ls_2 = m__io->read_u2le();
m_media_code = m__io->read_u1();
m_ls_per_fat = m__io->read_u2le();
m_ps_per_track = m__io->read_u2le();
m_num_heads = m__io->read_u2le();
m_num_hidden_sectors = m__io->read_u4le();
m_total_ls_4 = m__io->read_u4le();
}
vfat_t::bios_param_block_t::~bios_param_block_t() {
_clean_up();
}
void vfat_t::bios_param_block_t::_clean_up() {
}
vfat_t::root_directory_rec_t::root_directory_rec_t(kaitai::kstream* p__io, vfat_t::root_directory_t* p__parent, vfat_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_attrs = nullptr;
m__io__raw_attrs = nullptr;
m_last_write_time = nullptr;
m__io__raw_last_write_time = nullptr;
_read();
}
void vfat_t::root_directory_rec_t::_read() {
m_file_name = m__io->read_bytes(11);
m__raw_attrs = m__io->read_bytes(1);
m__io__raw_attrs = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_attrs));
m_attrs = std::unique_ptr<attr_flags_t>(new attr_flags_t(m__io__raw_attrs.get(), this, m__root));
m_reserved = m__io->read_bytes(10);
m__raw_last_write_time = m__io->read_bytes(4);
m__io__raw_last_write_time = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_last_write_time));
m_last_write_time = std::unique_ptr<dos_datetime_t>(new dos_datetime_t(m__io__raw_last_write_time.get()));
m_start_clus = m__io->read_u2le();
m_file_size = m__io->read_u4le();
}
vfat_t::root_directory_rec_t::~root_directory_rec_t() {
_clean_up();
}
void vfat_t::root_directory_rec_t::_clean_up() {
}
vfat_t::root_directory_rec_t::attr_flags_t::attr_flags_t(kaitai::kstream* p__io, vfat_t::root_directory_rec_t* p__parent, vfat_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
f_long_name = false;
_read();
}
void vfat_t::root_directory_rec_t::attr_flags_t::_read() {
m_read_only = m__io->read_bits_int_le(1);
m_hidden = m__io->read_bits_int_le(1);
m_system = m__io->read_bits_int_le(1);
m_volume_id = m__io->read_bits_int_le(1);
m_is_directory = m__io->read_bits_int_le(1);
m_archive = m__io->read_bits_int_le(1);
m_reserved = m__io->read_bits_int_le(2);
}
vfat_t::root_directory_rec_t::attr_flags_t::~attr_flags_t() {
_clean_up();
}
void vfat_t::root_directory_rec_t::attr_flags_t::_clean_up() {
}
bool vfat_t::root_directory_rec_t::attr_flags_t::long_name() {
if (f_long_name)
return m_long_name;
m_long_name = ((read_only()) && (hidden()) && (system()) && (volume_id())) ;
f_long_name = true;
return m_long_name;
}
vfat_t::root_directory_t::root_directory_t(kaitai::kstream* p__io, vfat_t* p__parent, vfat_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
m_records = nullptr;
_read();
}
void vfat_t::root_directory_t::_read() {
m_records = std::unique_ptr<std::vector<std::unique_ptr<root_directory_rec_t>>>(new std::vector<std::unique_ptr<root_directory_rec_t>>());
const int l_records = _root()->boot_sector()->bpb()->max_root_dir_rec();
for (int i = 0; i < l_records; i++) {
m_records->push_back(std::move(std::unique_ptr<root_directory_rec_t>(new root_directory_rec_t(m__io, this, m__root))));
}
}
vfat_t::root_directory_t::~root_directory_t() {
_clean_up();
}
void vfat_t::root_directory_t::_clean_up() {
}
vfat_t::ext_bios_param_block_fat16_t::ext_bios_param_block_fat16_t(kaitai::kstream* p__io, vfat_t::boot_sector_t* p__parent, vfat_t* p__root) : kaitai::kstruct(p__io) {
m__parent = p__parent;
m__root = p__root;
_read();
}
void vfat_t::ext_bios_param_block_fat16_t::_read() {
m_phys_drive_num = m__io->read_u1();
m_reserved1 = m__io->read_u1();
m_ext_boot_sign = m__io->read_u1();
m_volume_id = m__io->read_bytes(4);
m_partition_volume_label = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(11), 32), std::string("ASCII"));
m_fs_type_str = kaitai::kstream::bytes_to_str(kaitai::kstream::bytes_strip_right(m__io->read_bytes(8), 32), std::string("ASCII"));
}
vfat_t::ext_bios_param_block_fat16_t::~ext_bios_param_block_fat16_t() {
_clean_up();
}
void vfat_t::ext_bios_param_block_fat16_t::_clean_up() {
}
std::vector<std::string>* vfat_t::fats() {
if (f_fats)
return m_fats.get();
std::streampos _pos = m__io->pos();
m__io->seek(boot_sector()->pos_fats());
m_fats = std::unique_ptr<std::vector<std::string>>(new std::vector<std::string>());
const int l_fats = boot_sector()->bpb()->num_fats();
for (int i = 0; i < l_fats; i++) {
m_fats->push_back(std::move(m__io->read_bytes(boot_sector()->size_fat())));
}
m__io->seek(_pos);
f_fats = true;
return m_fats.get();
}
vfat_t::root_directory_t* vfat_t::root_dir() {
if (f_root_dir)
return m_root_dir.get();
std::streampos _pos = m__io->pos();
m__io->seek(boot_sector()->pos_root_dir());
m__raw_root_dir = m__io->read_bytes(boot_sector()->size_root_dir());
m__io__raw_root_dir = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_root_dir));
m_root_dir = std::unique_ptr<root_directory_t>(new root_directory_t(m__io__raw_root_dir.get(), this, m__root));
m__io->seek(_pos);
f_root_dir = true;
return m_root_dir.get();
}