<commit_before>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *    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.
 */

/**
 *  @file
 *    This file contains implementation of Device class. The objects of this
 *    class will be used by Controller applications to interact with CHIP
 *    devices. The class provides mechanism to construct, send and receive
 *    messages to and from the corresponding CHIP devices.
 */

#include <controller/CHIPDevice.h>

#if CONFIG_DEVICE_LAYER
#include <platform/CHIPDeviceLayer.h>
#endif

#if CHIP_SYSTEM_CONFIG_USE_LWIP
#include <lwip/tcp.h>
#include <lwip/tcpip.h>
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP

#include <app/CommandSender.h>
#include <app/server/DataModelHandler.h>
#include <core/CHIPCore.h>
#include <core/CHIPEncoding.h>
#include <core/CHIPSafeCasts.h>
#include <support/Base64.h>
#include <support/CHIPMem.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/ReturnMacros.h>
#include <support/SafeInt.h>
#include <support/logging/CHIPLogging.h>
#include <system/TLVPacketBufferBackingStore.h>

using namespace chip::Inet;
using namespace chip::System;
using namespace chip::Callback;

namespace chip {
namespace Controller {

CHIP_ERROR Device::SendMessage(System::PacketBufferHandle buffer, PayloadHeader & payloadHeader)
{
    System::PacketBufferHandle resend;
    bool loadedSecureSession = false;

    VerifyOrReturnError(mSessionManager != nullptr, CHIP_ERROR_INCORRECT_STATE);
    VerifyOrReturnError(!buffer.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);

    ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(loadedSecureSession));

    if (!loadedSecureSession)
    {
        // Secure connection already existed
        // Hold on to the buffer, in case session resumption and resend is needed
        // Cloning data, instead of increasing the ref count, as the original
        // buffer might get modified by lower layers before the send fails. So,
        // that buffer cannot be used for resends.
        resend = buffer.CloneData();
    }

    CHIP_ERROR err = mSessionManager->SendMessage(mSecureSession, payloadHeader, std::move(buffer));

    buffer = nullptr;
    ChipLogDetail(Controller, "SendMessage returned %d", err);

    // The send could fail due to network timeouts (e.g. broken pipe)
    // Try session resumption if needed
    if (err != CHIP_NO_ERROR && !resend.IsNull() && mState == ConnectionState::SecureConnected)
    {
        mState = ConnectionState::NotConnected;

        ReturnErrorOnFailure(LoadSecureSessionParameters(ResetTransport::kYes));

        err = mSessionManager->SendMessage(mSecureSession, std::move(resend));
        ChipLogDetail(Controller, "Re-SendMessage returned %d", err);
        ReturnErrorOnFailure(err);
    }

    return CHIP_NO_ERROR;
}

CHIP_ERROR Device::LoadSecureSessionParametersIfNeeded(bool & didLoad)
{
    didLoad = false;

    // If there is no secure connection to the device, try establishing it
    if (mState != ConnectionState::SecureConnected)
    {
        ReturnErrorOnFailure(LoadSecureSessionParameters(ResetTransport::kNo));
        didLoad = true;
    }
    else
    {
        Transport::PeerConnectionState * connectionState = nullptr;
        connectionState                                  = mSessionManager->GetPeerConnectionState(mSecureSession);

        // Check if the connection state has the correct transport information
        if (connectionState == nullptr || connectionState->GetPeerAddress().GetTransportType() == Transport::Type::kUndefined ||
            connectionState->GetTransport() != nullptr)
        {
            mState = ConnectionState::NotConnected;
            ReturnErrorOnFailure(LoadSecureSessionParameters(ResetTransport::kNo));
            didLoad = true;
        }
    }

    return CHIP_NO_ERROR;
}

CHIP_ERROR Device::SendCommands()
{
    bool loadedSecureSession = false;
    ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(loadedSecureSession));
    VerifyOrReturnError(mCommandSender != nullptr, CHIP_ERROR_INCORRECT_STATE);
    return mCommandSender->SendCommandRequest(mDeviceId, mAdminId);
}

CHIP_ERROR Device::SendMessage(System::PacketBufferHandle buffer)
{
    PayloadHeader unusedHeader;
    return SendMessage(std::move(buffer), unusedHeader);
}

CHIP_ERROR Device::Serialize(SerializedDevice & output)
{
    CHIP_ERROR error       = CHIP_NO_ERROR;
    uint16_t serializedLen = 0;
    SerializableDevice serializable;

    static_assert(BASE64_ENCODED_LEN(sizeof(serializable)) <= sizeof(output.inner),
                  "Size of serializable should be <= size of output");

    CHIP_ZERO_AT(serializable);

    memmove(&serializable.mOpsCreds, &mPairing, sizeof(mPairing));
    serializable.mDeviceId   = Encoding::LittleEndian::HostSwap64(mDeviceId);
    serializable.mDevicePort = Encoding::LittleEndian::HostSwap16(mDevicePort);
    serializable.mAdminId    = Encoding::LittleEndian::HostSwap16(mAdminId);
    VerifyOrExit(
        CHIP_NO_ERROR ==
            Inet::GetInterfaceName(mInterface, Uint8::to_char(serializable.mInterfaceName), sizeof(serializable.mInterfaceName)),
        error = CHIP_ERROR_INTERNAL);
    static_assert(sizeof(serializable.mDeviceAddr) <= INET6_ADDRSTRLEN, "Size of device address must fit within INET6_ADDRSTRLEN");
    mDeviceAddr.ToString(Uint8::to_char(serializable.mDeviceAddr), sizeof(serializable.mDeviceAddr));

    serializedLen = chip::Base64Encode(Uint8::to_const_uchar(reinterpret_cast<uint8_t *>(&serializable)),
                                       static_cast<uint16_t>(sizeof(serializable)), Uint8::to_char(output.inner));
    VerifyOrExit(serializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(serializedLen < sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT);
    output.inner[serializedLen] = '\0';

exit:
    return error;
}

CHIP_ERROR Device::Deserialize(const SerializedDevice & input)
{
    CHIP_ERROR error = CHIP_NO_ERROR;
    SerializableDevice serializable;
    size_t maxlen            = BASE64_ENCODED_LEN(sizeof(serializable));
    size_t len               = strnlen(Uint8::to_const_char(&input.inner[0]), maxlen);
    uint16_t deserializedLen = 0;

    VerifyOrExit(len < sizeof(SerializedDevice), error = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(CanCastTo<uint16_t>(len), error = CHIP_ERROR_INVALID_ARGUMENT);

    CHIP_ZERO_AT(serializable);
    deserializedLen = Base64Decode(Uint8::to_const_char(input.inner), static_cast<uint16_t>(len),
                                   Uint8::to_uchar(reinterpret_cast<uint8_t *>(&serializable)));

    VerifyOrExit(deserializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(deserializedLen <= sizeof(serializable), error = CHIP_ERROR_INVALID_ARGUMENT);

    // The second parameter to FromString takes the strlen value. We are subtracting 1
    // from the sizeof(serializable.mDeviceAddr) to account for null termination, since
    // strlen doesn't include null character in the size.
    VerifyOrExit(
        IPAddress::FromString(Uint8::to_const_char(serializable.mDeviceAddr), sizeof(serializable.mDeviceAddr) - 1, mDeviceAddr),
        error = CHIP_ERROR_INVALID_ADDRESS);

    memmove(&mPairing, &serializable.mOpsCreds, sizeof(mPairing));
    mDeviceId   = Encoding::LittleEndian::HostSwap64(serializable.mDeviceId);
    mDevicePort = Encoding::LittleEndian::HostSwap16(serializable.mDevicePort);
    mAdminId    = Encoding::LittleEndian::HostSwap16(serializable.mAdminId);

    // The InterfaceNameToId() API requires initialization of mInterface, and lock/unlock of
    // LwIP stack.
    mInterface = INET_NULL_INTERFACEID;
    if (serializable.mInterfaceName[0] != '\0')
    {
#if CHIP_SYSTEM_CONFIG_USE_LWIP
        LOCK_TCPIP_CORE();
#endif
        INET_ERROR inetErr = Inet::InterfaceNameToId(Uint8::to_const_char(serializable.mInterfaceName), mInterface);
#if CHIP_SYSTEM_CONFIG_USE_LWIP
        UNLOCK_TCPIP_CORE();
#endif
        VerifyOrExit(CHIP_NO_ERROR == inetErr, error = CHIP_ERROR_INTERNAL);
    }

exit:
    return error;
}

void Device::OnNewConnection(SecureSessionHandle session, SecureSessionMgr * mgr)
{
    mState         = ConnectionState::SecureConnected;
    mSecureSession = session;
}

void Device::OnConnectionExpired(SecureSessionHandle session, SecureSessionMgr * mgr)
{
    mState         = ConnectionState::NotConnected;
    mSecureSession = SecureSessionHandle{};
}

void Device::OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, SecureSessionHandle session,
                               System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr)
{
    if (mState == ConnectionState::SecureConnected)
    {
        if (mStatusDelegate != nullptr)
        {
            mStatusDelegate->OnMessage(std::move(msgBuf));
        }
        else
        {
            HandleDataModelMessage(mDeviceId, std::move(msgBuf));
        }
    }
}

CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, PairingWindowOption option, SetupPayload & setupPayload)
{
    // TODO: This code is temporary, and must be updated to use the Cluster API.
    // Issue: https://github.com/project-chip/connectedhomeip/issues/4725

    // Construct and send "open pairing window" message to the device
    System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
    System::PacketBufferTLVWriter writer;

    writer.Init(std::move(buf));
    writer.ImplicitProfileId = chip::Protocols::kProtocol_ServiceProvisioning;

    ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 1), timeout));

    if (option != PairingWindowOption::kOriginalSetupCode)
    {
        ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 2), setupPayload.discriminator));

        PASEVerifier verifier;
        bool randomSetupPIN = (option == PairingWindowOption::kTokenWithRandomPIN);
        ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, randomSetupPIN, setupPayload.setUpPINCode));
        ReturnErrorOnFailure(writer.PutBytes(TLV::ProfileTag(writer.ImplicitProfileId, 3),
                                             reinterpret_cast<const uint8_t *>(verifier), sizeof(verifier)));
    }

    System::PacketBufferHandle outBuffer;
    ReturnErrorOnFailure(writer.Finalize(&outBuffer));

    PayloadHeader header;

    header.SetMessageType(chip::Protocols::kProtocol_ServiceProvisioning, 0);

    ReturnErrorOnFailure(SendMessage(std::move(outBuffer), header));

    setupPayload.version               = 1;
    setupPayload.rendezvousInformation = RendezvousInformationFlags::kBLE;

    return CHIP_NO_ERROR;
}

CHIP_ERROR Device::LoadSecureSessionParameters(ResetTransport resetNeeded)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PASESession pairingSession;

    if (mSessionManager == nullptr || mState == ConnectionState::SecureConnected)
    {
        ExitNow(err = CHIP_ERROR_INCORRECT_STATE);
    }

    err = pairingSession.FromSerializable(mPairing);
    SuccessOrExit(err);

    if (resetNeeded == ResetTransport::kYes)
    {
        err = mTransportMgr->ResetTransport(
            Transport::UdpListenParameters(mInetLayer).SetAddressType(kIPAddressType_IPv6).SetListenPort(mListenPort)
#if INET_CONFIG_ENABLE_IPV4
                ,
            Transport::UdpListenParameters(mInetLayer).SetAddressType(kIPAddressType_IPv4).SetListenPort(mListenPort)
#endif
        );
        SuccessOrExit(err);
    }

    err = mSessionManager->NewPairing(
        Optional<Transport::PeerAddress>::Value(Transport::PeerAddress::UDP(mDeviceAddr, mDevicePort, mInterface)), mDeviceId,
        &pairingSession, SecureSessionMgr::PairingDirection::kInitiator, mAdminId);
    SuccessOrExit(err);

exit:

    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(Controller, "LoadSecureSessionParameters returning error %d\n", err);
    }
    return err;
}

bool Device::GetIpAddress(Inet::IPAddress & addr) const
{
    if (mState == ConnectionState::NotConnected)
        return false;
    addr = mDeviceAddr;
    return true;
}

void Device::AddResponseHandler(uint8_t seqNum, Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback)
{
    mCallbacksMgr.AddResponseCallback(mDeviceId, seqNum, onSuccessCallback, onFailureCallback);
}

