internal STFSDescriptor(byte[] xDescriptor, uint xTotalBlocks, uint xOldBlocks, byte xType) { xStruct = xDescriptor; XSetStructure((STFSType)(xType & 1)); TopRecord = new BlockRecord(((uint)(xType >> 1) << 30 | (uint)xOldBlocks << 15)); if (xTotalBlocks > SpaceBetween[2]) { xStruct = null; return; } xBlockCount = xTotalBlocks; xBaseByte = (byte)((ThisType == STFSType.Type0) ? 0xB : 0xA); xOldBlocks = 0; }
public static bool ContainsBlock(this List<BlockRecord> x, BlockRecord y) { foreach (BlockRecord z in x) { if (z.ThisBlock == y.ThisBlock) return true; } return false; }
void SwitchNWrite(BlockRecord RecIn, SwitchType Change) { // As a temp, this will just grab the correct offset and write to it // I disabled the switch/backup effect in order to preserve functionality // // RECONSTRUCT // bool canswitch = (xSTFSStruct.ThisType == STFSType.Type1); //const uint basetable = 0xFFFFF000; BlockRecord current = xSTFSStruct.TopRecord; long[] pos = new long[] { 0, 0, 0 }; // Grab base starting points if (RecIn.ThisBlock >= Constants.BlockLevel[0] || xSTFSStruct.xBlockCount > Constants.BlockLevel[0]) { if (RecIn.ThisBlock >= Constants.BlockLevel[1] || xSTFSStruct.xBlockCount > Constants.BlockLevel[1]) pos[0] = xSTFSStruct.GenerateHashOffset(RecIn.ThisBlock, TreeLevel.L2) + 0x14; pos[1] = xSTFSStruct.GenerateHashOffset(RecIn.ThisBlock, TreeLevel.L1) + 0x14; } pos[2] = xSTFSStruct.GenerateHashOffset(RecIn.ThisBlock, TreeLevel.L0) + 0x14; //bool wipe = current.BlocksFree >= (Constants.BlockLevel[1] * Constants.BlockLevel[0]); long len = GenerateDataOffset(RecIn.ThisBlock) + 0x1000; if (xIO.Length < len) xIO.SetLength(len); if (Change == SwitchType.Allocate) xSTFSStruct.TopRecord.BlocksFree--; else if (Change == SwitchType.Delete) xSTFSStruct.TopRecord.BlocksFree++; if (pos[0] != 0) { //if (wipe) //{ // xIO.Position = (pos[0] & basetable) + (current.Index << 0xC); // xIO.Write(new byte[0x1000]); // xIO.Flush(); //} /*if (canswitch) // If this table hasn't been switched yet { if (!switched2) { xIO.Position = (pos[0] & basetable) + (current.Index << 0xC); // Get starting of table byte[] data = xIO.ReadBytes(0x1000); // Read it xSTFSStruct.TopRecord.Switch(); // Switch the index pos[0] += (xSTFSStruct.TopRecord.Index << 0xC); // Add to the base STFS function result xIO.Position = (pos[0] & basetable); // Go to new position and write it xIO.Write(data); xIO.Flush(); data = null; switched2 = true; } else pos[0] += (current.Index << 0xC); // Already switched, add the index }*/ //KILL ON RECONSTRUCTION if (canswitch) pos[0] += (current.Index << 0xC); // --------------------- xIO.Position = pos[0]; current = new BlockRecord(xIO.ReadUInt32()); //wipe = current.BlocksFree >= Constants.BlockLevel[1]; if (Change != SwitchType.None) { if (Change == SwitchType.Allocate) current.BlocksFree--; // Takes away a free block else current.BlocksFree++; // Adds a free block xIO.Position = pos[0]; xIO.Write(current.Flags); xIO.Flush(); } } // Follows same pattern if (pos[1] != 0) { //if (wipe) //{ // xIO.Position = (pos[1] & basetable) + (current.Index << 0xC); // xIO.Write(new byte[0x1000]); // xIO.Flush(); //} /*if (canswitch) { if (!switched1.Contains((int)(RecIn.ThisBlock / Constants.BlockLevel[1]))) { xIO.Position = (pos[1] & basetable) + (current.Index << 0xC); byte[] data = xIO.ReadBytes(0x1000); current.Switch(); pos[1] += (current.Index << 0xC); xIO.Position = (pos[1] & basetable); xIO.Write(data); xIO.Flush(); data = null; if (pos[0] != 0) { xIO.Position = pos[0]; xIO.Write(current.Flags); xIO.Flush(); } switched1.Add((int)(RecIn.ThisBlock / Constants.BlockLevel[1])); if (xSTFSStruct.xBlockCount <= Constants.BlockLevel[1]) xSTFSStruct.TopRecord.Switch(); } else pos[1] += (current.Index << 0xC); }*/ //KILL ON RECONSTRUCTION if (canswitch) pos[1] += (current.Index << 0xC); // --------------------- xIO.Position = pos[1]; current = new BlockRecord(xIO.ReadUInt32()); //wipe = current.BlocksFree >= Constants.BlockLevel[0]; if (Change != SwitchType.None) { if (Change == SwitchType.Allocate) current.BlocksFree--; // Takes away a free block else current.BlocksFree++; // Adds a free block xIO.Position = pos[1]; xIO.Write(current.Flags); xIO.Flush(); } } //if (wipe) //{ // xIO.Position = (pos[0] & basetable) + (current.Index << 0xC); // xIO.Write(new byte[0x1000]); // xIO.Flush(); //} /*if (canswitch) { if (!switched0.Contains((int)(RecIn.ThisBlock / Constants.BlockLevel[0]))) { xIO.Position = (pos[2] & basetable) + (current.Index << 0xC); byte[] data = xIO.ReadBytes(0x1000); current.Switch(); pos[2] += (current.Index << 0xC); xIO.Position = (pos[2] & basetable); xIO.Write(data); xIO.Flush(); data = null; if (pos[1] != 0) { xIO.Position = pos[1]; xIO.Write(current.Flags); xIO.Flush(); } switched1.Add((int)(RecIn.ThisBlock / Constants.BlockLevel[0])); if (xSTFSStruct.xBlockCount <= Constants.BlockLevel[0]) xSTFSStruct.TopRecord.Switch(); } else pos[2] += (current.Index << 0xC); }*/ //KILL ON RECONSTRUCTION if (canswitch) pos[2] += (current.Index << 0xC); // --------------------- if (Change == SwitchType.Allocate) { if (RecIn.Status == HashStatus.Old) RecIn.Status = HashStatus.Reused; else RecIn.Status = HashStatus.New; } else if (Change == SwitchType.Delete) RecIn.MarkOld(); xIO.Position = pos[2]; xIO.Write(RecIn.Flags); xIO.Flush(); if (RecIn.ThisBlock >= xSTFSStruct.xBlockCount) xSTFSStruct.xBlockCount = RecIn.ThisBlock + 1; }
BlockRecord GetRecord(uint xBlock, TreeLevel xLevel) { if (xLevel == TreeLevel.LT) return xSTFSStruct.TopRecord; BlockRecord current = xSTFSStruct.TopRecord; bool canswitch = (xSTFSStruct.ThisType == STFSType.Type1); if (xSTFSStruct.xBlockCount > Constants.BlockLevel[1]) { // Grab base position xIO.Position = (xSTFSStruct.GenerateHashOffset(xBlock, TreeLevel.L2) + 0x14); if (canswitch) xIO.Position += (current.Index << 0xC); current = new BlockRecord(xIO.ReadUInt32()); // Read new flag if (xLevel == TreeLevel.L2) { // return if needed current.ThisBlock = xBlock; current.ThisLevel = TreeLevel.L2; return current; } } else if (xLevel == TreeLevel.L2) return xSTFSStruct.TopRecord; // Follows same procedure if (xSTFSStruct.xBlockCount > Constants.BlockLevel[0]) { xIO.Position = (xSTFSStruct.GenerateHashOffset(xBlock, TreeLevel.L1)) + 0x14; if (canswitch) xIO.Position += (current.Index << 0xC); current = new BlockRecord(xIO.ReadUInt32()); if (xLevel == TreeLevel.L1) { current.ThisBlock = xBlock; current.ThisLevel = TreeLevel.L1; return current; } } else if (xLevel == TreeLevel.L1) return xSTFSStruct.TopRecord; xIO.Position = (xSTFSStruct.GenerateHashOffset(xBlock, TreeLevel.L0)) + 0x14; if (canswitch) xIO.Position += (current.Index << 0xC); current = new BlockRecord(xIO.ReadUInt32()); current.ThisBlock = xBlock; current.ThisLevel = TreeLevel.L0; return current; }
/// <summary> /// Writes a file via blocks /// </summary> /// <param name="xIOIn"></param> /// <param name="xBlocks"></param> /// <returns></returns> internal bool xWriteTo(ref DJsIO xIOIn, BlockRecord[] xBlocks) { if (!xIOIn.Accessed || (xIOIn.BlockCountSTFS() != xBlocks.Length)) return false; try { xIOIn.Position = 0; for (int i = 0; i < xBlocks.Length - 1; i++) { // Finds spot and writes block of data xIO.Position = GenerateDataOffset(xBlocks[i].ThisBlock); xIO.Write(xIOIn.ReadBytes(0x1000)); } xIO.Position = GenerateDataOffset(xBlocks[xBlocks.Length - 1].ThisBlock); xIO.Write(xIOIn.ReadBytes(xIOIn.BlockRemainderSTFS())); xIO.Flush(); return true; } catch { return false; } }
internal bool xWriteChain(BlockRecord[] xRecs) { for (int i = 0; i < xRecs.Length; i++) { if ((i + 1) < xRecs.Length) xRecs[i].NextBlock = xRecs[i + 1].ThisBlock; else xRecs[i].NextBlock = Constants.STFSEnd; SwitchNWrite(xRecs[i], SwitchType.Allocate); } return true; }
/// <summary> /// Add a file to the package /// </summary> /// <param name="xIOIn"></param> /// <param name="xEntAlloc"></param> /// <param name="xFileAlloc"></param> /// <returns></returns> internal bool xDoAdd(ref DJsIO xIOIn, ref BlockRecord[] xEntAlloc, ref BlockRecord[] xFileAlloc) { // Gets Entry Table file DJsIO xEntFile; if (!xEntriesToFile(out xEntFile)) return (xActive = false); // Writes it AddToLog("Adding new entry table to package"); if (!xWriteTo(ref xEntFile, xEntAlloc)) { xEntFile.Close(); VariousFunctions.DeleteFile(xEntFile.FileNameLong); return (xActive = false); } xEntFile.Close(); VariousFunctions.DeleteFile(xEntFile.FileNameLong); // Writes the new file AddToLog("Writing file to package"); if (!xWriteTo(ref xIOIn, xFileAlloc)) return (xActive = false); if (!xWriteChain(xEntAlloc)) return (xActive = false); if (!xWriteChain(xFileAlloc)) return (xActive = false); // Fixes internal variables and then writes hashes AddToLog("Fixing Package variables"); xDeleteChain(xFileBlocks); xFileBlocks = xEntAlloc; xSTFSStruct.xDirectoryBlock = xEntAlloc[0].ThisBlock; foreach (FileEntry x in xFileDirectory) x.xFixOffset(); foreach (FolderEntry x in xFolderDirectory) x.xFixOffset(); xWriteDescriptor(ref xIO); return !(xActive = false); }
internal bool xDeleteChain(BlockRecord[] xBlocks) { if (xBlocks == null) return true; foreach (BlockRecord x in xBlocks) { SwitchNWrite(x, SwitchType.Delete); } return true; }
internal BlockRecord[] xAllocateBlocks(uint count, uint xStart) { if ((xSTFSStruct.BlockCount + count) > xSTFSStruct.SpaceBetween[2]) return new BlockRecord[0]; List<BlockRecord> xReturn = new List<BlockRecord>(); for (uint i = 0; i < count; i++) { BlockRecord x = null; while (x == null) { if (xStart > xSTFSStruct.SpaceBetween[2]) break; // Grab record or make new one if (xStart < xSTFSStruct.xBlockCount) { BlockRecord y = GetRecord(xStart, TreeLevel.L0); if (y.Status == HashStatus.Old || y.Status == HashStatus.Unused) x = y; } else { if (xStart == Constants.BlockLevel[0]) { xIO.Position = GenerateHashOffset(0, TreeLevel.L1) + (xSTFSStruct.TopRecord.Index << 0xC) + 0x14; xIO.Write(xSTFSStruct.TopRecord.Flags); xIO.Flush(); } else if (xStart == Constants.BlockLevel[1]) { xIO.Position = GenerateHashOffset(0, TreeLevel.L2) + (xSTFSStruct.TopRecord.Index << 0xC) + 0x14; xIO.Write(xSTFSStruct.TopRecord.Flags); xIO.Flush(); } x = new BlockRecord(HashStatus.New, Constants.STFSEnd); x.ThisBlock = xStart; x.ThisLevel = TreeLevel.L0; } xStart++; } xReturn.Add(x); } return xReturn.ToArray(); }
/// <summary> /// Returns the blocks of a file /// </summary> /// <param name="xCount"></param> /// <param name="xStartBlock"></param> /// <param name="xOutBlocks"></param> /// <returns></returns> internal bool GetBlocks(uint xCount, uint xStartBlock, out BlockRecord[] xOutBlocks) { // Follows the blocks for the specified max count List<BlockRecord> xBlockList = new List<BlockRecord>(); BlockRecord xBlock = GetRecord(xStartBlock, TreeLevel.L0); if (xBlock.ThisBlock >= xSTFSStruct.xBlockCount) throw STFSExcepts.InvalBlock; for (uint i = 0; i < xCount; i++) { if (!xBlockList.ContainsBlock(xBlock)) xBlockList.Add(xBlock); else break; // If it contains, it's just going to loop if (xBlock.NextBlock == Constants.STFSEnd) break; // Stop means stop if (xBlock.NextBlock >= xSTFSStruct.xBlockCount) throw STFSExcepts.InvalBlock; // Gets the next block record xBlock = GetRecord(xBlock.NextBlock, TreeLevel.L0); } xOutBlocks = xBlockList.ToArray(); // Success if 1 - end block is reached and 2 - count is the count of the blocks found return (xBlockList.Count == xCount); }
internal STFSDescriptor(STFSPackage xPackage) { xPackage.xIO.Position = 0x340; xPackage.xIO.IsBigEndian = true; int xBlockInfo = xPackage.xIO.ReadInt32(); xBaseByte = (byte)(((xBlockInfo + 0xFFF) & 0xF000) >> 0xC); xPackage.xIO.Position = 0x379; if (xPackage.xIO.ReadByte() != 0x24) // Struct Size throw STFSExcepts.Type; if (xPackage.xIO.ReadByte() != 0) // Reversed throw STFSExcepts.Type; /* STRUCT OF THE NEXT 6 BYTES: * byte for block separation * Little Endian File Table block count short (2 bytes) * 3 bytes in Little Endian for the starting block of the File Table */ byte idx = (byte)(xPackage.xIO.ReadByte() & 3); xStruct = xPackage.xIO.ReadBytes(5); xPackage.xIO.Position = 0x395; xBlockCount = xPackage.xIO.ReadUInt32(); uint xOldBlocks = xPackage.xIO.ReadUInt32(); // Checks the type of Structure if (xBaseByte == 0xB) { if (idx == 1) XSetStructure(STFSType.Type0); else throw STFSExcepts.Type; } else if (xBaseByte == 0xA) { if (idx == 0 || idx == 2) XSetStructure(STFSType.Type1); else throw STFSExcepts.Type; } else throw STFSExcepts.Type; if (xBlockCount > SpaceBetween[2]) throw STFSExcepts.MaxOver; TopRecord = new BlockRecord(((uint)((idx >> 1) & 1) << 30 | (uint)xOldBlocks << 15)); // Grab Real Block Count for (uint i = (xBlockCount - 1); i >= 0; i--) { xBlockCount = (i + 1); if (GenerateDataOffset(i) < xPackage.xIO.Length) break; } }
internal STFSDescriptor(STFSPackage xPackage) { xPackage.xIO.Position = 0x340; xPackage.xIO.IsBigEndian = true; int xBlockInfo = xPackage.xIO.ReadInt32(); xBaseByte = (byte)(((xBlockInfo + 0xFFF) & 0xF000) >> 0xC); xPackage.xIO.Position = 0x379; if (xPackage.xIO.ReadByte() != 0x24) // Struct Size { throw STFSExcepts.Type; } if (xPackage.xIO.ReadByte() != 0) // Reversed { throw STFSExcepts.Type; } /* STRUCT OF THE NEXT 6 BYTES: * byte for block separation * Little Endian File Table block count short (2 bytes) * 3 bytes in Little Endian for the starting block of the File Table */ byte idx = (byte)(xPackage.xIO.ReadByte() & 3); xStruct = xPackage.xIO.ReadBytes(5); xPackage.xIO.Position = 0x395; xBlockCount = xPackage.xIO.ReadUInt32(); uint xOldBlocks = xPackage.xIO.ReadUInt32(); // Checks the type of Structure if (xBaseByte == 0xB) { if (idx == 1) { XSetStructure(STFSType.Type0); } else { throw STFSExcepts.Type; } } else if (xBaseByte == 0xA) { if (idx == 0 || idx == 2) { XSetStructure(STFSType.Type1); } else { throw STFSExcepts.Type; } } else { throw STFSExcepts.Type; } if (xBlockCount > SpaceBetween[2]) { throw STFSExcepts.MaxOver; } TopRecord = new BlockRecord(((uint)((idx >> 1) & 1) << 30 | (uint)xOldBlocks << 15)); // Grab Real Block Count for (uint i = (xBlockCount - 1); i >= 0; i--) { xBlockCount = (i + 1); if (GenerateDataOffset(i) < xPackage.xIO.Length) { break; } } }
void SwitchNWrite(BlockRecord RecIn, SwitchType Change) { bool canswitch = (xSTFSStruct.ThisType == STFSType.Type1); BlockRecord current = xSTFSStruct.TopRecord; long[] pos = new long[] { 0, 0, 0 }; // Grab base starting points if (RecIn.ThisBlock >= Constants.BlockLevel[0] || xSTFSStruct.xBlockCount > Constants.BlockLevel[0]) { if (RecIn.ThisBlock >= Constants.BlockLevel[1] || xSTFSStruct.xBlockCount > Constants.BlockLevel[1]) pos[0] = xSTFSStruct.GenerateHashOffset(RecIn.ThisBlock, TreeLevel.L2) + 0x14; pos[1] = xSTFSStruct.GenerateHashOffset(RecIn.ThisBlock, TreeLevel.L1) + 0x14; } pos[2] = xSTFSStruct.GenerateHashOffset(RecIn.ThisBlock, TreeLevel.L0) + 0x14; long len = GenerateDataOffset(RecIn.ThisBlock) + 0x1000; if (xIO.Length < len) xIO.SetLength(len); if (Change == SwitchType.Allocate) xSTFSStruct.TopRecord.BlocksFree--; else if (Change == SwitchType.Delete) xSTFSStruct.TopRecord.BlocksFree++; if (pos[0] != 0) { if (canswitch) pos[0] += (current.Index << 0xC); // --------------------- xIO.Position = pos[0]; current = new BlockRecord(xIO.ReadUInt32()); if (Change != SwitchType.None) { if (Change == SwitchType.Allocate) current.BlocksFree--; // Takes away a free block else current.BlocksFree++; // Adds a free block xIO.Position = pos[0]; xIO.Write(current.Flags); xIO.Flush(); } } // Follows same pattern if (pos[1] != 0) { if (canswitch) pos[1] += (current.Index << 0xC); // --------------------- xIO.Position = pos[1]; current = new BlockRecord(xIO.ReadUInt32()); if (Change != SwitchType.None) { if (Change == SwitchType.Allocate) current.BlocksFree--; // Takes away a free block else current.BlocksFree++; // Adds a free block xIO.Position = pos[1]; xIO.Write(current.Flags); xIO.Flush(); } } if (canswitch) pos[2] += (current.Index << 0xC); // --------------------- if (Change == SwitchType.Allocate) { if (RecIn.Status == HashStatus.Old) RecIn.Status = HashStatus.Reused; else RecIn.Status = HashStatus.New; } else if (Change == SwitchType.Delete) RecIn.MarkOld(); xIO.Position = pos[2]; xIO.Write(RecIn.Flags); xIO.Flush(); if (RecIn.ThisBlock >= xSTFSStruct.xBlockCount) xSTFSStruct.xBlockCount = RecIn.ThisBlock + 1; }
internal bool xWriteTo(MemoryStream ms, BlockRecord[] xBlocks) { //try { ms.Seek(0, SeekOrigin.Begin); var br = new BinaryReader(ms); for (int i = 0; i < xBlocks.Length - 1; i++) { // Finds spot and writes block of data xIO.Position = GenerateDataOffset(xBlocks[i].ThisBlock); var b = br.ReadBytes(0x1000); xIO.Write(b); } xIO.Position = GenerateDataOffset(xBlocks[xBlocks.Length - 1].ThisBlock); var remainder = BlockRemainderSTFS(ms.Length); var b2 = br.ReadBytes(remainder); xIO.Write(b2); xIO.Flush(); return true; } //catch { return false; } }