Skip to content

Commit 0d38f0b

Browse files
committed
Allow Index files to be loaded without Index2 files in a read-only mode.
1 parent c3709d0 commit 0d38f0b

File tree

2 files changed

+57
-13
lines changed

2 files changed

+57
-13
lines changed

xivModdingFramework/SqPack/DataContainers/IndexFile.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ public enum IndexType
2424
/// </summary>
2525
public class IndexFile
2626
{
27+
public bool ReadOnlyMode
28+
{
29+
get; private set;
30+
}
31+
2732
// Header bytes (1024 in length usually)
2833
private byte[] Index1Header;
2934

@@ -71,12 +76,23 @@ public IndexFile(XivDataFile dataFile, BinaryReader index1Stream, BinaryReader i
7176
DataFile = dataFile;
7277

7378
ReadIndex1File(index1Stream);
74-
ReadIndex2File(index2Stream);
79+
80+
if (index2Stream != null)
81+
{
82+
ReadIndex2File(index2Stream);
83+
ReadOnlyMode = false;
84+
} else
85+
{
86+
ReadOnlyMode = true;
87+
}
7588

7689
if(disposeStreams)
7790
{
7891
index1Stream.Dispose();
79-
index2Stream.Dispose();
92+
if (index2Stream != null)
93+
{
94+
index2Stream.Dispose();
95+
}
8096
}
8197
}
8298

xivModdingFramework/SqPack/FileTypes/Index.cs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ public byte[] GetIndexSection3Hash(DirectoryInfo indexPath)
201201
public async Task<long> GetDataOffset(string fullPath)
202202
{
203203
var dataFile = IOUtil.GetDataFileFromPath(fullPath);
204-
var index = await GetIndexFile(dataFile);
204+
var index = await GetIndexFile(dataFile, false, true);
205205
return index.Get8xDataOffset(fullPath);
206206
}
207207

@@ -565,8 +565,8 @@ public Task<long> GetDataOffset(int hashedFolder, int hashedFile, XivDataFile da
565565
public async Task<List<int>> GetFolderExistsList(Dictionary<int, int> hashNumDictionary, XivDataFile dataFile)
566566
{
567567
var ret = new List<int>();
568-
var index = await GetIndexFile(dataFile);
569-
foreach(var hashKv in hashNumDictionary)
568+
var index = await GetIndexFile(dataFile, false, true);
569+
foreach (var hashKv in hashNumDictionary)
570570
{
571571
if (index.FolderExists((uint) hashKv.Key)) {
572572
ret.Add(hashKv.Value);
@@ -610,7 +610,7 @@ public async Task<bool> FileExists(string fullPath)
610610
/// <returns>True if it exists, False otherwise</returns>
611611
public async Task<bool> FileExists(string filePath, XivDataFile dataFile)
612612
{
613-
var index = await GetIndexFile(dataFile);
613+
var index = await GetIndexFile(dataFile, false, true);
614614
return index.FileExists(filePath);
615615
}
616616

@@ -622,7 +622,7 @@ public async Task<bool> FileExists(string filePath, XivDataFile dataFile)
622622
/// <returns>True if it exists, False otherwise</returns>
623623
public async Task<bool> FolderExists(string folder, XivDataFile dataFile)
624624
{
625-
var index = await GetIndexFile(dataFile);
625+
var index = await GetIndexFile(dataFile, false, true);
626626
return index.FolderExists(folder);
627627
}
628628

@@ -634,7 +634,7 @@ public async Task<bool> FolderExists(string folder, XivDataFile dataFile)
634634
/// <returns>A list of all of the offsets in the given folder</returns>
635635
public async Task<List<long>> GetAllFileOffsetsInFolder(int hashedFolder, XivDataFile dataFile)
636636
{
637-
var index = await GetIndexFile(dataFile);
637+
var index = await GetIndexFile(dataFile, false, true);
638638
var entries = index.GetEntriesInFolder((uint)hashedFolder);
639639

640640
var hashes = entries.Select(x => ((long)x.RawOffset) * 8L);
@@ -649,7 +649,7 @@ public async Task<List<long>> GetAllFileOffsetsInFolder(int hashedFolder, XivDat
649649
/// <returns>A list containing the hashed values of the files in the given folder</returns>
650650
public async Task<List<int>> GetAllHashedFilesInFolder(int hashedFolder, XivDataFile dataFile)
651651
{
652-
var index = await GetIndexFile(dataFile);
652+
var index = await GetIndexFile(dataFile, false, true);
653653
var entries = index.GetEntriesInFolder((uint)hashedFolder);
654654

655655
var hashes = entries.Select(x => (int)x.FileNameHash);
@@ -661,7 +661,7 @@ public async Task<List<int>> GetAllHashedFilesInFolder(int hashedFolder, XivData
661661
/// </summary>
662662
public async Task<Dictionary<uint, HashSet<uint>>> GetAllHashes(XivDataFile dataFile)
663663
{
664-
var index = await GetIndexFile(dataFile);
664+
var index = await GetIndexFile(dataFile, false, true);
665665
return index.GetAllHashes();
666666
}
667667

@@ -696,12 +696,14 @@ public async Task<bool> DeleteFileDescriptor(string fullPath, XivDataFile dataFi
696696
private static Dictionary<XivDataFile, long> _IndexLastModifiedTime = new Dictionary<XivDataFile, long>();
697697
private static Dictionary<XivDataFile, IndexFile> _CachedIndexFiles = new Dictionary<XivDataFile, IndexFile>();
698698

699+
private static Dictionary<XivDataFile, long> _ReadOnlyIndexLastModifiedTime = new Dictionary<XivDataFile, long>();
700+
private static Dictionary<XivDataFile, IndexFile> _CachedReadOnlyIndexFiles = new Dictionary<XivDataFile, IndexFile>();
699701
/// <summary>
700702
/// Creates an Index File object from the game index files.
701703
/// </summary>
702704
/// <param name="dataFile"></param>
703705
/// <returns></returns>
704-
public async Task<IndexFile> GetIndexFile(XivDataFile dataFile, bool alreadySemaphoreLocked = false)
706+
public async Task<IndexFile> GetIndexFile(XivDataFile dataFile, bool alreadySemaphoreLocked = false, bool allowReadOnly = false)
705707
{
706708
var index1Path = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");
707709
var index2Path = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{Index2Extension}");
@@ -725,19 +727,45 @@ public async Task<IndexFile> GetIndexFile(XivDataFile dataFile, bool alreadySema
725727
// If we don't have the file cached or the write time doesn't match exactly.
726728
if (!_IndexLastModifiedTime.ContainsKey(dataFile) || lastTime != _IndexLastModifiedTime[dataFile] || lastTime == creationTime || lastTime == 0)
727729
{
728-
using (var index1Stream = new BinaryReader(File.Open(index1Path, FileMode.Open)))
730+
using (var index1Stream = new BinaryReader(File.OpenRead(index1Path)))
729731
{
730-
using (var index2Stream = new BinaryReader(File.Open(index2Path, FileMode.Open)))
732+
using (var index2Stream = new BinaryReader(File.OpenRead(index2Path)))
731733
{
732734
index = new IndexFile(dataFile, index1Stream, index2Stream);
733735
}
734736
}
735737

736738
_IndexLastModifiedTime[dataFile] = lastTime;
737739
_CachedIndexFiles[dataFile] = index;
740+
_ReadOnlyIndexLastModifiedTime[dataFile] = lastTime;
741+
_CachedReadOnlyIndexFiles[dataFile] = index;
738742
return index;
739743
}
740744
}
745+
catch(Exception ex)
746+
{
747+
// The index2 file may be read/write locked.
748+
if (!allowReadOnly) throw;
749+
var lastTime = File.GetLastWriteTimeUtc(index1Path).Ticks;
750+
var creationTime = File.GetCreationTimeUtc(index1Path).Ticks;
751+
752+
// If we don't have the file cached or the write time doesn't match exactly.
753+
if (!_IndexLastModifiedTime.ContainsKey(dataFile) || lastTime != _ReadOnlyIndexLastModifiedTime[dataFile] || lastTime == creationTime || lastTime == 0)
754+
{
755+
using (var index1Stream = new BinaryReader(File.OpenRead(index1Path)))
756+
{
757+
index = new IndexFile(dataFile, index1Stream, null);
758+
}
759+
760+
_ReadOnlyIndexLastModifiedTime[dataFile] = lastTime;
761+
_CachedReadOnlyIndexFiles[dataFile] = index;
762+
return index;
763+
} else
764+
{
765+
return _CachedReadOnlyIndexFiles[dataFile];
766+
}
767+
768+
}
741769
finally
742770
{
743771
if (!alreadySemaphoreLocked)

0 commit comments

Comments
 (0)