Skip to content

Commit c0126dc

Browse files
committed
[fat] refactor 3 types implementation as enum
1 parent d45760b commit c0126dc

File tree

3 files changed

+150
-80
lines changed

3 files changed

+150
-80
lines changed

src/main/java/DiscUtils/Fat/FatBuffer.java

+12-75
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.List;
2828
import java.util.Map;
2929

30-
import DiscUtils.Streams.Util.EndianUtilities;
3130
import dotnet4j.io.Stream;
3231

3332

@@ -39,15 +38,15 @@ public class FatBuffer {
3938
* The actual end-of-chain marker bits on disk vary by FAT type, and can end
4039
* ...F8 through ...FF.
4140
*/
42-
public static final int EndOfChain = 0xFFFFFFFF;
41+
public static final int EndOfChain = 0xffff_ffff;
4342

4443
/**
4544
* The Bad-Cluster marker to WRITE (SetNext). Don't use this value to test
4645
* for bad clusters.
4746
*
4847
* The actual bad-cluster marker bits on disk vary by FAT type.
4948
*/
50-
public static final int BadCluster = 0xFFFFFFF7;
49+
public static final int BadCluster = 0xffff_fff7;
5150

5251
/**
5352
* The Free-Cluster marker to WRITE (SetNext). Don't use this value to test
@@ -74,14 +73,7 @@ public FatBuffer(FatType type, byte[] buffer) {
7473
}
7574

7675
public int getNumEntries() {
77-
switch (_type) {
78-
case Fat12:
79-
return _buffer.length / 3 * 2;
80-
case Fat16:
81-
return _buffer.length / 2;
82-
default:
83-
return _buffer.length / 4;
84-
}
76+
return _type.getNumEntries(_buffer);
8577
}
8678

8779
// FAT32
@@ -94,47 +86,15 @@ public boolean isFree(int val) {
9486
}
9587

9688
public boolean isEndOfChain(int val) {
97-
switch (_type) {
98-
case Fat12:
99-
return (val & 0x0FFF) >= 0x0FF8;
100-
case Fat16:
101-
return (val & 0xFFFF) >= 0xFFF8;
102-
case Fat32:
103-
return (val & 0x0FFFFFF8) >= 0x0FFFFFF8;
104-
default:
105-
throw new IllegalArgumentException("Unknown FAT type");
106-
107-
}
89+
return _type.isEndOfChain(val);
10890
}
10991

11092
public boolean isBadCluster(int val) {
111-
switch (_type) {
112-
case Fat12:
113-
return (val & 0x0FFF) == 0x0FF7;
114-
case Fat16:
115-
return (val & 0xFFFF) == 0xFFF7;
116-
case Fat32:
117-
return (val & 0x0FFFFFFF) == 0x0FFFFFF7; // TODO bug report
118-
default:
119-
throw new IllegalArgumentException("Unknown FAT type");
120-
}
93+
return _type.isBadCluster(val);
12194
}
12295

12396
public int getNext(int cluster) {
124-
if (_type == FatType.Fat16) {
125-
return EndianUtilities.toUInt16LittleEndian(_buffer, cluster * 2);
126-
}
127-
128-
if (_type == FatType.Fat32) {
129-
return EndianUtilities.toUInt32LittleEndian(_buffer, cluster * 4) & 0x0FFFFFFF;
130-
}
131-
132-
// FAT12
133-
if ((cluster & 1) != 0) {
134-
return (EndianUtilities.toUInt16LittleEndian(_buffer, cluster + cluster / 2) >>> 4) & 0x0FFF;
135-
}
136-
137-
return EndianUtilities.toUInt16LittleEndian(_buffer, cluster + cluster / 2) & 0x0FFF;
97+
return _type.getNext(cluster, _buffer);
13898
}
13999

140100
public void setEndOfChain(int cluster) {
@@ -154,41 +114,18 @@ public void setFree(int cluster) {
154114
}
155115

156116
public void setNext(int cluster, int next) {
157-
if (_type == FatType.Fat16) {
158-
markDirty(cluster * 2);
159-
EndianUtilities.writeBytesLittleEndian((short) next, _buffer, cluster * 2);
160-
} else if (_type == FatType.Fat32) {
161-
markDirty(cluster * 4);
162-
int oldVal = EndianUtilities.toUInt32LittleEndian(_buffer, cluster * 4);
163-
int newVal = (oldVal & 0xF0000000) | (next & 0x0FFFFFFF);
164-
EndianUtilities.writeBytesLittleEndian(newVal, _buffer, cluster * 4);
165-
} else {
166-
int offset = cluster + cluster / 2;
167-
markDirty(offset);
168-
markDirty(offset + 1);
169-
// On alternate sector boundaries, cluster info crosses two sectors
170-
short maskedOldVal;
171-
if ((cluster & 1) != 0) {
172-
next = next << 4;
173-
maskedOldVal = (short) (EndianUtilities.toUInt16LittleEndian(_buffer, offset) & 0x000F);
174-
} else {
175-
next = next & 0x0FFF;
176-
maskedOldVal = (short) (EndianUtilities.toUInt16LittleEndian(_buffer, offset) & 0xF000);
177-
}
178-
short newVal = (short) (maskedOldVal | next);
179-
EndianUtilities.writeBytesLittleEndian(newVal, _buffer, offset);
180-
}
117+
_type.setNext(cluster, next, _buffer, this::markDirty);
181118
}
182119

183120
/**
184121
* @param cluster {@cs out}
185122
*/
186123
public boolean tryGetFreeCluster(int[] cluster) {
187124
// Simple scan - don't hold a free list...
188-
int numEntries = getNumEntries();
125+
int numEntries = _type.getNumEntries(_buffer);
189126
for (int i = 0; i < numEntries; i++) {
190127
int candidate = (i + _nextFreeCandidate) % numEntries;
191-
if (isFree(getNext(candidate))) {
128+
if (isFree(_type.getNext(candidate, _buffer))) {
192129
cluster[0] = candidate;
193130
_nextFreeCandidate = candidate + 1;
194131
return true;
@@ -209,15 +146,15 @@ public List<Integer> getChain(int head) {
209146
List<Integer> result = new ArrayList<>();
210147
if (head != 0) {
211148
int focus = head;
212-
while (!isEndOfChain(focus)) {
149+
while (!_type.isEndOfChain(focus)) {
213150
result.add(focus);
214-
focus = getNext(focus);
151+
focus = _type.getNext(focus, _buffer);
215152
}
216153
}
217154
return result;
218155
}
219156

220-
public void markDirty(int offset) {
157+
private void markDirty(int offset) {
221158
_dirtySectors.put(offset / DirtyRegionSize, offset / DirtyRegionSize);
222159
}
223160

src/main/java/DiscUtils/Fat/FatFileSystem.java

+36-1
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,11 @@
3333
import java.util.HashMap;
3434
import java.util.List;
3535
import java.util.Map;
36+
import java.util.logging.Level;
3637
import java.util.regex.Pattern;
3738

39+
import vavi.util.Debug;
40+
3841
import DiscUtils.Core.DiscFileSystem;
3942
import DiscUtils.Core.FileSystemParameters;
4043
import DiscUtils.Core.FloppyDiskType;
@@ -1420,6 +1423,19 @@ private static FatType detectFATType(byte[] bpb) {
14201423
int totalSec = bpbTotSec16 != 0 ? bpbTotSec16 : bpbTotSec32;
14211424
int dataSec = totalSec - (bpbResvdSecCnt + bpbNumFATs * fatSz + rootDirSectors);
14221425
int countOfClusters = dataSec / bpbSecPerClus;
1426+
//Debug.println(Level.FINE, "bpbBytesPerSec: " + bpbBytesPerSec);
1427+
//Debug.println(Level.FINE, "bpbRootEntCnt: " + bpbRootEntCnt);
1428+
//Debug.println(Level.FINE, "bpbFATSz16: " + bpbFATSz16);
1429+
//Debug.println(Level.FINE, "bpbFATSz32: " + bpbFATSz32);
1430+
//Debug.println(Level.FINE, "bpbTotSec16: " + bpbTotSec16);
1431+
//Debug.println(Level.FINE, "bpbTotSec32: " + bpbTotSec32);
1432+
//Debug.println(Level.FINE, "bpbNumFATs: " + bpbNumFATs);
1433+
//Debug.println(Level.FINE, "bpbSecPerClus: " + bpbSecPerClus);
1434+
//Debug.println(Level.FINE, "rootDirSectors: " + rootDirSectors);
1435+
//Debug.println(Level.FINE, "fatSz: " + fatSz);
1436+
//Debug.println(Level.FINE, "totalSec: " + totalSec);
1437+
//Debug.println(Level.FINE, "dataSec: " + dataSec);
1438+
//Debug.println(Level.FINE, "countOfClusters: " + countOfClusters);
14231439
if (countOfClusters < 4085) {
14241440
return FatType.Fat12;
14251441
}
@@ -1444,7 +1460,7 @@ private void initialize(Stream data) {
14441460
_data = data;
14451461
_data.setPosition(0);
14461462
_bootSector = StreamUtilities.readSector(_data);
1447-
//Debug.println(StringUtil.getDump(_bootSector, 64));
1463+
//Debug.println(Level.FINE, "\n" + StringUtil.getDump(_bootSector, 64));
14481464
setFatVariant(detectFATType(_bootSector));
14491465
readBPB();
14501466
loadFAT();
@@ -1461,6 +1477,8 @@ private void loadClusterReader() {
14611477
private void loadRootDirectory() {
14621478
Stream fatStream;
14631479
if (_fatVariant != FatType.Fat32) {
1480+
//Debug.printf(Level.FINE, "%016x, %016x\n", ((_bpbRsvdSecCnt & 0xffff) + getFatCount() * (_bpbFATSz16 & 0xffff)) *
1481+
// (_bpbBytesPerSec & 0xffff), (_bpbRootEntCnt & 0xffff) * 32);
14641482
fatStream = new SubStream(_data,
14651483
((_bpbRsvdSecCnt & 0xffff) + getFatCount() * (_bpbFATSz16 & 0xffff)) *
14661484
(_bpbBytesPerSec & 0xffff),
@@ -1505,6 +1523,18 @@ private void readBPB() {
15051523
_bpbBkBootSec = EndianUtilities.toUInt16LittleEndian(_bootSector, 50);
15061524
readBS(64);
15071525
}
1526+
//Debug.println(Level.FINE, "bpbBytesPerSec: " + _bpbBytesPerSec);
1527+
//Debug.println(Level.FINE, "sectorsPerCluster: " + getSectorsPerCluster());
1528+
//Debug.println(Level.FINE, "_bpbRsvdSecCnt: " + _bpbRsvdSecCnt);
1529+
//Debug.println(Level.FINE, "fatCount: " + getFatCount());
1530+
//Debug.println(Level.FINE, "_bpbRootEntCnt: " + _bpbRootEntCnt);
1531+
//Debug.println(Level.FINE, "_bpbTotSec16: " + _bpbTotSec16);
1532+
Debug.printf(Level.FINE, "media: %02x\n", getMedia());
1533+
//Debug.println(Level.FINE, "_bpbFATSz16: " + _bpbFATSz16);
1534+
//Debug.println(Level.FINE, "_bpbSecPerTrk: " + _bpbSecPerTrk);
1535+
//Debug.println(Level.FINE, "_bpbNumHeads: " + _bpbNumHeads);
1536+
//Debug.println(Level.FINE, "_bpbHiddSec: " + _bpbHiddSec);
1537+
//Debug.println(Level.FINE, "_bpbTotSec32: " + _bpbTotSec32);
15081538
}
15091539

15101540
private void readBS(int offset) {
@@ -1867,4 +1897,9 @@ public static FatFileSystem formatPartition(Stream stream,
18671897
stream.setPosition(pos);
18681898
return new FatFileSystem(stream);
18691899
}
1900+
1901+
@Override
1902+
public String toString() {
1903+
return getFriendlyName() + ", " + getOemName();
1904+
}
18701905
}

src/main/java/DiscUtils/Fat/FatType.java

+102-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
package DiscUtils.Fat;
2424

2525
import java.util.Arrays;
26+
import java.util.function.Consumer;
27+
28+
import DiscUtils.Streams.Util.EndianUtilities;
2629

2730

2831
/**
@@ -32,19 +35,104 @@ public enum FatType {
3235
/**
3336
* Represents no known FAT type.
3437
*/
35-
None(0, "Unknown FAT"),
38+
None(0, "Unknown FAT") {
39+
@Override public boolean isEndOfChain(int val) {
40+
throw new IllegalStateException("Unknown FAT type");
41+
}
42+
@Override public int getNumEntries(byte[] _buffer) {
43+
throw new IllegalStateException("Unknown FAT type");
44+
}
45+
@Override public boolean isBadCluster(int val) {
46+
throw new IllegalStateException("Unknown FAT type");
47+
}
48+
@Override public int getNext(int cluster, byte[] _buffer) {
49+
throw new IllegalStateException("Unknown FAT type");
50+
}
51+
@Override public void setNext(int cluster, int next, byte[] _buffer, Consumer<Integer> markDirty) {
52+
throw new IllegalStateException("Unknown FAT type");
53+
}
54+
},
3655
/**
3756
* Represents a 12-bit FAT.
3857
*/
39-
Fat12(12, "Microsoft FAT12"),
58+
Fat12(12, "Microsoft FAT12") {
59+
@Override public boolean isEndOfChain(int val) {
60+
return (val & 0x0fff) >= 0x0ff8;
61+
}
62+
@Override public int getNumEntries(byte[] _buffer) {
63+
return _buffer.length / 3 * 2;
64+
}
65+
@Override public boolean isBadCluster(int val) {
66+
return (val & 0x0fff) == 0x0ff7;
67+
}
68+
@Override public int getNext(int cluster, byte[] _buffer) {
69+
if ((cluster & 1) != 0) {
70+
return (EndianUtilities.toUInt16LittleEndian(_buffer, cluster + cluster / 2) >>> 4) & 0x0fff;
71+
} else {
72+
return EndianUtilities.toUInt16LittleEndian(_buffer, cluster + cluster / 2) & 0x0fff;
73+
}
74+
}
75+
@Override public void setNext(int cluster, int next, byte[] _buffer, Consumer<Integer> markDirty) {
76+
int offset = cluster + cluster / 2;
77+
markDirty.accept(offset);
78+
markDirty.accept(offset + 1);
79+
// On alternate sector boundaries, cluster info crosses two sectors
80+
short maskedOldVal;
81+
if ((cluster & 1) != 0) {
82+
next = next << 4;
83+
maskedOldVal = (short) (EndianUtilities.toUInt16LittleEndian(_buffer, offset) & 0x000f);
84+
} else {
85+
next = next & 0x0fff;
86+
maskedOldVal = (short) (EndianUtilities.toUInt16LittleEndian(_buffer, offset) & 0xf000);
87+
}
88+
short newVal = (short) (maskedOldVal | next);
89+
EndianUtilities.writeBytesLittleEndian(newVal, _buffer, offset);
90+
}
91+
},
4092
/**
4193
* Represents a 16-bit FAT.
4294
*/
43-
Fat16(16, "Microsoft FAT16"),
95+
Fat16(16, "Microsoft FAT16") {
96+
@Override public boolean isEndOfChain(int val) {
97+
return (val & 0xffff) >= 0xfff8;
98+
}
99+
@Override public int getNumEntries(byte[] _buffer) {
100+
return _buffer.length / 2;
101+
}
102+
@Override public boolean isBadCluster(int val) {
103+
return (val & 0xffff) == 0xfff7;
104+
}
105+
@Override public int getNext(int cluster, byte[] _buffer) {
106+
return EndianUtilities.toUInt16LittleEndian(_buffer, cluster * 2);
107+
}
108+
@Override public void setNext(int cluster, int next, byte[] _buffer, Consumer<Integer> markDirty) {
109+
markDirty.accept(cluster * 2);
110+
EndianUtilities.writeBytesLittleEndian((short) next, _buffer, cluster * 2);
111+
}
112+
},
44113
/**
45114
* Represents a 32-bit FAT.
46115
*/
47-
Fat32(32, "Microsoft FAT32");
116+
Fat32(32, "Microsoft FAT32") {
117+
@Override public boolean isEndOfChain(int val) {
118+
return (val & 0x0fff_fff8) >= 0x0fff_fff8;
119+
}
120+
@Override public int getNumEntries(byte[] _buffer) {
121+
return _buffer.length / 4;
122+
}
123+
@Override public boolean isBadCluster(int val) {
124+
return (val & 0x0fff_ffff) == 0x0fff_fff7; // TODO bug report
125+
}
126+
@Override public int getNext(int cluster, byte[] _buffer) {
127+
return EndianUtilities.toUInt32LittleEndian(_buffer, cluster * 4) & 0x0fff_ffff;
128+
}
129+
@Override public void setNext(int cluster, int next, byte[] _buffer, Consumer<Integer> markDirty) {
130+
markDirty.accept(cluster * 4);
131+
int oldVal = EndianUtilities.toUInt32LittleEndian(_buffer, cluster * 4);
132+
int newVal = (oldVal & 0xf000_0000) | (next & 0x0fff_ffff);
133+
EndianUtilities.writeBytesLittleEndian(newVal, _buffer, cluster * 4);
134+
}
135+
};
48136

49137
private int value;
50138
private String friendlyName;
@@ -57,6 +145,16 @@ public String getFriendlyName() {
57145
return friendlyName;
58146
}
59147

148+
public abstract int getNumEntries(byte[] _buffer);
149+
150+
public abstract boolean isEndOfChain(int val);
151+
152+
public abstract boolean isBadCluster(int val);
153+
154+
public abstract int getNext(int cluster, byte[] _buffer);
155+
156+
public abstract void setNext(int cluster, int next, byte[] _buffer, Consumer<Integer> markDirty);
157+
60158
private FatType(int value, String friendlyName) {
61159
this.value = value;
62160
this.friendlyName = friendlyName;

0 commit comments

Comments
 (0)