<commit_before>/*
 * Copyright (c) 2015 Intel Corporation.  All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library 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
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "BleCharacteristic.h"

#include "internal/ble_client.h"

#define BLE_CCCD_DESCRIPTOR_UUID 0x2092

#define BLE_CCCD_NOTIFY_EN_MASK   0x1
#define BLE_CCCD_INDICATE_EN_MASK 0x2

/* Each characteristic has a Client Characteristic Configuration Descriptor (CCCD)
 * This callback is invoked whenever the CCCD for a given characteristic is updated
 * by a remote client to enable/disable receipt of notifications/indications
 */
void
_cccdEventHandler(BleDescriptor &cccd, BleDescriptorEvent event, void *arg)
{
    if (BLE_DESC_EVENT_WRITE == event) {
        BleStatus status;
        uint16_t cccdVal;
        BleCharacteristic *ch = (BleCharacteristic *)arg;

        status = cccd.getValue(cccdVal);
        if (BLE_STATUS_SUCCESS != status)
            return;

        ch->_notifyEnabled = (cccdVal & BLE_CCCD_NOTIFY_EN_MASK) ? true : false;
        ch->_indicateEnabled = (cccdVal & BLE_CCCD_INDICATE_EN_MASK) ? true : false;
    }
}

BleCharacteristic::BleCharacteristic(const uint16_t maxLength,
                                     const BleClientAccessMode clientAccess,
                                     const BleClientNotifyMode clientNotify)
    : _cccd(BLE_CCCD_DESCRIPTOR_UUID, sizeof(uint16_t), BLE_CLIENT_ACCESS_READ_WRITE)
{
    _initialised = false;
    _connected = false;
    _notifyEnabled = false;
    _indicateEnabled = false;

    _data_len = 0;
    _data[0] = 0;

    _clientAccess = clientAccess;
    _clientNotify = clientNotify;

    memset(&_char_data, 0, sizeof(_char_data));

    _char_data.p_uuid = &_uuid;

    if ((_clientAccess == BLE_CLIENT_ACCESS_READ_ONLY) ||
        (_clientAccess == BLE_CLIENT_ACCESS_READ_WRITE)) {
        _char_data.perms.rd = GAP_SEC_MODE_1 | GAP_SEC_LEVEL_1;
        _char_data.props.props |= BLE_GATT_CHAR_PROP_BIT_READ;

        /* Enable notifications only if characteristic is also readable by client */
        if (_clientNotify == BLE_CLIENT_NOTIFY_ENABLED)
            _char_data.props.props |= BLE_GATT_CHAR_PROP_BIT_NOTIFY;
        else if (_clientNotify == BLE_CLIENT_NOTIFY_WITH_ACK)
            _char_data.props.props |= BLE_GATT_CHAR_PROP_BIT_INDICATE;
    }
    else {
        _char_data.perms.rd = GAP_SEC_NO_PERMISSION;
    }

    if ((_clientAccess == BLE_CLIENT_ACCESS_WRITE_ONLY) ||
        (_clientAccess == BLE_CLIENT_ACCESS_READ_WRITE)) {
        _char_data.perms.wr = GAP_SEC_MODE_1 | GAP_SEC_LEVEL_1;
        _char_data.props.props |= (BLE_GATT_CHAR_PROP_BIT_WRITE | BLE_GATT_CHAR_PROP_BIT_WRITE_NR);
    }
    else {
        _char_data.perms.wr = GAP_SEC_NO_PERMISSION;
    }

    _char_data.init_len = _data_len;
    _char_data.max_len = maxLength > BLE_MAX_ATTR_DATA_LEN ? BLE_MAX_ATTR_DATA_LEN : maxLength;
    _char_data.p_value = _data;
}

BleCharacteristic::BleCharacteristic(const uint16_t uuid16,
                                     const uint16_t maxLength,
                                     const BleClientAccessMode clientAccess,
                                     const BleClientNotifyMode clientNotify)
    : BleCharacteristic(maxLength, clientAccess, clientNotify)
{
    _uuid.type = BT_UUID16;
    _uuid.uuid16 = uuid16;
}

BleCharacteristic::BleCharacteristic(const uint8_t uuid128[],
                                     const uint16_t maxLength,
                                     const BleClientAccessMode clientAccess,
                                     const BleClientNotifyMode clientNotify)
    : BleCharacteristic(maxLength, clientAccess, clientNotify)
{
    _uuid.type = BT_UUID128;
    memcpy(&_uuid.uuid128, uuid128, MAX_UUID_SIZE);
}

