code: def _read_mff_header(filepath):
      """Read mff header."""
      _soft_import("defusedxml", "reading EGI MFF data")
      from defusedxml.minidom import parse
  
      all_files = _get_signalfname(filepath)
      eeg_file = all_files["EEG"]["signal"]
      eeg_info_file = all_files["EEG"]["info"]
  
      info_filepath = op.join(filepath, "info.xml")  # add with filepath
      tags = ["mffVersion", "recordTime"]
      version_and_date = _extract(tags, filepath=info_filepath)
      version = ""
      if len(version_and_date["mffVersion"]):
          version = version_and_date["mffVersion"][0]
  
      fname = op.join(filepath, eeg_file)
      signal_blocks = _get_blocks(fname)
      epochs = _get_ep_info(filepath)
      summaryinfo = dict(eeg_fname=eeg_file, info_fname=eeg_info_file)
      summaryinfo.update(signal_blocks)
      # sanity check and update relevant values
      record_time = version_and_date["recordTime"][0]
      # e.g.,
      # 2018-07-30T10:47:01.021673-04:00
      # 2017-09-20T09:55:44.072000000+01:00
      g = re.match(
          r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.(\d{6}(?:\d{3})?)[+-]\d{2}:\d{2}",  # noqa: E501
          record_time,
      )
      if g is None:
          raise RuntimeError(
              "Could not parse recordTime %r" % (record_time,)
          )
      frac = g.groups()[0]
      assert len(frac) in (6, 9) and all(
          f.isnumeric() for f in frac
      )  # regex
      div = 1000 if len(frac) == 6 else 1000000
      for key in ("last_samps", "first_samps"):
          # convert from times in µS to samples
          for ei, e in enumerate(epochs[key]):
              if e % div != 0:
                  raise RuntimeError(
                      "Could not parse epoch time %s" % (e,)
                  )
              epochs[key][ei] = e // div
          epochs[key] = np.array(epochs[key], np.uint64)
          # I guess they refer to times in milliseconds?
          # What we really need to do here is:
          # epochs[key] *= signal_blocks['sfreq']
          # epochs[key] //= 1000
          # But that multiplication risks an overflow, so let's only multiply
          # by what we need to (e.g., a sample rate of 500 means we can multiply
          # by 1 and divide by 2 rather than multiplying by 500 and dividing by
          # 1000)
          numerator = int(signal_blocks["sfreq"])
          denominator = 1000
          this_gcd = math.gcd(numerator, denominator)
          numerator = numerator // this_gcd
          denominator = denominator // this_gcd
          with np.errstate(over="raise"):
              epochs[key] *= numerator
          epochs[key] //= denominator
          # Should be safe to cast to int now, which makes things later not
          # upbroadcast to float
          epochs[key] = epochs[key].astype(np.int64)
      n_samps_block = signal_blocks["samples_block"].sum()
      n_samps_epochs = (
          epochs["last_samps"] - epochs["first_samps"]
      ).sum()
      bad = (
          n_samps_epochs != n_samps_block
          or not (epochs["first_samps"] < epochs["last_samps"]).all()
          or not (
              epochs["first_samps"][1:] >= epochs["last_samps"][:-1]
          ).all()
      )
      if bad:
          raise RuntimeError(
              "EGI epoch first/last samps could not be parsed:\n"
              "%s\n%s"
              % (
                  list(epochs["first_samps"]),
                  list(epochs["last_samps"]),
              )
          )
      summaryinfo.update(epochs)
      # index which samples in raw are actually readable from disk (i.e., not
      # in a skip)
      disk_samps = np.full(epochs["last_samps"][-1], -1)
      offset = 0
      for first, last in zip(
          epochs["first_samps"], epochs["last_samps"]
      ):
          n_this = last - first
          disk_samps[first:last] = np.arange(offset, offset + n_this)
          offset += n_this
      summaryinfo["disk_samps"] = disk_samps
  
      # Add the sensor info.
      sensor_layout_file = op.join(filepath, "sensorLayout.xml")
      sensor_layout_obj = parse(sensor_layout_file)
      summaryinfo["device"] = sensor_layout_obj.getElementsByTagName(
          "name"
      )[0].firstChild.data
      sensors = sensor_layout_obj.getElementsByTagName("sensor")
      chan_type = list()
      chan_unit = list()
      n_chans = 0
      numbers = list()  # used for identification
      for sensor in sensors:
          sensortype = int(
              sensor.getElementsByTagName("type")[0].firstChild.data
          )
          if sensortype in [0, 1]:
              sn = sensor.getElementsByTagName("number")[
                  0
              ].firstChild.data
              sn = sn.encode()
              numbers.append(sn)
              chan_type.append("eeg")
              chan_unit.append("uV")
              n_chans = n_chans + 1
      if n_chans != summaryinfo["n_channels"]:
          raise RuntimeError(
              "Number of defined channels (%d) did not match the "
              "expected channels (%d)"
              % (n_chans, summaryinfo["n_channels"])
          )
  
      # Check presence of PNS data
      pns_names = []
      if "PNS" in all_files:
          pns_fpath = op.join(filepath, all_files["PNS"]["signal"])
          pns_blocks = _get_blocks(pns_fpath)
          pns_samples = pns_blocks["samples_block"]
          signal_samples = signal_blocks["samples_block"]
          same_blocks = np.array_equal(
              pns_samples[:-1], signal_samples[:-1]
          ) and pns_samples[-1] in (signal_samples[-1] - np.arange(2))
          if not same_blocks:
              raise RuntimeError(
                  "PNS and signals samples did not match:\n"
                  "%s\nvs\n%s"
                  % (list(pns_samples), list(signal_samples))
              )
  
          pns_file = op.join(filepath, "pnsSet.xml")
          pns_obj = parse(pns_file)
          sensors = pns_obj.getElementsByTagName("sensor")
          pns_types = []
          pns_units = []
          for sensor in sensors:
              # sensor number:
              # sensor.getElementsByTagName('number')[0].firstChild.data
              name = sensor.getElementsByTagName("name")[
                  0
              ].firstChild.data
              unit_elem = sensor.getElementsByTagName("unit")[
                  0
              ].firstChild
              unit = ""
              if unit_elem is not None:
                  unit = unit_elem.data
  
              if name == "ECG":
                  ch_type = "ecg"
              elif "EMG" in name:
                  ch_type = "emg"
              else:
                  ch_type = "bio"
              pns_types.append(ch_type)
              pns_units.append(unit)
              pns_names.append(name)
  
          summaryinfo.update(
              pns_types=pns_types,
              pns_units=pns_units,
              pns_fname=all_files["PNS"]["signal"],
              pns_sample_blocks=pns_blocks,
          )
      summaryinfo.update(
          pns_names=pns_names,
          version=version,
          date=version_and_date["recordTime"][0],
          chan_type=chan_type,
          chan_unit=chan_unit,
          numbers=numbers,
      )
  
      return summaryinfo
  
imports: import datetime
  import math
  import os.path
  import re
  from collections import OrderedDict
  from pathlib import Path
  import numpy
  from ..._fiff.constants import FIFF
  from ..._fiff.meas_info import _empty_info, _ensure_meas_date_none_or_dt, create_info
  from ..._fiff.proj import setup_proj
  from ..._fiff.utils import _create_chs, _mult_cal_one
  from ...annotations import Annotations
  from ...channels.montage import make_dig_montage
  from ...evoked import EvokedArray
  from ...utils import _check_fname, _check_option, _soft_import, logger, verbose, warn
  from ..base import BaseRaw
  from .events import _combine_triggers, _read_events
  from .general import _block_r, _extract, _get_blocks, _get_ep_info, _get_gains, _get_signalfname
label_desc: Use image node_id 1 for calling a global function with example usage: _read_mff_header(filepath) and returns: summaryinfo