diff --git a/SabreTools.Serialization.Readers.Test/ISO9660Tests.cs b/SabreTools.Serialization.Readers.Test/ISO9660Tests.cs
index 91504c40..5367a104 100644
--- a/SabreTools.Serialization.Readers.Test/ISO9660Tests.cs
+++ b/SabreTools.Serialization.Readers.Test/ISO9660Tests.cs
@@ -1,5 +1,8 @@
+using System.Collections.Generic;
using System.IO;
using System.Linq;
+using SabreTools.Data.Models.ISO9660;
+using SabreTools.Numerics;
using Xunit;
namespace SabreTools.Serialization.Readers.Test
@@ -68,5 +71,113 @@ public void InvalidStream_Null()
var actual = deserializer.Deserialize(data);
Assert.Null(actual);
}
+
+ [Fact]
+ public void ParseDirectory_AmbiguousExtentLocation_ParsesBothExtents()
+ {
+ // Little-endian location points to sector 1, big-endian location to sector 2
+ byte[] image = new byte[4 * 2048];
+ WriteDirectory(image, 1);
+ WriteDirectory(image, 2);
+ var dr = new DirectoryRecord
+ {
+ ExtentLocation = new BothInt32(1, 2),
+ ExtentLength = 2048,
+ FileFlags = FileFlags.DIRECTORY,
+ };
+
+ var actual = ISO9660.ParseDirectory(new MemoryStream(image), 2048, 2048, dr, false);
+
+ Assert.NotNull(actual);
+ Assert.True(actual.ContainsKey(1));
+ Assert.True(actual.ContainsKey(2));
+ }
+
+ [Fact]
+ public void ParseDirectory_ConsistentExtentLocation_ReadsEachDirectoryOnce()
+ {
+ // Sector 1 holds directory A at sector 2, which holds directory B at sector 3
+ byte[] image = new byte[5 * 2048];
+ WriteDirectory(image, 1, "A", 2);
+ WriteDirectory(image, 2, "B", 3);
+ WriteDirectory(image, 3);
+ var dr = new DirectoryRecord
+ {
+ ExtentLocation = 1,
+ ExtentLength = 2048,
+ FileFlags = FileFlags.DIRECTORY,
+ };
+ var stream = new SeekCountingStream(image);
+
+ var actual = ISO9660.ParseDirectory(stream, 2048, 2048, dr, false);
+
+ Assert.NotNull(actual);
+ Assert.Equal(3, actual.Count);
+ Assert.Equal(1, stream.SeeksTo(1 * 2048));
+ Assert.Equal(1, stream.SeeksTo(2 * 2048));
+ Assert.Equal(1, stream.SeeksTo(3 * 2048));
+ }
+
+ ///
+ /// Write a one-sector directory extent with self and parent records and an optional child directory
+ ///
+ private static void WriteDirectory(byte[] image, int sector, string? childName = null, int childSector = 0)
+ {
+ int offset = sector * 2048;
+ offset = WriteRecord(image, offset, Constants.CurrentDirectory, sector);
+ offset = WriteRecord(image, offset, Constants.ParentDirectory, sector);
+ if (childName is not null)
+ WriteRecord(image, offset, System.Text.Encoding.ASCII.GetBytes(childName), childSector);
+ }
+
+ ///
+ /// Write a directory record for a one-sector directory extent, returns the offset after the record
+ ///
+ private static int WriteRecord(byte[] image, int offset, byte[] identifier, int location)
+ {
+ int length = 33 + identifier.Length + (identifier.Length % 2 == 0 ? 1 : 0);
+ image[offset] = (byte)length;
+ WriteBothEndian(image, offset + 2, location);
+ WriteBothEndian(image, offset + 10, 2048);
+ image[offset + 25] = (byte)FileFlags.DIRECTORY;
+ image[offset + 28] = 1;
+ image[offset + 31] = 1;
+ image[offset + 32] = (byte)identifier.Length;
+ identifier.CopyTo(image, offset + 33);
+ return offset + length;
+ }
+
+ ///
+ /// Write a 32-bit value in both-endian format
+ ///
+ private static void WriteBothEndian(byte[] image, int offset, int value)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ image[offset + i] = (byte)(value >> (8 * i));
+ image[offset + 7 - i] = (byte)(value >> (8 * i));
+ }
+ }
+
+ ///
+ /// Memory stream that counts absolute seeks per offset
+ ///
+ private sealed class SeekCountingStream : MemoryStream
+ {
+ private readonly Dictionary _seeks = [];
+
+ public SeekCountingStream(byte[] buffer) : base(buffer) { }
+
+ public int SeeksTo(long offset)
+ => _seeks.TryGetValue(offset, out int count) ? count : 0;
+
+ public override long Seek(long offset, SeekOrigin loc)
+ {
+ if (loc == SeekOrigin.Begin)
+ _seeks[offset] = SeeksTo(offset) + 1;
+
+ return base.Seek(offset, loc);
+ }
+ }
}
}
diff --git a/SabreTools.Serialization.Readers/ISO9660.cs b/SabreTools.Serialization.Readers/ISO9660.cs
index ca233422..7ddd2358 100644
--- a/SabreTools.Serialization.Readers/ISO9660.cs
+++ b/SabreTools.Serialization.Readers/ISO9660.cs
@@ -770,7 +770,7 @@ public static List ParsePathTableGroup(Stream data, short sector
}
// If the extent location field is ambiguous, also parse the big-endian directory extent
- if (!bigEndian && dr.ExtentLocation.IsValid)
+ if (!bigEndian && !dr.ExtentLocation.IsValid)
{
var bigEndianDir = ParseDirectory(data, sectorLength, blockLength, dr, true);
if (bigEndianDir is not null)