BleStatus
BleCharacteristic::addUserDescription(const char *description)
{
    if (_initialised)
        return BLE_STATUS_WRONG_STATE;

    if (description && description[0]) {
        _user_desc.len = strlen(description);
        if (_user_desc.len > sizeof(_user_desc_data))
            _user_desc.len = sizeof(_user_desc_data);
        memset(_user_desc_data, 0, sizeof(_user_desc_data));
        memcpy(_user_desc_data, description, _user_desc.len);
        _user_desc.buffer = _user_desc_data;

        _char_data.p_user_desc = &_user_desc;
    }

    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::addPresentationFormat(const uint8_t  format,
                                         const int8_t   exponent,
                                         const uint16_t unit,
                                         const uint8_t  nameSpace,
                                         const uint16_t description)
{
    if (_initialised)
        return BLE_STATUS_WRONG_STATE;

    _pf_desc.format = format;
    _pf_desc.exp = exponent;
    _pf_desc.unit = unit;
    _pf_desc.name_spc = nameSpace;
    _pf_desc.descr = description;

    _char_data.p_char_pf_desc = &_pf_desc;

    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::_setValue(void)
{
    BleStatus status;

    if (!_initialised)
        return BLE_STATUS_WRONG_STATE;

    if ((_data_len > BLE_MAX_ATTR_DATA_LEN) && (_data_len > _char_data.max_len))
        return BLE_STATUS_NOT_ALLOWED;

    status = ble_client_gatts_set_attribute_value(_handles.value_handle,
                                                  _data_len, _data, 0);
    if (BLE_STATUS_SUCCESS != status)
        return status;

    if (_notifyEnabled || _indicateEnabled) {
        status = ble_client_gatts_send_notif_ind(_handles.value_handle, _data_len, _data, 0, _indicateEnabled);
        if (BLE_STATUS_SUCCESS != status)
            return status;

        if (_indicateEnabled && _event_cb)
            _event_cb(*this, BLE_CHAR_EVENT_INDICATION_ACK, _event_cb_arg);
    }

    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::setValue(const uint8_t value[], const uint16_t length)
{
    if (!value)
        return BLE_STATUS_NOT_ALLOWED;
    if (length > _char_data.max_len)
        return BLE_STATUS_NOT_ALLOWED;

    /* Cache the value locally */
    memcpy(_data, value, length);
    _data_len = length;

    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const String &str)
{
    str.getBytes((unsigned char *)&_data, (unsigned int)_char_data.max_len, 0U);
    _data_len = str.length() + 1;
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const char *cstr)
{
    return setValue((uint8_t *)cstr, (uint16_t) (strlen(cstr) + 1));
}

BleStatus
BleCharacteristic::setValue(const char &value)
{
    uint8_t *p = _data;
    INT8_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const unsigned char &value)
{
    uint8_t *p = _data;
    UINT8_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const short &value)
{
    uint8_t *p = _data;
    INT16_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const unsigned short &value)
{
    uint8_t *p = _data;
    UINT16_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const int &value)
{
    uint8_t *p = _data;
    INT32_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const unsigned int &value)
{
    uint8_t *p = _data;
    UINT32_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const long &value)
{
    uint8_t *p = _data;
    INT32_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const unsigned long &value)
{
    uint8_t *p = _data;
    UINT32_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::getValue(uint8_t value[], uint16_t &length) const
{
    if (!_initialised)
        return BLE_STATUS_WRONG_STATE;

    memcpy(value, _data, _data_len);
    length = _data_len;

    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(String &str) const
{
    str = (char *)_data;
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(char *cstr) const
{
    memcpy(cstr, _data, _data_len);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(char &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_INT8(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(unsigned char &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_UINT8(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(short &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_INT16(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(unsigned short &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_UINT16(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(int &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_INT32(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(unsigned int &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_UINT32(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(long &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_INT32(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(unsigned long &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_UINT32(p, value);
    return BLE_STATUS_SUCCESS;
}

void
BleCharacteristic::setEventCallback(BleCharacteristicEventCb callback,
                                    void *arg)
{
    noInterrupts();
    _event_cb = callback; /* callback disabled if NULL */
    _event_cb_arg = arg;
    interrupts();
}

BleStatus
BleCharacteristic::addDescriptor(BleDescriptor &descriptor)
{
    BleStatus status;

    if (!_initialised)
        return BLE_STATUS_WRONG_STATE;
    if (_num_descriptors >= BLE_MAX_DESCRIPTORS)
        return BLE_STATUS_ERROR;

    /* If this service has a 128-bit UUID, it shall be inherited
     * by included services, characteristics, and descriptors
     */
    if ((BT_UUID128 == _uuid.type) && (BT_UUID16 == descriptor._uuid.type))
        BLE_UUID16_TO_UUID128(descriptor._uuid, _uuid);

    status = ble_client_gatts_add_descriptor(_svc_handle,
                                             &descriptor._desc,
                                             &descriptor._handle);
    if (BLE_STATUS_SUCCESS == status) {
        descriptor._initialised = true;
        _descriptors[_num_descriptors++] = &descriptor;
    }

    return status;
}

BleDescriptor *
BleCharacteristic::_matchDescriptor(uint16_t handle) const
{
    for (unsigned i = 0; i < _num_descriptors; i++) {
        BleDescriptor *desc = _descriptors[i];
        if (handle == desc->_handle)
            return desc;
    }

    return NULL;
}

void
BleCharacteristic::_addCCCDescriptor(void)
{
    /* Activate our CCCD descriptor object */
    _cccd._handle = _handles.cccd_handle;
    _cccd._initialised = true;
    _cccd.setEventCallback(_cccdEventHandler, (void *)this);
    _descriptors[_num_descriptors++] = &_cccd;
}

void
BleCharacteristic::_setConnectedState(boolean_t connected)
{
    _connected = connected;

    /* Reset the state of these internal variables when connection is dropped */
    if (!connected) {
        _notifyEnabled = false;
        _indicateEnabled = false;
    }

    /* Cascade the connected-state update to descriptors */
    for (unsigned i = 0; i < _num_descriptors; i++)
        _descriptors[i]->_setConnectedState(connected);
}
<commit_msg>Fix Klocwork#2051,2060: Array may be outside index<commit_after>/*
 * Copyright (c) 2015 Intel Corporation.  All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library 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
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "BleCharacteristic.h"

#include "internal/ble_client.h"

#define BLE_CCCD_DESCRIPTOR_UUID 0x2092

#define BLE_CCCD_NOTIFY_EN_MASK   0x1
#define BLE_CCCD_INDICATE_EN_MASK 0x2

/* Each characteristic has a Client Characteristic Configuration Descriptor (CCCD)
 * This callback is invoked whenever the CCCD for a given characteristic is updated
 * by a remote client to enable/disable receipt of notifications/indications
 */
void
_cccdEventHandler(BleDescriptor &cccd, BleDescriptorEvent event, void *arg)
{
    if (BLE_DESC_EVENT_WRITE == event) {
        BleStatus status;
        uint16_t cccdVal;
        BleCharacteristic *ch = (BleCharacteristic *)arg;

        status = cccd.getValue(cccdVal);
        if (BLE_STATUS_SUCCESS != status)
            return;

        ch->_notifyEnabled = (cccdVal & BLE_CCCD_NOTIFY_EN_MASK) ? true : false;
        ch->_indicateEnabled = (cccdVal & BLE_CCCD_INDICATE_EN_MASK) ? true : false;
    }
}

BleCharacteristic::BleCharacteristic(const uint16_t maxLength,
                                     const BleClientAccessMode clientAccess,
                                     const BleClientNotifyMode clientNotify)
    : _cccd(BLE_CCCD_DESCRIPTOR_UUID, sizeof(uint16_t), BLE_CLIENT_ACCESS_READ_WRITE)
{
    _initialised = false;
    _connected = false;
    _notifyEnabled = false;
    _indicateEnabled = false;

    _data_len = 0;
    _data[0] = 0;

    _clientAccess = clientAccess;
    _clientNotify = clientNotify;

    memset(&_char_data, 0, sizeof(_char_data));

    _char_data.p_uuid = &_uuid;

    if ((_clientAccess == BLE_CLIENT_ACCESS_READ_ONLY) ||
        (_clientAccess == BLE_CLIENT_ACCESS_READ_WRITE)) {
        _char_data.perms.rd = GAP_SEC_MODE_1 | GAP_SEC_LEVEL_1;
        _char_data.props.props |= BLE_GATT_CHAR_PROP_BIT_READ;

        /* Enable notifications only if characteristic is also readable by client */
        if (_clientNotify == BLE_CLIENT_NOTIFY_ENABLED)
            _char_data.props.props |= BLE_GATT_CHAR_PROP_BIT_NOTIFY;
        else if (_clientNotify == BLE_CLIENT_NOTIFY_WITH_ACK)
            _char_data.props.props |= BLE_GATT_CHAR_PROP_BIT_INDICATE;
    }
    else {
        _char_data.perms.rd = GAP_SEC_NO_PERMISSION;
    }

    if ((_clientAccess == BLE_CLIENT_ACCESS_WRITE_ONLY) ||
        (_clientAccess == BLE_CLIENT_ACCESS_READ_WRITE)) {
        _char_data.perms.wr = GAP_SEC_MODE_1 | GAP_SEC_LEVEL_1;
        _char_data.props.props |= (BLE_GATT_CHAR_PROP_BIT_WRITE | BLE_GATT_CHAR_PROP_BIT_WRITE_NR);
    }
    else {
        _char_data.perms.wr = GAP_SEC_NO_PERMISSION;
    }

    _char_data.init_len = _data_len;
    _char_data.max_len = maxLength > BLE_MAX_ATTR_DATA_LEN ? BLE_MAX_ATTR_DATA_LEN : maxLength;
    _char_data.p_value = _data;
}

BleCharacteristic::BleCharacteristic(const uint16_t uuid16,
                                     const uint16_t maxLength,
                                     const BleClientAccessMode clientAccess,
                                     const BleClientNotifyMode clientNotify)
    : BleCharacteristic(maxLength, clientAccess, clientNotify)
{
    _uuid.type = BT_UUID16;
    _uuid.uuid16 = uuid16;
}

BleCharacteristic::BleCharacteristic(const uint8_t uuid128[],
                                     const uint16_t maxLength,
                                     const BleClientAccessMode clientAccess,
                                     const BleClientNotifyMode clientNotify)
    : BleCharacteristic(maxLength, clientAccess, clientNotify)
{
    _uuid.type = BT_UUID128;
    memcpy(&_uuid.uuid128, uuid128, MAX_UUID_SIZE);
}

BleStatus
BleCharacteristic::addUserDescription(const char *description)
{
    if (_initialised)
        return BLE_STATUS_WRONG_STATE;

    if (description && description[0]) {
        _user_desc.len = strlen(description);
        if (_user_desc.len > sizeof(_user_desc_data))
            _user_desc.len = sizeof(_user_desc_data);
        memset(_user_desc_data, 0, sizeof(_user_desc_data));
        memcpy(_user_desc_data, description, _user_desc.len);
        _user_desc.buffer = _user_desc_data;

        _char_data.p_user_desc = &_user_desc;
    }

    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::addPresentationFormat(const uint8_t  format,
                                         const int8_t   exponent,
                                         const uint16_t unit,
                                         const uint8_t  nameSpace,
                                         const uint16_t description)
{
    if (_initialised)
        return BLE_STATUS_WRONG_STATE;

    _pf_desc.format = format;
    _pf_desc.exp = exponent;
    _pf_desc.unit = unit;
    _pf_desc.name_spc = nameSpace;
    _pf_desc.descr = description;

    _char_data.p_char_pf_desc = &_pf_desc;

    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::_setValue(void)
{
    BleStatus status;

    if (!_initialised)
        return BLE_STATUS_WRONG_STATE;

    if ((_data_len > BLE_MAX_ATTR_DATA_LEN) || (_data_len > _char_data.max_len))
        return BLE_STATUS_NOT_ALLOWED;

    status = ble_client_gatts_set_attribute_value(_handles.value_handle,
                                                  _data_len, _data, 0);
    if (BLE_STATUS_SUCCESS != status)
        return status;

    if (_notifyEnabled || _indicateEnabled) {
        status = ble_client_gatts_send_notif_ind(_handles.value_handle, _data_len, _data, 0, _indicateEnabled);
        if (BLE_STATUS_SUCCESS != status)
            return status;

        if (_indicateEnabled && _event_cb)
            _event_cb(*this, BLE_CHAR_EVENT_INDICATION_ACK, _event_cb_arg);
    }

    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::setValue(const uint8_t value[], const uint16_t length)
{
    if (!value)
        return BLE_STATUS_NOT_ALLOWED;
    if (length > _char_data.max_len)
        return BLE_STATUS_NOT_ALLOWED;

    /* Cache the value locally */
    memcpy(_data, value, length);
    _data_len = length;

    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const String &str)
{
    str.getBytes((unsigned char *)&_data, (unsigned int)_char_data.max_len, 0U);
    _data_len = str.length() + 1;
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const char *cstr)
{
    return setValue((uint8_t *)cstr, (uint16_t) (strlen(cstr) + 1));
}

BleStatus
BleCharacteristic::setValue(const char &value)
{
    uint8_t *p = _data;
    INT8_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const unsigned char &value)
{
    uint8_t *p = _data;
    UINT8_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const short &value)
{
    uint8_t *p = _data;
    INT16_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const unsigned short &value)
{
    uint8_t *p = _data;
    UINT16_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const int &value)
{
    uint8_t *p = _data;
    INT32_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const unsigned int &value)
{
    uint8_t *p = _data;
    UINT32_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const long &value)
{
    uint8_t *p = _data;
    INT32_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::setValue(const unsigned long &value)
{
    uint8_t *p = _data;
    UINT32_TO_LESTREAM(p, value);
    _data_len = sizeof(value);
    return _setValue();
}

BleStatus
BleCharacteristic::getValue(uint8_t value[], uint16_t &length) const
{
    if (!_initialised)
        return BLE_STATUS_WRONG_STATE;

    memcpy(value, _data, _data_len);
    length = _data_len;

    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(String &str) const
{
    str = (char *)_data;
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(char *cstr) const
{
    memcpy(cstr, _data, _data_len);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(char &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_INT8(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(unsigned char &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_UINT8(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(short &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_INT16(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(unsigned short &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_UINT16(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(int &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_INT32(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(unsigned int &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_UINT32(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(long &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_INT32(p, value);
    return BLE_STATUS_SUCCESS;
}

BleStatus
BleCharacteristic::getValue(unsigned long &value) const
{
    const uint8_t *p = _data;
    LESTREAM_TO_UINT32(p, value);
    return BLE_STATUS_SUCCESS;
}

void
BleCharacteristic::setEventCallback(BleCharacteristicEventCb callback,
                                    void *arg)
{
    noInterrupts();
    _event_cb = callback; /* callback disabled if NULL */
    _event_cb_arg = arg;
    interrupts();
}

BleStatus
BleCharacteristic::addDescriptor(BleDescriptor &descriptor)
{
    BleStatus status;

    if (!_initialised)
        return BLE_STATUS_WRONG_STATE;
    if (_num_descriptors >= BLE_MAX_DESCRIPTORS)
        return BLE_STATUS_ERROR;

    /* If this service has a 128-bit UUID, it shall be inherited
     * by included services, characteristics, and descriptors
     */
    if ((BT_UUID128 == _uuid.type) && (BT_UUID16 == descriptor._uuid.type))
        BLE_UUID16_TO_UUID128(descriptor._uuid, _uuid);

    status = ble_client_gatts_add_descriptor(_svc_handle,
                                             &descriptor._desc,
                                             &descriptor._handle);
    if (BLE_STATUS_SUCCESS == status) {
        descriptor._initialised = true;
        _descriptors[_num_descriptors++] = &descriptor;
    }

    return status;
}

BleDescriptor *
BleCharacteristic::_matchDescriptor(uint16_t handle) const
{
    for (unsigned i = 0; i < _num_descriptors; i++) {
        BleDescriptor *desc = _descriptors[i];
        if (handle == desc->_handle)
            return desc;
    }

    return NULL;
}

void
BleCharacteristic::_addCCCDescriptor(void)
{
    /* Activate our CCCD descriptor object */
    _cccd._handle = _handles.cccd_handle;
    _cccd._initialised = true;
    _cccd.setEventCallback(_cccdEventHandler, (void *)this);
    _descriptors[_num_descriptors++] = &_cccd;
}

void
BleCharacteristic::_setConnectedState(boolean_t connected)
{
    _connected = connected;

    /* Reset the state of these internal variables when connection is dropped */
    if (!connected) {
        _notifyEnabled = false;
        _indicateEnabled = false;
    }

    /* Cascade the connected-state update to descriptors */
    for (unsigned i = 0; i < _num_descriptors; i++)
        _descriptors[i]->_setConnectedState(connected);
}
<|endoftext|>


<commit_before>#pragma once

#include <stdexcept>
#include <string>
#include <cassert>

#define NEVER_INLINE  __attribute__((noinline))
#define ALWAYS_INLINE __attribute__((always_inline))
#define UNUSED __attribute__((unused))

#define likely(x)   __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

#define MICROSCOPES_DCHECK(expr, msg) \
  do { \
    if (unlikely(!(expr))) \
      throw ::std::runtime_error(msg); \
  } while (0)

// from https://code.google.com/p/protobuf/source/browse/trunk/src/google/protobuf/stubs/common.h
#define MICROSCOPES_ARRAYSIZE(a) \
  ((sizeof(a) / sizeof(*(a))) / \
      static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))

#define _STRINGIFY(x) #x

/**
 * __LINE__ comes from the preprocessor as an int.
 * Stringify hack comes from:
 * http://www.decompile.com/cpp/faq/file_and_line_error_string.htm
 */
#define _LINEHACK(x) _STRINGIFY(x)

#define _SOURCE_INFO \
  (::std::string(__PRETTY_FUNCTION__) + \
   ::std::string(" (" __FILE__ ":" _LINEHACK(__LINE__) ")"))

#define MICROSCOPES_NOT_REACHABLE() \
  do { \
    throw ::std::runtime_error( \
      ::std::string("Should not be reached: ") + \
      ::std::string(_SOURCE_INFO)); \
  } while (0)

#ifdef NDEBUG
  #define ALWAYS_ASSERT(expr) (likely((expr)) ? (void)0 : abort())
#else
  #define ALWAYS_ASSERT(expr) assert((expr))
#endif

#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
  #define GCC_AT_LEAST_47 1
#else
  #define GCC_AT_LEAST_47 0
#endif

// g++-4.6 does not support override, so we define it to be a no-op
#if !GCC_AT_LEAST_47
  #define override
#endif
<commit_msg>don't redefine override on __clang__<commit_after>#pragma once

#include <stdexcept>
#include <string>
#include <cassert>

#define NEVER_INLINE  __attribute__((noinline))
#define ALWAYS_INLINE __attribute__((always_inline))
#define UNUSED __attribute__((unused))

#define likely(x)   __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

#define MICROSCOPES_DCHECK(expr, msg) \
  do { \
    if (unlikely(!(expr))) \
      throw ::std::runtime_error(msg); \
  } while (0)

// from https://code.google.com/p/protobuf/source/browse/trunk/src/google/protobuf/stubs/common.h
#define MICROSCOPES_ARRAYSIZE(a) \
  ((sizeof(a) / sizeof(*(a))) / \
      static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))

#define _STRINGIFY(x) #x

/**
 * __LINE__ comes from the preprocessor as an int.
 * Stringify hack comes from:
 * http://www.decompile.com/cpp/faq/file_and_line_error_string.htm
 */
#define _LINEHACK(x) _STRINGIFY(x)

#define _SOURCE_INFO \
  (::std::string(__PRETTY_FUNCTION__) + \
   ::std::string(" (" __FILE__ ":" _LINEHACK(__LINE__) ")"))

#define MICROSCOPES_NOT_REACHABLE() \
  do { \
    throw ::std::runtime_error( \
      ::std::string("Should not be reached: ") + \
      ::std::string(_SOURCE_INFO)); \
  } while (0)

#ifdef NDEBUG
  #define ALWAYS_ASSERT(expr) (likely((expr)) ? (void)0 : abort())
#else
  #define ALWAYS_ASSERT(expr) assert((expr))
#endif

#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
  #define GCC_AT_LEAST_47 1
#else
  #define GCC_AT_LEAST_47 0
#endif

// g++-4.6 does not support override, so we define it to be a no-op
#if !defined(__clang__) && !GCC_AT_LEAST_47
  #define override
#endif
<|endoftext|>


<commit_before>/*
    Copyright (C) 2004 by Jorrit Tyberghein
	      (C) 2004 by Frank Richter

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csutil/databuf.h"
#include "csutil/scanstr.h"
#include "csutil/util.h"
#include "csutil/xmltiny.h"
#include "csgfx/shaderexp.h"

#include "imap/services.h"
#include "iutil/verbositymanager.h"
#include "iutil/vfs.h"
#include "ivaria/reporter.h"

#include "csplugincommon/shader/shaderprogram.h"

void csShaderProgram::ProgramParam::SetValue (float val)
{
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));
  var->SetValue (val);
  valid = true;
}

void csShaderProgram::ProgramParam::SetValue (const csVector4& val)
{
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));
  var->SetValue (val);
  valid = true;
}

//---------------------------------------------------------------------------

CS_LEAKGUARD_IMPLEMENT (csShaderProgram);

csShaderProgram::csShaderProgram (iObjectRegistry* objectReg)
  : scfImplementationType (this)
{
  InitCommonTokens (commonTokens);

  csShaderProgram::objectReg = objectReg;
  synsrv = csQueryRegistry<iSyntaxService> (objectReg);
  stringsSvName = csQueryRegistryTagInterface<iShaderVarStringSet>
    (objectReg, "crystalspace.shader.variablenameset");

  csRef<iVerbosityManager> verbosemgr (
    csQueryRegistry<iVerbosityManager> (objectReg));
  if (verbosemgr)
    doVerbose = verbosemgr->Enabled("renderer.shader");
  else
    doVerbose = false;
}

csShaderProgram::~csShaderProgram ()
{
}

bool csShaderProgram::ProgramParamParser::ParseProgramParam (
  iDocumentNode* node, ProgramParam& param, uint types)
{
  const char* type = node->GetAttributeValue ("type");
  if (type == 0)
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "No 'type' attribute");
    return false;
  }

  // Var for static data
  csRef<csShaderVariable> var;
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));

  ProgramParamType paramType = ParamInvalid;
  if (strcmp (type, "shadervar") == 0)
  {
    const char* value = node->GetContentsValue();
    if (!value)
    {
      synsrv->Report ("crystalspace.graphics3d.shader.common",
	CS_REPORTER_SEVERITY_WARNING,
	node,
	"Node has no contents");
      return false;
    }

    CS::Graphics::ShaderVarNameParser nameParse (value);
    param.name = stringsSvName->Request (nameParse.GetShaderVarName());
    for (size_t n = 0; n < nameParse.GetIndexNum(); n++)
    {
      param.indices.Push (nameParse.GetIndexValue (n));
    }
    param.valid = true;
    return true;
  }
  else if (strcmp (type, "int") == 0)
  {
    paramType = ParamInt;
  }
  else if (strcmp (type, "float") == 0)
  {
    paramType = ParamFloat;
  }
  else if (strcmp (type, "vector2") == 0)
  {
    paramType = ParamVector2;
  }
  else if (strcmp (type, "vector3") == 0)
  {
    paramType = ParamVector3;
  }
  else if (strcmp (type, "vector4") == 0)
  {
    paramType = ParamVector4;
  }
  else if (strcmp (type, "matrix") == 0)
  {
    paramType = ParamMatrix;
  }
  else if (strcmp (type, "transform") == 0)
  {
    paramType = ParamTransform;
  }
  else if ((strcmp (type, "expression") == 0) || (strcmp (type, "expr") == 0))
  {
    // Parse exp and save it
    csRef<iShaderVariableAccessor> acc = synsrv->ParseShaderVarExpr (node);
    var->SetAccessor (acc);
    param.var = var;
    param.valid = true;
    return true;
  }
  else if (strcmp (type, "array") == 0)
  {
    csArray<ProgramParam> allParams;
    ProgramParam tmpParam;
    csRef<iDocumentNodeIterator> it = node->GetNodes ();
    while (it->HasNext ())
    {
      csRef<iDocumentNode> child = it->Next ();
      ParseProgramParam (child, tmpParam, types & 0x3F);
      allParams.Push (tmpParam);
    }

    //Save the params
    var->SetType (csShaderVariable::ARRAY);
    var->SetArraySize (allParams.GetSize ());

    for (uint i = 0; i < allParams.GetSize (); i++)
    {
      var->SetArrayElement (i, allParams[i].var);
    }
    paramType = ParamArray;
  }
  else
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "Unknown type '%s'", type);
    return false;
  }

  if (!(types & paramType))
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "Type '%s' not supported by this parameter", type);
    return false;
  }

  const uint directValueTypes = ParamInt | ParamFloat | ParamVector2
    | ParamVector3 | ParamVector4 | ParamMatrix | ParamTransform;
  switch (paramType & directValueTypes)
  {
    case ParamInvalid:
      return false;
      break;
    case ParamInt:
      {
	int x = node->GetContentsValueAsInt ();
	var->SetValue (x);
      }
      break;
    case ParamFloat:
      {
	float x = node->GetContentsValueAsFloat ();
	var->SetValue (x);
      }
      break;
    case ParamVector2:
      {
	float x, y;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f", &x, &y) != 2)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector2 '%s'", value);
	  return false;
	}
	var->SetValue (csVector2 (x,y));
      }
      break;
    case ParamVector3:
      {
	float x, y, z;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f,%f", &x, &y, &z) != 3)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector3 '%s'", value);
	  return false;
	}
	var->SetValue (csVector3 (x,y,z));
      }
      break;
    case ParamVector4:
      {
	float x, y, z, w;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f,%f,%f", &x, &y, &z, &w) != 4)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector4 '%s'", value);
	  return false;
	}
	var->SetValue (csVector4 (x,y,z,w));
      }
      break;
    case ParamMatrix:
      {
        csMatrix3 matrix;
	if (!synsrv->ParseMatrix (node, matrix))
	  return false;
        var->SetValue (matrix);
      }
      break;
    case ParamTransform:
      {
        csReversibleTransform t;
        csRef<iDocumentNode> matrix_node = node->GetNode ("matrix");
        if (matrix_node)
        {
          csMatrix3 m;
          if (!synsrv->ParseMatrix (matrix_node, m))
            return false;
          t.SetT2O (m);
        }
        csRef<iDocumentNode> vector_node = node->GetNode ("v");
        if (vector_node)
        {
          csVector3 v;
          if (!synsrv->ParseVector (vector_node, v))
            return false;
          t.SetOrigin (v);
        }
        var->SetValue (t);
      }
      break;
  }

  param.var = var;
  param.valid = true;
  return true;
}

bool csShaderProgram::ParseCommon (iDocumentNode* child)
{
  const char* value = child->GetValue ();
  csStringID id = commonTokens.Request (value);
  switch (id)
  {
    case XMLTOKEN_VARIABLEMAP:
      {
        //@@ REWRITE
	const char* destname = child->GetAttributeValue ("destination");
	if (!destname)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING, child,
	    "<variablemap> has no 'destination' attribute");
	  return false;
	}

	const char* varname = child->GetAttributeValue ("variable");
	if (!varname)
	{
	  // "New style" variable mapping
	  VariableMapEntry vme (CS::InvalidShaderVarStringID, destname);
	  if (!ParseProgramParam (child, vme.mappingParam,
	    ParamFloat | ParamVector2 | ParamVector3 | ParamVector4))
	    return false;
	  variablemap.Push (vme);
	}
	else
	{
	  // "Classic" variable mapping
	  CS::Graphics::ShaderVarNameParser nameParse (varname);
	  VariableMapEntry vme (
	    stringsSvName->Request (nameParse.GetShaderVarName()),
	    destname);
	  for (size_t n = 0; n < nameParse.GetIndexNum(); n++)
	  {
	    vme.mappingParam.indices.Push (nameParse.GetIndexValue (n));
	  }
	  variablemap.Push (vme);
	}
      }
      break;
    case XMLTOKEN_PROGRAM:
      {
	const char* filename = child->GetAttributeValue ("file");
	if (filename != 0)
	{
	  programFileName = filename;

	  csRef<iVFS> vfs = csQueryRegistry<iVFS> (objectReg);
	  csRef<iFile> file = vfs->Open (filename, VFS_FILE_READ);
	  if (!file.IsValid())
	  {
	    synsrv->Report ("crystalspace.graphics3d.shader.common",
	      CS_REPORTER_SEVERITY_WARNING, child,
	      "Could not open '%s'", filename);
	    return false;
	  }

	  programFile = file;
	}
	else
	  programNode = child;
      }
      break;

    case XMLTOKEN_DESCRIPTION:
      description = child->GetContentsValue();
      break;
    default:
      synsrv->ReportBadToken (child);
      return false;
  }
  return true;
}

#include "csutil/custom_new_disable.h"
iDocumentNode* csShaderProgram::GetProgramNode ()
{
  if (programNode.IsValid ())
    return programNode;

  if (programFile.IsValid ())
  {
    csRef<iDocumentSystem> docsys =
      csQueryRegistry<iDocumentSystem> (objectReg);
    if (!docsys)
      docsys.AttachNew (new csTinyDocumentSystem ());
    csRef<iDocument> doc (docsys->CreateDocument ());

    const char* err = doc->Parse (programFile, true);
    if (err != 0)
    {
      csReport (objectReg,
	CS_REPORTER_SEVERITY_WARNING,
	"crystalspace.graphics3d.shader.common",
	"Error parsing %s: %s", programFileName.GetData(), err);
      return 0;
    }
    programNode = doc->GetRoot ();
    programFile = 0;
    return programNode;
  }

  return 0;
}

csPtr<iDataBuffer> csShaderProgram::GetProgramData ()
{
  if (programFile.IsValid())
  {
    return programFile->GetAllData ();
  }

  if (programNode.IsValid())
  {
    char* data = CS::StrDup (programNode->GetContentsValue ());

    csRef<iDataBuffer> newbuff;
    newbuff.AttachNew (new CS::DataBuffer<> (data, data ? strlen (data) : 0));
    return csPtr<iDataBuffer> (newbuff);
  }

  return 0;
}
#include "csutil/custom_new_enable.h"

void csShaderProgram::DumpProgramInfo (csString& output)
{
  output << "Program description: " <<
    (description.Length () ? description.GetData () : "<none>") << "\n";
  output << "Program file name: " << programFileName << "\n";
}

void csShaderProgram::DumpVariableMappings (csString& output)
{
  for (size_t v = 0; v < variablemap.GetSize (); v++)
  {
    const VariableMapEntry& vme = variablemap[v];

    output << stringsSvName->Request (vme.name);
    output << '(' << vme.name << ") -> ";
    output << vme.destination << ' ';
    output << vme.userVal << ' ';
    output << '\n';
  }
}

void csShaderProgram::GetUsedShaderVarsFromVariableMappings (
  csBitArray& bits) const
{
  for (size_t i = 0; i < variablemap.GetSize(); i++)
  {
    TryAddUsedShaderVarName (variablemap[i].name, bits);
  }
}

void csShaderProgram::GetUsedShaderVars (csBitArray& bits) const
{
  GetUsedShaderVarsFromVariableMappings (bits);
}

iShaderProgram::CacheLoadResult csShaderProgram::LoadFromCache (
  iHierarchicalCache* cache, iBase* previous, iDocumentNode* programNode,
  csRef<iString>* failReason, csRef<iString>*)
{
  csRef<iShaderDestinationResolver> resolver =
    scfQueryInterfaceSafe<iShaderDestinationResolver> (previous);

  if (Load (resolver, programNode))
    return loadSuccessShaderValid;
  else
    return loadSuccessShaderInvalid;
}
<commit_msg>Default LoadFromCache() must not only call Load(), but also Compile()<commit_after>/*
    Copyright (C) 2004 by Jorrit Tyberghein
	      (C) 2004 by Frank Richter

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "csutil/databuf.h"
#include "csutil/scanstr.h"
#include "csutil/util.h"
#include "csutil/xmltiny.h"
#include "csgfx/shaderexp.h"

#include "imap/services.h"
#include "iutil/verbositymanager.h"
#include "iutil/vfs.h"
#include "ivaria/reporter.h"

#include "csplugincommon/shader/shaderprogram.h"

void csShaderProgram::ProgramParam::SetValue (float val)
{
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));
  var->SetValue (val);
  valid = true;
}

void csShaderProgram::ProgramParam::SetValue (const csVector4& val)
{
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));
  var->SetValue (val);
  valid = true;
}

//---------------------------------------------------------------------------

CS_LEAKGUARD_IMPLEMENT (csShaderProgram);

csShaderProgram::csShaderProgram (iObjectRegistry* objectReg)
  : scfImplementationType (this)
{
  InitCommonTokens (commonTokens);

  csShaderProgram::objectReg = objectReg;
  synsrv = csQueryRegistry<iSyntaxService> (objectReg);
  stringsSvName = csQueryRegistryTagInterface<iShaderVarStringSet>
    (objectReg, "crystalspace.shader.variablenameset");

  csRef<iVerbosityManager> verbosemgr (
    csQueryRegistry<iVerbosityManager> (objectReg));
  if (verbosemgr)
    doVerbose = verbosemgr->Enabled("renderer.shader");
  else
    doVerbose = false;
}

csShaderProgram::~csShaderProgram ()
{
}

bool csShaderProgram::ProgramParamParser::ParseProgramParam (
  iDocumentNode* node, ProgramParam& param, uint types)
{
  const char* type = node->GetAttributeValue ("type");
  if (type == 0)
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "No 'type' attribute");
    return false;
  }

  // Var for static data
  csRef<csShaderVariable> var;
  var.AttachNew (new csShaderVariable (CS::InvalidShaderVarStringID));

  ProgramParamType paramType = ParamInvalid;
  if (strcmp (type, "shadervar") == 0)
  {
    const char* value = node->GetContentsValue();
    if (!value)
    {
      synsrv->Report ("crystalspace.graphics3d.shader.common",
	CS_REPORTER_SEVERITY_WARNING,
	node,
	"Node has no contents");
      return false;
    }

    CS::Graphics::ShaderVarNameParser nameParse (value);
    param.name = stringsSvName->Request (nameParse.GetShaderVarName());
    for (size_t n = 0; n < nameParse.GetIndexNum(); n++)
    {
      param.indices.Push (nameParse.GetIndexValue (n));
    }
    param.valid = true;
    return true;
  }
  else if (strcmp (type, "int") == 0)
  {
    paramType = ParamInt;
  }
  else if (strcmp (type, "float") == 0)
  {
    paramType = ParamFloat;
  }
  else if (strcmp (type, "vector2") == 0)
  {
    paramType = ParamVector2;
  }
  else if (strcmp (type, "vector3") == 0)
  {
    paramType = ParamVector3;
  }
  else if (strcmp (type, "vector4") == 0)
  {
    paramType = ParamVector4;
  }
  else if (strcmp (type, "matrix") == 0)
  {
    paramType = ParamMatrix;
  }
  else if (strcmp (type, "transform") == 0)
  {
    paramType = ParamTransform;
  }
  else if ((strcmp (type, "expression") == 0) || (strcmp (type, "expr") == 0))
  {
    // Parse exp and save it
    csRef<iShaderVariableAccessor> acc = synsrv->ParseShaderVarExpr (node);
    var->SetAccessor (acc);
    param.var = var;
    param.valid = true;
    return true;
  }
  else if (strcmp (type, "array") == 0)
  {
    csArray<ProgramParam> allParams;
    ProgramParam tmpParam;
    csRef<iDocumentNodeIterator> it = node->GetNodes ();
    while (it->HasNext ())
    {
      csRef<iDocumentNode> child = it->Next ();
      ParseProgramParam (child, tmpParam, types & 0x3F);
      allParams.Push (tmpParam);
    }

    //Save the params
    var->SetType (csShaderVariable::ARRAY);
    var->SetArraySize (allParams.GetSize ());

    for (uint i = 0; i < allParams.GetSize (); i++)
    {
      var->SetArrayElement (i, allParams[i].var);
    }
    paramType = ParamArray;
  }
  else
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "Unknown type '%s'", type);
    return false;
  }

  if (!(types & paramType))
  {
    synsrv->Report ("crystalspace.graphics3d.shader.common",
      CS_REPORTER_SEVERITY_WARNING,
      node,
      "Type '%s' not supported by this parameter", type);
    return false;
  }

  const uint directValueTypes = ParamInt | ParamFloat | ParamVector2
    | ParamVector3 | ParamVector4 | ParamMatrix | ParamTransform;
  switch (paramType & directValueTypes)
  {
    case ParamInvalid:
      return false;
      break;
    case ParamInt:
      {
	int x = node->GetContentsValueAsInt ();
	var->SetValue (x);
      }
      break;
    case ParamFloat:
      {
	float x = node->GetContentsValueAsFloat ();
	var->SetValue (x);
      }
      break;
    case ParamVector2:
      {
	float x, y;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f", &x, &y) != 2)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector2 '%s'", value);
	  return false;
	}
	var->SetValue (csVector2 (x,y));
      }
      break;
    case ParamVector3:
      {
	float x, y, z;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f,%f", &x, &y, &z) != 3)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector3 '%s'", value);
	  return false;
	}
	var->SetValue (csVector3 (x,y,z));
      }
      break;
    case ParamVector4:
      {
	float x, y, z, w;
	const char* value = node->GetContentsValue();
	if (!value)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Node has no contents");
	  return false;
	}
	if (csScanStr (value, "%f,%f,%f,%f", &x, &y, &z, &w) != 4)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING,
	    node,
	    "Couldn't parse vector4 '%s'", value);
	  return false;
	}
	var->SetValue (csVector4 (x,y,z,w));
      }
      break;
    case ParamMatrix:
      {
        csMatrix3 matrix;
	if (!synsrv->ParseMatrix (node, matrix))
	  return false;
        var->SetValue (matrix);
      }
      break;
    case ParamTransform:
      {
        csReversibleTransform t;
        csRef<iDocumentNode> matrix_node = node->GetNode ("matrix");
        if (matrix_node)
        {
          csMatrix3 m;
          if (!synsrv->ParseMatrix (matrix_node, m))
            return false;
          t.SetT2O (m);
        }
        csRef<iDocumentNode> vector_node = node->GetNode ("v");
        if (vector_node)
        {
          csVector3 v;
          if (!synsrv->ParseVector (vector_node, v))
            return false;
          t.SetOrigin (v);
        }
        var->SetValue (t);
      }
      break;
  }

  param.var = var;
  param.valid = true;
  return true;
}

bool csShaderProgram::ParseCommon (iDocumentNode* child)
{
  const char* value = child->GetValue ();
  csStringID id = commonTokens.Request (value);
  switch (id)
  {
    case XMLTOKEN_VARIABLEMAP:
      {
        //@@ REWRITE
	const char* destname = child->GetAttributeValue ("destination");
	if (!destname)
	{
	  synsrv->Report ("crystalspace.graphics3d.shader.common",
	    CS_REPORTER_SEVERITY_WARNING, child,
	    "<variablemap> has no 'destination' attribute");
	  return false;
	}

	const char* varname = child->GetAttributeValue ("variable");
	if (!varname)
	{
	  // "New style" variable mapping
	  VariableMapEntry vme (CS::InvalidShaderVarStringID, destname);
	  if (!ParseProgramParam (child, vme.mappingParam,
	    ParamFloat | ParamVector2 | ParamVector3 | ParamVector4))
	    return false;
	  variablemap.Push (vme);
	}
	else
	{
	  // "Classic" variable mapping
	  CS::Graphics::ShaderVarNameParser nameParse (varname);
	  VariableMapEntry vme (
	    stringsSvName->Request (nameParse.GetShaderVarName()),
	    destname);
	  for (size_t n = 0; n < nameParse.GetIndexNum(); n++)
	  {
	    vme.mappingParam.indices.Push (nameParse.GetIndexValue (n));
	  }
	  variablemap.Push (vme);
	}
      }
      break;
    case XMLTOKEN_PROGRAM:
      {
	const char* filename = child->GetAttributeValue ("file");
	if (filename != 0)
	{
	  programFileName = filename;

	  csRef<iVFS> vfs = csQueryRegistry<iVFS> (objectReg);
	  csRef<iFile> file = vfs->Open (filename, VFS_FILE_READ);
	  if (!file.IsValid())
	  {
	    synsrv->Report ("crystalspace.graphics3d.shader.common",
	      CS_REPORTER_SEVERITY_WARNING, child,
	      "Could not open '%s'", filename);
	    return false;
	  }

	  programFile = file;
	}
	else
	  programNode = child;
      }
      break;

    case XMLTOKEN_DESCRIPTION:
      description = child->GetContentsValue();
      break;
    default:
      synsrv->ReportBadToken (child);
      return false;
  }
  return true;
}

#include "csutil/custom_new_disable.h"
iDocumentNode* csShaderProgram::GetProgramNode ()
{
  if (programNode.IsValid ())
    return programNode;

  if (programFile.IsValid ())
  {
    csRef<iDocumentSystem> docsys =
      csQueryRegistry<iDocumentSystem> (objectReg);
    if (!docsys)
      docsys.AttachNew (new csTinyDocumentSystem ());
    csRef<iDocument> doc (docsys->CreateDocument ());

    const char* err = doc->Parse (programFile, true);
    if (err != 0)
    {
      csReport (objectReg,
	CS_REPORTER_SEVERITY_WARNING,
	"crystalspace.graphics3d.shader.common",
	"Error parsing %s: %s", programFileName.GetData(), err);
      return 0;
    }
    programNode = doc->GetRoot ();
    programFile = 0;
    return programNode;
  }

  return 0;
}

csPtr<iDataBuffer> csShaderProgram::GetProgramData ()
{
  if (programFile.IsValid())
  {
    return programFile->GetAllData ();
  }

  if (programNode.IsValid())
  {
    char* data = CS::StrDup (programNode->GetContentsValue ());

    csRef<iDataBuffer> newbuff;
    newbuff.AttachNew (new CS::DataBuffer<> (data, data ? strlen (data) : 0));
    return csPtr<iDataBuffer> (newbuff);
  }

  return 0;
}
#include "csutil/custom_new_enable.h"

void csShaderProgram::DumpProgramInfo (csString& output)
{
  output << "Program description: " <<
    (description.Length () ? description.GetData () : "<none>") << "\n";
  output << "Program file name: " << programFileName << "\n";
}

void csShaderProgram::DumpVariableMappings (csString& output)
{
  for (size_t v = 0; v < variablemap.GetSize (); v++)
  {
    const VariableMapEntry& vme = variablemap[v];

    output << stringsSvName->Request (vme.name);
    output << '(' << vme.name << ") -> ";
    output << vme.destination << ' ';
    output << vme.userVal << ' ';
    output << '\n';
  }
}

void csShaderProgram::GetUsedShaderVarsFromVariableMappings (
  csBitArray& bits) const
{
  for (size_t i = 0; i < variablemap.GetSize(); i++)
  {
    TryAddUsedShaderVarName (variablemap[i].name, bits);
  }
}

void csShaderProgram::GetUsedShaderVars (csBitArray& bits) const
{
  GetUsedShaderVarsFromVariableMappings (bits);
}

iShaderProgram::CacheLoadResult csShaderProgram::LoadFromCache (
  iHierarchicalCache* cache, iBase* previous, iDocumentNode* programNode,
  csRef<iString>* failReason, csRef<iString>* tag)
{
  csRef<iShaderDestinationResolver> resolver =
    scfQueryInterfaceSafe<iShaderDestinationResolver> (previous);

  if (Load (resolver, programNode) && Compile (0, tag))
    return loadSuccessShaderValid;
  else
    return loadSuccessShaderInvalid;
}
<|endoftext|>


<commit_before>/*
* Salsa20 / XSalsa20
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/salsa20.h>
#include <botan/loadstor.h>
#include <botan/rotate.h>
#include <botan/internal/xor_buf.h>

namespace Botan {

namespace {

/*
* Generate HSalsa20 cipher stream (for XSalsa20 IV setup)
*/
void hsalsa20(u32bit output[8], const u32bit input[16])
   {
   u32bit x00 = input[0];
   u32bit x01 = input[1];
   u32bit x02 = input[2];
   u32bit x03 = input[3];
   u32bit x04 = input[4];
   u32bit x05 = input[5];
   u32bit x06 = input[6];
   u32bit x07 = input[7];
   u32bit x08 = input[8];
   u32bit x09 = input[9];
   u32bit x10 = input[10];
   u32bit x11 = input[11];
   u32bit x12 = input[12];
   u32bit x13 = input[13];
   u32bit x14 = input[14];
   u32bit x15 = input[15];

   for(u32bit i = 0; i != 10; ++i)
      {
      x04 ^= rotate_left(x00 + x12,  7);
      x08 ^= rotate_left(x04 + x00,  9);
      x12 ^= rotate_left(x08 + x04, 13);
      x00 ^= rotate_left(x12 + x08, 18);
      x09 ^= rotate_left(x05 + x01,  7);
      x13 ^= rotate_left(x09 + x05,  9);
      x01 ^= rotate_left(x13 + x09, 13);
      x05 ^= rotate_left(x01 + x13, 18);
      x14 ^= rotate_left(x10 + x06,  7);
      x02 ^= rotate_left(x14 + x10,  9);
      x06 ^= rotate_left(x02 + x14, 13);
      x10 ^= rotate_left(x06 + x02, 18);
      x03 ^= rotate_left(x15 + x11,  7);
      x07 ^= rotate_left(x03 + x15,  9);
      x11 ^= rotate_left(x07 + x03, 13);
      x15 ^= rotate_left(x11 + x07, 18);

      x01 ^= rotate_left(x00 + x03,  7);
      x02 ^= rotate_left(x01 + x00,  9);
      x03 ^= rotate_left(x02 + x01, 13);
      x00 ^= rotate_left(x03 + x02, 18);
      x06 ^= rotate_left(x05 + x04,  7);
      x07 ^= rotate_left(x06 + x05,  9);
      x04 ^= rotate_left(x07 + x06, 13);
      x05 ^= rotate_left(x04 + x07, 18);
      x11 ^= rotate_left(x10 + x09,  7);
      x08 ^= rotate_left(x11 + x10,  9);
      x09 ^= rotate_left(x08 + x11, 13);
      x10 ^= rotate_left(x09 + x08, 18);
      x12 ^= rotate_left(x15 + x14,  7);
      x13 ^= rotate_left(x12 + x15,  9);
      x14 ^= rotate_left(x13 + x12, 13);
      x15 ^= rotate_left(x14 + x13, 18);
      }

   output[0] = x00;
   output[1] = x05;
   output[2] = x10;
   output[3] = x15;
   output[4] = x06;
   output[5] = x07;
   output[6] = x08;
   output[7] = x09;
   }

/*
* Generate Salsa20 cipher stream
*/
void salsa20(byte output[64], const u32bit input[16])
   {
   u32bit x00 = input[0];
   u32bit x01 = input[1];
   u32bit x02 = input[2];
   u32bit x03 = input[3];
   u32bit x04 = input[4];
   u32bit x05 = input[5];
   u32bit x06 = input[6];
   u32bit x07 = input[7];
   u32bit x08 = input[8];
   u32bit x09 = input[9];
   u32bit x10 = input[10];
   u32bit x11 = input[11];
   u32bit x12 = input[12];
   u32bit x13 = input[13];
   u32bit x14 = input[14];
   u32bit x15 = input[15];

   for(u32bit i = 0; i != 10; ++i)
      {
      x04 ^= rotate_left(x00 + x12,  7);
      x08 ^= rotate_left(x04 + x00,  9);
      x12 ^= rotate_left(x08 + x04, 13);
      x00 ^= rotate_left(x12 + x08, 18);
      x09 ^= rotate_left(x05 + x01,  7);
      x13 ^= rotate_left(x09 + x05,  9);
      x01 ^= rotate_left(x13 + x09, 13);
      x05 ^= rotate_left(x01 + x13, 18);
      x14 ^= rotate_left(x10 + x06,  7);
      x02 ^= rotate_left(x14 + x10,  9);
      x06 ^= rotate_left(x02 + x14, 13);
      x10 ^= rotate_left(x06 + x02, 18);
      x03 ^= rotate_left(x15 + x11,  7);
      x07 ^= rotate_left(x03 + x15,  9);
      x11 ^= rotate_left(x07 + x03, 13);
      x15 ^= rotate_left(x11 + x07, 18);

      x01 ^= rotate_left(x00 + x03,  7);
      x02 ^= rotate_left(x01 + x00,  9);
      x03 ^= rotate_left(x02 + x01, 13);
      x00 ^= rotate_left(x03 + x02, 18);
      x06 ^= rotate_left(x05 + x04,  7);
      x07 ^= rotate_left(x06 + x05,  9);
      x04 ^= rotate_left(x07 + x06, 13);
      x05 ^= rotate_left(x04 + x07, 18);
      x11 ^= rotate_left(x10 + x09,  7);
      x08 ^= rotate_left(x11 + x10,  9);
      x09 ^= rotate_left(x08 + x11, 13);
      x10 ^= rotate_left(x09 + x08, 18);
      x12 ^= rotate_left(x15 + x14,  7);
      x13 ^= rotate_left(x12 + x15,  9);
      x14 ^= rotate_left(x13 + x12, 13);
      x15 ^= rotate_left(x14 + x13, 18);
      }

   store_le(x00 + input[ 0], output + 4 *  0);
   store_le(x01 + input[ 1], output + 4 *  1);
   store_le(x02 + input[ 2], output + 4 *  2);
   store_le(x03 + input[ 3], output + 4 *  3);
   store_le(x04 + input[ 4], output + 4 *  4);
   store_le(x05 + input[ 5], output + 4 *  5);
   store_le(x06 + input[ 6], output + 4 *  6);
   store_le(x07 + input[ 7], output + 4 *  7);
   store_le(x08 + input[ 8], output + 4 *  8);
   store_le(x09 + input[ 9], output + 4 *  9);
   store_le(x10 + input[10], output + 4 * 10);
   store_le(x11 + input[11], output + 4 * 11);
   store_le(x12 + input[12], output + 4 * 12);
   store_le(x13 + input[13], output + 4 * 13);
   store_le(x14 + input[14], output + 4 * 14);
   store_le(x15 + input[15], output + 4 * 15);
   }

}

/*
* Combine cipher stream with message
*/
void Salsa20::cipher(const byte in[], byte out[], u32bit length)
   {
   while(length >= buffer.size() - position)
      {
      xor_buf(out, in, &buffer[position], buffer.size() - position);
      length -= (buffer.size() - position);
      in += (buffer.size() - position);
      out += (buffer.size() - position);
      salsa20(&buffer[0], state);

      ++state[8];
      if(!state[8]) // if overflow in state[8]
         ++state[9]; // carry to state[9]

      position = 0;
      }

   xor_buf(out, in, &buffer[position], length);

   position += length;
   }

/*
* Salsa20 Key Schedule
*/
void Salsa20::key_schedule(const byte key[], u32bit length)
   {
   static const u32bit TAU[] =
      { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 };

   static const u32bit SIGMA[] =
      { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };

   clear();

   if(length == 16)
      {
      state[0] = TAU[0];
      state[1] = load_le<u32bit>(key, 0);
      state[2] = load_le<u32bit>(key, 1);
      state[3] = load_le<u32bit>(key, 2);
      state[4] = load_le<u32bit>(key, 3);
      state[5] = TAU[1];
      state[10] = TAU[2];
      state[11] = load_le<u32bit>(key, 0);
      state[12] = load_le<u32bit>(key, 1);
      state[13] = load_le<u32bit>(key, 2);
      state[14] = load_le<u32bit>(key, 3);
      state[15] = TAU[3];
      }
   else if(length == 32)
      {
      state[0] = SIGMA[0];
      state[1] = load_le<u32bit>(key, 0);
      state[2] = load_le<u32bit>(key, 1);
      state[3] = load_le<u32bit>(key, 2);
      state[4] = load_le<u32bit>(key, 3);
      state[5] = SIGMA[1];
      state[10] = SIGMA[2];
      state[11] = load_le<u32bit>(key, 4);
      state[12] = load_le<u32bit>(key, 5);
      state[13] = load_le<u32bit>(key, 6);
      state[14] = load_le<u32bit>(key, 7);
      state[15] = SIGMA[3];
      }

   const byte ZERO[8] = { 0 };
   set_iv(ZERO, sizeof(ZERO));
   }

/*
* Return the name of this type
*/
void Salsa20::set_iv(const byte iv[], u32bit length)
   {
   if(!valid_iv_length(length))
      throw Invalid_IV_Length(name(), length);

   if(length == 8)
      {
      // Salsa20
      state[6] = load_le<u32bit>(iv, 0);
      state[7] = load_le<u32bit>(iv, 1);
      }
   else
      {
      // XSalsa20
      state[6] = load_le<u32bit>(iv, 0);
      state[7] = load_le<u32bit>(iv, 1);
      state[8] = load_le<u32bit>(iv, 2);
      state[9] = load_le<u32bit>(iv, 3);

      SecureVector<u32bit> hsalsa(8);
      hsalsa20(hsalsa, state);

      state[ 1] = hsalsa[0];
      state[ 2] = hsalsa[1];
      state[ 3] = hsalsa[2];
      state[ 4] = hsalsa[3];
      state[ 6] = load_le<u32bit>(iv, 4);
      state[ 7] = load_le<u32bit>(iv, 5);
      state[11] = hsalsa[4];
      state[12] = hsalsa[5];
      state[13] = hsalsa[6];
      state[14] = hsalsa[7];
      }

   state[8] = 0;
   state[9] = 0;

   salsa20(&buffer[0], state);
   ++state[8];
   if(!state[8]) // if overflow in state[8]
      ++state[9]; // carry to state[9]

   position = 0;
   }

/*
* Return the name of this type
*/
std::string Salsa20::name() const
   {
   return "Salsa20";
   }

/*
* Clear memory of sensitive data
*/
void Salsa20::clear()
   {
   state.clear();
   buffer.clear();
   position = 0;
   }

/*
* Salsa20 Constructor
*/
Salsa20::Salsa20() : StreamCipher(16, 32, 16)
   {
   clear();
   }

}
<commit_msg>Use a macro to make Salsa20 code a bit more compact<commit_after>/*
* Salsa20 / XSalsa20
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/salsa20.h>
#include <botan/loadstor.h>
#include <botan/rotate.h>
#include <botan/internal/xor_buf.h>

namespace Botan {

namespace {

#define SALSA20_QUARTER_ROUND(x1, x2, x3, x4)    \
   do {                                          \
      x2 ^= rotate_left(x1 + x4,  7);            \
      x3 ^= rotate_left(x2 + x1,  9);            \
      x4 ^= rotate_left(x3 + x2, 13);            \
      x1 ^= rotate_left(x4 + x3, 18);            \
   } while(0)

/*
* Generate HSalsa20 cipher stream (for XSalsa20 IV setup)
*/
void hsalsa20(u32bit output[8], const u32bit input[16])
   {
   u32bit x00 = input[0];
   u32bit x01 = input[1];
   u32bit x02 = input[2];
   u32bit x03 = input[3];
   u32bit x04 = input[4];
   u32bit x05 = input[5];
   u32bit x06 = input[6];
   u32bit x07 = input[7];
   u32bit x08 = input[8];
   u32bit x09 = input[9];
   u32bit x10 = input[10];
   u32bit x11 = input[11];
   u32bit x12 = input[12];
   u32bit x13 = input[13];
   u32bit x14 = input[14];
   u32bit x15 = input[15];

   for(u32bit i = 0; i != 10; ++i)
      {
      SALSA20_QUARTER_ROUND(x00, x04, x08, x12);
      SALSA20_QUARTER_ROUND(x05, x09, x13, x01);
      SALSA20_QUARTER_ROUND(x10, x14, x02, x06);
      SALSA20_QUARTER_ROUND(x15, x03, x07, x11);

      SALSA20_QUARTER_ROUND(x00, x01, x02, x03);
      SALSA20_QUARTER_ROUND(x05, x06, x07, x04);
      SALSA20_QUARTER_ROUND(x10, x11, x08, x09);
      SALSA20_QUARTER_ROUND(x15, x12, x13, x14);
      }

   output[0] = x00;
   output[1] = x05;
   output[2] = x10;
   output[3] = x15;
   output[4] = x06;
   output[5] = x07;
   output[6] = x08;
   output[7] = x09;
   }

/*
* Generate Salsa20 cipher stream
*/
void salsa20(byte output[64], const u32bit input[16])
   {
   u32bit x00 = input[0];
   u32bit x01 = input[1];
   u32bit x02 = input[2];
   u32bit x03 = input[3];
   u32bit x04 = input[4];
   u32bit x05 = input[5];
   u32bit x06 = input[6];
   u32bit x07 = input[7];
   u32bit x08 = input[8];
   u32bit x09 = input[9];
   u32bit x10 = input[10];
   u32bit x11 = input[11];
   u32bit x12 = input[12];
   u32bit x13 = input[13];
   u32bit x14 = input[14];
   u32bit x15 = input[15];

   for(u32bit i = 0; i != 10; ++i)
      {
      SALSA20_QUARTER_ROUND(x00, x04, x08, x12);
      SALSA20_QUARTER_ROUND(x05, x09, x13, x01);
      SALSA20_QUARTER_ROUND(x10, x14, x02, x06);
      SALSA20_QUARTER_ROUND(x15, x03, x07, x11);

      SALSA20_QUARTER_ROUND(x00, x01, x02, x03);
      SALSA20_QUARTER_ROUND(x05, x06, x07, x04);
      SALSA20_QUARTER_ROUND(x10, x11, x08, x09);
      SALSA20_QUARTER_ROUND(x15, x12, x13, x14);
      }

   store_le(x00 + input[ 0], output + 4 *  0);
   store_le(x01 + input[ 1], output + 4 *  1);
   store_le(x02 + input[ 2], output + 4 *  2);
   store_le(x03 + input[ 3], output + 4 *  3);
   store_le(x04 + input[ 4], output + 4 *  4);
   store_le(x05 + input[ 5], output + 4 *  5);
   store_le(x06 + input[ 6], output + 4 *  6);
   store_le(x07 + input[ 7], output + 4 *  7);
   store_le(x08 + input[ 8], output + 4 *  8);
   store_le(x09 + input[ 9], output + 4 *  9);
   store_le(x10 + input[10], output + 4 * 10);
   store_le(x11 + input[11], output + 4 * 11);
   store_le(x12 + input[12], output + 4 * 12);
   store_le(x13 + input[13], output + 4 * 13);
   store_le(x14 + input[14], output + 4 * 14);
   store_le(x15 + input[15], output + 4 * 15);
   }

}

/*
* Combine cipher stream with message
*/
void Salsa20::cipher(const byte in[], byte out[], u32bit length)
   {
   while(length >= buffer.size() - position)
      {
      xor_buf(out, in, &buffer[position], buffer.size() - position);
      length -= (buffer.size() - position);
      in += (buffer.size() - position);
      out += (buffer.size() - position);
      salsa20(&buffer[0], state);

      ++state[8];
      if(!state[8]) // if overflow in state[8]
         ++state[9]; // carry to state[9]

      position = 0;
      }

   xor_buf(out, in, &buffer[position], length);

   position += length;
   }

/*
* Salsa20 Key Schedule
*/
void Salsa20::key_schedule(const byte key[], u32bit length)
   {
   static const u32bit TAU[] =
      { 0x61707865, 0x3120646e, 0x79622d36, 0x6b206574 };

   static const u32bit SIGMA[] =
      { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };

   clear();

   if(length == 16)
      {
      state[0] = TAU[0];
      state[1] = load_le<u32bit>(key, 0);
      state[2] = load_le<u32bit>(key, 1);
      state[3] = load_le<u32bit>(key, 2);
      state[4] = load_le<u32bit>(key, 3);
      state[5] = TAU[1];
      state[10] = TAU[2];
      state[11] = load_le<u32bit>(key, 0);
      state[12] = load_le<u32bit>(key, 1);
      state[13] = load_le<u32bit>(key, 2);
      state[14] = load_le<u32bit>(key, 3);
      state[15] = TAU[3];
      }
   else if(length == 32)
      {
      state[0] = SIGMA[0];
      state[1] = load_le<u32bit>(key, 0);
      state[2] = load_le<u32bit>(key, 1);
      state[3] = load_le<u32bit>(key, 2);
      state[4] = load_le<u32bit>(key, 3);
      state[5] = SIGMA[1];
      state[10] = SIGMA[2];
      state[11] = load_le<u32bit>(key, 4);
      state[12] = load_le<u32bit>(key, 5);
      state[13] = load_le<u32bit>(key, 6);
      state[14] = load_le<u32bit>(key, 7);
      state[15] = SIGMA[3];
      }

   const byte ZERO[8] = { 0 };
   set_iv(ZERO, sizeof(ZERO));
   }

/*
* Return the name of this type
*/
void Salsa20::set_iv(const byte iv[], u32bit length)
   {
   if(!valid_iv_length(length))
      throw Invalid_IV_Length(name(), length);

   if(length == 8)
      {
      // Salsa20
      state[6] = load_le<u32bit>(iv, 0);
      state[7] = load_le<u32bit>(iv, 1);
      }
   else
      {
      // XSalsa20
      state[6] = load_le<u32bit>(iv, 0);
      state[7] = load_le<u32bit>(iv, 1);
      state[8] = load_le<u32bit>(iv, 2);
      state[9] = load_le<u32bit>(iv, 3);

      SecureVector<u32bit> hsalsa(8);
      hsalsa20(hsalsa, state);

      state[ 1] = hsalsa[0];
      state[ 2] = hsalsa[1];
      state[ 3] = hsalsa[2];
      state[ 4] = hsalsa[3];
      state[ 6] = load_le<u32bit>(iv, 4);
      state[ 7] = load_le<u32bit>(iv, 5);
      state[11] = hsalsa[4];
      state[12] = hsalsa[5];
      state[13] = hsalsa[6];
      state[14] = hsalsa[7];
      }

   state[8] = 0;
   state[9] = 0;

   salsa20(&buffer[0], state);
   ++state[8];
   if(!state[8]) // if overflow in state[8]
      ++state[9]; // carry to state[9]

   position = 0;
   }

/*
* Return the name of this type
*/
std::string Salsa20::name() const
   {
   return "Salsa20";
   }

/*
* Clear memory of sensitive data
*/
void Salsa20::clear()
   {
   state.clear();
   buffer.clear();
   position = 0;
   }

/*
* Salsa20 Constructor
*/
Salsa20::Salsa20() : StreamCipher(16, 32, 16)
   {
   clear();
   }

}
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
/// \file mean_variance.hpp
//----------------------------------------------------------------------------
/// This file contains classes used for calculating mean and
/// variance.  They are used mainly in unit tests.
//----------------------------------------------------------------------------
// Copyright (c) 2010 Omnibius, LLC
// Author:  Serge Aleynikov <saleyn@mail.com>
// Created: 2010-05-20
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#ifndef _UTXX_MEAN_VARIANCE_HPP_
#define _UTXX_MEAN_VARIANCE_HPP_

namespace utxx {
namespace detail {

template <class T>
double mean(const T* begin, const T* end) {
    size_t count = 0;
    double sum = 0;
    for (const T* p=begin; p != end; ++p, ++count)
        sum += *p;
    return (double)sum / count;
}

template <class T>
double variance(const T* begin, const T* end) {
    double avg = mean(begin, end);
    size_t count = 0;
    double sum = 0;
    for (const T* p=begin; p != end; ++p, ++count)
        sum += (*p - avg) * (*p - avg);
    return sum / count;
}

// A numerically stable algorithm for the computation
// of the variance (and the mean as well).
template <class T>
double online_variance(const T* begin, const T* end) {
	double count = 0;
	double mean = 0;
	double sum = 0;

	for (const T* p=begin; p != end; ++p) {
		count = count + 1;
		double delta = *p - mean;
		mean = mean + delta/count;
		sum = sum + delta*(*p - mean);
	}

	return sum/count;
}

}  // namespace detail
}  // namespace utxx

#endif // _UTXX_MEAN_VARIANCE_HPP_

<commit_msg>Format the code with 4-space tabulation<commit_after>//----------------------------------------------------------------------------
/// \file mean_variance.hpp
//----------------------------------------------------------------------------
/// This file contains classes used for calculating mean and
/// variance.  They are used mainly in unit tests.
//----------------------------------------------------------------------------
// Copyright (c) 2010 Omnibius, LLC
// Author:  Serge Aleynikov <saleyn@mail.com>
// Created: 2010-05-20
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project

Copyright (C) 2010 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library 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
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/

#ifndef _UTXX_MEAN_VARIANCE_HPP_
#define _UTXX_MEAN_VARIANCE_HPP_

namespace utxx {
namespace detail {

template <class T>
double mean(const T* begin, const T* end) {
    size_t count = 0;
    double sum = 0;
    for (const T* p=begin; p != end; ++p, ++count)
        sum += *p;
    return (double)sum / count;
}

template <class T>
double variance(const T* begin, const T* end) {
    double avg = mean(begin, end);
    size_t count = 0;
    double sum = 0;
    for (const T* p=begin; p != end; ++p, ++count)
        sum += (*p - avg) * (*p - avg);
    return sum / count;
}

// A numerically stable algorithm for the computation
// of the variance (and the mean as well).
template <class T>
double online_variance(const T* begin, const T* end) {
    double count = 0;
    double mean = 0;
    double sum = 0;

    for (const T* p=begin; p != end; ++p) {
        count = count + 1;
        double delta = *p - mean;
        mean = mean + delta/count;
        sum = sum + delta*(*p - mean);
    }

    return sum/count;
}

}  // namespace detail
}  // namespace utxx

#endif // _UTXX_MEAN_VARIANCE_HPP_

<|endoftext|>