void Device::AddReportHandler(EndpointId endpoint, ClusterId cluster, AttributeId attribute,
                              Callback::Cancelable * onReportCallback)
{
    mCallbacksMgr.AddReportCallback(mDeviceId, endpoint, cluster, attribute, onReportCallback);
}

} // namespace Controller
} // namespace chip
<commit_msg>Replace memmove of PASESessionSerializable (#5029)<commit_after>/*
 *
 *    Copyright (c) 2020 Project CHIP Authors
 *    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.
 */

/**
 *  @file
 *    This file contains implementation of Device class. The objects of this
 *    class will be used by Controller applications to interact with CHIP
 *    devices. The class provides mechanism to construct, send and receive
 *    messages to and from the corresponding CHIP devices.
 */

#include <controller/CHIPDevice.h>

#if CONFIG_DEVICE_LAYER
#include <platform/CHIPDeviceLayer.h>
#endif

#if CHIP_SYSTEM_CONFIG_USE_LWIP
#include <lwip/tcp.h>
#include <lwip/tcpip.h>
#endif // CHIP_SYSTEM_CONFIG_USE_LWIP

#include <app/CommandSender.h>
#include <app/server/DataModelHandler.h>
#include <core/CHIPCore.h>
#include <core/CHIPEncoding.h>
#include <core/CHIPSafeCasts.h>
#include <support/Base64.h>
#include <support/CHIPMem.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/ReturnMacros.h>
#include <support/SafeInt.h>
#include <support/logging/CHIPLogging.h>
#include <system/TLVPacketBufferBackingStore.h>

using namespace chip::Inet;
using namespace chip::System;
using namespace chip::Callback;

namespace chip {
namespace Controller {

CHIP_ERROR Device::SendMessage(System::PacketBufferHandle buffer, PayloadHeader & payloadHeader)
{
    System::PacketBufferHandle resend;
    bool loadedSecureSession = false;

    VerifyOrReturnError(mSessionManager != nullptr, CHIP_ERROR_INCORRECT_STATE);
    VerifyOrReturnError(!buffer.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);

    ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(loadedSecureSession));

    if (!loadedSecureSession)
    {
        // Secure connection already existed
        // Hold on to the buffer, in case session resumption and resend is needed
        // Cloning data, instead of increasing the ref count, as the original
        // buffer might get modified by lower layers before the send fails. So,
        // that buffer cannot be used for resends.
        resend = buffer.CloneData();
    }

    CHIP_ERROR err = mSessionManager->SendMessage(mSecureSession, payloadHeader, std::move(buffer));

    buffer = nullptr;
    ChipLogDetail(Controller, "SendMessage returned %d", err);

    // The send could fail due to network timeouts (e.g. broken pipe)
    // Try session resumption if needed
    if (err != CHIP_NO_ERROR && !resend.IsNull() && mState == ConnectionState::SecureConnected)
    {
        mState = ConnectionState::NotConnected;

        ReturnErrorOnFailure(LoadSecureSessionParameters(ResetTransport::kYes));

        err = mSessionManager->SendMessage(mSecureSession, std::move(resend));
        ChipLogDetail(Controller, "Re-SendMessage returned %d", err);
        ReturnErrorOnFailure(err);
    }

    return CHIP_NO_ERROR;
}

CHIP_ERROR Device::LoadSecureSessionParametersIfNeeded(bool & didLoad)
{
    didLoad = false;

    // If there is no secure connection to the device, try establishing it
    if (mState != ConnectionState::SecureConnected)
    {
        ReturnErrorOnFailure(LoadSecureSessionParameters(ResetTransport::kNo));
        didLoad = true;
    }
    else
    {
        Transport::PeerConnectionState * connectionState = nullptr;
        connectionState                                  = mSessionManager->GetPeerConnectionState(mSecureSession);

        // Check if the connection state has the correct transport information
        if (connectionState == nullptr || connectionState->GetPeerAddress().GetTransportType() == Transport::Type::kUndefined ||
            connectionState->GetTransport() != nullptr)
        {
            mState = ConnectionState::NotConnected;
            ReturnErrorOnFailure(LoadSecureSessionParameters(ResetTransport::kNo));
            didLoad = true;
        }
    }

    return CHIP_NO_ERROR;
}

CHIP_ERROR Device::SendCommands()
{
    bool loadedSecureSession = false;
    ReturnErrorOnFailure(LoadSecureSessionParametersIfNeeded(loadedSecureSession));
    VerifyOrReturnError(mCommandSender != nullptr, CHIP_ERROR_INCORRECT_STATE);
    return mCommandSender->SendCommandRequest(mDeviceId, mAdminId);
}

CHIP_ERROR Device::SendMessage(System::PacketBufferHandle buffer)
{
    PayloadHeader unusedHeader;
    return SendMessage(std::move(buffer), unusedHeader);
}

CHIP_ERROR Device::Serialize(SerializedDevice & output)
{
    CHIP_ERROR error       = CHIP_NO_ERROR;
    uint16_t serializedLen = 0;
    SerializableDevice serializable;

    static_assert(BASE64_ENCODED_LEN(sizeof(serializable)) <= sizeof(output.inner),
                  "Size of serializable should be <= size of output");

    CHIP_ZERO_AT(serializable);

    serializable.mOpsCreds   = mPairing;
    serializable.mDeviceId   = Encoding::LittleEndian::HostSwap64(mDeviceId);
    serializable.mDevicePort = Encoding::LittleEndian::HostSwap16(mDevicePort);
    serializable.mAdminId    = Encoding::LittleEndian::HostSwap16(mAdminId);
    VerifyOrExit(
        CHIP_NO_ERROR ==
            Inet::GetInterfaceName(mInterface, Uint8::to_char(serializable.mInterfaceName), sizeof(serializable.mInterfaceName)),
        error = CHIP_ERROR_INTERNAL);
    static_assert(sizeof(serializable.mDeviceAddr) <= INET6_ADDRSTRLEN, "Size of device address must fit within INET6_ADDRSTRLEN");
    mDeviceAddr.ToString(Uint8::to_char(serializable.mDeviceAddr), sizeof(serializable.mDeviceAddr));

    serializedLen = chip::Base64Encode(Uint8::to_const_uchar(reinterpret_cast<uint8_t *>(&serializable)),
                                       static_cast<uint16_t>(sizeof(serializable)), Uint8::to_char(output.inner));
    VerifyOrExit(serializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(serializedLen < sizeof(output.inner), error = CHIP_ERROR_INVALID_ARGUMENT);
    output.inner[serializedLen] = '\0';

exit:
    return error;
}

CHIP_ERROR Device::Deserialize(const SerializedDevice & input)
{
    CHIP_ERROR error = CHIP_NO_ERROR;
    SerializableDevice serializable;
    size_t maxlen            = BASE64_ENCODED_LEN(sizeof(serializable));
    size_t len               = strnlen(Uint8::to_const_char(&input.inner[0]), maxlen);
    uint16_t deserializedLen = 0;

    VerifyOrExit(len < sizeof(SerializedDevice), error = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(CanCastTo<uint16_t>(len), error = CHIP_ERROR_INVALID_ARGUMENT);

    CHIP_ZERO_AT(serializable);
    deserializedLen = Base64Decode(Uint8::to_const_char(input.inner), static_cast<uint16_t>(len),
                                   Uint8::to_uchar(reinterpret_cast<uint8_t *>(&serializable)));

    VerifyOrExit(deserializedLen > 0, error = CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrExit(deserializedLen <= sizeof(serializable), error = CHIP_ERROR_INVALID_ARGUMENT);

    // The second parameter to FromString takes the strlen value. We are subtracting 1
    // from the sizeof(serializable.mDeviceAddr) to account for null termination, since
    // strlen doesn't include null character in the size.
    VerifyOrExit(
        IPAddress::FromString(Uint8::to_const_char(serializable.mDeviceAddr), sizeof(serializable.mDeviceAddr) - 1, mDeviceAddr),
        error = CHIP_ERROR_INVALID_ADDRESS);

    mPairing    = serializable.mOpsCreds;
    mDeviceId   = Encoding::LittleEndian::HostSwap64(serializable.mDeviceId);
    mDevicePort = Encoding::LittleEndian::HostSwap16(serializable.mDevicePort);
    mAdminId    = Encoding::LittleEndian::HostSwap16(serializable.mAdminId);

    // The InterfaceNameToId() API requires initialization of mInterface, and lock/unlock of
    // LwIP stack.
    mInterface = INET_NULL_INTERFACEID;
    if (serializable.mInterfaceName[0] != '\0')
    {
#if CHIP_SYSTEM_CONFIG_USE_LWIP
        LOCK_TCPIP_CORE();
#endif
        INET_ERROR inetErr = Inet::InterfaceNameToId(Uint8::to_const_char(serializable.mInterfaceName), mInterface);
#if CHIP_SYSTEM_CONFIG_USE_LWIP
        UNLOCK_TCPIP_CORE();
#endif
        VerifyOrExit(CHIP_NO_ERROR == inetErr, error = CHIP_ERROR_INTERNAL);
    }

exit:
    return error;
}

void Device::OnNewConnection(SecureSessionHandle session, SecureSessionMgr * mgr)
{
    mState         = ConnectionState::SecureConnected;
    mSecureSession = session;
}

void Device::OnConnectionExpired(SecureSessionHandle session, SecureSessionMgr * mgr)
{
    mState         = ConnectionState::NotConnected;
    mSecureSession = SecureSessionHandle{};
}

void Device::OnMessageReceived(const PacketHeader & header, const PayloadHeader & payloadHeader, SecureSessionHandle session,
                               System::PacketBufferHandle msgBuf, SecureSessionMgr * mgr)
{
    if (mState == ConnectionState::SecureConnected)
    {
        if (mStatusDelegate != nullptr)
        {
            mStatusDelegate->OnMessage(std::move(msgBuf));
        }
        else
        {
            HandleDataModelMessage(mDeviceId, std::move(msgBuf));
        }
    }
}

CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, PairingWindowOption option, SetupPayload & setupPayload)
{
    // TODO: This code is temporary, and must be updated to use the Cluster API.
    // Issue: https://github.com/project-chip/connectedhomeip/issues/4725

    // Construct and send "open pairing window" message to the device
    System::PacketBufferHandle buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
    System::PacketBufferTLVWriter writer;

    writer.Init(std::move(buf));
    writer.ImplicitProfileId = chip::Protocols::kProtocol_ServiceProvisioning;

    ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 1), timeout));

    if (option != PairingWindowOption::kOriginalSetupCode)
    {
        ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 2), setupPayload.discriminator));

        PASEVerifier verifier;
        bool randomSetupPIN = (option == PairingWindowOption::kTokenWithRandomPIN);
        ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, randomSetupPIN, setupPayload.setUpPINCode));
        ReturnErrorOnFailure(writer.PutBytes(TLV::ProfileTag(writer.ImplicitProfileId, 3),
                                             reinterpret_cast<const uint8_t *>(verifier), sizeof(verifier)));
    }

    System::PacketBufferHandle outBuffer;
    ReturnErrorOnFailure(writer.Finalize(&outBuffer));

    PayloadHeader header;

    header.SetMessageType(chip::Protocols::kProtocol_ServiceProvisioning, 0);

    ReturnErrorOnFailure(SendMessage(std::move(outBuffer), header));

    setupPayload.version               = 1;
    setupPayload.rendezvousInformation = RendezvousInformationFlags::kBLE;

    return CHIP_NO_ERROR;
}

CHIP_ERROR Device::LoadSecureSessionParameters(ResetTransport resetNeeded)
{
    CHIP_ERROR err = CHIP_NO_ERROR;
    PASESession pairingSession;

    if (mSessionManager == nullptr || mState == ConnectionState::SecureConnected)
    {
        ExitNow(err = CHIP_ERROR_INCORRECT_STATE);
    }

    err = pairingSession.FromSerializable(mPairing);
    SuccessOrExit(err);

    if (resetNeeded == ResetTransport::kYes)
    {
        err = mTransportMgr->ResetTransport(
            Transport::UdpListenParameters(mInetLayer).SetAddressType(kIPAddressType_IPv6).SetListenPort(mListenPort)
#if INET_CONFIG_ENABLE_IPV4
                ,
            Transport::UdpListenParameters(mInetLayer).SetAddressType(kIPAddressType_IPv4).SetListenPort(mListenPort)
#endif
        );
        SuccessOrExit(err);
    }

    err = mSessionManager->NewPairing(
        Optional<Transport::PeerAddress>::Value(Transport::PeerAddress::UDP(mDeviceAddr, mDevicePort, mInterface)), mDeviceId,
        &pairingSession, SecureSessionMgr::PairingDirection::kInitiator, mAdminId);
    SuccessOrExit(err);

exit:

    if (err != CHIP_NO_ERROR)
    {
        ChipLogError(Controller, "LoadSecureSessionParameters returning error %d\n", err);
    }
    return err;
}

bool Device::GetIpAddress(Inet::IPAddress & addr) const
{
    if (mState == ConnectionState::NotConnected)
        return false;
    addr = mDeviceAddr;
    return true;
}

void Device::AddResponseHandler(uint8_t seqNum, Callback::Cancelable * onSuccessCallback, Callback::Cancelable * onFailureCallback)
{
    mCallbacksMgr.AddResponseCallback(mDeviceId, seqNum, onSuccessCallback, onFailureCallback);
}

void Device::AddReportHandler(EndpointId endpoint, ClusterId cluster, AttributeId attribute,
                              Callback::Cancelable * onReportCallback)
{
    mCallbacksMgr.AddReportCallback(mDeviceId, endpoint, cluster, attribute, onReportCallback);
}

} // namespace Controller
} // namespace chip
<|endoftext|>


