private static unsafe void ProcessFatMachO()

in net/JetBrains.FormatRipper/src/MachO/MachOSignatureInjector.cs [58:140]


  private static unsafe void ProcessFatMachO(Stream sourceStream, Stream outputStream, MH fatMagic, IMachOSignatureTransferData signatureTransferData)
  {
    var isFatLittleEndian = fatMagic is MH.FAT_MAGIC or MH.FAT_MAGIC_64;
    var needSwap = BitConverter.IsLittleEndian != isFatLittleEndian;

    uint GetU4(uint v) => needSwap ? MemoryUtil.SwapU4(v) : v;
    ulong GetU8(ulong v) => needSwap ? MemoryUtil.SwapU8(v) : v;

    fat_header fh;
    StreamUtil.ReadBytes(sourceStream, (byte*)&fh, sizeof(fat_header));
    var nFatArch = GetU4(fh.nfat_arch);

    if (signatureTransferData.SectionSignatures.Length != nFatArch)
      throw new SignatureInjectionException($"Cannot transfer signatures: source and destination files have different number of sections. The source file has {signatureTransferData.SectionSignatures.Length} section(s) and the destination file has {nFatArch} section(s).");

    uint rawFatMagic = MemoryUtil.GetLeU4((uint)fatMagic);
    StreamUtil.WriteBytes(outputStream, (byte*)&rawFatMagic, sizeof(uint));
    StreamUtil.WriteBytes(outputStream, (byte*)&fh, sizeof(fat_header));

    long fatNodesOffset = sourceStream.Position;

    if (fatMagic is MH.FAT_CIGAM_64 or MH.FAT_MAGIC_64)
    {
      var fatNodes = new fat_arch_64[checked((int)nFatArch)];
      fixed (fat_arch_64* ptr = fatNodes)
      {
        int fatNodesSize = checked((int)nFatArch * sizeof(fat_arch_64));
        StreamUtil.ReadBytes(sourceStream, (byte*)ptr, fatNodesSize);
        StreamUtil.WriteBytes(outputStream, (byte*)ptr, fatNodesSize);

        for (var n = 0; n < nFatArch; n++)
        {
          var processedSection = ProcessSection(
            sourceStream,
            outputStream,
            new MachOSectionInfo()
            {
              SectionOffset = checked((long)GetU8(fatNodes[n].offset)),
              SectionSize = checked((long)GetU8(fatNodes[n].size)),
              Alignment = (int)GetU4(fatNodes[n].align)
            },
            signatureTransferData.SectionSignatures[n]);

          fatNodes[n].offset = GetU8((ulong)processedSection.SectionOffset);
          fatNodes[n].size = GetU8((ulong)processedSection.SectionSize);
        }

        outputStream.Seek(fatNodesOffset, SeekOrigin.Begin);
        StreamUtil.WriteBytes(outputStream, (byte*)ptr, fatNodesSize);
      }
    }
    else
    {
      var fatNodes = new fat_arch[checked((int)nFatArch)];
      fixed (fat_arch* ptr = fatNodes)
      {
        int fatNodesSize = checked((int)nFatArch * sizeof(fat_arch));
        StreamUtil.ReadBytes(sourceStream, (byte*)ptr, fatNodesSize);
        StreamUtil.WriteBytes(outputStream, (byte*)ptr, fatNodesSize);

        for (var n = 0; n < nFatArch; n++)
        {
          var processedSection = ProcessSection(
            sourceStream,
            outputStream,
            new MachOSectionInfo()
            {
              SectionOffset = GetU4(fatNodes[n].offset),
              SectionSize = GetU4(fatNodes[n].size),
              Alignment = (int)GetU4(fatNodes[n].align)
            },
            signatureTransferData.SectionSignatures[n]);

          fatNodes[n].offset = GetU4(checked((uint)processedSection.SectionOffset));
          fatNodes[n].size = GetU4(checked((uint)processedSection.SectionSize));
        }

        // Update fat nodes with new offsets and sizes
        outputStream.Seek(fatNodesOffset, SeekOrigin.Begin);
        StreamUtil.WriteBytes(outputStream, (byte*)ptr, fatNodesSize);
      }
    }
  }