code: def decode_options(self, buffer):
          
          fmt = b"!"
          options = {}
  
          log.debug("decode_options: buffer is: %s", repr(buffer))
          log.debug("size of buffer is %d bytes", len(buffer))
          if len(buffer) == 0:
              log.debug("size of buffer is zero, returning empty hash")
              return {}
  
          # Count the nulls in the buffer. Each one terminates a string.
          log.debug("about to iterate options buffer counting nulls")
          length = 0
          for i in range(len(buffer)):
              if ord(buffer[i:i+1]) == 0:
                  log.debug("found a null at length %d", length)
                  if length > 0:
                      fmt += b"%dsx" % length
                      length = -1
                  else:
                      raise TftpException("Invalid options in buffer")
              length += 1
  
          log.debug("about to unpack, fmt is: %s", fmt)
          mystruct = struct.unpack(fmt, buffer)
  
          tftpassert(len(mystruct) % 2 == 0,
                     "packet with odd number of option/value pairs")
  
          for i in range(0, len(mystruct), 2):
              key = mystruct[i].decode('ascii')
              val = mystruct[i+1].decode('ascii')
              log.debug("setting option %s to %s", key, val)
              log.debug("types are %s and %s", type(key), type(val))
              options[key] = val
  
          return options
docs: This method decodes the section of the buffer that contains an
          unknown number of options. It returns a dictionary of option names and
          values.