<commit_before>/*
 * Copyright 2022 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/core/SkPaintParamsKey.h"

#include <cstring>
#include "src/core/SkKeyHelpers.h"
#include "src/core/SkShaderCodeDictionary.h"

//--------------------------------------------------------------------------------------------------
SkPaintParamsKeyBuilder::SkPaintParamsKeyBuilder(const SkShaderCodeDictionary* dict,
                                                 SkBackend backend)
        : fDict(dict)
        , fBackend(backend) {
}

#ifdef SK_DEBUG
void SkPaintParamsKeyBuilder::checkReset() {
    SkASSERT(!this->isLocked());
    SkASSERT(this->sizeInBytes() == 0);
    SkASSERT(this->numPointers() == 0);
    SkASSERT(fIsValid);
    SkASSERT(fStack.empty());
#ifdef SK_GRAPHITE_ENABLED
    SkASSERT(fBlendInfo == skgpu::BlendInfo());
#endif
}
#endif

// Block headers have the following structure:
//  1st byte: codeSnippetID
//  2nd byte: total blockSize in bytes
// This call stores the header's offset in the key on the stack to be used in 'endBlock'
void SkPaintParamsKeyBuilder::beginBlock(int codeSnippetID) {
    if (!this->isValid()) {
        return;
    }

    if (!fDict->isValidID(codeSnippetID)) {
        // SKGPU_LOG_W("Unknown code snippet ID.");
        this->makeInvalid();
        return;
    }

#ifdef SK_DEBUG
    if (!fStack.empty()) {
        // The children of a block should appear before any of the parent's data
        SkASSERT(fStack.back().fCurDataPayloadEntry == 0);
        fStack.back().fNumActualChildren++;
    }

    static const SkPaintParamsKey::DataPayloadField kHeader[2] = {
            {"snippetID", SkPaintParamsKey::DataPayloadType::kByte, 1},
            {"blockSize", SkPaintParamsKey::DataPayloadType::kByte, 1},
    };

    static const SkSpan<const SkPaintParamsKey::DataPayloadField> kHeaderExpectations(kHeader, 2);
#endif

    SkASSERT(!this->isLocked());

    fStack.push_back({ codeSnippetID, this->sizeInBytes(),
                       SkDEBUGCODE(kHeaderExpectations, 0) });

    this->addByte(SkTo<uint8_t>(codeSnippetID));
    this->addByte(0);  // this will be filled in when endBlock is called

#ifdef SK_DEBUG
    const SkShaderSnippet* snippet = fDict->getEntry(codeSnippetID);

    fStack.back().fDataPayloadExpectations = snippet->fDataPayloadExpectations;
    fStack.back().fCurDataPayloadEntry = 0;
    fStack.back().fNumExpectedChildren = snippet->fNumChildren;
    fStack.back().fNumActualChildren = 0;
    fStack.back().fNumExpectedPointers = snippet->fNumPointers;
    fStack.back().fNumActualPointers = 0;
#endif
}

// Update the size byte of a block header
void SkPaintParamsKeyBuilder::endBlock() {
    if (!this->isValid()) {
        return;
    }

    if (fStack.empty()) {
        // SKGPU_LOG_W("Mismatched beginBlock/endBlocks.");
        this->makeInvalid();
        return;
    }

    // All the expected fields should be filled in at this point
    SkASSERT(fStack.back().fCurDataPayloadEntry ==
             SkTo<int>(fStack.back().fDataPayloadExpectations.size()));
    SkASSERT(fStack.back().fNumActualChildren == fStack.back().fNumExpectedChildren);
    SkASSERT(fStack.back().fNumActualPointers == fStack.back().fNumExpectedPointers);
    SkASSERT(!this->isLocked());

    int headerOffset = fStack.back().fHeaderOffset;

    SkPaintParamsKey::Header* header =
            reinterpret_cast<SkPaintParamsKey::Header*>(&fData[headerOffset]);
    SkASSERT(header->codeSnippetID == fStack.back().fCodeSnippetID);
    SkASSERT(header->blockSize == 0);

    int blockSize = this->sizeInBytes() - headerOffset;
    if (blockSize > SkPaintParamsKey::kMaxBlockSize) {
        // SKGPU_LOG_W("Key's data payload is too large.");
        this->makeInvalid();
        return;
    }

    header->blockSize = blockSize;

    fStack.pop();

#ifdef SK_DEBUG
    if (!fStack.empty()) {
        // The children of a block should appear before any of the parent's data
        SkASSERT(fStack.back().fCurDataPayloadEntry == 0);
    }
#endif
}

#ifdef SK_DEBUG
void SkPaintParamsKeyBuilder::checkExpectations(SkPaintParamsKey::DataPayloadType actualType,
                                                uint32_t actualCount) {
    StackFrame& frame = fStack.back();
    const auto& expectations = frame.fDataPayloadExpectations;

    // TODO: right now we reject writing 'n' bytes one at a time. We could allow it by tracking
    // the number of bytes written in the stack frame.
    SkASSERT(expectations[frame.fCurDataPayloadEntry].fType == actualType);
    SkASSERT(expectations[frame.fCurDataPayloadEntry].fCount == actualCount);

    frame.fCurDataPayloadEntry++;
}
#endif // SK_DEBUG

void SkPaintParamsKeyBuilder::addBytes(uint32_t numBytes, const uint8_t* data) {
    if (!this->isValid()) {
        return;
    }

    if (fStack.empty()) {
        // SKGPU_LOG_W("Missing call to 'beginBlock'.");
        this->makeInvalid();
        return;
    }

    SkDEBUGCODE(this->checkExpectations(SkPaintParamsKey::DataPayloadType::kByte, numBytes);)
    SkASSERT(!this->isLocked());

    fData.append(numBytes, data);
}

void SkPaintParamsKeyBuilder::add(const SkColor4f& color) {
    if (!this->isValid()) {
        return;
    }

    if (fStack.empty()) {
        // SKGPU_LOG_W("Missing call to 'beginBlock'.");
        this->makeInvalid();
        return;
    }

    SkDEBUGCODE(this->checkExpectations(SkPaintParamsKey::DataPayloadType::kFloat4, 1);)
    SkASSERT(!this->isLocked());

    fData.append(16, reinterpret_cast<const uint8_t*>(&color));
}

void SkPaintParamsKeyBuilder::addPointer(const void* ptr) {
    if (!this->isValid()) {
        return;
    }

    if (fStack.empty()) {
        // SKGPU_LOG_W("Missing call to 'beginBlock'.");
        this->makeInvalid();
        return;
    }

#ifdef SK_DEBUG
    StackFrame& frame = fStack.back();
    SkASSERT(frame.fNumActualPointers < frame.fNumExpectedPointers);
    frame.fNumActualPointers++;
#endif

    SkDEBUGCODE(this->checkExpectations(SkPaintParamsKey::DataPayloadType::kPointerIndex, 1);)
    SkASSERT(!this->isLocked());
    SkASSERT(fPointerData.size() <= 0xFF);
    fData.append((uint8_t)fPointerData.size());
    fPointerData.push_back(ptr);
}

SkPaintParamsKey SkPaintParamsKeyBuilder::lockAsKey() {
    if (!fStack.empty()) {
        // SKGPU_LOG_W("Mismatched beginBlock/endBlocks.");
        this->makeInvalid();  // fall through
    }

    SkASSERT(!this->isLocked());

    // Partially reset for reuse. Note that the key resulting from this call will be holding a lock
    // on this builder and must be deleted before this builder is fully reset.
    fIsValid = true;
    fStack.rewind();

    return SkPaintParamsKey(SkSpan(fData.begin(), fData.count()),
                            SkSpan(fPointerData.begin(), fPointerData.count()),
                            this);
}

void SkPaintParamsKeyBuilder::makeInvalid() {
    SkASSERT(fIsValid);
    SkASSERT(!this->isLocked());

    fStack.rewind();
    fData.rewind();
    fPointerData.rewind();
    this->beginBlock(SkBuiltInCodeSnippetID::kError);
    this->endBlock();

    SkASSERT(fIsValid);
    fIsValid = false;
}

//--------------------------------------------------------------------------------------------------
SkPaintParamsKey::SkPaintParamsKey(SkSpan<const uint8_t> span,
                                   SkSpan<const void*> pointerSpan,
                                   SkPaintParamsKeyBuilder* originatingBuilder)
        : fData(span)
        , fPointerData(pointerSpan)
        , fOriginatingBuilder(originatingBuilder) {
    fOriginatingBuilder->lock();
}

SkPaintParamsKey::SkPaintParamsKey(SkSpan<const uint8_t> rawData)
        : fData(rawData)
        , fOriginatingBuilder(nullptr) {
}

SkPaintParamsKey::~SkPaintParamsKey() {
    if (fOriginatingBuilder) {
        fOriginatingBuilder->unlock();
    }
}

bool SkPaintParamsKey::operator==(const SkPaintParamsKey& that) const {
    // Pointer data is intentionally ignored here; a cached key will not have pointer data.
    return fData.size() == that.fData.size() &&
           !memcmp(fData.data(), that.fData.data(), fData.size());
}

SkPaintParamsKey::BlockReader SkPaintParamsKey::reader(const SkShaderCodeDictionary* dict,
                                                       int headerOffset) const {
    // TODO(skia:13428): block reader needs to provide pointer data
    return BlockReader(dict, fData, headerOffset);
}

#ifdef SK_DEBUG

// This just iterates over the top-level blocks calling block-specific dump methods.
void SkPaintParamsKey::dump(const SkShaderCodeDictionary* dict) const {
    SkDebugf("--------------------------------------\n");
    SkDebugf("SkPaintParamsKey (%dB):\n", this->sizeInBytes());

    int curHeaderOffset = 0;
    while (curHeaderOffset < this->sizeInBytes()) {
        BlockReader reader = this->reader(dict, curHeaderOffset);
        reader.dump(dict, /* indent */ 0);
        curHeaderOffset += reader.blockSize();
    }
}
#endif // SK_DEBUG

void SkPaintParamsKey::AddBlockToShaderInfo(SkShaderCodeDictionary* dict,
                                            const SkPaintParamsKey::BlockReader& reader,
                                            SkShaderInfo* result) {

    result->add(reader);
#ifdef SK_GRAPHITE_ENABLED
    result->addFlags(dict->getSnippetRequirementFlags(reader.codeSnippetId()));
#endif

    // The child blocks appear right after the parent block's header in the key and go
    // right after the parent's SnippetEntry in the shader info
    for (int i = 0; i < reader.numChildren(); ++i) {
        SkPaintParamsKey::BlockReader childReader = reader.child(dict, i);

        AddBlockToShaderInfo(dict, childReader, result);
    }
}

void SkPaintParamsKey::toShaderInfo(SkShaderCodeDictionary* dict, SkShaderInfo* result) const {

    int curHeaderOffset = 0;
    while (curHeaderOffset < this->sizeInBytes()) {
        SkPaintParamsKey::BlockReader reader = this->reader(dict, curHeaderOffset);
        AddBlockToShaderInfo(dict, reader, result);
        curHeaderOffset += reader.blockSize();
    }
}

#if GR_TEST_UTILS
bool SkPaintParamsKey::isErrorKey() const {
    return this->sizeInBytes() == sizeof(Header) &&
           fData[0] == static_cast<int>(SkBuiltInCodeSnippetID::kError) &&
           fData[1] == sizeof(Header);
}
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace {

#ifdef SK_DEBUG
void output_indent(int indent) {
    SkDebugf("%*c", 4 * indent, ' ');
}
#endif

SkPaintParamsKey::Header read_header(SkSpan<const uint8_t> parentSpan, int headerOffset) {
    SkASSERT(headerOffset + sizeof(SkPaintParamsKey::Header) <= parentSpan.size());

    const SkPaintParamsKey::Header* header =
            reinterpret_cast<const SkPaintParamsKey::Header*>(&parentSpan[headerOffset]);
    SkASSERT(header->blockSize >= sizeof(SkPaintParamsKey::Header));
    SkASSERT(headerOffset + header->blockSize <= static_cast<int>(parentSpan.size()));

    return *header;
}

} // anonymous namespace

SkPaintParamsKey::BlockReader::BlockReader(const SkShaderCodeDictionary* dict,
                                           SkSpan<const uint8_t> parentSpan,
                                           int offsetInParent) {
    Header header = read_header(parentSpan, offsetInParent);

    fBlock = parentSpan.subspan(offsetInParent, header.blockSize);
    fEntry = dict->getEntry(header.codeSnippetID);
    SkASSERT(fEntry);
}

int SkPaintParamsKey::BlockReader::numChildren() const { return fEntry->fNumChildren; }

SkPaintParamsKey::BlockReader SkPaintParamsKey::BlockReader::child(
        const SkShaderCodeDictionary* dict,
        int childIndex) const {
    SkASSERT(childIndex < fEntry->fNumChildren);

    int childOffset = sizeof(Header);
    for (int i = 0; i < childIndex; ++i) {
        Header header = read_header(fBlock, childOffset);
        childOffset += header.blockSize;
    }

    return BlockReader(dict, fBlock, childOffset);
}

