mirror of
				https://github.com/OpenKMIP/PyKMIP.git
				synced 2025-11-04 05:25:17 +01:00 
			
		
		
		
	This change updates the PyKMIP object hierarchy's read/write method signatures to support propagation of the KMIP version. The introduction of KMIP 2.0 introduces future KMIP message encodings that break backwards compatibility; to support this, PyKMIP must know what KMIP version is being used when encoding or decoding an object; the KMIP version residing in the client or server alone is now insufficient. Prior versions of KMIP, namely 1.0 - 1.4, have been backwards compatible, obviating the need for the KMIP version at encode/decode time. Going forward, this is no longer true. The PyKMIP client and server have been updated to include the KMIP version when making calls to read/write, as have the associated test cases covering this functionality.
		
			
				
	
	
		
			1153 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			1153 lines
		
	
	
		
			39 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Copyright (c) 2014 The Johns Hopkins University/Applied Physics Laboratory
 | 
						|
# All Rights Reserved.
 | 
						|
#
 | 
						|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
 | 
						|
# not use this file except in compliance with the License. You may obtain
 | 
						|
# a copy of the License at
 | 
						|
#
 | 
						|
#    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
#
 | 
						|
# Unless required by applicable law or agreed to in writing, software
 | 
						|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 | 
						|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 | 
						|
# License for the specific language governing permissions and limitations
 | 
						|
# under the License.
 | 
						|
 | 
						|
import enum as enumeration
 | 
						|
import logging
 | 
						|
import six
 | 
						|
import struct
 | 
						|
import sys
 | 
						|
import time
 | 
						|
 | 
						|
from struct import pack, unpack
 | 
						|
 | 
						|
from kmip.core import enums
 | 
						|
from kmip.core import exceptions
 | 
						|
from kmip.core import utils
 | 
						|
 | 
						|
 | 
						|
