public AtomCallbackArgs(uint type, long size, Stream stream, long startPosition, SequentialStreamReader reader)
 {
     Type = type;
     Size = size;
     Stream = stream;
     StartPosition = startPosition;
     Reader = reader;
 }
        /// <summary>
        /// Reads atom data from <paramref name="stream"/>, invoking <paramref name="handler"/> for each atom encountered.
        /// </summary>
        /// <param name="stream">The stream to read atoms from.</param>
        /// <param name="handler">A callback function to handle each atom.</param>
        /// <param name="stopByBytes">The maximum number of bytes to process before discontinuing.</param>
        public static void ProcessAtoms([NotNull] Stream stream, [NotNull] Action<AtomCallbackArgs> handler, long stopByBytes = -1)
        {
            var reader = new SequentialStreamReader(stream);

            var seriesStartPos = stream.Position;

            while (stopByBytes == -1 || stream.Position < seriesStartPos + stopByBytes)
            {
                var atomStartPos = stream.Position;

                // Length of the atom's data, in bytes, including size bytes
                long atomSize;
                try
                {
                    atomSize = reader.GetUInt32();
                }
                catch (IOException)
                {
                    // TODO don't use exception to trap end of stream
                    return;
                }

                // Typically four ASCII characters, but may be non-printable.
                // By convention, lowercase 4CCs are reserved by Apple.
                var atomType = reader.GetUInt32();

                if (atomSize == 1)
                {
                    // Size doesn't fit in 32 bits so read the 64 bit size here
                    // TODO GetUInt64 (i.e. unsigned)
                    atomSize = reader.GetInt64();
                }
                else
                {
                    Debug.Assert(atomSize >= 8, "Atom should be at least 8 bytes long");
                }

                var args = new AtomCallbackArgs(atomType, atomSize, stream, atomStartPos, reader);

                handler(args);

                if (args.Cancel)
                    return;

                if (atomSize == 0)
                    return;

                var toSkip = atomStartPos + atomSize - stream.Position;

                if (toSkip < 0)
                    throw new Exception("Handler moved stream beyond end of atom");

                reader.TrySkip(toSkip);
            }
        }