public static unsafe DmgFile Parse()

in net/JetBrains.FormatRipper/src/Dmg/DmgFile.cs [69:234]


    public static unsafe DmgFile Parse(Stream stream, Mode mode = Mode.Default)
    {
      if (stream.Length < sizeof(UDIF))
        throw new ArgumentException("Provided stream is too short to be a valid DMG file");

      stream.Seek(-sizeof(UDIF), SeekOrigin.End);

      UDIF udif;
      StreamUtil.ReadBytes(stream, (byte*)&udif, sizeof(UDIF));

      if ((DmgMagic)MemoryUtil.GetBeU4(udif.Magic) != DmgMagic.KOLY)
        throw new FormatException("Invalid DMG file UDIF structure magic");

      ulong signatureOffset = MemoryUtil.GetBeU8(udif.CodeSignatureOffset);
      ulong signatureLength = MemoryUtil.GetBeU8(udif.CodeSignatureLength);

      if (signatureOffset + signatureLength > (ulong)stream.Length)
        throw new FormatException($"Invalid signature position. Signature position ({signatureOffset}) + signature length ({signatureLength}) is greater that stream length ({stream.Length})");

      var hasSignature = signatureLength != 0;
      byte[]? codeDirectoryBlob = null;
      byte[]? cmsSignatureBlob = null;
      IDmgSignatureTransferData? signatureTransferData = null;
      List<HashVerificationUnit> hashVerificationUnits = new List<HashVerificationUnit>();
      List<CDHash> cdHashes = new List<CDHash>();

      if ((mode & Mode.SignatureData) == Mode.SignatureData && hasSignature)
      {
        var imageRange = new StreamRange(0, stream.Length);

        stream.Position = checked(imageRange.Position + (long)signatureOffset);

        signatureTransferData = new DmgSignatureTransferData()
        {
          SignatureOffset = checked((long)signatureOffset),
          SignatureLength = checked((long)signatureLength),
          SignatureBlob = StreamUtil.ReadBytes(stream, checked((int)signatureLength)),
        };

        stream.Position = checked(imageRange.Position + (long)signatureOffset);

        CS_SuperBlob cssb;
        StreamUtil.ReadBytes(stream, (byte*)&cssb, sizeof(CS_SuperBlob));
        if ((CSMAGIC)MemoryUtil.GetBeU4(cssb.magic) != CSMAGIC.CSMAGIC_EMBEDDED_SIGNATURE)
          throw new FormatException("Invalid DMG code embedded signature magic");
        var csLength = MemoryUtil.GetBeU4(cssb.length);
        if (csLength < sizeof(CS_SuperBlob))
          throw new FormatException("Too small DMG code signature super blob");

        var csCount = MemoryUtil.GetBeU4(cssb.count);
        fixed (byte* scBuf = StreamUtil.ReadBytes(stream, checked((int)csLength - sizeof(CS_SuperBlob))))
        {
          ComputeHashInfo[] specialSlotPositions = new ComputeHashInfo[CSSLOT.CSSLOT_HASHABLE_ENTRIES_MAX - 1];

          for (int superBlobEntryIndex = 0; superBlobEntryIndex < csCount; superBlobEntryIndex++)
          {
            var scPtr = scBuf + superBlobEntryIndex * sizeof(CS_BlobIndex);
            CS_BlobIndex csbi;
            MemoryUtil.CopyBytes(scPtr, (byte*)&csbi, sizeof(CS_BlobIndex));
            uint slotType = MemoryUtil.GetBeU4(csbi.type);

            if (slotType >= CSSLOT.CSSLOT_INFOSLOT && slotType <= CSSLOT.CSSLOT_LIBRARY_CONSTRAINT)
            {
              uint offset = MemoryUtil.GetBeU4(csbi.offset);
              var csOffsetPtr = scBuf + offset - sizeof(CS_SuperBlob);

              CS_Blob csb;
              MemoryUtil.CopyBytes(csOffsetPtr, (byte*)&csb, sizeof(CS_Blob));

              specialSlotPositions[slotType - 1] = new ComputeHashInfo(0, new[]
              {
                new StreamRange(checked(imageRange.Position + (long)signatureOffset + offset), MemoryUtil.GetBeU4(csb.length))
              }, 0);
            }
          }

          for (var scPtr = scBuf; csCount-- > 0; scPtr += sizeof(CS_BlobIndex))
          {
            CS_BlobIndex csbi;
            MemoryUtil.CopyBytes(scPtr, (byte*)&csbi, sizeof(CS_BlobIndex));
            uint offset = MemoryUtil.GetBeU4(csbi.offset);
            var csOffsetPtr = scBuf + offset - sizeof(CS_SuperBlob);
            uint slotType = MemoryUtil.GetBeU4(csbi.type);
            switch (slotType)
            {
              case CSSLOT.CSSLOT_CODEDIRECTORY:
              case CSSLOT.CSSLOT_ALTERNATE_CODEDIRECTORIES:
              case CSSLOT.CSSLOT_ALTERNATE_CODEDIRECTORIES1:
              case CSSLOT.CSSLOT_ALTERNATE_CODEDIRECTORIES2:
              case CSSLOT.CSSLOT_ALTERNATE_CODEDIRECTORIES3:
              case CSSLOT.CSSLOT_ALTERNATE_CODEDIRECTORIES4:
              {
                CS_CodeDirectory cscd;
                MemoryUtil.CopyBytes(csOffsetPtr, (byte*)&cscd, sizeof(CS_CodeDirectory));
                if ((CSMAGIC)MemoryUtil.GetBeU4(cscd.magic) != CSMAGIC.CSMAGIC_CODEDIRECTORY)
                  throw new FormatException("Invalid DMG code directory signature magic");
                var cscdLength = MemoryUtil.GetBeU4(cscd.length);

                byte[] currentCodeDirectoryBlob = MemoryUtil.CopyBytes(csOffsetPtr, checked((int)cscdLength));

                if (slotType == CSSLOT.CSSLOT_CODEDIRECTORY)
                  codeDirectoryBlob = currentCodeDirectoryBlob;

                int codeSlots = checked((int)MemoryUtil.GetBeU4(cscd.nCodeSlots));
                int specialSlots = checked((int)MemoryUtil.GetBeU4(cscd.nSpecialSlots));
                uint zeroHashOffset = MemoryUtil.GetBeU4(cscd.hashOffset);
                long codeLimit = MemoryUtil.GetBeU4(cscd.codeLimit);
                int pageSize = cscd.pageSize > 0 ? 1 << cscd.pageSize : 0;
                string hashName = CS_HASHTYPE.GetHashName(cscd.hashType);

                var cdHash = new CDHash(hashName, new ComputeHashInfo(0, new[]
                {
                  new StreamRange(checked(imageRange.Position + (long)signatureOffset + offset), cscdLength)
                }, 0));

                cdHashes.Add(cdHash);

                for (int i = 0; i < codeSlots; i++)
                {
                  byte[] hash = new byte[cscd.hashSize];
                  Array.Copy(currentCodeDirectoryBlob, checked((int)zeroHashOffset + i * cscd.hashSize), hash, 0, cscd.hashSize);

                  long pageStart = i * pageSize;
                  long currentPageSize;
                  if (pageSize > 0)
                    currentPageSize = pageStart + pageSize > codeLimit ? codeLimit - pageStart : pageSize;
                  else
                    currentPageSize = codeLimit - pageStart;

                  var computeHashInfo = new ComputeHashInfo(0, new[]
                  {
                    new StreamRange(pageStart + imageRange.Position, currentPageSize)
                  }, 0);

                  hashVerificationUnits.Add(new HashVerificationUnit(hashName, hash, computeHashInfo));
                }

                for (uint i = 1; i <= specialSlots; i++)
                {
                  byte[] hash = new byte[cscd.hashSize];
                  Array.Copy(currentCodeDirectoryBlob, checked((int)(zeroHashOffset - i * cscd.hashSize)), hash, 0, cscd.hashSize);

                  if (specialSlotPositions[i - 1] != null)
                    hashVerificationUnits.Add(new HashVerificationUnit(hashName, hash, specialSlotPositions[i - 1]));
                }
              }
                break;
              case CSSLOT.CSSLOT_CMS_SIGNATURE:
              {
                CS_Blob csb;
                MemoryUtil.CopyBytes(csOffsetPtr, (byte*)&csb, sizeof(CS_Blob));
                if ((CSMAGIC)MemoryUtil.GetBeU4(csb.magic) != CSMAGIC.CSMAGIC_BLOBWRAPPER)
                  throw new FormatException("Invalid DMG blob wrapper signature magic");
                var csbLength = MemoryUtil.GetBeU4(csb.length);
                if (csbLength < sizeof(CS_Blob))
                  throw new FormatException("Too small DMG cms signature blob length");
                cmsSignatureBlob = MemoryUtil.CopyBytes(csOffsetPtr + sizeof(CS_Blob), checked((int)csbLength - sizeof(CS_Blob)));
              }
                break;
            }
          }
        }
      }

      return new DmgFile(hasSignature, new SignatureData(codeDirectoryBlob, cmsSignatureBlob), hashVerificationUnits, cdHashes, signatureTransferData);
    }