class ComponentProperty(object):
    def __init__(self, data=None):
        if (data):
            self._from_rsp_data(data)

    @staticmethod
    def from_data(component_id, data):
        if isinstance(data, str):
            data = [ord(c) for c in data]

        if component_id is PROPERTY_GENERAL_PROPERTIES:
            return ComponentPropertyGeneral(data)
        elif component_id is PROPERTY_CURRENT_VERSION:
            return ComponentPropertyCurrentVersion(data)
        elif component_id is PROPERTY_DESCRIPTION_STRING:
            return ComponentPropertyDescriptionString(data)
        elif component_id is PROPERTY_ROLLBACK_VERSION:
            return ComponentPropertyRollbackVersion(data)
        elif component_id is PROPERTY_DEFERRED_VERSION:
            return ComponentPropertyDeferredVersion(data)
        elif component_id in PROPERTY_OEM:
            raise NotImplementedError class ComponentPropertyDescriptionString(ComponentProperty):

    def _from_rsp_data(self, data):
        descr = py3_array_tobytes(array('B', data))
        descr = py3dec_unic_bytes_fix(descr)
        # strip '\x00'
        descr = descr.replace('\0', '')
        self.description = descr class ComponentPropertyGeneral(ComponentProperty):

    ROLLBACK_SUPPORT_MASK = 0x03
    PREPARATION_SUPPORT_MASK = 0x04
    COMPARISON_SUPPORT_MASK = 0x08
    DEFERRED_ACTIVATION_SUPPORT_MASK = 0x10
    PAYLOAD_COLD_RESET_REQ_SUPPORT_MASK = 0x20

    def _from_rsp_data(self, data):
        support = []
        cap = data[0]

        if cap & self.ROLLBACK_SUPPORT_MASK == 0:
            support.append('rollback_backup_not_supported')
        elif cap & self.ROLLBACK_SUPPORT_MASK == 1:
            support.append('rollback_is_supported')
        elif cap & self.ROLLBACK_SUPPORT_MASK == 2:
            support.append('rollback_is_supported')
        elif cap & self.ROLLBACK_SUPPORT_MASK == 3:
            support.append('reserved')

        if cap & self.PREPARATION_SUPPORT_MASK:
            support.append('prepartion')
        if cap & self.COMPARISON_SUPPORT_MASK:
            support.append('comparison')
        if cap & self.DEFERRED_ACTIVATION_SUPPORT_MASK:
            support.append('deferred_activation')
        if cap & self.PAYLOAD_COLD_RESET_REQ_SUPPORT_MASK:
            support.append('payload_cold_reset_required')

        self.general = support class ComponentPropertyCurrentVersion(ComponentProperty):

    def _from_rsp_data(self, data):
        self.version = VersionField(data) class ComponentPropertyDeferredVersion(ComponentProperty):

    def _from_rsp_data(self, data):
        self.version = VersionField(data) class ComponentPropertyRollbackVersion(ComponentProperty):

    def _from_rsp_data(self, data):
        self.version = VersionField(data) class UpgradeActionRecord(object):

    ACTIONS = (
        "Backup",
        "Prepare",
        "Upload for Upgrade",
        "Upload for Compare"
    )

    def __init__(self, data=None):
        self.action_type = array('B', data)[0]
        if data:
            (self.action, self.components, self.checksum) \
                = struct.unpack('BBB', data[0:3])
            self.length = 3

    @staticmethod
    def create_from_data(data):
        action_type = array('B', data)[0]
        if action_type == ACTION_BACKUP_COMPONENT:
            return UpgradeActionRecordBackup(data)
        elif action_type == ACTION_PREPARE_COMPONENT:
            return UpgradeActionRecordPrepare(data)
        elif action_type == ACTION_UPLOAD_FOR_UPGRADE:
            return UpgradeActionRecordUploadForUpgrade(data)
        elif action_type == ACTION_UPLOAD_FOR_COMPARE:
            return UpgradeActionRecordUploadForCompare(data)
        else:
            raise HpmError('unsupported ActionRecord')

    def __str__(self):
        str = []
        str.append("Action Record Type: 0x%x (%s) " %
                   (self.action, self.ACTIONS[self.action]))
        str.append(" Components: 0x%02x" % self.components)
        return "\n".join(str) class UpgradeActionRecordBackup(UpgradeActionRecord):
    pass class UpgradeActionRecordPrepare(UpgradeActionRecord):
    pass class UpgradeActionRecordUploadForUpgrade(UpgradeActionRecord):
    def __init__(self, data=None):
        UpgradeActionRecord.__init__(self, data)
        if data:
            self.firmware_version = \
                VersionField(
                    data[3:3 + VersionField.VERSION_WITH_AUX_FIELD_LEN])
            self.firmware_description_string \
                = py3dec_unic_bytes_fix(data[9:30])
            self.firmware_length = struct.unpack('<L', data[30:34])[0]
            self.firmware_image_data = data[34:(34 + self.firmware_length)]
            self.length += 31 + self.firmware_length class UpgradeActionRecordUploadForCompare(UpgradeActionRecord):
    pass class UpgradeImage(object):
    def __init__(self, filename=None):
        self.actions = None

        if filename:
            self._from_file(filename)

    def __str__(self):
        str = []
        return "\n".join(str)

    def _check_md5_sum(self, filedata):
        summer = hashlib.md5()
        self.checksum_actual \
            = summer.update(filedata[:-HPM_IMAGE_CHECKSUM_SIZE])
        self.checksum_expected = filedata[-HPM_IMAGE_CHECKSUM_SIZE:]

    def _from_file(self, filename):

        try:
            file = open(filename, "rb")
        except IOError:
            print('Error open file "%s"' % filename)

        ################################
        # get file size
        file_size = os.stat(filename).st_size
        file_data = file.read(file_size)

        ################################
        # get image checksum
        self._check_md5_sum(file_data)
        # XXX verify checksum

        ################################
        # Upgrade Image Header
        self.header = UpgradeImageHeaderRecord(file_data)
        off = self.header.length

        ################################
        # Upgrade Actions
        self.actions = []
        while (off + HPM_IMAGE_CHECKSUM_SIZE) < len(file_data):
            action = UpgradeActionRecord.create_from_data(file_data[off:])
            self.actions.append(action)
            off += action.length

        ################################
        # Image checksum
        self.checksum = ImageChecksumRecord(file_data[off:file_size])

        file.close() PROPERTY_GENERAL_PROPERTIES = 0 PROPERTY_CURRENT_VERSION = 1 PROPERTY_DESCRIPTION_STRING = 2 PROPERTY_ROLLBACK_VERSION = 3 PROPERTY_DEFERRED_VERSION = 4
import os
import nose
from nose.tools import eq_, ok_
from pyipmi.hpm import (ComponentProperty, ComponentPropertyDescriptionString,
                        ComponentPropertyGeneral,
                        ComponentPropertyCurrentVersion,
                        ComponentPropertyDeferredVersion,
                        ComponentPropertyRollbackVersion,
                        UpgradeActionRecord, UpgradeActionRecordBackup,
                        UpgradeActionRecordPrepare,
                        UpgradeActionRecordUploadForUpgrade,
                        UpgradeActionRecordUploadForCompare, UpgradeImage,
                        PROPERTY_GENERAL_PROPERTIES, PROPERTY_CURRENT_VERSION,
                        PROPERTY_DESCRIPTION_STRING, PROPERTY_ROLLBACK_VERSION,
                        PROPERTY_DEFERRED_VERSION)
#!/usr/bin/env python
# -*- coding: utf-8 -*-





class TestComponentProperty(object):
    def test_general(self):
        prop = ComponentProperty().from_data(PROPERTY_GENERAL_PROPERTIES, b'\xaa')

        eq_(type(prop), ComponentPropertyGeneral)