Skip to content

Commit 6c885a5

Browse files
committed
- Folder creation/deletion.
- Added test function for checking if a filepath is default or not.
1 parent ff2c433 commit 6c885a5

File tree

1 file changed

+79
-32
lines changed
  • xivModdingFramework/SqPack/FileTypes

1 file changed

+79
-32
lines changed

xivModdingFramework/SqPack/FileTypes/Index.cs

Lines changed: 79 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,32 @@ public async Task<bool> FileExists(string fullPath)
372372
return await FileExists(fileHash, pathHash, dataFile);
373373
}
374374

375-
/// <summary>
376-
/// Determines whether the given file path exists
377-
/// </summary>
378-
/// <param name="fileHash">The hashed file</param>
379-
/// <param name="folderHash">The hashed folder</param>
380-
/// <param name="dataFile">The data file</param>
381-
/// <returns>True if it exists, False otherwise</returns>
382-
public async Task<bool> FileExists(int fileHash, int folderHash, XivDataFile dataFile)
375+
376+
/// <summary>
377+
/// Tests if a given file path in FFXIV's internal directory structure
378+
/// is one that ships with FFXIV, or something added by the framework.
379+
/// </summary>
380+
/// <returns></returns>
381+
public async Task<bool> IsDefaultFilePath(string fullPath)
382+
{
383+
// The framework adds flag files alongside every custom created file.
384+
// This lets you check for them even if the Modlist gets corrupted/lost.
385+
var exists = await FileExists(fullPath);
386+
var hasFlag = await FileExists(fullPath + ".flag");
387+
388+
// In order to be considered a DEFAULT file, the file must both EXIST *and* not have a flag.
389+
var stockFile = exists && hasFlag;
390+
return stockFile;
391+
}
392+
393+
/// <summary>
394+
/// Determines whether the given file path exists
395+
/// </summary>
396+
/// <param name="fileHash">The hashed file</param>
397+
/// <param name="folderHash">The hashed folder</param>
398+
/// <param name="dataFile">The data file</param>
399+
/// <returns>True if it exists, False otherwise</returns>
400+
public async Task<bool> FileExists(int fileHash, int folderHash, XivDataFile dataFile)
383401
{
384402
var indexPath = Path.Combine(_gameDirectory.FullName, $"{dataFile.GetDataFileName()}{IndexExtension}");
385403

@@ -747,13 +765,26 @@ public bool DeleteFileDescriptor(string fullPath, XivDataFile dataFile)
747765
// Update folder size
748766
if (iHash == uPathHash)
749767
{
750-
foundFolder = true;
751-
Array.Copy(BitConverter.GetBytes(iFolderSize - 16), 0, modifiedIndex, position + 8, 4);
768+
if(iFolderSize == 0)
769+
{
770+
// No more files in the folder, the folder needs to be deleted from the listing
771+
// (0 size folders are not listed, even if they're parent folders for other folders)
772+
remainder = modifiedIndex.Length - position - 16;
773+
Array.Copy(modifiedIndex, position + 16, modifiedIndex, position, remainder);
774+
775+
var newIndex = new byte[modifiedIndex.Length - 16];
776+
Array.Copy(modifiedIndex, 0, modifiedIndex, 0, newIndex.Length);
777+
foundFolder = true;
778+
} else
779+
{
780+
Array.Copy(BitConverter.GetBytes(iFolderSize - 16), 0, modifiedIndex, position + 8, 4);
781+
}
752782
}
753783
}
754784

755785
if (!foundFolder)
756786
{
787+
// Something went wrong here / The index is in a bad state.
757788
return false;
758789
}
759790

@@ -876,14 +907,15 @@ public bool DeleteFileDescriptor(string fullPath, XivDataFile dataFile)
876907
return true;
877908
}
878909