SkSpan<const uint8_t> SkPaintParamsKey::BlockReader::dataPayload() const {
    int payloadOffset = sizeof(Header);
    for (int i = 0; i < fEntry->fNumChildren; ++i) {
        Header header = read_header(fBlock, payloadOffset);
        payloadOffset += header.blockSize;
    }

    int payloadSize = this->blockSize() - payloadOffset;
    return fBlock.subspan(payloadOffset, payloadSize);
}

SkSpan<const uint8_t> SkPaintParamsKey::BlockReader::bytes(int fieldIndex) const {
    SkASSERT(fEntry->fDataPayloadExpectations[fieldIndex].fType == DataPayloadType::kByte);

    int byteOffsetInPayload = 0;
    for (int i = 0; i < fieldIndex; ++i) {
        SkASSERT(fEntry->fDataPayloadExpectations[i].fType == DataPayloadType::kByte);
        byteOffsetInPayload += fEntry->fDataPayloadExpectations[i].fCount;
    }

    SkSpan<const uint8_t> dataPayload = this->dataPayload();
    return dataPayload.subspan(byteOffsetInPayload,
                               fEntry->fDataPayloadExpectations[fieldIndex].fCount);
}

#ifdef SK_DEBUG

int SkPaintParamsKey::BlockReader::numDataPayloadFields() const {
    return fEntry->fDataPayloadExpectations.size();
}

void SkPaintParamsKey::BlockReader::dump(const SkShaderCodeDictionary* dict, int indent) const {
    uint8_t id = static_cast<uint8_t>(this->codeSnippetId());
    uint8_t blockSize = this->blockSize();

    auto entry = dict->getEntry(id);
    if (!entry) {
        output_indent(indent);
        SkDebugf("unknown block! (%dB)\n", blockSize);
    }

    output_indent(indent);
    SkDebugf("%s block (%dB)\n", entry->fStaticFunctionName, blockSize);

    for (int i = 0; i < this->numChildren(); ++i) {
        output_indent(indent);
        // TODO: it would be nice if the names of the children were also stored (i.e., "src"/"dst")
        SkDebugf("child %d:\n", i);

        SkPaintParamsKey::BlockReader childReader = this->child(dict, i);
        childReader.dump(dict, indent+1);
    }

    for (int i = 0; i < (int) fEntry->fDataPayloadExpectations.size(); ++i) {
        output_indent(indent);
        SkDebugf("%s[%d]: ",
                 fEntry->fDataPayloadExpectations[i].fName,
                 fEntry->fDataPayloadExpectations[i].fCount);
        SkSpan<const uint8_t> bytes = this->bytes(i);
        for (uint8_t b : bytes) {
            SkDebugf("%d,", b);
        }

        SkDebugf("\n");
    }
}

#endif // SK_DEBUG
<commit_msg>Add method to calculate size of a DataPayloadField.<commit_after>/*
 * Copyright 2022 Google LLC
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/core/SkPaintParamsKey.h"

#include <cstring>
#include "src/core/SkKeyHelpers.h"
#include "src/core/SkShaderCodeDictionary.h"

using DataPayloadType  = SkPaintParamsKey::DataPayloadType;
using DataPayloadField = SkPaintParamsKey::DataPayloadField;

//--------------------------------------------------------------------------------------------------
SkPaintParamsKeyBuilder::SkPaintParamsKeyBuilder(const SkShaderCodeDictionary* dict,
                                                 SkBackend backend)
        : fDict(dict)
        , fBackend(backend) {
}

#ifdef SK_DEBUG
void SkPaintParamsKeyBuilder::checkReset() {
    SkASSERT(!this->isLocked());
    SkASSERT(this->sizeInBytes() == 0);
    SkASSERT(this->numPointers() == 0);
    SkASSERT(fIsValid);
    SkASSERT(fStack.empty());
#ifdef SK_GRAPHITE_ENABLED
    SkASSERT(fBlendInfo == skgpu::BlendInfo());
#endif
}
#endif

// Block headers have the following structure:
//  1st byte: codeSnippetID
//  2nd byte: total blockSize in bytes
// This call stores the header's offset in the key on the stack to be used in 'endBlock'
void SkPaintParamsKeyBuilder::beginBlock(int codeSnippetID) {
    if (!this->isValid()) {
        return;
    }

    if (!fDict->isValidID(codeSnippetID)) {
        // SKGPU_LOG_W("Unknown code snippet ID.");
        this->makeInvalid();
        return;
    }

#ifdef SK_DEBUG
    if (!fStack.empty()) {
        // The children of a block should appear before any of the parent's data
        SkASSERT(fStack.back().fCurDataPayloadEntry == 0);
        fStack.back().fNumActualChildren++;
    }

    static constexpr DataPayloadField kHeader[2] = {
            {"snippetID", DataPayloadType::kByte, 1},
            {"blockSize", DataPayloadType::kByte, 1},
    };

    static const SkSpan<const DataPayloadField> kHeaderExpectations(kHeader);
#endif

    SkASSERT(!this->isLocked());

    fStack.push_back({ codeSnippetID, this->sizeInBytes(),
                       SkDEBUGCODE(kHeaderExpectations, 0) });

    this->addByte(SkTo<uint8_t>(codeSnippetID));
    this->addByte(0);  // this will be filled in when endBlock is called

#ifdef SK_DEBUG
    const SkShaderSnippet* snippet = fDict->getEntry(codeSnippetID);

    fStack.back().fDataPayloadExpectations = snippet->fDataPayloadExpectations;
    fStack.back().fCurDataPayloadEntry = 0;
    fStack.back().fNumExpectedChildren = snippet->fNumChildren;
    fStack.back().fNumActualChildren = 0;
    fStack.back().fNumExpectedPointers = snippet->fNumPointers;
    fStack.back().fNumActualPointers = 0;
#endif
}

// Update the size byte of a block header
void SkPaintParamsKeyBuilder::endBlock() {
    if (!this->isValid()) {
        return;
    }

    if (fStack.empty()) {
        // SKGPU_LOG_W("Mismatched beginBlock/endBlocks.");
        this->makeInvalid();
        return;
    }

    // All the expected fields should be filled in at this point
    SkASSERT(fStack.back().fCurDataPayloadEntry ==
             SkTo<int>(fStack.back().fDataPayloadExpectations.size()));
    SkASSERT(fStack.back().fNumActualChildren == fStack.back().fNumExpectedChildren);
    SkASSERT(fStack.back().fNumActualPointers == fStack.back().fNumExpectedPointers);
    SkASSERT(!this->isLocked());

    int headerOffset = fStack.back().fHeaderOffset;

    SkPaintParamsKey::Header* header =
            reinterpret_cast<SkPaintParamsKey::Header*>(&fData[headerOffset]);
    SkASSERT(header->codeSnippetID == fStack.back().fCodeSnippetID);
    SkASSERT(header->blockSize == 0);

    int blockSize = this->sizeInBytes() - headerOffset;
    if (blockSize > SkPaintParamsKey::kMaxBlockSize) {
        // SKGPU_LOG_W("Key's data payload is too large.");
        this->makeInvalid();
        return;
    }

    header->blockSize = blockSize;

    fStack.pop();

#ifdef SK_DEBUG
    if (!fStack.empty()) {
        // The children of a block should appear before any of the parent's data
        SkASSERT(fStack.back().fCurDataPayloadEntry == 0);
    }
#endif
}

#ifdef SK_DEBUG
void SkPaintParamsKeyBuilder::checkExpectations(DataPayloadType actualType, uint32_t actualCount) {
    StackFrame& frame = fStack.back();
    const auto& expectations = frame.fDataPayloadExpectations;

    // TODO: right now we reject writing 'n' bytes one at a time. We could allow it by tracking
    // the number of bytes written in the stack frame.
    SkASSERT(expectations[frame.fCurDataPayloadEntry].fType == actualType);
    SkASSERT(expectations[frame.fCurDataPayloadEntry].fCount == actualCount);

    frame.fCurDataPayloadEntry++;
}
#endif // SK_DEBUG

void SkPaintParamsKeyBuilder::addBytes(uint32_t numBytes, const uint8_t* data) {
    if (!this->isValid()) {
        return;
    }

    if (fStack.empty()) {
        // SKGPU_LOG_W("Missing call to 'beginBlock'.");
        this->makeInvalid();
        return;
    }

    SkDEBUGCODE(this->checkExpectations(DataPayloadType::kByte, numBytes);)
    SkASSERT(!this->isLocked());

    fData.append(numBytes, data);
}

void SkPaintParamsKeyBuilder::add(const SkColor4f& color) {
    if (!this->isValid()) {
        return;
    }

    if (fStack.empty()) {
        // SKGPU_LOG_W("Missing call to 'beginBlock'.");
        this->makeInvalid();
        return;
    }

    SkDEBUGCODE(this->checkExpectations(DataPayloadType::kFloat4, 1);)
    SkASSERT(!this->isLocked());

    fData.append(16, reinterpret_cast<const uint8_t*>(&color));
}

void SkPaintParamsKeyBuilder::addPointer(const void* ptr) {
    if (!this->isValid()) {
        return;
    }

    if (fStack.empty()) {
        // SKGPU_LOG_W("Missing call to 'beginBlock'.");
        this->makeInvalid();
        return;
    }

#ifdef SK_DEBUG
    StackFrame& frame = fStack.back();
    SkASSERT(frame.fNumActualPointers < frame.fNumExpectedPointers);
    frame.fNumActualPointers++;
#endif

    SkDEBUGCODE(this->checkExpectations(SkPaintParamsKey::DataPayloadType::kPointerIndex, 1);)
    SkASSERT(!this->isLocked());
    SkASSERT(fPointerData.size() <= 0xFF);
    fData.append((uint8_t)fPointerData.size());
    fPointerData.push_back(ptr);
}

SkPaintParamsKey SkPaintParamsKeyBuilder::lockAsKey() {
    if (!fStack.empty()) {
        // SKGPU_LOG_W("Mismatched beginBlock/endBlocks.");
        this->makeInvalid();  // fall through
    }

    SkASSERT(!this->isLocked());

    // Partially reset for reuse. Note that the key resulting from this call will be holding a lock
    // on this builder and must be deleted before this builder is fully reset.
    fIsValid = true;
    fStack.rewind();

    return SkPaintParamsKey(SkSpan(fData.begin(), fData.count()),
                            SkSpan(fPointerData.begin(), fPointerData.count()),
                            this);
}

void SkPaintParamsKeyBuilder::makeInvalid() {
    SkASSERT(fIsValid);
    SkASSERT(!this->isLocked());

    fStack.rewind();
    fData.rewind();
    fPointerData.rewind();
    this->beginBlock(SkBuiltInCodeSnippetID::kError);
    this->endBlock();

    SkASSERT(fIsValid);
    fIsValid = false;
}

//--------------------------------------------------------------------------------------------------
SkPaintParamsKey::SkPaintParamsKey(SkSpan<const uint8_t> span,
                                   SkSpan<const void*> pointerSpan,
                                   SkPaintParamsKeyBuilder* originatingBuilder)
        : fData(span)
        , fPointerData(pointerSpan)
        , fOriginatingBuilder(originatingBuilder) {
    fOriginatingBuilder->lock();
}

SkPaintParamsKey::SkPaintParamsKey(SkSpan<const uint8_t> rawData)
        : fData(rawData)
        , fOriginatingBuilder(nullptr) {
}

SkPaintParamsKey::~SkPaintParamsKey() {
    if (fOriginatingBuilder) {
        fOriginatingBuilder->unlock();
    }
}

bool SkPaintParamsKey::operator==(const SkPaintParamsKey& that) const {
    // Pointer data is intentionally ignored here; a cached key will not have pointer data.
    return fData.size() == that.fData.size() &&
           !memcmp(fData.data(), that.fData.data(), fData.size());
}

SkPaintParamsKey::BlockReader SkPaintParamsKey::reader(const SkShaderCodeDictionary* dict,
                                                       int headerOffset) const {
    // TODO(skia:13428): block reader needs to provide pointer data
    return BlockReader(dict, fData, headerOffset);
}

#ifdef SK_DEBUG

// This just iterates over the top-level blocks calling block-specific dump methods.
void SkPaintParamsKey::dump(const SkShaderCodeDictionary* dict) const {
    SkDebugf("--------------------------------------\n");
    SkDebugf("SkPaintParamsKey (%dB):\n", this->sizeInBytes());

    int curHeaderOffset = 0;
    while (curHeaderOffset < this->sizeInBytes()) {
        BlockReader reader = this->reader(dict, curHeaderOffset);
        reader.dump(dict, /* indent */ 0);
        curHeaderOffset += reader.blockSize();
    }
}
#endif // SK_DEBUG

