Package dns :: Module wiredata |
[hide private]
[frames] | no frames]

# Source Code for Module dns.wiredata

      1  # Copyright (C) 2011 Nominum, Inc.
      2  #
      3  # Permission to use, copy, modify, and distribute this software and its
      4  # documentation for any purpose with or without fee is hereby granted,
      5  # provided that the above copyright notice and this permission notice
      6  # appear in all copies.
      7  #
      8  # THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
      9  # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
     11  # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
     14  # OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15
     16  """DNS Wire Data Helper"""
     17
     18  import sys
     19
     20  import dns.exception
     21  from ._compat import binary_type, string_types
     22
     23  # Figure out what constant python passes for an unspecified slice bound.
     24  # It's supposed to be sys.maxint, yet on 64-bit windows sys.maxint is 2^31 - 1
     25  # but Python uses 2^63 - 1 as the constant.  Rather than making pointless
     26  # extra comparisons, duplicating code, or weakening WireData, we just figure
     27  # out what constant Python will use.
     28
     29
     30 -class _SliceUnspecifiedBound(binary_type):
     31
     32 -    def __getitem__(self, key):
     33          return key.stop
     34
     35      if sys.version_info < (3,):
     36 -        def __getslice__(self, i, j):  # pylint: disable=getslice-method
     37              return self.__getitem__(slice(i, j))
     38
     39  _unspecified_bound = _SliceUnspecifiedBound()[1:]
     40
     41
     42 -class WireData(binary_type):
     43      # WireData is a string with stricter slicing
     44
     45 -    def __getitem__(self, key):
     46          try:
     47              if isinstance(key, slice):
     48                  # make sure we are not going outside of valid ranges,
     49                  # do stricter control of boundaries than python does
     50                  # by default
     51                  start = key.start
     52                  stop = key.stop
     53
     54                  if sys.version_info < (3,):
     55                      if stop == _unspecified_bound:
     56                          # handle the case where the right bound is unspecified
     57                          stop = len(self)
     58
     59                      if start < 0 or stop < 0:
     60                          raise dns.exception.FormError
     61                      # If it's not an empty slice, access left and right bounds
     62                      # to make sure they're valid
     63                      if start != stop:
     64                          super(WireData, self).__getitem__(start)
     65                          super(WireData, self).__getitem__(stop - 1)
     66                  else:
     67                      for index in (start, stop):
     68                          if index is None:
     69                              continue
     70                          elif abs(index) > len(self):
     71                              raise dns.exception.FormError
     72
     73                  return WireData(super(WireData, self).__getitem__(
     74                      slice(start, stop)))
     75              return bytearray(self.unwrap())[key]
     76          except IndexError:
     77              raise dns.exception.FormError
     78
     79      if sys.version_info < (3,):
     80 -        def __getslice__(self, i, j):  # pylint: disable=getslice-method
     81              return self.__getitem__(slice(i, j))
     82
     83 -    def __iter__(self):
     84          i = 0
     85          while 1:
     86              try:
     87                  yield self[i]
     88                  i += 1
     89              except dns.exception.FormError:
     90                  raise StopIteration
     91
     92 -    def unwrap(self):
     93          return binary_type(self)
     94
     95
     96 -def maybe_wrap(wire):
     97      if isinstance(wire, WireData):
     98          return wire
     99      elif isinstance(wire, binary_type):
    100          return WireData(wire)
    101      elif isinstance(wire, string_types):
    102          return WireData(wire.encode())
    103      raise ValueError("unhandled type %s" % type(wire))
    104