879-
/// <summary>
880-
/// Adds a new file descriptor/stub into the Index files.
881-
/// </summary>
882-
/// <param name="fullPath">Full path to the new file.</param>
883-
/// <param name="dataOffset">Raw DAT file offset to use for the new file.</param>
884-
/// <param name="dataFile">Which data file set to use.</param>
885-
/// <returns></returns>
886-
public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataFile)
910+
911+
/// <summary>
912+
/// Adds a new file descriptor/stub into the Index files.
913+
/// </summary>
914+
/// <param name="fullPath">Full path to the new file.</param>
915+
/// <param name="dataOffset">Raw DAT file offset to use for the new file.</param>
916+
/// <param name="dataFile">Which data file set to use.</param>
917+
/// <returns></returns>
918+
public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataFile)
887919
{
888920
fullPath = fullPath.Replace("\\", "/");
889921
var pathHash = HashGenerator.GetHash(fullPath.Substring(0, fullPath.LastIndexOf("/", StringComparison.Ordinal)));
@@ -910,7 +942,6 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
910942

911943
// Dump the index into memory, since we're going to have to inject data.
912944
byte[] originalIndex = File.ReadAllBytes(indexPath);
913-
byte[] modifiedIndex = new byte[originalIndex.Length + 16];
914945

915946
// Get all the segment header data
916947
for (int i = 0; i < SegmentHeaders.Length; i++)
@@ -946,6 +977,11 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
946977
injectLocation = position;
947978
break;
948979
}
980+
} else if (iPathHash > uPathHash)
981+
{
982+
// This is where the folder should go, it just has no files currently.
983+
injectLocation = position;
984+
break;
949985
}
950986
else
951987
{
@@ -958,11 +994,9 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
958994
}
959995
}
960996

961-
// Cancel if we failed to find the path.
962-
if (foundFolder == false)
963-
{
964-
return false;
965-
}
997+
998+
var totalInjectSize = foundFolder ? 16 : 32;
999+
byte[] modifiedIndex = new byte[originalIndex.Length + totalInjectSize];
9661000

9671001
// Split the file at the injection point.
9681002
int remainder = originalIndex.Length - injectLocation;
@@ -983,8 +1017,16 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
9831017
// Update other segments' offsets.
9841018
else
9851019
{
1020+
9861021
SegmentOffsets[i] += 16;
9871022
Array.Copy(BitConverter.GetBytes(SegmentOffsets[i]), 0, modifiedIndex, SegmentHeaders[i] + 4, 4);
1023+
1024+
// We need to create the folder as well.
1025+
if (i == 3 && !foundFolder)
1026+
{
1027+
SegmentSizes[i] += 16;
1028+
Array.Copy(BitConverter.GetBytes(SegmentSizes[i]), 0, modifiedIndex, SegmentHeaders[i] + 8, 4);
1029+
}
9881030
}
9891031
}
9901032

@@ -995,7 +1037,7 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
9951037

9961038
// Update the folder structure
9971039
var folderCount = SegmentSizes[3] / 16;
998-
foundFolder = false;
1040+
var foundFolder2 = false;
9991041

10001042
for (int i = 0; i < folderCount; i++)
10011043
{
@@ -1010,19 +1052,24 @@ public bool AddFileDescriptor(string fullPath, int dataOffset, XivDataFile dataF
10101052
Array.Copy(BitConverter.GetBytes(iOffset + 16), 0, modifiedIndex, position + 4, 4);
10111053
}
10121054

1013-
// Update folder size
1055+
// Folder exists, but needs its size updated.
10141056
if (iHash == uPathHash)
10151057
{
1016-
foundFolder = true;
10171058
Array.Copy(BitConverter.GetBytes(iFolderSize + 16), 0, modifiedIndex, position + 8, 4);
1059+
} else if (foundFolder == false && iHash > uPathHash) {
1060+
foundFolder = true;
1061+
// This is where we need to cut the index the second time to make room for the folder data.
1062+
remainder = modifiedIndex.Length - position - 16;
1063+
Array.Copy(modifiedIndex, position, modifiedIndex, position +16, remainder);
1064+
1065+
// The new folder entry now goes at the 16 bytes starting at position
1066+
Array.Copy(BitConverter.GetBytes(uPathHash), 0, modifiedIndex, position, 4);
1067+
Array.Copy(BitConverter.GetBytes(injectLocation), 0, modifiedIndex, position + 4, 4);
1068+
Array.Copy(BitConverter.GetBytes(16), 0, modifiedIndex, position + 8, 4);
1069+
Array.Copy(BitConverter.GetBytes(16), 0, modifiedIndex, position + 12, 4);
10181070
}
10191071
}
10201072

1021-
if(!foundFolder)
1022-
{
1023-
return false;
1024-
}
1025-
10261073
// Update SHA-1 Hashes.
10271074
SHA1 sha = new SHA1CryptoServiceProvider();
10281075
byte[] shaHash;

0 commit comments

Comments
 (0)