void SkPaintParamsKey::AddBlockToShaderInfo(SkShaderCodeDictionary* dict,
                                            const SkPaintParamsKey::BlockReader& reader,
                                            SkShaderInfo* result) {

    result->add(reader);
#ifdef SK_GRAPHITE_ENABLED
    result->addFlags(dict->getSnippetRequirementFlags(reader.codeSnippetId()));
#endif

    // The child blocks appear right after the parent block's header in the key and go
    // right after the parent's SnippetEntry in the shader info
    for (int i = 0; i < reader.numChildren(); ++i) {
        SkPaintParamsKey::BlockReader childReader = reader.child(dict, i);

        AddBlockToShaderInfo(dict, childReader, result);
    }
}

void SkPaintParamsKey::toShaderInfo(SkShaderCodeDictionary* dict, SkShaderInfo* result) const {

    int curHeaderOffset = 0;
    while (curHeaderOffset < this->sizeInBytes()) {
        SkPaintParamsKey::BlockReader reader = this->reader(dict, curHeaderOffset);
        AddBlockToShaderInfo(dict, reader, result);
        curHeaderOffset += reader.blockSize();
    }
}

#if GR_TEST_UTILS
bool SkPaintParamsKey::isErrorKey() const {
    return this->sizeInBytes() == sizeof(Header) &&
           fData[0] == static_cast<int>(SkBuiltInCodeSnippetID::kError) &&
           fData[1] == sizeof(Header);
}
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////

namespace {

#ifdef SK_DEBUG
void output_indent(int indent) {
    SkDebugf("%*c", 4 * indent, ' ');
}
#endif

SkPaintParamsKey::Header read_header(SkSpan<const uint8_t> parentSpan, int headerOffset) {
    SkASSERT(headerOffset + sizeof(SkPaintParamsKey::Header) <= parentSpan.size());

    const SkPaintParamsKey::Header* header =
            reinterpret_cast<const SkPaintParamsKey::Header*>(&parentSpan[headerOffset]);
    SkASSERT(header->blockSize >= sizeof(SkPaintParamsKey::Header));
    SkASSERT(headerOffset + header->blockSize <= static_cast<int>(parentSpan.size()));

    return *header;
}

} // anonymous namespace

SkPaintParamsKey::BlockReader::BlockReader(const SkShaderCodeDictionary* dict,
                                           SkSpan<const uint8_t> parentSpan,
                                           int offsetInParent) {
    Header header = read_header(parentSpan, offsetInParent);

    fBlock = parentSpan.subspan(offsetInParent, header.blockSize);
    fEntry = dict->getEntry(header.codeSnippetID);
    SkASSERT(fEntry);
}

int SkPaintParamsKey::BlockReader::numChildren() const { return fEntry->fNumChildren; }

SkPaintParamsKey::BlockReader SkPaintParamsKey::BlockReader::child(
        const SkShaderCodeDictionary* dict,
        int childIndex) const {
    SkASSERT(childIndex < fEntry->fNumChildren);

    int childOffset = sizeof(Header);
    for (int i = 0; i < childIndex; ++i) {
        Header header = read_header(fBlock, childOffset);
        childOffset += header.blockSize;
    }

    return BlockReader(dict, fBlock, childOffset);
}

SkSpan<const uint8_t> SkPaintParamsKey::BlockReader::dataPayload() const {
    int payloadOffset = sizeof(Header);
    for (int i = 0; i < fEntry->fNumChildren; ++i) {
        Header header = read_header(fBlock, payloadOffset);
        payloadOffset += header.blockSize;
    }

    int payloadSize = this->blockSize() - payloadOffset;
    return fBlock.subspan(payloadOffset, payloadSize);
}

static int field_size(const DataPayloadField& field) {
    switch (field.fType) {
        case DataPayloadType::kByte:
        case DataPayloadType::kPointerIndex: return field.fCount;
        case DataPayloadType::kFloat4:       return field.fCount * 16;
    }
    SkUNREACHABLE;
}

SkSpan<const uint8_t> SkPaintParamsKey::BlockReader::bytes(int fieldIndex) const {
    SkASSERT(fEntry->fDataPayloadExpectations[fieldIndex].fType == DataPayloadType::kByte);

    int byteOffsetInPayload = 0;
    for (int i = 0; i < fieldIndex; ++i) {
        byteOffsetInPayload += field_size(fEntry->fDataPayloadExpectations[i]);
    }

    SkSpan<const uint8_t> dataPayload = this->dataPayload();
    return dataPayload.subspan(byteOffsetInPayload,
                               field_size(fEntry->fDataPayloadExpectations[fieldIndex]));
}

#ifdef SK_DEBUG

int SkPaintParamsKey::BlockReader::numDataPayloadFields() const {
    return fEntry->fDataPayloadExpectations.size();
}

void SkPaintParamsKey::BlockReader::dump(const SkShaderCodeDictionary* dict, int indent) const {
    uint8_t id = static_cast<uint8_t>(this->codeSnippetId());
    uint8_t blockSize = this->blockSize();

    auto entry = dict->getEntry(id);
    if (!entry) {
        output_indent(indent);
        SkDebugf("unknown block! (%dB)\n", blockSize);
    }

    output_indent(indent);
    SkDebugf("%s block (%dB)\n", entry->fStaticFunctionName, blockSize);

    for (int i = 0; i < this->numChildren(); ++i) {
        output_indent(indent);
        // TODO: it would be nice if the names of the children were also stored (i.e., "src"/"dst")
        SkDebugf("child %d:\n", i);

        SkPaintParamsKey::BlockReader childReader = this->child(dict, i);
        childReader.dump(dict, indent+1);
    }

    for (int i = 0; i < (int) fEntry->fDataPayloadExpectations.size(); ++i) {
        output_indent(indent);
        SkDebugf("%s[%d]: ",
                 fEntry->fDataPayloadExpectations[i].fName,
                 fEntry->fDataPayloadExpectations[i].fCount);
        SkSpan<const uint8_t> bytes = this->bytes(i);
        for (uint8_t b : bytes) {
            SkDebugf("%d,", b);
        }

        SkDebugf("\n");
    }
}

