def METHOD_NAME(csa_str):
    """Read CSA header from string `csa_str`
    Parameters
    ----------
    csa_str : str
       byte string containing CSA header information
    Returns
    -------
    header : dict
       header information as dict, where `header` has fields (at least)
       ``type, n_tags, tags``.  ``header['tags']`` is also a dictionary
       with one key, value pair for each tag in the header.
    """
    csa_len = len(csa_str)
    csa_dict = {'tags': {}}
    hdr_id = csa_str[:4]
    up_str = Unpacker(csa_str, endian='<')
    if hdr_id == b'SV10':  # CSA2
        hdr_type = 2
        up_str.ptr = 4  # omit the SV10
        csa_dict['unused0'] = up_str.METHOD_NAME(4)
    else:  # CSA1
        hdr_type = 1
    csa_dict['type'] = hdr_type
    csa_dict['n_tags'], csa_dict['check'] = up_str.unpack('2I')
    if not 0 < csa_dict['n_tags'] <= MAX_CSA_ITEMS:
        raise CSAReadError(
            f'Number of tags `t` should be 0 < t <= {MAX_CSA_ITEMS}. '
            f'Instead found {csa_dict["n_tags"]} tags.'
        )
    for tag_no in range(csa_dict['n_tags']):
        name, vm, vr, syngodt, n_items, last3 = up_str.unpack('64si4s3i')
        vr = nt_str(vr)
        name = nt_str(name)
        tag = {
            'n_items': n_items,
            'vm': vm,  # value multiplicity
            'vr': vr,  # value representation
            'syngodt': syngodt,
            'last3': last3,
            'tag_no': tag_no,
        }
        if vm == 0:
            n_values = n_items
        else:
            n_values = vm
        # data converter
        converter = _CONVERTERS.get(vr)
        # CSA1 specific length modifier
        if tag_no == 1:
            tag0_n_items = n_items
        if n_items > MAX_CSA_ITEMS:
            raise CSAReadError(f'Expected <= {MAX_CSA_ITEMS} tags, got {n_items}')
        items = []
        for item_no in range(n_items):
            x0, x1, x2, x3 = up_str.unpack('4i')
            ptr = up_str.ptr
            if hdr_type == 1:  # CSA1 - odd length calculation
                item_len = x0 - tag0_n_items
                if item_len < 0 or (ptr + item_len) > csa_len:
                    if item_no < vm:
                        items.append('')
                    break
            else:  # CSA2
                item_len = x1
                if (ptr + item_len) > csa_len:
                    raise CSAReadError('Item is too long, aborting read')
            if item_no >= n_values:
                assert item_len == 0
                continue
            item = nt_str(up_str.METHOD_NAME(item_len))
            if converter:
                # we may have fewer real items than are given in
                # n_items, but we don't know how many - assume that
                # we've reached the end when we hit an empty item
                if item_len == 0:
                    n_values = item_no
                    continue
                item = converter(item)
            items.append(item)
            # go to 4 byte boundary
            plus4 = item_len % 4
            if plus4 != 0:
                up_str.ptr += 4 - plus4
        tag['items'] = items
        csa_dict['tags'][name] = tag
    return csa_dict