class Base(object):
 | 
						|
    TAG_SIZE = 3
 | 
						|
    TYPE_SIZE = 1
 | 
						|
    LENGTH_SIZE = 4
 | 
						|
 | 
						|
    def __init__(self, tag=enums.Tags.DEFAULT, type=enums.Types.DEFAULT):
 | 
						|
        self.tag = tag
 | 
						|
        self.type = type
 | 
						|
        self.length = None
 | 
						|
 | 
						|
    # TODO (peter-hamilton) Convert this into a classmethod, class name can be
 | 
						|
    #                       obtained from cls parameter that replaces self
 | 
						|
    def is_oversized(self, stream):
 | 
						|
        extra = len(stream.peek())
 | 
						|
        if extra > 0:
 | 
						|
            raise exceptions.StreamNotEmptyError(Base.__name__, extra)
 | 
						|
 | 
						|
    def read_tag(self, istream):
 | 
						|
        # Read in the bytes for the tag
 | 
						|
        tts = istream.read(self.TAG_SIZE)
 | 
						|
        tag = unpack('!I', b'\x00' + tts[0:self.TAG_SIZE])[0]
 | 
						|
 | 
						|
        enum_tag = enums.Tags(tag)
 | 
						|
 | 
						|
        # Verify that the tag matches for the current object
 | 
						|
        if enum_tag is not self.tag:
 | 
						|
            raise exceptions.ReadValueError(
 | 
						|
                Base.__name__,
 | 
						|
                'tag',
 | 
						|
                hex(self.tag.value),
 | 
						|
                hex(tag)
 | 
						|
            )
 | 
						|
 | 
						|
    def read_type(self, istream):
 | 
						|
        # Read in the bytes for the type
 | 
						|
        tts = istream.read(self.TYPE_SIZE)
 | 
						|
        num_bytes = len(tts)
 | 
						|
        if num_bytes != self.TYPE_SIZE:
 | 
						|
            min_bytes = 'a minimum of {0} bytes'.format(self.TYPE_SIZE)
 | 
						|
            raise exceptions.ReadValueError(
 | 
						|
                Base.__name__,
 | 
						|
                'type',
 | 
						|
                min_bytes,
 | 
						|
                '{0} bytes'.format(num_bytes)
 | 
						|
            )
 | 
						|
        typ = unpack('!B', tts)[0]
 | 
						|
 | 
						|
        enum_typ = enums.Types(typ)
 | 
						|
 | 
						|
        if enum_typ is not self.type:
 | 
						|
            raise exceptions.ReadValueError(
 | 
						|
                Base.__name__,
 | 
						|
                'type',
 | 
						|
                self.type.value,
 | 
						|
                typ
 | 
						|
            )
 | 
						|
 | 
						|
    def read_length(self, istream):
 | 
						|
        # Read in the bytes for the length
 | 
						|
        lst = istream.read(self.LENGTH_SIZE)
 | 
						|
        num_bytes = len(lst)
 | 
						|
        if num_bytes != self.LENGTH_SIZE:
 | 
						|
            min_bytes = 'a minimum of {0} bytes'.format(self.LENGTH_SIZE)
 | 
						|
            raise exceptions.ReadValueError(
 | 
						|
                Base.__name__,
 | 
						|
                'length',
 | 
						|
                min_bytes,
 | 
						|
                '{0} bytes'.format(num_bytes)
 | 
						|
            )
 | 
						|
        self.length = unpack('!I', lst)[0]
 | 
						|
 | 
						|
    def read_value(self, istream):
 | 
						|
        raise NotImplementedError()
 | 
						|
 | 
						|
    def read(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        self.read_tag(istream)
 | 
						|
        self.read_type(istream)
 | 
						|
        self.read_length(istream)
 | 
						|
 | 
						|
    def write_tag(self, ostream):
 | 
						|
        # Write the tag to the output stream
 | 
						|
        ostream.write(pack('!I', self.tag.value)[1:])
 | 
						|
 | 
						|
    def write_type(self, ostream):
 | 
						|
        if type(self.type) is not enums.Types:
 | 
						|
            msg = exceptions.ErrorStrings.BAD_EXP_RECV
 | 
						|
            raise TypeError(msg.format(Base.__name__, 'type',
 | 
						|
                                       enums.Types, type(self.type)))
 | 
						|
        ostream.write(pack('!B', self.type.value))
 | 
						|
 | 
						|
    def write_length(self, ostream):
 | 
						|
        if type(self.length) is not int:
 | 
						|
            msg = exceptions.ErrorStrings.BAD_EXP_RECV
 | 
						|
            raise TypeError(msg.format(Base.__name__, 'length',
 | 
						|
                                       int, type(self.length)))
 | 
						|
        num_bytes = utils.count_bytes(self.length)
 | 
						|
        if num_bytes > self.LENGTH_SIZE:
 | 
						|
            raise exceptions.WriteOverflowError(
 | 
						|
                Base.__name__,
 | 
						|
                'length',
 | 
						|
                self.LENGTH_SIZE,
 | 
						|
                num_bytes
 | 
						|
            )
 | 
						|
        ostream.write(pack('!I', self.length))
 | 
						|
 | 
						|
    def write_value(self, ostream):
 | 
						|
        raise NotImplementedError()
 | 
						|
 | 
						|
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        self.write_tag(ostream)
 | 
						|
        self.write_type(ostream)
 | 
						|
        self.write_length(ostream)
 | 
						|
 | 
						|
    def validate(self):
 | 
						|
        raise NotImplementedError()
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def is_tag_next(tag, stream):
 | 
						|
        next_tag = stream.peek(Base.TAG_SIZE)
 | 
						|
        if len(next_tag) != Base.TAG_SIZE:
 | 
						|
            return False
 | 
						|
        next_tag = unpack('!I', b'\x00' + next_tag)[0]
 | 
						|
        if next_tag == tag.value:
 | 
						|
            return True
 | 
						|
        else:
 | 
						|
            return False
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def is_type_next(kmip_type, stream):
 | 
						|
        tag_type_size = Base.TAG_SIZE + Base.TYPE_SIZE
 | 
						|
        tt = stream.peek(tag_type_size)
 | 
						|
 | 
						|
        if len(tt) != tag_type_size:
 | 
						|
            return False
 | 
						|
 | 
						|
        typ = unpack('!B', tt[Base.TAG_SIZE:])[0]
 | 
						|
 | 
						|
        if typ == kmip_type.value:
 | 
						|
            return True
 | 
						|
        else:
 | 
						|
            return False
 | 
						|
 | 
						|
 | 
						|
class Struct(Base):
 | 
						|
 | 
						|
    def __init__(self, tag=enums.Tags.DEFAULT):
 | 
						|
        super(Struct, self).__init__(tag, type=enums.Types.STRUCTURE)
 | 
						|
 | 
						|
    # NOTE (peter-hamilton) If seen, should indicate repr needs to be defined
 | 
						|
    def __repr__(self):
 | 
						|
        return "Struct()"
 | 
						|
 | 
						|
 | 
						|
class Integer(Base):
 | 
						|
    LENGTH = 4
 | 
						|
 | 
						|
    # Set for signed 32-bit integers
 | 
						|
    MIN = -2147483648
 | 
						|
    MAX = 2147483647
 | 
						|
 | 
						|
    def __init__(self, value=None, tag=enums.Tags.DEFAULT, signed=True):
 | 
						|
        super(Integer, self).__init__(tag, type=enums.Types.INTEGER)
 | 
						|
 | 
						|
        self.value = value
 | 
						|
        if self.value is None:
 | 
						|
            self.value = 0
 | 
						|
 | 
						|
        self.length = self.LENGTH
 | 
						|
        self.padding_length = self.LENGTH
 | 
						|
        if signed:
 | 
						|
            self.pack_string = '!i'
 | 
						|
        else:
 | 
						|
            self.pack_string = '!I'
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def read_value(self, istream):
 | 
						|
        if self.length is not self.LENGTH:
 | 
						|
            raise exceptions.ReadValueError(
 | 
						|
                Integer.__name__,
 | 
						|
                'length',
 | 
						|
                self.LENGTH,
 | 
						|
                self.length
 | 
						|
            )
 | 
						|
 | 
						|
        self.value = unpack(self.pack_string, istream.read(self.length))[0]
 | 
						|
        pad = unpack(self.pack_string, istream.read(self.padding_length))[0]
 | 
						|
 | 
						|
        if pad != 0:
 | 
						|
            raise exceptions.ReadValueError(
 | 
						|
                Integer.__name__,
 | 
						|
                'pad',
 | 
						|
                0,
 | 
						|
                pad
 | 
						|
            )
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def read(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        super(Integer, self).read(istream, kmip_version=kmip_version)
 | 
						|
        self.read_value(istream)
 | 
						|
 | 
						|
    def write_value(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        ostream.write(pack(self.pack_string, self.value))
 | 
						|
        ostream.write(pack(self.pack_string, 0))
 | 
						|
 | 
						|
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        super(Integer, self).write(ostream, kmip_version=kmip_version)
 | 
						|
        self.write_value(ostream, kmip_version=kmip_version)
 | 
						|
 | 
						|
    def validate(self):
 | 
						|
        """
 | 
						|
        Verify that the value of the Integer object is valid.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            TypeError: if the value is not of type int or long
 | 
						|
            ValueError: if the value cannot be represented by a signed 32-bit
 | 
						|
                integer
 | 
						|
        """
 | 
						|
        if self.value is not None:
 | 
						|
            if type(self.value) not in six.integer_types:
 | 
						|
                raise TypeError('expected (one of): {0}, observed: {1}'.format(
 | 
						|
                    six.integer_types, type(self.value)))
 | 
						|
            else:
 | 
						|
                if self.value > Integer.MAX:
 | 
						|
                    raise ValueError('integer value greater than accepted max')
 | 
						|
                elif self.value < Integer.MIN:
 | 
						|
                    raise ValueError('integer value less than accepted min')
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "{0}(value={1})".format(type(self).__name__, self.value)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return str(self.value)
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if isinstance(other, Integer):
 | 
						|
            return self.value == other.value
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        if isinstance(other, Integer):
 | 
						|
            return not self.__eq__(other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __lt__(self, other):
 | 
						|
        if isinstance(other, Integer):
 | 
						|
            return self.value < other.value
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __gt__(self, other):
 | 
						|
        if isinstance(other, Integer):
 | 
						|
            return self.value > other.value
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __le__(self, other):
 | 
						|
        if isinstance(other, Integer):
 | 
						|
            return self.__eq__(other) or self.__lt__(other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __ge__(self, other):
 | 
						|
        if isinstance(other, Integer):
 | 
						|
            return self.__eq__(other) or self.__gt__(other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
 | 
						|
class LongInteger(Base):
 | 
						|
    """
 | 
						|
    An encodeable object representing a long integer value.
 | 
						|
 | 
						|
    A LongInteger is one of the KMIP primitive object types. It is encoded as
 | 
						|
    a signed, big-endian, 64-bit integer. For more information, see Section
 | 
						|
    9.1 of the KMIP 1.1 specification.
 | 
						|
    """
 | 
						|
 | 
						|
    LENGTH = 8
 | 
						|
 | 
						|
    # Bounds for signed 64-bit integers
 | 
						|
    MIN = -9223372036854775808
 | 
						|
    MAX = 9223372036854775807
 | 
						|
 | 
						|
    def __init__(self, value=0, tag=enums.Tags.DEFAULT):
 | 
						|
        """
 | 
						|
        Create a LongInteger.
 | 
						|
 | 
						|
        Args:
 | 
						|
            value (int): The value of the LongInteger. Optional, defaults to 0.
 | 
						|
            tag (Tags): An enumeration defining the tag of the LongInteger.
 | 
						|
                Optional, defaults to Tags.DEFAULT.
 | 
						|
        """
 | 
						|
        super(LongInteger, self).__init__(tag, type=enums.Types.LONG_INTEGER)
 | 
						|
        self.value = value
 | 
						|
        self.length = LongInteger.LENGTH
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def read(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Read the encoding of the LongInteger from the input stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            istream (stream): A buffer containing the encoded bytes of a
 | 
						|
                LongInteger. Usually a BytearrayStream object. Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be decoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            InvalidPrimitiveLength: if the long integer encoding read in has
 | 
						|
                an invalid encoded length.
 | 
						|
        """
 | 
						|
        super(LongInteger, self).read(istream, kmip_version=kmip_version)
 | 
						|
 | 
						|
        if self.length is not LongInteger.LENGTH:
 | 
						|
            raise exceptions.InvalidPrimitiveLength(
 | 
						|
                "invalid long integer length read; "
 | 
						|
                "expected: {0}, observed: {1}".format(
 | 
						|
                    LongInteger.LENGTH, self.length))
 | 
						|
 | 
						|
        self.value = unpack('!q', istream.read(self.length))[0]
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Write the encoding of the LongInteger to the output stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            ostream (stream): A buffer to contain the encoded bytes of a
 | 
						|
                LongInteger. Usually a BytearrayStream object. Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be encoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
        """
 | 
						|
        super(LongInteger, self).write(ostream, kmip_version=kmip_version)
 | 
						|
        ostream.write(pack('!q', self.value))
 | 
						|
 | 
						|
    def validate(self):
 | 
						|
        """
 | 
						|
        Verify that the value of the LongInteger is valid.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            TypeError: if the value is not of type int or long
 | 
						|
            ValueError: if the value cannot be represented by a signed 64-bit
 | 
						|
                integer
 | 
						|
        """
 | 
						|
        if self.value is not None:
 | 
						|
            if not isinstance(self.value, six.integer_types):
 | 
						|
                raise TypeError('expected (one of): {0}, observed: {1}'.format(
 | 
						|
                    six.integer_types, type(self.value)))
 | 
						|
            else:
 | 
						|
                if self.value > LongInteger.MAX:
 | 
						|
                    raise ValueError(
 | 
						|
                        'long integer value greater than accepted max')
 | 
						|
                elif self.value < LongInteger.MIN:
 | 
						|
                    raise ValueError(
 | 
						|
                        'long integer value less than accepted min')
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "LongInteger(value={0}, tag={1})".format(self.value, self.tag)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return str(self.value)
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if isinstance(other, LongInteger):
 | 
						|
            if self.value == other.value:
 | 
						|
                return True
 | 
						|
            else:
 | 
						|
                return False
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        if isinstance(other, LongInteger):
 | 
						|
            return not self.__eq__(other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
 | 
						|
class BigInteger(Base):
 | 
						|
    """
 | 
						|
    An encodeable object representing a big integer value.
 | 
						|
 | 
						|
    A BigInteger is one of the KMIP primitive object types. It is encoded as
 | 
						|
    a signed, big-endian, integer of arbitrary size. For more information, see
 | 
						|
    Section 9.1 of the KMIP 1.1 specification.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, value=0, tag=enums.Tags.DEFAULT):
 | 
						|
        super(BigInteger, self).__init__(tag, type=enums.Types.BIG_INTEGER)
 | 
						|
        self.value = value
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def read(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Read the encoding of the BigInteger from the input stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            istream (stream): A buffer containing the encoded bytes of the
 | 
						|
                value of a BigInteger. Usually a BytearrayStream object.
 | 
						|
                Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be decoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            InvalidPrimitiveLength: if the big integer encoding read in has
 | 
						|
                an invalid encoded length.
 | 
						|
        """
 | 
						|
        super(BigInteger, self).read(istream, kmip_version=kmip_version)
 | 
						|
 | 
						|
        # Check for a valid length before even trying to parse the value.
 | 
						|
        if self.length % 8:
 | 
						|
            raise exceptions.InvalidPrimitiveLength(
 | 
						|
                "invalid big integer length read; "
 | 
						|
                "expected: multiple of 8, observed: {0}".format(self.length))
 | 
						|
 | 
						|
        sign = 1
 | 
						|
        binary = ''
 | 
						|
 | 
						|
        # Read the value byte by byte and convert it into binary, padding each
 | 
						|
        # byte as needed.
 | 
						|
        for _ in range(self.length):
 | 
						|
            byte = struct.unpack('!B', istream.read(1))[0]
 | 
						|
            bits = "{0:b}".format(byte)
 | 
						|
            pad = len(bits) % 8
 | 
						|
            if pad:
 | 
						|
                bits = ('0' * (8 - pad)) + bits
 | 
						|
            binary += bits
 | 
						|
 | 
						|
        # If the value is negative, convert via two's complement.
 | 
						|
        if binary[0] == '1':
 | 
						|
            sign = -1
 | 
						|
            binary = binary.replace('1', 'i')
 | 
						|
            binary = binary.replace('0', '1')
 | 
						|
            binary = binary.replace('i', '0')
 | 
						|
 | 
						|
            pivot = binary.rfind('0')
 | 
						|
            binary = binary[0:pivot] + '1' + ('0' * len(binary[pivot + 1:]))
 | 
						|
 | 
						|
        # Convert the value back to an integer and reapply the sign.
 | 
						|
        self.value = int(binary, 2) * sign
 | 
						|
 | 
						|
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Write the encoding of the BigInteger to the output stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            ostream (Stream): A buffer to contain the encoded bytes of a
 | 
						|
                BigInteger object. Usually a BytearrayStream object.
 | 
						|
                Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be encoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
        """
 | 
						|
        # Convert the value to binary and pad it as needed.
 | 
						|
        binary = "{0:b}".format(abs(self.value))
 | 
						|
        binary = ("0" * (64 - (len(binary) % 64))) + binary
 | 
						|
 | 
						|
        # If the value is negative, convert via two's complement.
 | 
						|
        if self.value < 0:
 | 
						|
            binary = binary.replace('1', 'i')
 | 
						|
            binary = binary.replace('0', '1')
 | 
						|
            binary = binary.replace('i', '0')
 | 
						|
 | 
						|
            pivot = binary.rfind('0')
 | 
						|
            binary = binary[0:pivot] + '1' + ('0' * len(binary[pivot + 1:]))
 | 
						|
 | 
						|
        # Convert each byte to hex and build the hex string for the value.
 | 
						|
        hexadecimal = b''
 | 
						|
        for i in range(0, len(binary), 8):
 | 
						|
            byte = binary[i:i + 8]
 | 
						|
            byte = int(byte, 2)
 | 
						|
            hexadecimal += struct.pack('!B', byte)
 | 
						|
 | 
						|
        self.length = len(hexadecimal)
 | 
						|
        super(BigInteger, self).write(ostream, kmip_version=kmip_version)
 | 
						|
        ostream.write(hexadecimal)
 | 
						|
 | 
						|
    def validate(self):
 | 
						|
        """
 | 
						|
        Verify that the value of the BigInteger is valid.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            TypeError: if the value is not of type int or long
 | 
						|
        """
 | 
						|
        if self.value is not None:
 | 
						|
            if not isinstance(self.value, six.integer_types):
 | 
						|
                raise TypeError('expected (one of): {0}, observed: {1}'.format(
 | 
						|
                    six.integer_types, type(self.value)))
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "BigInteger(value={0}, tag={1})".format(self.value, self.tag)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return str(self.value)
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if isinstance(other, BigInteger):
 | 
						|
            if self.value == other.value:
 | 
						|
                return True
 | 
						|
            else:
 | 
						|
                return False
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        if isinstance(other, BigInteger):
 | 
						|
            return not self.__eq__(other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
 | 
						|
class Enumeration(Base):
 | 
						|
    """
 | 
						|
    An encodeable object representing an enumeration.
 | 
						|
 | 
						|
    An Enumeration is one of the KMIP primitive object types. It is encoded as
 | 
						|
    an unsigned, big-endian, 32-bit integer. For more information, see Section
 | 
						|
    9.1 of the KMIP 1.1 specification.
 | 
						|
    """
 | 
						|
    LENGTH = 4
 | 
						|
 | 
						|
    # Bounds for unsigned 32-bit integers
 | 
						|
    MIN = 0
 | 
						|
    MAX = 4294967296
 | 
						|
 | 
						|
    def __init__(self, enum, value=None, tag=enums.Tags.DEFAULT):
 | 
						|
        """
 | 
						|
        Create an Enumeration.
 | 
						|
 | 
						|
        Args:
 | 
						|
            enum (class): The enumeration class of which value is a member
 | 
						|
                (e.g., Tags). Required.
 | 
						|
            value (int): The value of the Enumeration, must be an integer
 | 
						|
                (e.g., Tags.DEFAULT). Optional, defaults to None.
 | 
						|
            tag (Tags): An enumeration defining the tag of the Enumeration.
 | 
						|
                Optional, defaults to Tags.DEFAULT.
 | 
						|
        """
 | 
						|
        super(Enumeration, self).__init__(tag, enums.Types.ENUMERATION)
 | 
						|
 | 
						|
        self.value = value
 | 
						|
        self.enum = enum
 | 
						|
        self.length = Enumeration.LENGTH
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def read(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Read the encoding of the Enumeration from the input stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            istream (stream): A buffer containing the encoded bytes of an
 | 
						|
                Enumeration. Usually a BytearrayStream object. Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be decoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            InvalidPrimitiveLength: if the Enumeration encoding read in has an
 | 
						|
                invalid encoded length.
 | 
						|
            InvalidPaddingBytes: if the Enumeration encoding read in does not
 | 
						|
                use zeroes for its padding bytes.
 | 
						|
        """
 | 
						|
        super(Enumeration, self).read(istream, kmip_version=kmip_version)
 | 
						|
 | 
						|
        # Check for a valid length before even trying to parse the value.
 | 
						|
        if self.length != Enumeration.LENGTH:
 | 
						|
            raise exceptions.InvalidPrimitiveLength(
 | 
						|
                "enumeration length must be {0}".format(Enumeration.LENGTH))
 | 
						|
 | 
						|
        # Decode the Enumeration value and the padding bytes.
 | 
						|
        value = unpack('!I', istream.read(Enumeration.LENGTH))[0]
 | 
						|
        self.value = self.enum(value)
 | 
						|
        pad = unpack('!I', istream.read(Enumeration.LENGTH))[0]
 | 
						|
 | 
						|
        # Verify that the padding bytes are zero bytes.
 | 
						|
        if pad != 0:
 | 
						|
            raise exceptions.InvalidPaddingBytes("padding bytes must be zero")
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Write the encoding of the Enumeration to the output stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            ostream (stream): A buffer to contain the encoded bytes of an
 | 
						|
                Enumeration. Usually a BytearrayStream object. Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be encoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
        """
 | 
						|
        super(Enumeration, self).write(ostream, kmip_version=kmip_version)
 | 
						|
        ostream.write(pack('!I', self.value.value))
 | 
						|
        ostream.write(pack('!I', 0))
 | 
						|
 | 
						|
    def validate(self):
 | 
						|
        """
 | 
						|
        Verify that the value of the Enumeration is valid.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            TypeError: if the enum is not of type Enum
 | 
						|
            ValueError: if the value is not of the expected Enum subtype or if
 | 
						|
                the value cannot be represented by an unsigned 32-bit integer
 | 
						|
        """
 | 
						|
        if not isinstance(self.enum, enumeration.EnumMeta):
 | 
						|
            raise TypeError(
 | 
						|
                'enumeration type {0} must be of type EnumMeta'.format(
 | 
						|
                    self.enum))
 | 
						|
        if self.value is not None:
 | 
						|
            if not isinstance(self.value, self.enum):
 | 
						|
                raise TypeError(
 | 
						|
                    'enumeration {0} must be of type {1}'.format(
 | 
						|
                        self.value, self.enum))
 | 
						|
            if type(self.value.value) not in six.integer_types:
 | 
						|
                raise TypeError('enumeration value must be an int')
 | 
						|
            else:
 | 
						|
                if self.value.value > Enumeration.MAX:
 | 
						|
                    raise ValueError(
 | 
						|
                        'enumeration value greater than accepted max')
 | 
						|
                elif self.value.value < Enumeration.MIN:
 | 
						|
                    raise ValueError(
 | 
						|
                        'enumeration value less than accepted min')
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        enum = "enum={0}".format(self.enum.__name__)
 | 
						|
        value = "value={0}".format(self.value)
 | 
						|
        tag = "tag={0}".format(self.tag)
 | 
						|
        return "Enumeration({0}, {1}, {2})".format(enum, value, tag)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return str(self.value)
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if isinstance(other, Enumeration):
 | 
						|
            return ((self.enum == other.enum) and (self.value == other.value))
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        if isinstance(other, Enumeration):
 | 
						|
            return not self.__eq__(other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
 | 
						|
class Boolean(Base):
 | 
						|
    """
 | 
						|
    An encodeable object representing a boolean value.
 | 
						|
 | 
						|
    A Boolean is one of the KMIP primitive object types. It is encoded as an
 | 
						|
    unsigned, big-endian, 8-byte value, capable of taking the values True (1)
 | 
						|
    or False (0). For more information, see Section 9.1 of the KMIP 1.1
 | 
						|
    specification.
 | 
						|
    """
 | 
						|
    LENGTH = 8
 | 
						|
 | 
						|
    def __init__(self, value=True, tag=enums.Tags.DEFAULT):
 | 
						|
        """
 | 
						|
        Create a Boolean object.
 | 
						|
 | 
						|
        Args:
 | 
						|
            value (bool): The value of the Boolean. Optional, defaults to True.
 | 
						|
            tag (Tags): An enumeration defining the tag of the Boolean object.
 | 
						|
                Optional, defaults to Tags.DEFAULT.
 | 
						|
        """
 | 
						|
        super(Boolean, self).__init__(tag, type=enums.Types.BOOLEAN)
 | 
						|
        self.logger = logging.getLogger(__name__)
 | 
						|
        self.value = value
 | 
						|
        self.length = self.LENGTH
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def read_value(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Read the value of the Boolean object from the input stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            istream (Stream): A buffer containing the encoded bytes of the
 | 
						|
                value of a Boolean object. Usually a BytearrayStream object.
 | 
						|
                Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be decoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            ValueError: if the read boolean value is not a 0 or 1.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            value = unpack('!Q', istream.read(self.LENGTH))[0]
 | 
						|
        except Exception:
 | 
						|
            self.logger.error("Error reading boolean value from buffer")
 | 
						|
            raise
 | 
						|
 | 
						|
        if value == 1:
 | 
						|
            self.value = True
 | 
						|
        elif value == 0:
 | 
						|
            self.value = False
 | 
						|
        else:
 | 
						|
            raise ValueError("expected: 0 or 1, observed: {0}".format(value))
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def read(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Read the encoding of the Boolean object from the input stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            istream (Stream): A buffer containing the encoded bytes of a
 | 
						|
                Boolean object. Usually a BytearrayStream object. Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be decoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
        """
 | 
						|
        super(Boolean, self).read(istream, kmip_version=kmip_version)
 | 
						|
        self.read_value(istream, kmip_version=kmip_version)
 | 
						|
 | 
						|
    def write_value(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Write the value of the Boolean object to the output stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            ostream (Stream): A buffer to contain the encoded bytes of the
 | 
						|
                value of a Boolean object. Usually a BytearrayStream object.
 | 
						|
                Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be encoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
        """
 | 
						|
        try:
 | 
						|
            ostream.write(pack('!Q', self.value))
 | 
						|
        except Exception:
 | 
						|
            self.logger.error("Error writing boolean value to buffer")
 | 
						|
            raise
 | 
						|
 | 
						|
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Write the encoding of the Boolean object to the output stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            ostream (Stream): A buffer to contain the encoded bytes of a
 | 
						|
                Boolean object. Usually a BytearrayStream object. Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be encoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
        """
 | 
						|
        super(Boolean, self).write(ostream, kmip_version=kmip_version)
 | 
						|
        self.write_value(ostream, kmip_version=kmip_version)
 | 
						|
 | 
						|
    def validate(self):
 | 
						|
        """
 | 
						|
        Verify that the value of the Boolean object is valid.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            TypeError: if the value is not of type bool.
 | 
						|
        """
 | 
						|
        if self.value:
 | 
						|
            if not isinstance(self.value, bool):
 | 
						|
                raise TypeError("expected: {0}, observed: {1}".format(
 | 
						|
                    bool, type(self.value)))
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "{0}(value={1})".format(type(self).__name__, repr(self.value))
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "{0}".format(repr(self.value))
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if isinstance(other, Boolean):
 | 
						|
            return self.value == other.value
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        if isinstance(other, Boolean):
 | 
						|
            return not self.__eq__(other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
 | 
						|
class TextString(Base):
 | 
						|
    PADDING_SIZE = 8
 | 
						|
    BYTE_FORMAT = '!c'
 | 
						|
 | 
						|
    def __init__(self, value=None, tag=enums.Tags.DEFAULT):
 | 
						|
        super(TextString, self).__init__(tag, type=enums.Types.TEXT_STRING)
 | 
						|
 | 
						|
        if value is None:
 | 
						|
            self.value = ''
 | 
						|
        else:
 | 
						|
            self.value = value
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
        if self.value is not None:
 | 
						|
            self.length = len(self.value)
 | 
						|
            self.padding_length = self.PADDING_SIZE - (self.length %
 | 
						|
                                                       self.PADDING_SIZE)
 | 
						|
            if self.padding_length == self.PADDING_SIZE:
 | 
						|
                self.padding_length = 0
 | 
						|
        else:
 | 
						|
            self.length = None
 | 
						|
            self.padding_length = None
 | 
						|
 | 
						|
    def read_value(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        # Read string text
 | 
						|
        self.value = ''
 | 
						|
        for _ in range(self.length):
 | 
						|
            c = unpack(self.BYTE_FORMAT, istream.read(1))[0]
 | 
						|
            if sys.version >= '3':
 | 
						|
                c = c.decode()
 | 
						|
            self.value += c
 | 
						|
 | 
						|
        # Read padding and check content
 | 
						|
        self.padding_length = self.PADDING_SIZE - (self.length %
 | 
						|
                                                   self.PADDING_SIZE)
 | 
						|
        if self.padding_length < self.PADDING_SIZE:
 | 
						|
            for _ in range(self.padding_length):
 | 
						|
                pad = unpack('!B', istream.read(1))[0]
 | 
						|
                if pad != 0:
 | 
						|
                    raise exceptions.ReadValueError(
 | 
						|
                        TextString.__name__,
 | 
						|
                        'pad',
 | 
						|
                        0,
 | 
						|
                        pad
 | 
						|
                    )
 | 
						|
 | 
						|
    def read(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        super(TextString, self).read(istream, kmip_version=kmip_version)
 | 
						|
        self.read_value(istream, kmip_version=kmip_version)
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def write_value(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        # Write string to stream
 | 
						|
        for char in self.value:
 | 
						|
            ostream.write(pack(self.BYTE_FORMAT, char.encode()))
 | 
						|
 | 
						|
        # Write padding to stream
 | 
						|
        for _ in range(self.padding_length):
 | 
						|
            ostream.write(pack('!B', 0))
 | 
						|
 | 
						|
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        super(TextString, self).write(ostream, kmip_version=kmip_version)
 | 
						|
        self.write_value(ostream, kmip_version=kmip_version)
 | 
						|
 | 
						|
    def validate(self):
 | 
						|
        self.__validate()
 | 
						|
 | 
						|
    def __validate(self):
 | 
						|
        if self.value is not None:
 | 
						|
            if not isinstance(self.value, six.string_types):
 | 
						|
                msg = exceptions.ErrorStrings.BAD_EXP_RECV
 | 
						|
                raise TypeError(msg.format('TextString', 'value', str,
 | 
						|
                                           type(self.value)))
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "{0}(value={1})".format(type(self).__name__, repr(self.value))
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "{0}".format(str(self.value))
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if isinstance(other, TextString):
 | 
						|
            return self.value == other.value
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        if isinstance(other, TextString):
 | 
						|
            return not (self == other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
 | 
						|
class ByteString(Base):
 | 
						|
    PADDING_SIZE = 8
 | 
						|
    BYTE_FORMAT = '!B'
 | 
						|
 | 
						|
    def __init__(self, value=None, tag=enums.Tags.DEFAULT):
 | 
						|
        super(ByteString, self).__init__(tag, type=enums.Types.BYTE_STRING)
 | 
						|
 | 
						|
        if value is None:
 | 
						|
            self.value = bytes()
 | 
						|
        else:
 | 
						|
            self.value = bytes(value)
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
        if self.value is not None:
 | 
						|
            self.length = len(self.value)
 | 
						|
            self.padding_length = self.PADDING_SIZE - (self.length %
 | 
						|
                                                       self.PADDING_SIZE)
 | 
						|
            if self.padding_length == self.PADDING_SIZE:
 | 
						|
                self.padding_length = 0
 | 
						|
        else:
 | 
						|
            self.length = None
 | 
						|
            self.padding_length = None
 | 
						|
 | 
						|
    def read_value(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        # Read bytes into bytearray
 | 
						|
        data = bytearray()
 | 
						|
        for _ in range(self.length):
 | 
						|
            data.append(istream.read(1)[0])
 | 
						|
        self.value = bytes(data)
 | 
						|
 | 
						|
        # Read padding and check content
 | 
						|
        self.padding_length = self.PADDING_SIZE - (self.length %
 | 
						|
                                                   self.PADDING_SIZE)
 | 
						|
        if self.padding_length == self.PADDING_SIZE:
 | 
						|
            self.padding_length = 0
 | 
						|
 | 
						|
        if self.padding_length < self.PADDING_SIZE:
 | 
						|
            for _ in range(self.padding_length):
 | 
						|
                pad = unpack('!B', istream.read(1))[0]
 | 
						|
                if pad != 0:
 | 
						|
                    raise exceptions.ReadValueError(
 | 
						|
                        TextString.__name__,
 | 
						|
                        'pad',
 | 
						|
                        0,
 | 
						|
                        pad
 | 
						|
                    )
 | 
						|
 | 
						|
    def read(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        super(ByteString, self).read(istream, kmip_version=kmip_version)
 | 
						|
        self.read_value(istream, kmip_version=kmip_version)
 | 
						|
 | 
						|
    def write_value(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        # Write bytes to stream
 | 
						|
        data = bytearray(self.value)
 | 
						|
        for byte in data:
 | 
						|
            ostream.write(pack(self.BYTE_FORMAT, byte))
 | 
						|
 | 
						|
        # Write padding to stream
 | 
						|
        for _ in range(self.padding_length):
 | 
						|
            ostream.write(pack('!B', 0))
 | 
						|
 | 
						|
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        super(ByteString, self).write(ostream, kmip_version=kmip_version)
 | 
						|
        self.write_value(ostream, kmip_version=kmip_version)
 | 
						|
 | 
						|
    def validate(self):
 | 
						|
        self.__validate()
 | 
						|
 | 
						|
    def __validate(self):
 | 
						|
        # TODO (peter-hamilton) Test is pointless, value is always bytes. Fix.
 | 
						|
        if self.value is not None:
 | 
						|
            data_type = type(self.value)
 | 
						|
            if data_type is not bytes:
 | 
						|
                msg = exceptions.ErrorStrings.BAD_EXP_RECV
 | 
						|
                raise TypeError(msg.format('ByteString', 'value', bytes,
 | 
						|
                                           data_type))
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "{0}(value={1})".format(type(self).__name__, repr(self.value))
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "{0}".format(str(self.value))
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if isinstance(other, ByteString):
 | 
						|
            return self.value == other.value
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        if isinstance(other, ByteString):
 | 
						|
            return not (self == other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
 | 
						|
class DateTime(LongInteger):
 | 
						|
    """
 | 
						|
    An encodeable object representing a date/time value.
 | 
						|
 | 
						|
    A DateTime is one of the KMIP primitive object types. It is encoded as
 | 
						|
    a signed, big-endian, 64-bit integer, representing a POSIX time value as
 | 
						|
    the number of seconds since the Epoch (1970 January 1, 00:00:00 UTC). For
 | 
						|
    more information, see Section 9.1 of the KMIP 1.1 specification.
 | 
						|
    """
 | 
						|
 | 
						|
    def __init__(self, value=None, tag=enums.Tags.DEFAULT):
 | 
						|
        """
 | 
						|
        Create a DateTime.
 | 
						|
 | 
						|
        Args:
 | 
						|
            value (int): The value of the DateTime in number of seconds since
 | 
						|
                the Epoch. See the time package for additional information.
 | 
						|
                Optional, defaults to the current time.
 | 
						|
            tag (Tags): An enumeration defining the tag of the LongInteger.
 | 
						|
                Optional, defaults to Tags.DEFAULT.
 | 
						|
        """
 | 
						|
        if value is None:
 | 
						|
            value = int(time.time())
 | 
						|
        super(DateTime, self).__init__(value, tag)
 | 
						|
        self.type = enums.Types.DATE_TIME
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "DateTime(value={0}, tag={1})".format(self.value, self.tag)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return time.asctime(time.gmtime(self.value))
 | 
						|
 | 
						|
 | 
						|
class Interval(Base):
 | 
						|
    """
 | 
						|
    An encodeable object representing an interval of time.
 | 
						|
 | 
						|
    An Interval is one of the KMIP primitive object types. It is encoded as
 | 
						|
    an unsigned, big-endian, 32-bit integer, where the value has a resolution
 | 
						|
    of one second. For more information, see Section 9.1 of the KMIP 1.1
 | 
						|
    specification.
 | 
						|
    """
 | 
						|
    LENGTH = 4
 | 
						|
 | 
						|
    # Bounds for unsigned 32-bit integers
 | 
						|
    MIN = 0
 | 
						|
    MAX = 4294967296
 | 
						|
 | 
						|
    def __init__(self, value=0, tag=enums.Tags.DEFAULT):
 | 
						|
        super(Interval, self).__init__(tag, type=enums.Types.INTERVAL)
 | 
						|
 | 
						|
        self.value = value
 | 
						|
        self.length = Interval.LENGTH
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def read(self, istream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Read the encoding of the Interval from the input stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            istream (stream): A buffer containing the encoded bytes of the
 | 
						|
                value of an Interval. Usually a BytearrayStream object.
 | 
						|
                Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be decoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            InvalidPrimitiveLength: if the Interval encoding read in has an
 | 
						|
                invalid encoded length.
 | 
						|
            InvalidPaddingBytes: if the Interval encoding read in does not use
 | 
						|
                zeroes for its padding bytes.
 | 
						|
        """
 | 
						|
        super(Interval, self).read(istream, kmip_version=kmip_version)
 | 
						|
 | 
						|
        # Check for a valid length before even trying to parse the value.
 | 
						|
        if self.length != Interval.LENGTH:
 | 
						|
            raise exceptions.InvalidPrimitiveLength(
 | 
						|
                "interval length must be {0}".format(Interval.LENGTH))
 | 
						|
 | 
						|
        # Decode the Interval value and the padding bytes.
 | 
						|
        self.value = unpack('!I', istream.read(Interval.LENGTH))[0]
 | 
						|
        pad = unpack('!I', istream.read(Interval.LENGTH))[0]
 | 
						|
 | 
						|
        # Verify that the padding bytes are zero bytes.
 | 
						|
        if pad != 0:
 | 
						|
            raise exceptions.InvalidPaddingBytes("padding bytes must be zero")
 | 
						|
 | 
						|
        self.validate()
 | 
						|
 | 
						|
    def write(self, ostream, kmip_version=enums.KMIPVersion.KMIP_1_0):
 | 
						|
        """
 | 
						|
        Write the encoding of the Interval to the output stream.
 | 
						|
 | 
						|
        Args:
 | 
						|
            ostream (stream): A buffer to contain the encoded bytes of an
 | 
						|
                Interval. Usually a BytearrayStream object. Required.
 | 
						|
            kmip_version (KMIPVersion): An enumeration defining the KMIP
 | 
						|
                version with which the object will be encoded. Optional,
 | 
						|
                defaults to KMIP 1.0.
 | 
						|
        """
 | 
						|
        super(Interval, self).write(ostream, kmip_version=kmip_version)
 | 
						|
        ostream.write(pack('!I', self.value))
 | 
						|
        ostream.write(pack('!I', 0))
 | 
						|
 | 
						|
    def validate(self):
 | 
						|
        """
 | 
						|
        Verify that the value of the Interval is valid.
 | 
						|
 | 
						|
        Raises:
 | 
						|
            TypeError: if the value is not of type int or long
 | 
						|
            ValueError: if the value cannot be represented by an unsigned
 | 
						|
                32-bit integer
 | 
						|
        """
 | 
						|
        if self.value is not None:
 | 
						|
            if type(self.value) not in six.integer_types:
 | 
						|
                raise TypeError('expected (one of): {0}, observed: {1}'.format(
 | 
						|
                    six.integer_types, type(self.value)))
 | 
						|
            else:
 | 
						|
                if self.value > Interval.MAX:
 | 
						|
                    raise ValueError(
 | 
						|
                        'interval value greater than accepted max')
 | 
						|
                elif self.value < Interval.MIN:
 | 
						|
                    raise ValueError('interval value less than accepted min')
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        value = "value={0}".format(self.value)
 | 
						|
        tag = "tag={0}".format(self.tag)
 | 
						|
        return "Interval({0}, {1})".format(value, tag)
 | 
						|
 | 
						|
    def __str__(self):
 | 
						|
        return "{0}".format(self.value)
 | 
						|
 | 
						|
    def __eq__(self, other):
 | 
						|
        if isinstance(other, Interval):
 | 
						|
            return self.value == other.value
 | 
						|
        else:
 | 
						|
            return NotImplemented
 | 
						|
 | 
						|
    def __ne__(self, other):
 | 
						|
        if isinstance(other, Interval):
 | 
						|
            return not self.__eq__(other)
 | 
						|
        else:
 | 
						|
            return NotImplemented
 |