openMSX
DiskImageUtils.hh
Go to the documentation of this file.
1#ifndef DISK_IMAGE_UTILS_HH
2#define DISK_IMAGE_UTILS_HH
3
4#include "AlignedBuffer.hh"
5#include "endian.hh"
6#include "ranges.hh"
7#include "stl.hh"
8
9#include <array>
10#include <span>
11#include <string>
12
13namespace openmsx {
14
15class SectorAccessibleDisk;
16
17enum class MSXBootSectorType : int {
18 DOS1 = 0,
19 DOS2 = 1,
20 NEXTOR = 2,
21};
22
24 std::array<uint8_t, 3> jumpCode; // + 0 0xE5 to boot program
25 std::array<uint8_t, 8> name; // + 3
26 Endian::UA_L16 bpSector; // +11 bytes per sector (always 512)
27 uint8_t spCluster; // +13 sectors per cluster
28 Endian::L16 resvSectors; // +14 nb of non-data sectors (incl boot sector)
29 uint8_t nrFats; // +16 nb of fats
30 Endian::UA_L16 dirEntries; // +17 max nb of files in root directory
31 Endian::UA_L16 nrSectors; // +19 nb of sectors on this disk (< 65536)
32 uint8_t descriptor; // +21 media descriptor
33 Endian::L16 sectorsFat; // +22 sectors per FAT
34 Endian::L16 sectorsTrack; // +24 sectors per track (0 for LBA volumes)
35 Endian::L16 nrSides; // +26 number of sides (heads) (0 for LBA volumes)
36 union {
37 struct {
38 Endian::L16 hiddenSectors; // +28 not used
39 std::array<uint8_t, 512-30> pad; // +30
41 struct {
42 Endian::L16 hiddenSectors; // +28 not used
43 std::array<uint8_t, 9> pad1; // +30
45 std::array<uint8_t, 512-43> pad2; // +43
47 struct {
48 Endian::L32 hiddenSectors; // +28 not used
49 Endian::L32 nrSectors; // +32 nb of sectors on this disk (>= 65536)
50 uint8_t physicalDriveNum; // +36
51 uint8_t reserved; // +37
52 uint8_t extendedBootSignature; // +38
54 std::array<uint8_t, 11> volumeLabel; // +43
55 std::array<uint8_t, 8> fileSystemType; // +54
56 std::array<uint8_t, 512-62> padding; // +62
59};
60static_assert(sizeof(MSXBootSector) == 512);
61
63 enum class Attrib : uint8_t {
64 REGULAR = 0x00, // Normal file
65 READONLY = 0x01, // Read-Only file
66 HIDDEN = 0x02, // Hidden file
67 SYSTEM = 0x04, // System file
68 VOLUME = 0x08, // filename is Volume Label
69 DIRECTORY = 0x10, // entry is a subdir
70 ARCHIVE = 0x20, // Archive bit
71 };
72 struct AttribValue {
73 uint8_t value;
74
75 constexpr AttribValue() = default;
76 constexpr /*implicit*/ AttribValue(Attrib v) : value(to_underlying(v)) {}
77 constexpr explicit AttribValue(uint8_t v) : value(v) {}
78 constexpr explicit operator bool() const { return value != 0; }
79 constexpr auto operator<=>(const AttribValue&) const = default;
80 friend constexpr AttribValue operator|(AttribValue x, AttribValue y) { return AttribValue(x.value | y.value); }
81 friend constexpr AttribValue operator&(AttribValue x, AttribValue y) { return AttribValue(x.value & y.value); }
82 };
83
84 std::array<char, 8 + 3> filename; // + 0
86 std::array<uint8_t, 10> reserved; // +12 unused
91
92 [[nodiscard]] auto base() const { return subspan<8>(filename, 0); }
93 [[nodiscard]] auto ext () const { return subspan<3>(filename, 8); }
94
95 bool operator==(const MSXDirEntry& other) const = default;
96};
97static_assert(sizeof(MSXDirEntry) == 32);
98
99// Note: can't use Endian::L32 for 'start' and 'size' because the Partition
100// struct itself is not 4-bytes aligned.
101struct Partition {
102 uint8_t boot_ind; // + 0 0x80 - active
103 uint8_t head; // + 1 starting head
104 uint8_t sector; // + 2 starting sector
105 uint8_t cyl; // + 3 starting cylinder
106 uint8_t sys_ind; // + 4 what partition type
107 uint8_t end_head; // + 5 end head
108 uint8_t end_sector; // + 6 end sector
109 uint8_t end_cyl; // + 7 end cylinder
110 Endian::UA_L32 start; // + 8 starting sector counting from 0
111 Endian::UA_L32 size; // +12 nr of sectors in partition
112};
113static_assert(sizeof(Partition) == 16);
114static_assert(alignof(Partition) == 1, "must not have alignment requirements");
115
117 std::array<char, 11> header; // + 0
118 std::array<char, 3> pad; // + 3
119 std::array<Partition, 31> part; // + 14,+30,..,+494 Not 4-byte aligned!!
121};
122static_assert(sizeof(PartitionTableSunrise) == 512);
123
125 std::array<char, 11> header; // + 0
126 std::array<char, 435> pad; // + 3
127 std::array<Partition, 4> part; // +446,+462,+478,+494 Not 4-byte aligned!!
129};
130static_assert(sizeof(PartitionTableNextor) == 512);
131
132
133// Buffer that can hold a (512-byte) disk sector.
134// The main advantages of this type over something like 'byte buf[512]' are:
135// - No need for reinterpret_cast<> when interpreting the data in a
136// specific way (this could in theory cause alignment problems).
137// - This type has a stricter alignment, so memcpy() and memset() can work
138// faster compared to using a raw byte array.
140 std::array<uint8_t, 512> raw; // raw byte data
141 MSXBootSector bootSector; // interpreted as bootSector
142 std::array<MSXDirEntry, 16> dirEntry; // interpreted as 16 dir entries
143 PartitionTableSunrise ptSunrise; // interpreted as Sunrise-IDE partition table
144 PartitionTableNextor ptNextor; // interpreted as Nextor partition table
145 AlignedBuffer aligned; // force big alignment (for faster memcpy)
146};
147static_assert(sizeof(SectorBuffer) == 512);
148
149
150namespace DiskImageUtils {
151
162
165 void checkSupportedPartition(const SectorAccessibleDisk& disk, unsigned partition);
166
169 [[nodiscard]] bool hasPartitionTable(const SectorAccessibleDisk& disk);
170
176 void format(SectorAccessibleDisk& disk, MSXBootSectorType bootType);
177 void format(SectorAccessibleDisk& disk, MSXBootSectorType bootType, size_t nbSectors);
178
184 unsigned partition(SectorAccessibleDisk& disk,
185 std::span<const unsigned> sizes, MSXBootSectorType bootType);
186
187 struct FatTimeDate {
188 uint16_t time, date;
189 };
190 FatTimeDate toTimeDate(time_t totalSeconds);
191 time_t fromTimeDate(FatTimeDate timeDate);
192
193 [[nodiscard]] std::string formatAttrib(MSXDirEntry::AttribValue attrib);
194};
195
196} // namespace openmsx
197
198#endif
bool hasPartitionTable(const SectorAccessibleDisk &disk)
Check whether the given disk is partitioned.
void checkSupportedPartition(const SectorAccessibleDisk &disk, unsigned partition)
Check whether partition is of type FAT12 or FAT16.
void format(SectorAccessibleDisk &disk, MSXBootSectorType bootType)
Format the given disk (= a single partition).
Partition & getPartition(const SectorAccessibleDisk &disk, unsigned partition, SectorBuffer &buf)
Gets the requested partition.
time_t fromTimeDate(FatTimeDate timeDate)
std::string formatAttrib(MSXDirEntry::AttribValue attrib)
unsigned partition(SectorAccessibleDisk &disk, std::span< const unsigned > sizes, MSXBootSectorType bootType)
Write a partition table to the given disk and format each partition.
FatTimeDate toTimeDate(time_t totalSeconds)
This file implemented 3 utility functions:
Definition Autofire.cc:11
constexpr auto to_underlying(E e) noexcept
Definition stl.hh:465
std::array< uint8_t, 512-30 > pad
struct openmsx::MSXBootSector::@0::@2 dos2
union openmsx::MSXBootSector::@0 params
struct openmsx::MSXBootSector::@0::@3 extended
std::array< uint8_t, 3 > jumpCode
std::array< uint8_t, 8 > fileSystemType
std::array< uint8_t, 8 > name
struct openmsx::MSXBootSector::@0::@1 dos1
std::array< uint8_t, 11 > volumeLabel
Endian::UA_L16 dirEntries
std::array< uint8_t, 512-62 > padding
std::array< uint8_t, 512-43 > pad2
std::array< uint8_t, 9 > pad1
constexpr AttribValue()=default
constexpr auto operator<=>(const AttribValue &) const =default
friend constexpr AttribValue operator|(AttribValue x, AttribValue y)
friend constexpr AttribValue operator&(AttribValue x, AttribValue y)
std::array< uint8_t, 10 > reserved
bool operator==(const MSXDirEntry &other) const =default
std::array< char, 8+3 > filename
std::array< char, 435 > pad
std::array< Partition, 4 > part
std::array< char, 11 > header
std::array< Partition, 31 > part
std::array< char, 11 > header
Endian::UA_L32 size
Endian::UA_L32 start
PartitionTableSunrise ptSunrise
std::array< uint8_t, 512 > raw
std::array< MSXDirEntry, 16 > dirEntry
PartitionTableNextor ptNextor