'Parse a bytestring as a full PROXY protocol header.
@param line: A bytestring that represents a valid HAProxy PROXY
protocol version 2 header.
@type line: bytes
@return: A L{_interfaces.IProxyInfo} containing the
parsed data.
@raises InvalidProxyHeader: If the bytestring does not represent a
valid PROXY header.'

@classmethod
def parse(cls, line):

    prefix = line[:12]
    addrInfo = None
    with convertError(IndexError, InvalidProxyHeader):
        versionCommand = ord(line[12:13])
        familyProto = ord(line[13:14])
    if (prefix != cls.PREFIX):
        raise InvalidProxyHeader()
    (version, command) = ((versionCommand & _HIGH), (versionCommand & _LOW))
    if ((version not in cls.VERSIONS) or (command not in cls.COMMANDS)):
        raise InvalidProxyHeader()
    if (cls.COMMANDS[command] == _LOCALCOMMAND):
        return _info.ProxyInfo(line, None, None)
    (family, netproto) = ((familyProto & _HIGH), (familyProto & _LOW))
    with convertError(ValueError, InvalidNetworkProtocol):
        family = NetFamily.lookupByValue(family)
        netproto = NetProtocol.lookupByValue(netproto)
    if ((family is NetFamily.UNSPEC) or (netproto is NetProtocol.UNSPEC)):
        return _info.ProxyInfo(line, None, None)
    addressFormat = cls.ADDRESSFORMATS[familyProto]
    addrInfo = line[16:(16 + struct.calcsize(addressFormat))]
    if (family is NetFamily.UNIX):
        with convertError(struct.error, MissingAddressData):
            (source, dest) = struct.unpack(addressFormat, addrInfo)
        return _info.ProxyInfo(line, address.UNIXAddress(source.rstrip('\x00')), address.UNIXAddress(dest.rstrip('\x00')))
    addrType = 'TCP'
    if (netproto is NetProtocol.DGRAM):
        addrType = 'UDP'
    addrCls = address.IPv4Address
    addrParser = cls._bytesToIPv4
    if (family is NetFamily.INET6):
        addrCls = address.IPv6Address
        addrParser = cls._bytesToIPv6
    with convertError(struct.error, MissingAddressData):
        info = struct.unpack(addressFormat, addrInfo)
        (source, dest, sPort, dPort) = info
    return _info.ProxyInfo(line, addrCls(addrType, addrParser(source), sPort), addrCls(addrType, addrParser(dest), dPort))