#endif // SK_DEBUG
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	NMEA デコード・クラス @n
			Copyright 2016 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include <cstring>

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  NMEA デコード・クラス
		@param[in]	SCI_IO	シリアルＩ／Ｏ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SCI_IO>
	class nmea_dec {

		SCI_IO&		sci_;

		uint16_t	pos_;
		char		line_[128];

		char		time_[11];  // 時間
		char		lat_[11];   // 緯度(latitude)
		char		ns_[2];     // 北緯、南緯
		char		lon_[11];   // 経度(longitude)
		char		ew_[2];     // 東経、西経
		char		q_[2];      // 品質
		char		satellite_[3];  // 衛星数

		char		date_[7];   // 日付

		uint32_t	id_;

		uint16_t word_(const char* src)
		{
			const char* top = src;
			char ch;
			while((ch = *src++) != 0) {
				if(ch == ',') return src - top;
			}
			return 0;
		}

		bool decode_()
		{
			if(line_[0] != '$') return false;
			if(std::strncmp(&line_[1], "GPGGA,", 6) == 0) {
				const char* p = &line_[7];
				uint16_t n = 0;
				uint16_t l;
				while((l = word_(p)) != 0) {
					if(n == 0) std::strncpy(time_, p, l - 1);
					else if(n == 1) std::strncpy(lat_, p, l - 1);
					else if(n == 2) std::strncpy(ns_, p, l - 1);
					else if(n == 3) std::strncpy(lon_, p, l - 1);
					else if(n == 4) std::strncpy(ew_, p, l - 1);
					else if(n == 5) std::strncpy(q_, p, l - 1);
					else if(n == 6) std::strncpy(satellite_, p, l - 1);
					else {
						++id_;
						return true;
					}
					p += l;
					++n;
				}
#if 0
			} else if(std::strncmp(&line_[1], "GPRMC,", 6) == 0) {
				const char* p = &line_[7];
				uint16_t n = 0;
				uint16_t l;
				while((l = word_(p)) != 0) {
					if(n == 8) std::strncpy(date_, p, l - 1);
					p += l;
					++n;
				}
#endif
			}
			return false;
		}

	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		nmea_dec(SCI_IO& sci) : sci_(sci), pos_(0), id_(0) {
			line_[0] = 0;
			time_[0] = 0;
			lat_[0] = 0;
			ns_[0] = 0;
			lon_[0] = 0;
			ew_[0] = 0;
			q_[0] = 0;
			satellite_[0] = 0;

			date_[0] = 0;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  処理ＩＤを取得
			@return 処理ＩＤ
        */
        //-----------------------------------------------------------------//
		uint32_t get_id() const { return id_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  時間を取得
			@return 時間
        */
        //-----------------------------------------------------------------//
		const char* get_time() const { return time_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  緯度を取得
			@return 緯度
        */
        //-----------------------------------------------------------------//
		const char* get_lat() const { return lat_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  経度を取得
			@return 経度
        */
        //-----------------------------------------------------------------//
		const char* get_lon() const { return lon_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  衛星数を取得
			@return 衛星数
        */
        //-----------------------------------------------------------------//
		const char* get_satellite() const { return satellite_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  スタート
        */
        //-----------------------------------------------------------------//
		void start()
		{
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  サービス
			@return 更新されたら「true」
        */
        //-----------------------------------------------------------------//
		bool service()
		{
			char ch;
			bool ret = false;
			while(sci_.recv_length() > 0) {
				ch = sci_.getch();
				if(ch == 0x0d) {
					line_[pos_] = 0;
					ret = decode_();
					pos_ = 0;
				} else {
					if(ch >= ' ' && ch <= 0x7f) {
						if(pos_ < sizeof(line_)) {
							line_[pos_] = ch;
							++pos_;
						}
					}
				}
			}
			return ret;
		}
	};
}

<commit_msg>update api<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	NMEA デコード・クラス @n
			Copyright 2016 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include <cstring>
#include "common/time.h"

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  NMEA デコード・クラス
		@param[in]	SCI_IO	シリアルＩ／Ｏ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class SCI_IO>
	class nmea_dec {

	public:

		static const uint32_t sinfo_num_ = 12;		///< 衛星情報の最大数

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief  衛星パラメーター
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		struct sat_info {
			char	no_[4];  	///< 衛星番号
			char	elv_[4];	///< 衛星仰角(Elevation)、０～９０度
			char	azi_[4];	///< 衛星方位角(Azimuth)、０～３５９度
			char	cn_[4];		///< キャリア／ノイズ比、０～９９dB

			sat_info() {
				no_[0] = 0;
				elv_[0] = 0;
				azi_[0] = 0;
				cn_[0] = 0;
			}
		};

	private:
		SCI_IO&		sci_;

		uint16_t	pos_;
		char		line_[128];

		char		time_[12];  // 時間
		char		lat_[12];   // 緯度(latitude)
		char		ns_[2];     // 北緯、南緯
		char		lon_[12];   // 経度(longitude)
		char		ew_[2];     // 東経、西経
		char		q_[2];      // 品質
		char		satellite_[4];  // 衛星数
		char		hq_[4];		// 水平精度低下率
		char		alt_[6];	// 海抜高度(Altitude above sea level)
		char		alt_unit_[2];	// 海抜高度単位

		char		date_[8];   // 日付

		uint16_t	sidx_;
		sat_info	sinfo_[sinfo_num_];	// 衛星情報

		uint32_t	id_;
		uint32_t	iid_;

		static uint16_t word_(const char* src)
		{
			const char* top = src;
			char ch;
			while((ch = *src++) != 0) {
				if(ch == ',' || ch == '*') return src - top;
			}
			return 0;
		}

		static void copy_word_(char* dst, const char* src, uint16_t len)
		{
			std::strncpy(dst, src, len);
			dst[len] = 0;
		}

		static int32_t get_dec_(const char* t, uint16_t n = 0)
		{
			int32_t val = 0;
			char ch;
			while((ch = *t++) != 0) {
				if('0' <= ch && ch <= '9') {
					val *= 10;
					val += ch - '0';
				} else {
					break;
				}
				if(n > 0) {
					--n;
					if(n == 0) break;
				}
			}
			return val;
		}

		bool decode_()
		{
			if(line_[0] != '$') return false;

			if(std::strncmp(&line_[1], "GPGGA,", 6) == 0) {
				const char* p = &line_[7];
				uint16_t n = 0;
				uint16_t l;
				while((l = word_(p)) != 0) {
					if(n == 0) copy_word_(time_, p, l - 1);
					else if(n == 1) copy_word_(lat_, p, l - 1);
					else if(n == 2) copy_word_(ns_, p, l - 1);
					else if(n == 3) copy_word_(lon_, p, l - 1);
					else if(n == 4) copy_word_(ew_, p, l - 1);
					else if(n == 5) copy_word_(q_, p, l - 1);
					else if(n == 6) copy_word_(satellite_, p, l - 1);
					else if(n == 7) copy_word_(hq_, p, l - 1);
					else if(n == 8) copy_word_(alt_, p, l - 1);
					else if(n == 9) copy_word_(alt_unit_, p, l - 1);
					else {
						break;
					}
					p += l;
					++n;
				}
			} else if(std::strncmp(&line_[1], "GPRMC,", 6) == 0) {
				const char* p = &line_[7];
				uint16_t n = 0;
				uint16_t l;
				while((l = word_(p)) != 0) {
					if(n == 8) copy_word_(date_, p, l - 1);
					p += l;
					++n;
				}
			} else if(std::strncmp(&line_[1], "GPGSV,", 6) == 0) {
				const char* p = &line_[7];
				uint16_t n = 0;
				uint16_t l;
				while((l = word_(p)) != 0) {
					if(n == 0) ;
					else if(n == 1) ;
// std::strncpy(date_, p, l - 1);
					p += l;
					++n;
				}
				++iid_;
			} else if(std::strncmp(&line_[1], "GPVTG,", 6) == 0) {
				++id_;
				return true;
			}
			return false;
		}

	public:
        //-----------------------------------------------------------------//
        /*!
            @brief  コンストラクター
        */
        //-----------------------------------------------------------------//
		nmea_dec(SCI_IO& sci) : sci_(sci), pos_(0), sidx_(0), id_(0), iid_(0) {
			line_[0] = 0;
			time_[0] = 0;
			lat_[0] = 0;
			ns_[0] = 0;
			lon_[0] = 0;
			ew_[0] = 0;
			q_[0] = 0;
			satellite_[0] = 0;
			hq_[0] = 0;
			alt_[0] = 0;
			alt_unit_[0] = 0;

			date_[0] = 0;
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  処理ＩＤを取得
			@return 処理ＩＤ
        */
        //-----------------------------------------------------------------//
		uint32_t get_id() const { return id_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  情報処理ＩＤを取得
			@return 情報処理ＩＤ
        */
        //-----------------------------------------------------------------//
		uint32_t get_iid() const { return iid_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  時間を取得
			@return 時間
        */
        //-----------------------------------------------------------------//
		const char* get_time() const { return time_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  日付を取得
			@return 日付
        */
        //-----------------------------------------------------------------//
		const char* get_date() const { return date_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  時間「time_t」を取得
			@return 時間「time_t」
        */
        //-----------------------------------------------------------------//
		time_t get_tm() const {
			tm ts;
			ts.tm_sec  = get_dec_(&time_[4], 2);
			ts.tm_min  = get_dec_(&time_[2], 2);
			ts.tm_hour = get_dec_(&time_[0], 2);
			ts.tm_mday = get_dec_(&date_[0], 2);
			ts.tm_mon  = get_dec_(&date_[2], 2);
			ts.tm_year = get_dec_(&date_[4], 2);
			ts.tm_year += 100;  // 起点１９００年
			return mktime_gmt(&ts);
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  緯度を取得
			@return 緯度
        */
        //-----------------------------------------------------------------//
		const char* get_lat() const { return lat_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  経度を取得
			@return 経度
        */
        //-----------------------------------------------------------------//
		const char* get_lon() const { return lon_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  品質を取得
			@return 品質
        */
        //-----------------------------------------------------------------//
		const char* get_quality() const { return q_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  衛星数を取得
			@return 衛星数
        */
        //-----------------------------------------------------------------//
		const char* get_satellite() const { return satellite_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  水平品質を取得
			@return 水平品質
        */
        //-----------------------------------------------------------------//
		const char* get_holizontal_quality() const { return hq_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  海抜高度を取得
			@return 海抜高度
        */
        //-----------------------------------------------------------------//
		const char* get_altitude() const { return alt_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  海抜高度単位を取得
			@return 海抜高度単位
        */
        //-----------------------------------------------------------------//
		const char* get_altitude_unit() const { return alt_unit_; }

        //-----------------------------------------------------------------//
        /*!
            @brief  衛星情報の取得
			@param[in]	idx	衛星インデックス
			@return 衛星情報
        */
        //-----------------------------------------------------------------//
		const sat_info& get_satellite_info(uint16_t idx) const
		{
			if(idx < sinfo_num_) {
				return sinfo_[idx];
			} else {
				static sat_info si;
				return si;
			}
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  スタート
        */
        //-----------------------------------------------------------------//
		void start()
		{
		}

        //-----------------------------------------------------------------//
        /*!
            @brief  サービス @n
					情報量に応じて呼ぶ（通常毎フレーム呼ぶ）
			@return 更新されたら「true」
        */
        //-----------------------------------------------------------------//
		bool service()
		{
			char ch;
			bool ret = false;
			while(sci_.recv_length() > 0) {
				ch = sci_.getch();
				if(ch == 0x0d) {
					line_[pos_] = 0;
					ret = decode_();
					pos_ = 0;
				} else {
					if(ch >= ' ' && ch <= 0x7f) {
						if(pos_ < sizeof(line_)) {
							line_[pos_] = ch;
							++pos_;
						}
					}
				}
			}
			return ret;
		}
	};
}

<|endoftext|>


<commit_before>#include "WorldViewProgram.h"
#include <KrisLibrary/Logger.h>
#include <Klampt/IO/XmlWorld.h>
#include <KrisLibrary/GLdraw/GL.h>
#include <KrisLibrary/GLdraw/drawextra.h>
#include <KrisLibrary/GLdraw/Widget.h>
#include <KrisLibrary/utils/stringutils.h>
#include <fstream>
using namespace Math3D;
using namespace GLDraw;
namespace Klampt {

WorldViewWidget::WorldViewWidget(WorldModel* _world)
  :world(_world), clickedRobot(NULL), clickedObject(NULL)
{}

bool WorldViewWidget::Hover(int x, int y, Camera::Viewport& viewport, double& distance)
{
  Ray3D r;
  viewport.getClickSource(float(x), float(y), r.source);
  viewport.getClickVector(float(x), float(y), r.direction);
  clickedRobot = world->RayCastRobot(r, body, localpt);
  if (clickedRobot) {
    Vector3 worldpt = clickedRobot->links[body].T_World*localpt;
    distance = r.direction.dot(worldpt - r.source);
  }
  Vector3 localpt2;
  clickedObject = world->RayCastObject(r, localpt2);
  if (clickedObject) {
    Vector3 worldpt2 = clickedObject->T*localpt2;
    Real distance2 = r.direction.dot(worldpt2 - r.source);
    if (clickedRobot && distance < distance2) {
      //robot is closest
      clickedObject = NULL;
    }
    else {
      clickedRobot = NULL;
      localpt = localpt2;
      distance = distance2;
    }
  }
  return clickedRobot || clickedObject;
}

 bool WorldViewWidget::BeginDrag(int x, int y, Camera::Viewport& viewport, double& distance)
 {
  bool res = Hover(x, y, viewport, distance);
  return false;
}

 void WorldViewWidget::DrawGL(Camera::Viewport& viewport)
 {
  glEnable(GL_LIGHTING);
  world->DrawGL();
}

bool LoadWorldCommandLine(WorldModel& world,int argc, const char** argv)
{
  XmlWorld xmlWorld;
  vector<string> configs;
  world.lights.resize(1);
  world.lights[0].setColor(GLColor(1, 1, 1));
  world.lights[0].setDirectionalLight(Vector3(0.2, -0.4, 1));

  for (int i = 1; i<argc; i++) {
    if (argv[i][0] == '-') {
      if (0 == strcmp(argv[i], "-config")) {
        configs.push_back(argv[i + 1]);
        i++;
      }
      else {
        printf("Unknown option %s", argv[i]);
        return false;
      }
    }
    else {
      const char* ext = FileExtension(argv[i]);
      if (0 == strcmp(ext, "xml")) {
        if (!xmlWorld.Load(argv[i])) {
          printf("Error loading world file %s\n", argv[i]);
          return false;
        }
        if (!xmlWorld.GetWorld(world)) {
          printf("Error loading world from %s\n", argv[i]);
          return false;
        }
      }
      else {
        if (world.LoadElement(argv[i]) < 0) {
          return false;
        }
      }
    }
  }

  if (configs.size() > world.robots.size()) {
    printf("Warning, too many configs specified\n");
  }
  for (size_t i = 0; i<configs.size(); i++) {
    if (i >= world.robots.size()) break;
    ifstream in(configs[i].c_str(), ios::in);
    if (!in) printf("Could not open config file %s\n", configs[i].c_str());
    Vector temp;
    in >> temp;
    if (!in) printf("Error reading config file %s\n", configs[i].c_str());
    if (temp.n != (int)world.robots[i]->links.size()) {
      printf("Incorrect number of DOFs in config %d\n", i);
      continue;
    }
    world.robots[i]->UpdateConfig(temp);
  }

  return true;
}

#if HAVE_GLUI || HAVE_GLUT

WorldViewProgram::WorldViewProgram(WorldModel* _world)
  :world(_world)
{
}

bool WorldViewProgram::Initialize()
{
  //TODO: read in the camera from the world?
  camera.dist = 6;
  viewport.n = 0.1;
  viewport.f = 100;
  viewport.setLensAngle(DtoR(60.0));

  glEnable(GL_CULL_FACE);
  glEnable(GL_DEPTH_TEST);
  glClearColor(world->background.rgba[0],world->background.rgba[1],world->background.rgba[2],world->background.rgba[3]);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  return BASE_PROGRAM::Initialize();
}

void WorldViewProgram::SetWorldLights()
{
  world->SetGLLights();
}
void WorldViewProgram::RefreshIdle() { SleepIdleCallback(0); }
void WorldViewProgram::RenderWorld()
{
  glDisable(GL_LIGHTING);
  drawCoords(0.1);
  glEnable(GL_LIGHTING);
  world->DrawGL();
}

void WorldViewProgram::DoFreeDrag(int dx,int dy,int button)
{
  if(button == GLUT_LEFT_BUTTON)  DragRotate(dx,dy);
}

void WorldViewProgram::DoCtrlDrag(int dx,int dy,int button)
{
  if(button == GLUT_LEFT_BUTTON)  DragPan(dx,dy);
}

void WorldViewProgram::DoAltDrag(int dx,int dy,int button)
{
  if(button == GLUT_LEFT_BUTTON)  DragZoom(dx,dy);
}

void WorldViewProgram::DoShiftDrag(int dx,int dy,int button)
{
  if(button == GLUT_LEFT_BUTTON) { camera.dist *= (1 + 0.01*Real(dy)); }
}

bool WorldViewProgram::LoadCommandLine(int argc,const char** argv)
{
  return LoadWorldCommandLine(*world, argc, argv);
}

void WorldViewProgram::ClickRay(int x,int y,Ray3D& r) const
{
  viewport.getClickSource(x,viewport.y+viewport.h-y,r.source);
  viewport.getClickVector(x,viewport.y+viewport.h-y,r.direction);
  //cout<<"Ray "<<r.source<<" -> "<<r.direction<<endl;
}

RobotModel* WorldViewProgram::ClickRobot(const Ray3D& r,int& body,Vector3& localpt) const
{
  return world->RayCastRobot(r,body,localpt);
}

RigidObjectModel* WorldViewProgram::ClickObject(const Ray3D& r,Vector3& localpt) const
{
  return world->RayCastObject(r,localpt);
}

} //namespace Klampt

#endif // HAVE_GLUI
<commit_msg>Fixed compile error if don't have GLUI<commit_after>#include "WorldViewProgram.h"
#include <KrisLibrary/Logger.h>
#include <Klampt/IO/XmlWorld.h>
#include <KrisLibrary/GLdraw/GL.h>
#include <KrisLibrary/GLdraw/drawextra.h>
#include <KrisLibrary/GLdraw/Widget.h>
#include <KrisLibrary/utils/stringutils.h>
#include <fstream>
using namespace Math3D;
using namespace GLDraw;
namespace Klampt {

WorldViewWidget::WorldViewWidget(WorldModel* _world)
  :world(_world), clickedRobot(NULL), clickedObject(NULL)
{}

bool WorldViewWidget::Hover(int x, int y, Camera::Viewport& viewport, double& distance)
{
  Ray3D r;
  viewport.getClickSource(float(x), float(y), r.source);
  viewport.getClickVector(float(x), float(y), r.direction);
  clickedRobot = world->RayCastRobot(r, body, localpt);
  if (clickedRobot) {
    Vector3 worldpt = clickedRobot->links[body].T_World*localpt;
    distance = r.direction.dot(worldpt - r.source);
  }
  Vector3 localpt2;
  clickedObject = world->RayCastObject(r, localpt2);
  if (clickedObject) {
    Vector3 worldpt2 = clickedObject->T*localpt2;
    Real distance2 = r.direction.dot(worldpt2 - r.source);
    if (clickedRobot && distance < distance2) {
      //robot is closest
      clickedObject = NULL;
    }
    else {
      clickedRobot = NULL;
      localpt = localpt2;
      distance = distance2;
    }
  }
  return clickedRobot || clickedObject;
}

 bool WorldViewWidget::BeginDrag(int x, int y, Camera::Viewport& viewport, double& distance)
 {
  bool res = Hover(x, y, viewport, distance);
  return false;
}

 void WorldViewWidget::DrawGL(Camera::Viewport& viewport)
 {
  glEnable(GL_LIGHTING);
  world->DrawGL();
}

bool LoadWorldCommandLine(WorldModel& world,int argc, const char** argv)
{
  XmlWorld xmlWorld;
  vector<string> configs;
  world.lights.resize(1);
  world.lights[0].setColor(GLColor(1, 1, 1));
  world.lights[0].setDirectionalLight(Vector3(0.2, -0.4, 1));

  for (int i = 1; i<argc; i++) {
    if (argv[i][0] == '-') {
      if (0 == strcmp(argv[i], "-config")) {
        configs.push_back(argv[i + 1]);
        i++;
      }
      else {
        printf("Unknown option %s", argv[i]);
        return false;
      }
    }
    else {
      const char* ext = FileExtension(argv[i]);
      if (0 == strcmp(ext, "xml")) {
        if (!xmlWorld.Load(argv[i])) {
          printf("Error loading world file %s\n", argv[i]);
          return false;
        }
        if (!xmlWorld.GetWorld(world)) {
          printf("Error loading world from %s\n", argv[i]);
          return false;
        }
      }
      else {
        if (world.LoadElement(argv[i]) < 0) {
          return false;
        }
      }
    }
  }

  if (configs.size() > world.robots.size()) {
    printf("Warning, too many configs specified\n");
  }
  for (size_t i = 0; i<configs.size(); i++) {
    if (i >= world.robots.size()) break;
    ifstream in(configs[i].c_str(), ios::in);
    if (!in) printf("Could not open config file %s\n", configs[i].c_str());
    Vector temp;
    in >> temp;
    if (!in) printf("Error reading config file %s\n", configs[i].c_str());
    if (temp.n != (int)world.robots[i]->links.size()) {
      printf("Incorrect number of DOFs in config %d\n", i);
      continue;
    }
    world.robots[i]->UpdateConfig(temp);
  }

  return true;
}

#if HAVE_GLUI || HAVE_GLUT

WorldViewProgram::WorldViewProgram(WorldModel* _world)
  :world(_world)
{
}

bool WorldViewProgram::Initialize()
{
  //TODO: read in the camera from the world?
  camera.dist = 6;
  viewport.n = 0.1;
  viewport.f = 100;
  viewport.setLensAngle(DtoR(60.0));

  glEnable(GL_CULL_FACE);
  glEnable(GL_DEPTH_TEST);
  glClearColor(world->background.rgba[0],world->background.rgba[1],world->background.rgba[2],world->background.rgba[3]);
  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  return BASE_PROGRAM::Initialize();
}

void WorldViewProgram::SetWorldLights()
{
  world->SetGLLights();
}
void WorldViewProgram::RefreshIdle() { SleepIdleCallback(0); }
void WorldViewProgram::RenderWorld()
{
  glDisable(GL_LIGHTING);
  drawCoords(0.1);
  glEnable(GL_LIGHTING);
  world->DrawGL();
}

void WorldViewProgram::DoFreeDrag(int dx,int dy,int button)
{
  if(button == GLUT_LEFT_BUTTON)  DragRotate(dx,dy);
}

void WorldViewProgram::DoCtrlDrag(int dx,int dy,int button)
{
  if(button == GLUT_LEFT_BUTTON)  DragPan(dx,dy);
}

void WorldViewProgram::DoAltDrag(int dx,int dy,int button)
{
  if(button == GLUT_LEFT_BUTTON)  DragZoom(dx,dy);
}

void WorldViewProgram::DoShiftDrag(int dx,int dy,int button)
{
  if(button == GLUT_LEFT_BUTTON) { camera.dist *= (1 + 0.01*Real(dy)); }
}

bool WorldViewProgram::LoadCommandLine(int argc,const char** argv)
{
  return LoadWorldCommandLine(*world, argc, argv);
}

void WorldViewProgram::ClickRay(int x,int y,Ray3D& r) const
{
  viewport.getClickSource(x,viewport.y+viewport.h-y,r.source);
  viewport.getClickVector(x,viewport.y+viewport.h-y,r.direction);
  //cout<<"Ray "<<r.source<<" -> "<<r.direction<<endl;
}

RobotModel* WorldViewProgram::ClickRobot(const Ray3D& r,int& body,Vector3& localpt) const
{
  return world->RayCastRobot(r,body,localpt);
}

RigidObjectModel* WorldViewProgram::ClickObject(const Ray3D& r,Vector3& localpt) const
{
  return world->RayCastObject(r,localpt);
}

#endif // HAVE_GLUI

} //namespace Klampt

<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

class Node;
class NormalEdge {
public:
    int startCharacterIndex;
	int endCharacterIndex;
	Node *startNode;
	Node *endNode;

    NormalEdge(){}

    NormalEdge(int _startCharacterIndex, int _endCharacterIndex, Node *_startNode, Node *_endNode)
	{
		this->startCharacterIndex=_startCharacterIndex;
		this->endCharacterIndex=_endCharacterIndex;
		this->startNode=_startNode;
		this->endNode=_endNode;
	}
};

//The suffix link
class SuffixEdge {
public:
    Node *startNode;
	Node *endNode;

	SuffixEdge(){}

	SuffixEdge(Node *_startNode, Node *_endNode)
	{
		this->startNode=_startNode;
		this->endNode=_endNode;
	}

};

class Node {
public:
    int number;
	SuffixEdge *suffixEdge;
	vector<NormalEdge> edges;
    Node() {}

    Node(int _number){
        this->number = _number;
		this->suffixEdge=NULL;
    }

	void RemoveEdge(NormalEdge *e){
		int index=-1;
		int fs=NULL;
		if(e->startNode!=NULL){
			fs=e->startNode->number;
		}
		int fe=NULL;
		if(e->endNode!=NULL){
			fe=e->endNode->number;
		}
		for(vector<NormalEdge>::iterator it = edges.begin(); it != edges.end(); ++it) {
			NormalEdge *edgeTmp=&(*it);
			int ss=NULL;
			if(edgeTmp->startNode!=NULL){
				ss=edgeTmp->startNode->number;
			}
			int se=NULL;
			if(edgeTmp->endNode!=NULL){
				se=edgeTmp->endNode->number;
			}
			if(fs==ss && fe==se){
				edges.erase(it);
				break;
			}
		}
	}
};

class Triple{
public:
	Node *activeNode;
	NormalEdge *activeEdge;
	int length;

	Triple() {}

	Triple(Node * _activeNode, int _length){
		this->activeNode=_activeNode;
		this->length=_length;
		this->activeEdge=NULL;
	}
};

class SuffixTree {
private:
    Node *root;
	int nodeNumber;
	int currentPosition;
	string inputString;
	Triple *activePoint;
	int remainder;
	stringstream graphvizOutput;   //Output is in dot notation (gaphviz)
	int startCharacterIndexForInsertInString;

public:
    SuffixTree(string _inputString){
        this->inputString = _inputString;
    }

    void CreateSuffixTree(){
		int inputStringLen=inputString.length();
		for(int i=0;i<inputStringLen; i++){
			AddCharacter(inputString[i]);
		}
	}

    //Handling a new character while following all the rules
	void AddCharacter(char c){
		//TODO
	}

    //Creating a new edge in the tree
	void AddNewEdge(Node *startNode, int startIndex, int endIndex){
			Node *leaf=new Node(nodeNumber);
			nodeNumber++;
			NormalEdge *edge=new NormalEdge(startIndex, endIndex, startNode, leaf);
			startNode->edges.push_back(*edge);
	}
};

//A link between two nodes represented by [index_of_first_char, index_of_last_char]

void WriteToFile(string str, char* fileName)
{
	ofstream outFile;
    outFile.open(fileName);
    outFile<<str;
    outFile.close();
}

string ReadFromFile(const char *filename)
{
  ifstream inFile(filename);
  if (inFile)
  {
    std::string input;
    inFile.seekg(0, std::ios::end);
    input.resize(inFile.tellg());
    inFile.seekg(0, std::ios::beg);
    inFile.read(&input[0], input.size());
    inFile.close();
    return(input);
  }
}

int main (int argc, char* argv[]) {
    return 0;
}
<commit_msg>Added some new private variables to class suffix tree. Added function for appendind new character to all leaf edges. Added function ti decide if nw edge must be inserted.<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;

class Node;
class NormalEdge {
public:
    int startCharacterIndex;
	int endCharacterIndex;
	Node *startNode;
	Node *endNode;

    NormalEdge(){}

    NormalEdge(int _startCharacterIndex, int _endCharacterIndex, Node *_startNode, Node *_endNode)
	{
		this->startCharacterIndex=_startCharacterIndex;
		this->endCharacterIndex=_endCharacterIndex;
		this->startNode=_startNode;
		this->endNode=_endNode;
	}
};

//The suffix link
class SuffixEdge {
public:
    Node *startNode;
	Node *endNode;

	SuffixEdge(){}

	SuffixEdge(Node *_startNode, Node *_endNode)
	{
		this->startNode=_startNode;
		this->endNode=_endNode;
	}

};

class Node {
public:
    int number;
	SuffixEdge *suffixEdge;
	vector<NormalEdge> edges;
    Node() {}

    Node(int _number){
        this->number = _number;
		this->suffixEdge=NULL;
    }

	void RemoveEdge(NormalEdge *e){
		int index=-1;
		int fs=NULL;
		if(e->startNode!=NULL){
			fs=e->startNode->number;
		}
		int fe=NULL;
		if(e->endNode!=NULL){
			fe=e->endNode->number;
		}
		for(vector<NormalEdge>::iterator it = edges.begin(); it != edges.end(); ++it) {
			NormalEdge *edgeTmp=&(*it);
			int ss=NULL;
			if(edgeTmp->startNode!=NULL){
				ss=edgeTmp->startNode->number;
			}
			int se=NULL;
			if(edgeTmp->endNode!=NULL){
				se=edgeTmp->endNode->number;
			}
			if(fs==ss && fe==se){
				edges.erase(it);
				break;
			}
		}
	}
};

class Triple{
public:
	Node *activeNode;
	NormalEdge *activeEdge;
	int length;

	Triple() {}

	Triple(Node * _activeNode, int _length){
		this->activeNode=_activeNode;
		this->length=_length;
		this->activeEdge=NULL;
	}
};

class SuffixTree {
private:
    Node *root;
	int nodeNumber;
	int currentPosition;
	string inputString;
	Triple *activePoint;
	int remainder;
	stringstream graphvizOutput;   //Output is in dot notation (gaphviz)
	int startCharacterIndexForInsertInString;
	Node *previousInsertedNode;

public:
    SuffixTree(string _inputString){
        this->inputString = _inputString;
		this->nodeNumber=1;
		Node *rootNode=new Node(this->nodeNumber);
		this->root=rootNode;
		this->nodeNumber++;
		this->currentPosition=-1;
		this->remainder=0;
		this->startCharacterIndexForInsertInString=0;
		this->graphvizOutput.clear();
		Triple *triple=new Triple(root, 0);
		this->activePoint=triple;
		this->previousInsertedNode=NULL;
    }

    void CreateSuffixTree(){
		int inputStringLen=inputString.length();
		for(int i=0;i<inputStringLen; i++){
			AddCharacter(inputString[i]);
		}
	}

    //Handling a new character while following all the rules
	void AddCharacter(char c){
		this->previousInsertedNode=NULL;
		this->currentPosition++;
		this->remainder++;
		AddSuffixToExistingEdges(root);

		while(this->remainder>0){
			if(this->activePoint->length==0){
				this->startCharacterIndexForInsertInString=this->currentPosition;
			}
			if(NeedToInsertNewEdge(false)){
				//TODO
			}
			else{
				//TODO
			}
		}

	}

    //Creating a new edge in the tree
	void AddNewEdge(Node *startNode, int startIndex, int endIndex){
			Node *leaf=new Node(nodeNumber);
			nodeNumber++;
			NormalEdge *edge=new NormalEdge(startIndex, endIndex, startNode, leaf);
			startNode->edges.push_back(*edge);
	}

	void AddSuffixToExistingEdges(Node *_startNode){
		int edgesSize=_startNode->edges.size();
		for(int i=0;i<edgesSize;i++){
			NormalEdge *tmpEdge=&_startNode->edges.at(i);
			if(tmpEdge->endNode->edges.size()==0){
				tmpEdge->endCharacterIndex++;
			}
			else{
				AddSuffixToExistingEdges(tmpEdge->endNode);
			}
		}
	}

	bool NeedToInsertNewEdge(bool useActiveLen){
		int len=1;
		if(useActiveLen){
			len+=activePoint->length;
		}
		if(activePoint->activeEdge==NULL){
			int edgesSize=activePoint->activeNode->edges.size();
			for(int i=0;i<edgesSize;i++){
				NormalEdge *tmp=&activePoint->activeNode->edges.at(i);
				string s1=inputString.substr(tmp->startCharacterIndex, len);
				string s2=inputString.substr(startCharacterIndexForInsertInString, len);

				if(s1.compare(s2)==0){//equals
					return false;
				}
			}
			return true;
		}
		else{
			string s1=inputString.substr(activePoint->activeEdge->startCharacterIndex, len);
			string s2=inputString.substr(startCharacterIndexForInsertInString, len);
			if(s1.compare(s2)==0){//equals
				return false;
			}
		}
		return true;
	}
};

//A link between two nodes represented by [index_of_first_char, index_of_last_char]

void WriteToFile(string str, char* fileName)
{
	ofstream outFile;
    outFile.open(fileName);
    outFile<<str;
    outFile.close();
}

string ReadFromFile(const char *filename)
{
  ifstream inFile(filename);
  if (inFile)
  {
    std::string input;
    inFile.seekg(0, std::ios::end);
    input.resize(inFile.tellg());
    inFile.seekg(0, std::ios::beg);
    inFile.read(&input[0], input.size());
    inFile.close();
    return(input);
  }
}

int main (int argc, char* argv[]) {
    return 0;
}
<|endoftext|>


<commit_before>#include <stdint.h>

#include "codecfactory.h"
#include "intersection.h"
#include "variablebyte.h"
#include "util.h"

using namespace SIMDCompressionLib;

// sorted
static shared_ptr<IntegerCODEC> codec_sorted =  CODECFactory::getFromName("s4-bp128-dm");

static CompositeCodec<SIMDBinaryPacking<SIMDBlockPacker<NoDelta, false>>, VariableByte<false>> composite_codec_unsorted = CompositeCodec<SIMDBinaryPacking<SIMDBlockPacker<NoDelta, false>>, VariableByte<false>>();

// variable byte
static VariableByte<false> codec_unsorted = VariableByte<false>();

static SIMDBinaryPacking<SIMDIntegratedBlockPacker<Max4DeltaSIMD, true>> simd_pack_sorted = SIMDBinaryPacking<SIMDIntegratedBlockPacker<Max4DeltaSIMD, true>>();

static SIMDBinaryPacking<SIMDBlockPacker<NoDelta, false>> simd_pack = SIMDBinaryPacking<SIMDBlockPacker<NoDelta, false>>();

static VariableByte<true> vint_codec = VariableByte<true>();
// SIMDBinaryPacking<SIMDBlockPacker<NoDelta, true>

extern "C" {

  // encode 128 u32 at a time.
  size_t encode_block128_native(
      uint32_t* begin,
      uint8_t* output,
      const size_t output_capacity) {
        size_t output_length = output_capacity / 4;
        simd_pack.encodeArray(begin,
                        128,
                        reinterpret_cast<uint32_t*>(output),
                        output_length);
        return output_length * 4;
  }

  // returns the number of byte that have been read.
  size_t decode_block128_native(
    const uint8_t* compressed_data,
    const size_t compressed_size,
    uint32_t* uncompressed) {
      size_t output_capacity = 128;
      const uint32_t* pointer_end = simd_pack.decodeArray(reinterpret_cast<const uint32_t*>(compressed_data), compressed_size / 4, uncompressed, output_capacity);
      const uint8_t* pointer_end_u8 = reinterpret_cast<const uint8_t*>(pointer_end);
      return static_cast<size_t>(pointer_end_u8 - compressed_data);

  }

  // encode 128 u32 at a time.
  size_t encode_sorted_block128_native(
      uint32_t* begin,
      uint8_t* output,
      const size_t output_capacity) {
        size_t output_length = output_capacity;
        simd_pack_sorted.encodeArray(begin,
                        128,
                        reinterpret_cast<uint32_t*>(output),
                        output_length);
        return output_length * 4;
  }

  // returns the number of byte that have been read.
  size_t decode_sorted_block128_native(
    const uint8_t* compressed_data,
    const size_t compressed_size,
    uint32_t* uncompressed) {
      size_t output_capacity = 128;
      const uint32_t* pointer_end = simd_pack_sorted.decodeArray(reinterpret_cast<const uint32_t*>(compressed_data), compressed_size / 4, uncompressed, output_capacity);
      const uint8_t* pointer_end_u8 = reinterpret_cast<const uint8_t*>(pointer_end);
      return static_cast<size_t>(pointer_end_u8 - compressed_data);

  }

  size_t encode_sorted_vint_native(
      uint32_t* begin,
      const size_t num_els,
      uint8_t* output,
      const size_t output_capacity) {
        size_t output_length = output_capacity / 4;
        vint_codec.encodeArray(begin,
                        num_els,
                        reinterpret_cast<uint32_t*>(output),
                        output_length);
        return output_length * 4;
  }

  size_t decode_sorted_vint_native(
    const uint8_t* compressed_data,
    const size_t compressed_size,
    uint32_t* uncompressed,
    const size_t uncompressed_capacity) {
      size_t num_ints = uncompressed_capacity;
      vint_codec.decodeArray(reinterpret_cast<const uint32_t*>(compressed_data), compressed_size / 4, uncompressed, num_ints);
      return num_ints;
  }

  size_t encode_s4_bp128_dm_native(
       uint32_t* begin,
       const size_t num_els,
       uint8_t* output,
       const size_t output_capacity) {
        size_t output_length = output_capacity / 4;
        codec_sorted -> encodeArray(begin,
                          num_els,
                          reinterpret_cast<uint32_t*>(output),
                          output_length);
        return output_length * 4;
  }

  size_t decode_s4_bp128_dm_native(
      const uint8_t* compressed_data,
      const size_t compressed_size,
      uint32_t* uncompressed,
      const size_t uncompressed_capacity) {
        size_t num_ints = uncompressed_capacity;
        codec_sorted -> decodeArray(reinterpret_cast<const uint32_t*>(compressed_data), compressed_size / 4, uncompressed, num_ints);
        return num_ints;
  }

    size_t encode_composite_native(
       uint32_t* uncompressed,
       const size_t num_els,
       uint8_t* output,
       const size_t output_capacity) {
        size_t output_length = output_capacity / 4;
        composite_codec_unsorted.encodeArray(uncompressed,
                          num_els,
                          reinterpret_cast<uint32_t*>(output),
                          output_length);
        return output_length * 4;
  }

  size_t decode_composite_native(
      const uint8_t* compressed_data,
      const size_t compressed_size,
      uint32_t* uncompressed,
      const size_t uncompressed_capacity) {
        size_t num_ints = uncompressed_capacity;
        composite_codec_unsorted.decodeArray(reinterpret_cast<const uint32_t*>(compressed_data), compressed_size/4, uncompressed, num_ints);
        return num_ints;
  }

  size_t encode_unsorted_native(
       uint32_t* begin,
       const size_t num_els,
       uint8_t* output,
       const size_t output_capacity) {
         size_t output_length = output_capacity / 4;
         codec_unsorted.encodeArray(begin,
                           num_els,
                           reinterpret_cast<uint32_t*>(output),
                           output_length);
        return output_length * 4;
  }

  size_t decode_unsorted_native(
      const uint8_t* compressed_data,
      const size_t compressed_size,
      uint32_t* uncompressed,
      const size_t uncompressed_capacity) {
         size_t num_ints = uncompressed_capacity;
         codec_unsorted.decodeArray(reinterpret_cast<const uint32_t*>(compressed_data), compressed_size / 4, uncompressed, num_ints);
         return num_ints;
  }

  size_t intersection_native(
      const uint32_t* left,
      const size_t left_size,
      const uint32_t* right,
      const size_t right_size,
      uint32_t* output) {
        return IntersectionFactory::getFromName("simd")(left, left_size, right, right_size, output);
  }
}
<commit_msg>NOBUG Remove useless file<commit_after><|endoftext|>


<commit_before>//
//  Factory.cpp
//  ee_x
//
//  Created by eps on 3/20/18.
//

#include "ee/core/PluginManager.hpp"

#include <string>
#include <unordered_map>

#include "ee/core/Platform.hpp"
#include "ee/core/internal/MessageBridge.hpp"

namespace ee {
namespace core {
using Self = PluginManager;

#if defined(EE_X_ANDROID)
template <>
bool Self::initializePlugins<Library::Core>() {
    auto&& bridge = MessageBridge::getInstance();
    Platform::registerHandlers(bridge);
    return true;
}

bool Self::addPlugin(Plugin plugin) {
    // FIXME.
    return false;
}

bool Self::removePlugin(Plugin plugin) {
    // FIXME.
    return false;
}
#endif // EE_X_ANDROID

#if defined(EE_X_IOS) || defined(EE_X_OSX)
extern "C" {
bool ee_staticInitializePlugins();
bool ee_staticAddPlugin(const std::string& name);
bool ee_staticRemovePlugin(const std::string& name);
} // extern "C"

template <>
bool Self::initializePlugins<Library::Core>() {
    auto&& bridge = MessageBridge::getInstance();
    Platform::registerHandlers(bridge);
    return ee_staticInitializePlugins();
}

namespace {
std::unordered_map<Plugin, std::string> pluginNames_ = {{
    {Plugin::AdMob, "AdMob"},
    {Plugin::AppLovin, "AppLovin"},
    {Plugin::AppsFlyer, "AppsFlyer"},
    {Plugin::CampaignReceiver, "CampaignReceiver"},
    {Plugin::Facebook, "Facebook"},
    {Plugin::FacebookAds, "FacebookAds"},
    {Plugin::FirebaseCore, "FirebaseCore"},
    {Plugin::FirebaseCrashlytics, "FirebaseCrashlytics"},
    {Plugin::FirebasePerformance, "FirebasePerformance"},
    {Plugin::GoogleAnalytics, "GoogleAnalytics"},
    {Plugin::IronSource, "IronSource"},
    {Plugin::Notification, "Notification"},
    {Plugin::Play, "Play"},
    {Plugin::Recorder, "Recorder"},
    {Plugin::Store, "Store"},
    {Plugin::Tenjin, "Tenjin"},
    {Plugin::UnityAds, "UnityAds"},
    {Plugin::Vungle, "Vungle"},
}};
} // namespace

bool Self::addPlugin(Plugin plugin) {
    auto&& name = pluginNames_.at(plugin);
    return ee_staticAddPlugin(name);
}

bool Self::removePlugin(Plugin plugin) {
    auto&& name = pluginNames_.at(plugin);
    return ee_staticRemovePlugin(name);
}
#endif // defined(EE_X_IOS) || defined(EE_X_OSX)
} // namespace core
} // namespace ee
<commit_msg>Fix to use const char* for bridging methods.<commit_after>//
//  Factory.cpp
//  ee_x
//
//  Created by eps on 3/20/18.
//

#include "ee/core/PluginManager.hpp"

#include <string>
#include <unordered_map>

#include "ee/core/Platform.hpp"
#include "ee/core/internal/MessageBridge.hpp"

namespace ee {
namespace core {
using Self = PluginManager;

#if defined(EE_X_ANDROID)
template <>
bool Self::initializePlugins<Library::Core>() {
    auto&& bridge = MessageBridge::getInstance();
    Platform::registerHandlers(bridge);
    return true;
}

bool Self::addPlugin(Plugin plugin) {
    // FIXME.
    return false;
}

bool Self::removePlugin(Plugin plugin) {
    // FIXME.
    return false;
}
#endif // EE_X_ANDROID

#if defined(EE_X_IOS) || defined(EE_X_OSX)
extern "C" {
bool ee_staticInitializePlugins();
bool ee_staticAddPlugin(const char* name);
bool ee_staticRemovePlugin(const char* name);
} // extern "C"

template <>
bool Self::initializePlugins<Library::Core>() {
    auto&& bridge = MessageBridge::getInstance();
    Platform::registerHandlers(bridge);
    return ee_staticInitializePlugins();
}

namespace {
std::unordered_map<Plugin, std::string> pluginNames_ = {{
    {Plugin::AdMob, "AdMob"},
    {Plugin::AppLovin, "AppLovin"},
    {Plugin::AppsFlyer, "AppsFlyer"},
    {Plugin::CampaignReceiver, "CampaignReceiver"},
    {Plugin::Facebook, "Facebook"},
    {Plugin::FacebookAds, "FacebookAds"},
    {Plugin::FirebaseCore, "FirebaseCore"},
    {Plugin::FirebaseCrashlytics, "FirebaseCrashlytics"},
    {Plugin::FirebasePerformance, "FirebasePerformance"},
    {Plugin::GoogleAnalytics, "GoogleAnalytics"},
    {Plugin::IronSource, "IronSource"},
    {Plugin::Notification, "Notification"},
    {Plugin::Play, "Play"},
    {Plugin::Recorder, "Recorder"},
    {Plugin::Store, "Store"},
    {Plugin::Tenjin, "Tenjin"},
    {Plugin::UnityAds, "UnityAds"},
    {Plugin::Vungle, "Vungle"},
}};
} // namespace

bool Self::addPlugin(Plugin plugin) {
    auto&& name = pluginNames_.at(plugin);
    return ee_staticAddPlugin(name.c_str());
}

bool Self::removePlugin(Plugin plugin) {
    auto&& name = pluginNames_.at(plugin);
    return ee_staticRemovePlugin(name.c_str());
}
#endif // defined(EE_X_IOS) || defined(EE_X_OSX)
} // namespace core
} // namespace ee
<|endoftext|>