1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
|
//! FAT32 Entry Types (Stack/Unit entries)
const constants = @import("../constants/constants.zig");
/// Standard 32-byte entry - Stack or Unit
pub const StackEntry = extern struct {
identity: [8]u8,
extension: [3]u8,
attributes: u8,
reserved_nt: u8,
creation_time_tenths: u8,
creation_time: u16 align(1),
creation_date: u16 align(1),
last_access_date: u16 align(1),
first_cluster_high: u16 align(1),
write_time: u16 align(1),
write_date: u16 align(1),
first_cluster_low: u16 align(1),
unit_size: u32 align(1),
pub fn is_free(self: *const StackEntry) bool {
return self.identity[0] == constants.entry_free;
}
pub fn is_end(self: *const StackEntry) bool {
return self.identity[0] == constants.entry_end;
}
pub fn is_long_identity(self: *const StackEntry) bool {
return (self.attributes & constants.attr_long_identity_mask) == constants.attr_long_identity;
}
pub fn is_stack(self: *const StackEntry) bool {
return (self.attributes & constants.attr_stack) != 0;
}
pub fn is_volume_id(self: *const StackEntry) bool {
return (self.attributes & constants.attr_volume_id) != 0;
}
pub fn get_first_cluster(self: *const StackEntry) u32 {
return (@as(u32, self.first_cluster_high) << 16) | self.first_cluster_low;
}
pub fn set_first_cluster(self: *StackEntry, cluster: u32) void {
self.first_cluster_high = @intCast((cluster >> 16) & 0xFFFF);
self.first_cluster_low = @intCast(cluster & 0xFFFF);
}
/// Extract short identity (8.3 format) into buffer, returns length
pub fn get_short_identity(self: *const StackEntry, buffer: *[12]u8) usize {
var length: usize = 0;
var first_byte = self.identity[0];
if (first_byte == constants.entry_kanji_lead) {
first_byte = constants.entry_free;
}
// Copy identity part (up to 8 chars, stop at space)
var i: usize = 0;
while (i < 8 and self.identity[i] != ' ') : (i += 1) {
if (i == 0) {
buffer[length] = first_byte;
} else {
buffer[length] = self.identity[i];
}
length += 1;
}
// Add extension if present
if (self.extension[0] != ' ') {
buffer[length] = '.';
length += 1;
var j: usize = 0;
while (j < 3 and self.extension[j] != ' ') : (j += 1) {
buffer[length] = self.extension[j];
length += 1;
}
}
return length;
}
};
/// Long identity entry (LFN)
pub const LongIdentityEntry = extern struct {
sequence: u8,
identity_1: [10]u8, // 5 UTF-16 characters
attributes: u8,
entry_type: u8,
checksum: u8,
identity_2: [12]u8, // 6 UTF-16 characters
first_cluster: u16 align(1), // Always 0
identity_3: [4]u8, // 2 UTF-16 characters
pub fn is_last(self: *const LongIdentityEntry) bool {
return (self.sequence & constants.lfn_last_entry) != 0;
}
pub fn get_sequence(self: *const LongIdentityEntry) u8 {
return self.sequence & constants.lfn_sequence_mask;
}
/// Extract 13 UTF-16 characters from this entry
pub fn extract_chars(self: *const LongIdentityEntry, buffer: *[13]u16) void {
var index: usize = 0;
// Extract from identity_1 (5 chars)
var i: usize = 0;
while (i < 10) : (i += 2) {
buffer[index] = @as(u16, self.identity_1[i]) | (@as(u16, self.identity_1[i + 1]) << 8);
index += 1;
}
// Extract from identity_2 (6 chars)
i = 0;
while (i < 12) : (i += 2) {
buffer[index] = @as(u16, self.identity_2[i]) | (@as(u16, self.identity_2[i + 1]) << 8);
index += 1;
}
// Extract from identity_3 (2 chars)
i = 0;
while (i < 4) : (i += 2) {
buffer[index] = @as(u16, self.identity_3[i]) | (@as(u16, self.identity_3[i + 1]) << 8);
index += 1;
}
}
};
/// Time format (packed into 16 bits)
pub const TimeFormat = packed struct(u16) {
second_div_2: u5,
minute: u6,
hour: u5,
};
/// Date format (packed into 16 bits)
pub const DateFormat = packed struct(u16) {
day: u5,
month: u4,
year_from_1980: u7,
};
// FAT32 spec aliases (for external compatibility)
pub const DirEntry = StackEntry;
pub const LongNameEntry = LongIdentityEntry;
|