# -*- encoding: utf-8 -*-
"""
libpydhcpserver.dhcp_types.conversion
=====================================
Provides convenience functions used to convert from friendly data-types into
packet-insertable data-types and vice-versa.
Legal
-----
This file is part of libpydhcpserver.
libpydhcpserver is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
(C) Neil Tallim, 2014 <flan@uguu.ca>
"""
try:
from types import StringTypes
except ImportError: #py3k
StringTypes = (str,)
_IPv4 = None #: Placeholder for a deferred import ot avoid a circular reference.
[docs]def listToNumber(l):
"""
Sums a sequence of bytes in big-endian order, producing an integer.
:param sequence l: A sequence of ints, between ``0`` and ``255``.
:return int: The corresponding value.
"""
value = 0
for (i, v) in enumerate(reversed(l)):
value += v << (8 * i)
return value
[docs]def listToInt(l):
"""
Converts a pair of bytes, in big-endian order, into an integer.
:param sequence l: A sequence of ints, between ``0`` and ``255``. If longer
than two, only the head is used; if less than two, zero-padded to LSD.
:return int: The corresponding value.
"""
return listToNumber(l[:2])
[docs]def listToInts(l):
"""
Converts pairs of bytes, in big-endian order, into integers.
:param sequence l: A sequence of ints, between ``0`` and ``255``. If not a
multiple of two, zero-padded to LSD.
:return list: A list of ints corresponding to the byte-pairs.
"""
ints = []
for i in xrange(len(l) >> 1):
p = i * 2
ints.append(listToInt(l[p:p + 2]))
return ints
[docs]def listToLong(l):
"""
Converts a quartet of bytes, in big-endian order, into an integer.
:param sequence l: A sequence of ints, between ``0`` and ``255``. If longer
than four, only the head is used; if less than four, zero-padded to LSD.
:return int: The corresponding value.
"""
return listToNumber(l[:4])
[docs]def listToLongs(l):
"""
Converts quartets of bytes, in big-endian order, into integers.
:param sequence l: A sequence of ints, between ``0`` and ``255``. If not a
multiple of four, zero-padded to LSD.
:return list: A list of ints corresponding to the byte-quartets.
"""
longs = []
for i in xrange(len(l) >> 2):
p = i * 4
longs.append(listToLong(l[p:p + 4]))
return longs
[docs]def intToList(i):
"""
Converts an integer into a pair of bytes in big-endian order.
:param int i: The integer to be converted. If outside the range of ``0`` to
``65535``, only the low-order sixteen bits are considered.
:return list(2): The converted value.
"""
return [
i >> 8 & 0xFF,
i & 0xFF,
]
[docs]def intsToList(l):
"""
Converts a sequence of integers into pairs of bytes in big-endian order.
:param sequence l: The sequence to be converted. If any values are outside
the range of ``0`` to ``65535``, only the low-order sixteen bits are
considered.
:return list: The converted values.
"""
pairs = []
for i in l:
pairs += intToList(i)
return pairs
[docs]def longToList(l):
"""
Converts an integer into a quartet of bytes in big-endian order.
:param int l: The integer to be converted. If outside the range of ``0`` to
``4294967296``, only the low-order thirty-two bits are considered.
:return list(4): The converted value.
"""
return [
l >> 24 & 0xFF,
l >> 16 & 0xFF,
l >> 8 & 0xFF,
l & 0xFF,
]
[docs]def longsToList(l):
"""
Converts a sequence of integers into quartets of bytes in big-endian order.
:param sequence l: The sequence to be converted. If any values are outside
the range of ``0`` to ``4294967296``, only the low-order thirty-two
bits are considered.
:return list: The converted values.
"""
bytes = []
for i in l:
bytes += longToList(i)
return bytes
[docs]def listToStr(l):
"""
Converts a sequence of bytes into a byte-string.
:param sequence l: The bytes to be converted.
:return str: The converted byte-string.
"""
return ''.join(chr(i) for i in l)
[docs]def strToList(s):
"""
Converts a string into a sequence of bytes.
This will also handle unicode strings, so sanitise all input.
:param str s: The string to be converted.
:return list: A sequence of bytes.
"""
return [ord(c) for c in s.encode('utf-8')]
[docs]def strToPaddedList(s, l):
"""
Converts a string into a sequence of bytes, with a fixed length.
This will also handle unicode strings, so sanitise all input.
:param str s: The string to be converted.
:param int l: The length of the resulting list.
:return list: A sequence of bytes of length ``l``, truncated or null-padded
as appropriate.
"""
padded_list = strToList(s)
if len(padded_list) < l:
padded_list += [0] * (l - len(padded_list))
return padded_list[:l]
[docs]def listToIP(l):
"""
Converts almost anything into an IPv4 address.
:param sequence(4) l: The bytes to be converted.
:return: The equivalent IPv4 address.
:except ValueError: The list could not be processed.
"""
global _IPv4
if not _IPv4:
from ipv4 import IPv4
_IPv4 = IPv4
return _IPv4(l)
[docs]def listToIPs(l):
"""
Converts almost anything into IPv4 addresses.
:param sequence l: The bytes to be converted, as a flat sequence with
length a multiple of four.
:return list: The equivalent IPv4 addresses.
:except ValueError: The list could not be processed.
"""
ips = []
for i in xrange(len(l) / 4):
p = i * 4
ips.append(listToIP(l[p:p + 4]))
return ips
[docs]def ipToList(ip):
"""
Converts an IPv4 address into a list of four bytes in big-endian order.
:param object ip: Any valid IPv4 format (string, 32-bit integer, list of
bytes, :class:`IPv4 <dhcp_types.IPv4>`).
:return list(4): The converted address.
:except ValueError: The IP could not be processed.
"""
global _IPv4
if not _IPv4:
from ipv4 import IPv4
_IPv4 = IPv4
if not isinstance(ip, _IPv4):
ip = _IPv4(ip)
return list(ip)
[docs]def ipsToList(ips):
"""
Converts a IPv4 addresses into a flat list of multiples of four bytes in
big-endian order.
:param list ips: A list of any valid IPv4 formats (string, 32-bit integer,
list of bytes, :class:`IPv4 <dhcp_types.IPv4>`).
:return list: The converted addresses.
:except ValueError: The IPs could not be processed.
"""
if isinstance(ips, StringTypes):
tokens = ips.split(',')
else:
tokens = ips
bytes = []
for ip in tokens:
bytes += ipToList(ip)
return bytes