private static TagFixup FinalizeFixup(TagFixup fixup, uint dataOffset) { return(new TagFixup { TargetOffset = fixup.TargetOffset, WriteOffset = dataOffset + fixup.WriteOffset }); }
private bool ExecuteAdd(HaloTag tag, List <string> args) { if (args.Count != 4) { return(false); } uint writeOffset, targetOffset; if (!uint.TryParse(args[2], NumberStyles.HexNumber, null, out writeOffset)) { return(false); } if (!uint.TryParse(args[3], NumberStyles.HexNumber, null, out targetOffset)) { return(false); } if (!CheckWriteOffset(tag, writeOffset)) { return(true); } if (!CheckTargetOffset(tag, targetOffset)) { return(true); } // Create a new fixup if there isn't one, otherwise overwrite it var fixup = tag.DataFixups.FirstOrDefault(f => f.WriteOffset == writeOffset); if (fixup == null) { fixup = new TagFixup(); tag.DataFixups.Add(fixup); } fixup.WriteOffset = writeOffset; fixup.TargetOffset = targetOffset; // Update the tag using (var stream = _fileInfo.Open(FileMode.Open, FileAccess.ReadWrite)) _cache.UpdateTag(stream, tag); Console.WriteLine("Added fixup at offset 0x{0:X} to 0x{1:X}.", writeOffset, targetOffset); return(true); }
public override bool Execute(List<string> args) { if (args.Count < 3) return false; int offset; if (!int.TryParse(args[1], NumberStyles.HexNumber, null, out offset)) return false; int elementSize; if (!int.TryParse(args[2], NumberStyles.HexNumber, null, out elementSize)) return false; // Find the tag var tag = FindTagWithOffset(offset); if (tag == null) return false; Console.Write("Detected tag: "); TagPrinter.PrintTagShort(tag); var offsetFromTag = offset - tag.Offset; using (var stream = _fileInfo.Open(FileMode.Open, FileAccess.ReadWrite)) { // Read block info stream.Position = offset; var reader = new BinaryReader(stream); var oldCount = reader.ReadInt32(); var newCount = oldCount; var address = reader.ReadUInt32(); var fixup = tag.DataFixups.FirstOrDefault(f => f.WriteOffset == offsetFromTag + 4); if (fixup == null) { if (address != 0) { Console.Error.WriteLine("0x{0:X8} doesn't look like a valid tag block offset!", offset); return true; } // Allocate space at the end of the tag fixup = new TagFixup { WriteOffset = (uint)offsetFromTag + 4, TargetOffset = tag.Size }; } var blockOffset = (int)fixup.TargetOffset; // Execute the subcommand bool result; switch (args[0]) { case "add": result = AddSubcommand(stream, tag, blockOffset, elementSize, ref newCount, args); break; case "remove": result = RemoveSubcommand(stream, tag, blockOffset, elementSize, ref newCount, args); break; case "insertat": result = InsertAtSubcommand(stream, tag, blockOffset, elementSize, ref newCount, args); break; case "removeat": result = RemoveAtSubcommand(stream, tag, blockOffset, elementSize, ref newCount, args); break; default: return false; } if (!result) return false; // Update the block pointer if necessary if (oldCount != newCount) { stream.Position = tag.Offset + fixup.WriteOffset - 4; var writer = new BinaryWriter(stream); writer.Write(newCount); if (newCount > 0) { fixup.TargetOffset = (uint)blockOffset; if (address == 0) tag.DataFixups.Add(fixup); } else { tag.DataFixups.Remove(fixup); writer.Write(0); } _cache.UpdateTag(stream, tag); } } Console.WriteLine("Done!"); return true; }
private static TagFixup FinalizeFixup(TagFixup fixup, uint dataOffset) { return new TagFixup { TargetOffset = fixup.TargetOffset, WriteOffset = dataOffset + fixup.WriteOffset }; }
private bool ExecuteAdd(HaloTag tag, List<string> args) { if (args.Count != 4) return false; uint writeOffset, targetOffset; if (!uint.TryParse(args[2], NumberStyles.HexNumber, null, out writeOffset)) return false; if (!uint.TryParse(args[3], NumberStyles.HexNumber, null, out targetOffset)) return false; if (!CheckWriteOffset(tag, writeOffset)) return true; if (!CheckTargetOffset(tag, targetOffset)) return true; // Create a new fixup if there isn't one, otherwise overwrite it var fixup = tag.DataFixups.FirstOrDefault(f => f.WriteOffset == writeOffset); if (fixup == null) { fixup = new TagFixup(); tag.DataFixups.Add(fixup); } fixup.WriteOffset = writeOffset; fixup.TargetOffset = targetOffset; // Update the tag using (var stream = _fileInfo.Open(FileMode.Open, FileAccess.ReadWrite)) _cache.UpdateTag(stream, tag); Console.WriteLine("Added fixup at offset 0x{0:X} to 0x{1:X}.", writeOffset, targetOffset); return true; }
private void AnalyzeStructure(BinaryReader reader, uint baseOffset, uint size, TagLayoutGuess result) { var lookBehind = new uint[4]; TagFixup potentialGuess = null; for (uint offset = 0; offset < size; offset += 4) { var val = reader.ReadUInt32(); TagFixup fixup; if (_resourceFixupsByWriteOffset.TryGetValue(baseOffset + offset, out fixup)) { // Value is a resource reference result.Add(offset, new ResourceReferenceGuess()); } else if (_dataFixupsByWriteOffset.TryGetValue(baseOffset + offset, out fixup)) { // Value is a pointer if (offset >= 0x4) { // Tag block or data reference - need another padding value to confirm it potentialGuess = fixup; } } else if (offset >= 0xC && lookBehind[0] == 0 && lookBehind[1] == 0 && _cache.ContainsClass(new MagicNumber((int)lookBehind[2]))) { // Tag reference if (val != 0xFFFFFFFF && val < _cache.Tags.Count) { var referencedTag = _cache.Tags[(int)val]; if (referencedTag != null && referencedTag.Class.Value == (int)lookBehind[2]) { result.Add(offset - 0xC, new TagReferenceGuess()); } } } else if (val == 0 && potentialGuess != null) { // Found a potential padding value - check if we can confirm the potential guess's type if (lookBehind[1] != 0) { // Tag block - seek to it and analyze it reader.BaseStream.Position = potentialGuess.TargetOffset; var elementLayout = AnalyzeStructure(reader, lookBehind[1]); reader.BaseStream.Position = baseOffset + offset + 4; result.Add(offset - 0x8, new TagBlockGuess(elementLayout)); } else if (offset >= 0x10 && lookBehind[1] == 0 && lookBehind[2] == 0 && lookBehind[3] != 0) { // Data reference result.Add(offset - 0x10, new DataReferenceGuess()); } potentialGuess = null; } else { // Tag block and data reference guesses must be followed by padding potentialGuess = null; } for (var i = 3; i > 0; i--) { lookBehind[i] = lookBehind[i - 1]; } lookBehind[0] = val; } }