Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/netaddr/strategy/eui64.py: 46%
122 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:45 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:45 +0000
1#-----------------------------------------------------------------------------
2# Copyright (c) 2008 by David P. D. Moss. All rights reserved.
3#
4# Released under the BSD license. See the LICENSE file for details.
5#-----------------------------------------------------------------------------
6"""
7IEEE 64-bit EUI (Extended Unique Indentifier) logic.
8"""
9import struct as _struct
10import re as _re
12from netaddr.core import AddrFormatError
13from netaddr.strategy import (
14 valid_words as _valid_words, int_to_words as _int_to_words,
15 words_to_int as _words_to_int, valid_bits as _valid_bits,
16 bits_to_int as _bits_to_int, int_to_bits as _int_to_bits,
17 valid_bin as _valid_bin, int_to_bin as _int_to_bin,
18 bin_to_int as _bin_to_int)
21# This is a fake constant that doesn't really exist. Here for completeness.
22AF_EUI64 = 64
24#: The width (in bits) of this address type.
25width = 64
27#: The AF_* constant value of this address type.
28family = AF_EUI64
30#: A friendly string name address type.
31family_name = 'EUI-64'
33#: The version of this address type.
34version = 64
36#: The maximum integer value that can be represented by this address type.
37max_int = 2 ** width - 1
39#-----------------------------------------------------------------------------
40# Dialect classes.
41#-----------------------------------------------------------------------------
43class eui64_base(object):
44 """A standard IEEE EUI-64 dialect class."""
45 #: The individual word size (in bits) of this address type.
46 word_size = 8
48 #: The number of words in this address type.
49 num_words = width // word_size
51 #: The maximum integer value for an individual word in this address type.
52 max_word = 2 ** word_size - 1
54 #: The separator character used between each word.
55 word_sep = '-'
57 #: The format string to be used when converting words to string values.
58 word_fmt = '%.2X'
60 #: The number base to be used when interpreting word values as integers.
61 word_base = 16
64class eui64_unix(eui64_base):
65 """A UNIX-style MAC address dialect class."""
66 word_size = 8
67 num_words = width // word_size
68 word_sep = ':'
69 word_fmt = '%x'
70 word_base = 16
73class eui64_unix_expanded(eui64_unix):
74 """A UNIX-style MAC address dialect class with leading zeroes."""
75 word_fmt = '%.2x'
78class eui64_cisco(eui64_base):
79 """A Cisco 'triple hextet' MAC address dialect class."""
80 word_size = 16
81 num_words = width // word_size
82 word_sep = '.'
83 word_fmt = '%.4x'
84 word_base = 16
87class eui64_bare(eui64_base):
88 """A bare (no delimiters) MAC address dialect class."""
89 word_size = 64
90 num_words = width // word_size
91 word_sep = ''
92 word_fmt = '%.16X'
93 word_base = 16
96#: The default dialect to be used when not specified by the user.
98DEFAULT_EUI64_DIALECT = eui64_base
100#-----------------------------------------------------------------------------
101#: Regular expressions to match all supported MAC address formats.
102RE_EUI64_FORMATS = (
103 # 2 bytes x 8 (UNIX, Windows, EUI-64)
104 '^' + ':'.join(['([0-9A-F]{1,2})'] * 8) + '$',
105 '^' + '-'.join(['([0-9A-F]{1,2})'] * 8) + '$',
107 # 4 bytes x 4 (Cisco like)
108 '^' + ':'.join(['([0-9A-F]{1,4})'] * 4) + '$',
109 '^' + '-'.join(['([0-9A-F]{1,4})'] * 4) + '$',
110 '^' + r'\.'.join(['([0-9A-F]{1,4})'] * 4) + '$',
112 # 16 bytes (bare, no delimiters)
113 '^(' + ''.join(['[0-9A-F]'] * 16) + ')$',
114)
115# For efficiency, each string regexp converted in place to its compiled
116# counterpart.
117RE_EUI64_FORMATS = [_re.compile(_, _re.IGNORECASE) for _ in RE_EUI64_FORMATS]
120def _get_match_result(address, formats):
121 for regexp in formats:
122 match = regexp.findall(address)
123 if match:
124 return match[0]
127def valid_str(addr):
128 """
129 :param addr: An IEEE EUI-64 indentifier in string form.
131 :return: ``True`` if EUI-64 indentifier is valid, ``False`` otherwise.
132 """
133 try:
134 if _get_match_result(addr, RE_EUI64_FORMATS):
135 return True
136 except TypeError:
137 pass
139 return False
142def str_to_int(addr):
143 """
144 :param addr: An IEEE EUI-64 indentifier in string form.
146 :return: An unsigned integer that is equivalent to value represented
147 by EUI-64 string address formatted according to the dialect
148 """
149 words = []
151 try:
152 words = _get_match_result(addr, RE_EUI64_FORMATS)
153 if not words:
154 raise TypeError
155 except TypeError:
156 raise AddrFormatError('invalid IEEE EUI-64 identifier: %r!' % (addr,))
158 if isinstance(words, tuple):
159 pass
160 else:
161 words = (words,)
163 if len(words) == 8:
164 # 2 bytes x 8 (UNIX, Windows, EUI-48)
165 int_val = int(''.join(['%.2x' % int(w, 16) for w in words]), 16)
166 elif len(words) == 4:
167 # 4 bytes x 4 (Cisco like)
168 int_val = int(''.join(['%.4x' % int(w, 16) for w in words]), 16)
169 elif len(words) == 1:
170 # 16 bytes (bare, no delimiters)
171 int_val = int('%016x' % int(words[0], 16), 16)
172 else:
173 raise AddrFormatError(
174 'bad word count for EUI-64 identifier: %r!' % addr)
176 return int_val
179def int_to_str(int_val, dialect=None):
180 """
181 :param int_val: An unsigned integer.
183 :param dialect: (optional) a Python class defining formatting options
185 :return: An IEEE EUI-64 identifier that is equivalent to unsigned integer.
186 """
187 if dialect is None:
188 dialect = eui64_base
189 words = int_to_words(int_val, dialect)
190 tokens = [dialect.word_fmt % i for i in words]
191 addr = dialect.word_sep.join(tokens)
192 return addr
195def int_to_packed(int_val):
196 """
197 :param int_val: the integer to be packed.
199 :return: a packed string that is equivalent to value represented by an
200 unsigned integer.
201 """
202 words = int_to_words(int_val)
203 return _struct.pack('>8B', *words)
206def packed_to_int(packed_int):
207 """
208 :param packed_int: a packed string containing an unsigned integer.
209 It is assumed that string is packed in network byte order.
211 :return: An unsigned integer equivalent to value of network address
212 represented by packed binary string.
213 """
214 words = list(_struct.unpack('>8B', packed_int))
216 int_val = 0
217 for i, num in enumerate(reversed(words)):
218 word = num
219 word = word << 8 * i
220 int_val = int_val | word
222 return int_val
225def valid_words(words, dialect=None):
226 if dialect is None:
227 dialect = DEFAULT_EUI64_DIALECT
228 return _valid_words(words, dialect.word_size, dialect.num_words)
231def int_to_words(int_val, dialect=None):
232 if dialect is None:
233 dialect = DEFAULT_EUI64_DIALECT
234 return _int_to_words(int_val, dialect.word_size, dialect.num_words)
237def words_to_int(words, dialect=None):
238 if dialect is None:
239 dialect = DEFAULT_EUI64_DIALECT
240 return _words_to_int(words, dialect.word_size, dialect.num_words)
243def valid_bits(bits, dialect=None):
244 if dialect is None:
245 dialect = DEFAULT_EUI64_DIALECT
246 return _valid_bits(bits, width, dialect.word_sep)
249def bits_to_int(bits, dialect=None):
250 if dialect is None:
251 dialect = DEFAULT_EUI64_DIALECT
252 return _bits_to_int(bits, width, dialect.word_sep)
255def int_to_bits(int_val, dialect=None):
256 if dialect is None:
257 dialect = DEFAULT_EUI64_DIALECT
258 return _int_to_bits(
259 int_val, dialect.word_size, dialect.num_words, dialect.word_sep)
262def valid_bin(bin_val, dialect=None):
263 if dialect is None:
264 dialect = DEFAULT_EUI64_DIALECT
265 return _valid_bin(bin_val, width)
268def int_to_bin(int_val):
269 return _int_to_bin(int_val, width)
272def bin_to_int(bin_val):
273 return _bin_to_int(bin_val, width)