<commit_before>/*
* Copyright (c) 2018 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* 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.
*/

/*
* The test is based on the assumption that trng will generate random data, random so
* there will not be any similar patterns in it, that kind of data will be impossible to
* compress, if compression will occur the test will result in failure.
*
* The test is composed out of three parts:
* the first, generate a trng buffer and try to compress it, at the end of first part
* we will reset the device.
* In second part we will generate a trng buffer with a different buffer size and try to
* compress it.
* In the third part we will again generate a trng buffer to see that the same trng output
* is not generated as the stored trng buffer from part one (before reseting), the new trng data will
* be concatenated to the trng data from the first part and then try to compress it
* together, if there are similar patterns the compression will succeed.
*
* We need to store and load the first part data before and after reset, the mechanism
* we chose is NVstore, mainly because its simplicity and the fact it is not platform
* dependent, in case a specific board does not support NVstore we will use the
* mbed greentea platform for sending and receving the data from the device to the
* host running the test and back, the problem with this mechanism is that it doesn't handle
* well certain characters, especially non ASCII ones, so we used the base64 algorithm
* to ensure all characters will be transmitted correctly.
*/

#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"
#include "hal/trng_api.h"
#include "base64b.h"
#include "nvstore.h"
#include "pithy.h"
#include <stdio.h>

#if !DEVICE_TRNG
#error [NOT_SUPPORTED] TRNG API not supported for this target
#endif

#define MSG_VALUE_DUMMY                 "0"
#define MSG_VALUE_LEN                   64
#define MSG_KEY_LEN                     32

#define BUFFER_LEN                      (MSG_VALUE_LEN/2)

#define MSG_TRNG_READY                  "ready"
#define MSG_TRNG_BUFFER                 "buffer"
#define MSG_TRNG_EXIT                   "exit"

#define MSG_TRNG_TEST_STEP1             "check_step1"
#define MSG_TRNG_TEST_STEP2             "check_step2"
#define MSG_TRNG_TEST_SUITE_ENDED       "Test_suite_ended"

#define RESULT_SUCCESS                  0

#define NVKEY                           1                  //NVstore key for storing and loading data

/*there are some issues with nvstore and greentea reset, so for now nvstore is disabled,
 *When solved delete current define and replace all NVSTORE_RESET with NVSTORE_ENABLED*/
#define NVSTORE_RESET                   (NVSTORE_ENABLED & 0)

using namespace utest::v1;

static int fill_buffer_trng(uint8_t *buffer, trng_t *trng_obj, size_t trng_len)
{
    size_t temp_size = 0, output_length = 0;
    int trng_res = 0;
    uint8_t *temp_in_buf = buffer;

    trng_init(trng_obj);
    memset(buffer, 0, BUFFER_LEN);

    while (true) {
        trng_res = trng_get_bytes(trng_obj, temp_in_buf, trng_len - temp_size, &output_length);
        TEST_ASSERT_EQUAL_INT_MESSAGE(0, trng_res, "trng_get_bytes error!");
        temp_size += output_length;
        temp_in_buf += output_length;
        trng_len -= output_length;
        if (temp_size >= trng_len) {
            break;
        }
    }

    temp_in_buf = NULL;
    trng_free(trng_obj);
    return 0;
}

static void compress_and_compare(char *key, char *value)
{
    trng_t trng_obj;
    uint8_t *out_comp_buf, *buffer;
    uint8_t *input_buf, *temp_buf;
    size_t comp_sz = 0;
    unsigned int result = 0;

#define OUT_COMP_BUF_SIZE ((BUFFER_LEN * 5) + 32)
#define TEMP_BUF_SIZE (BUFFER_LEN * 2)

    out_comp_buf = new uint8_t[OUT_COMP_BUF_SIZE];
    buffer = new uint8_t[BUFFER_LEN];
    input_buf = new uint8_t[BUFFER_LEN * 4];
    temp_buf = new uint8_t[BUFFER_LEN * 2];

#if NVSTORE_RESET
    NVStore& nvstore = NVStore::get_instance();
#endif

    /*At the begining of step 2 load trng buffer from step 1*/
    if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {
#if NVSTORE_RESET
        uint16_t actual = 0;
        result = nvstore.get(NVKEY, BUFFER_LEN, buffer, actual);
        TEST_ASSERT_EQUAL(RESULT_SUCCESS, result);
#else
        /*Using base64 to decode data sent from host*/

        uint32_t lengthWritten = 0;
        uint32_t charsProcessed = 0;
        result = trng_DecodeNBase64((const char *)value,
                                    MSG_VALUE_LEN,
                                    buffer,
                                    BUFFER_LEN,
                                    &lengthWritten,
                                    &charsProcessed);
        TEST_ASSERT_EQUAL(0, result);
#endif
        memcpy(input_buf, buffer, BUFFER_LEN);
    }

    if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
        /*Fill buffer with trng values*/
        result = fill_buffer_trng(buffer, &trng_obj, BUFFER_LEN);
        TEST_ASSERT_EQUAL(0, result);
        memcpy(input_buf, buffer, BUFFER_LEN);
    }
    /*pithy_Compress will try to compress the random data, if it succeeded it means the data is not really random*/
    else if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {

        comp_sz = pithy_Compress((char *)buffer,
                                 BUFFER_LEN,
                                 (char *)out_comp_buf,
                                 OUT_COMP_BUF_SIZE,
                                 9);
        TEST_ASSERT_MESSAGE(comp_sz > BUFFER_LEN,
                        "TRNG_TEST_STEP1: trng_get_bytes was able to compress thus not random");

        /*pithy_Compress will try to compress the random data with a different buffer sizem*/
        result = fill_buffer_trng(temp_buf, &trng_obj, TEMP_BUF_SIZE);
        TEST_ASSERT_EQUAL(0, result);

        comp_sz = pithy_Compress((char *)temp_buf,
                                 TEMP_BUF_SIZE,
                                 (char *)out_comp_buf,
                                 OUT_COMP_BUF_SIZE,
                                 9);
        TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE,
                        "TRNG_TEST_STEP2: trng_get_bytes was able to compress thus not random");

        memcpy(input_buf + BUFFER_LEN, temp_buf, TEMP_BUF_SIZE);
        /*pithy_Compress will try to compress the random data from before reset concatenated with new random data*/
        comp_sz = pithy_Compress((char *)input_buf,
                                 TEMP_BUF_SIZE + BUFFER_LEN,
                                 (char *)out_comp_buf,
                                 OUT_COMP_BUF_SIZE,
                                 9);
        TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE + BUFFER_LEN,
                        "TRNG_TEST_STEP3: concatenated buffer after reset was able to compress thus not random");
        greentea_send_kv(MSG_TRNG_TEST_SUITE_ENDED, MSG_VALUE_DUMMY);
    }

    /*At the end of step 1 store trng buffer and reset the device*/
    if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
        int result = 0;
#if NVSTORE_RESET
        result = nvstore.set(NVKEY, BUFFER_LEN, buffer);
        TEST_ASSERT_EQUAL(RESULT_SUCCESS, result);
#else
        /*Using base64 to encode data sending from host*/
        result = trng_EncodeBase64(buffer,
                                   BUFFER_LEN,
                                   (char *)out_comp_buf,
                                   OUT_COMP_BUF_SIZE);
        TEST_ASSERT_EQUAL(RESULT_SUCCESS, result);

        greentea_send_kv(MSG_TRNG_BUFFER, (const char *)out_comp_buf);
#endif
    }

    delete[] out_comp_buf;
    delete[] buffer;
    delete[] input_buf;
    delete[] temp_buf;
}

/*This method call first and second steps, it directs by the key received from the host*/
void trng_test()
{
    greentea_send_kv(MSG_TRNG_READY, MSG_VALUE_DUMMY);

    char key[MSG_KEY_LEN + 1] = { };
    char *value = new char[MSG_VALUE_LEN + 1];
    do {
        memset(key, 0, MSG_KEY_LEN + 1);
        memset(value, 0, MSG_VALUE_LEN + 1);

        greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);

        if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
            /*create trng data buffer and try to compress it, store it for later checks*/
            compress_and_compare(key, value);
        }

        if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {
            /*create another trng data buffer and concatenate it to the stored trng data buffer
            try to compress them both*/
            compress_and_compare(key, value);
        }
    } while (strcmp(key, MSG_TRNG_EXIT) != 0);

    delete[] value;
}

Case cases[] = {
    Case("TRNG: trng_test", trng_test),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
    GREENTEA_SETUP(100, "trng_reset");
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
    bool ret = !Harness::run(specification);

    return ret;
}
<commit_msg>Remove NVstore unused mechanism<commit_after>/*
* Copyright (c) 2018 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* 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.
*/

/*
* The test is based on the assumption that trng will generate random data, random so
* there will not be any similar patterns in it, that kind of data will be impossible to
* compress, if compression will occur the test will result in failure.
*
* The test is composed out of three parts:
* the first, generate a trng buffer and try to compress it, at the end of first part
* we will reset the device.
* In second part we will generate a trng buffer with a different buffer size and try to
* compress it.
* In the third part we will again generate a trng buffer to see that the same trng output
* is not generated as the stored trng buffer from part one (before reseting), the new trng data will
* be concatenated to the trng data from the first part and then try to compress it
* together, if there are similar patterns the compression will succeed.
*
* We need to store and load the first part data before and after reset, the mechanism
* we will use is the mbed greentea platform for sending and receving the data from the device
* to the host running the test and back, the problem with this mechanism is that it doesn't
* handle well certain characters, especially non ASCII ones, so we use the base64 algorithm
* to ensure all characters will be transmitted correctly.
*/

#include "greentea-client/test_env.h"
#include "unity/unity.h"
#include "utest/utest.h"
#include "hal/trng_api.h"
#include "base64b.h"
#include "pithy.h"
#include <stdio.h>

#if !DEVICE_TRNG
#error [NOT_SUPPORTED] TRNG API not supported for this target
#endif

#define MSG_VALUE_DUMMY                 "0"
#define MSG_VALUE_LEN                   64
#define MSG_KEY_LEN                     32

#define BUFFER_LEN                      (MSG_VALUE_LEN/2)

#define MSG_TRNG_READY                  "ready"
#define MSG_TRNG_BUFFER                 "buffer"
#define MSG_TRNG_EXIT                   "exit"

#define MSG_TRNG_TEST_STEP1             "check_step1"
#define MSG_TRNG_TEST_STEP2             "check_step2"
#define MSG_TRNG_TEST_SUITE_ENDED       "Test_suite_ended"

#define RESULT_SUCCESS                  0

using namespace utest::v1;

static int fill_buffer_trng(uint8_t *buffer, trng_t *trng_obj, size_t trng_len)
{
    size_t temp_size = 0, output_length = 0;
    int trng_res = 0;
    uint8_t *temp_in_buf = buffer;

    trng_init(trng_obj);
    memset(buffer, 0, BUFFER_LEN);

    while (true) {
        trng_res = trng_get_bytes(trng_obj, temp_in_buf, trng_len - temp_size, &output_length);
        TEST_ASSERT_EQUAL_INT_MESSAGE(0, trng_res, "trng_get_bytes error!");
        temp_size += output_length;
        temp_in_buf += output_length;
        trng_len -= output_length;
        if (temp_size >= trng_len) {
            break;
        }
    }

    temp_in_buf = NULL;
    trng_free(trng_obj);
    return 0;
}

static void compress_and_compare(char *key, char *value)
{
    trng_t trng_obj;
    uint8_t *out_comp_buf, *buffer;
    uint8_t *input_buf, *temp_buf;
    size_t comp_sz = 0;
    unsigned int result = 0;

#define OUT_COMP_BUF_SIZE ((BUFFER_LEN * 5) + 32)
#define TEMP_BUF_SIZE (BUFFER_LEN * 2)

    out_comp_buf = new uint8_t[OUT_COMP_BUF_SIZE];
    buffer = new uint8_t[BUFFER_LEN];
    input_buf = new uint8_t[BUFFER_LEN * 4];
    temp_buf = new uint8_t[BUFFER_LEN * 2];

    /*At the begining of step 2 load trng buffer from step 1*/
    if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {
        /*Using base64 to decode data sent from host*/
        uint32_t lengthWritten = 0;
        uint32_t charsProcessed = 0;
        result = trng_DecodeNBase64((const char *)value,
                                    MSG_VALUE_LEN,
                                    buffer,
                                    BUFFER_LEN,
                                    &lengthWritten,
                                    &charsProcessed);
        TEST_ASSERT_EQUAL(0, result);
        memcpy(input_buf, buffer, BUFFER_LEN);
    }

    if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
        /*Fill buffer with trng values*/
        result = fill_buffer_trng(buffer, &trng_obj, BUFFER_LEN);
        TEST_ASSERT_EQUAL(0, result);
        memcpy(input_buf, buffer, BUFFER_LEN);
    }
    /*pithy_Compress will try to compress the random data, if it succeeded it means the data is not really random*/
    else if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {

        comp_sz = pithy_Compress((char *)buffer,
                                 BUFFER_LEN,
                                 (char *)out_comp_buf,
                                 OUT_COMP_BUF_SIZE,
                                 9);
        TEST_ASSERT_MESSAGE(comp_sz > BUFFER_LEN,
                        "TRNG_TEST_STEP1: trng_get_bytes was able to compress thus not random");

        /*pithy_Compress will try to compress the random data with a different buffer sizem*/
        result = fill_buffer_trng(temp_buf, &trng_obj, TEMP_BUF_SIZE);
        TEST_ASSERT_EQUAL(0, result);

        comp_sz = pithy_Compress((char *)temp_buf,
                                 TEMP_BUF_SIZE,
                                 (char *)out_comp_buf,
                                 OUT_COMP_BUF_SIZE,
                                 9);
        TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE,
                        "TRNG_TEST_STEP2: trng_get_bytes was able to compress thus not random");

        memcpy(input_buf + BUFFER_LEN, temp_buf, TEMP_BUF_SIZE);
        /*pithy_Compress will try to compress the random data from before reset concatenated with new random data*/
        comp_sz = pithy_Compress((char *)input_buf,
                                 TEMP_BUF_SIZE + BUFFER_LEN,
                                 (char *)out_comp_buf,
                                 OUT_COMP_BUF_SIZE,
                                 9);
        TEST_ASSERT_MESSAGE(comp_sz > TEMP_BUF_SIZE + BUFFER_LEN,
                        "TRNG_TEST_STEP3: concatenated buffer after reset was able to compress thus not random");
        greentea_send_kv(MSG_TRNG_TEST_SUITE_ENDED, MSG_VALUE_DUMMY);
    }

    /*At the end of step 1 store trng buffer and reset the device*/
    if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
        int result = 0;
        /*Using base64 to encode data sending from host*/
        result = trng_EncodeBase64(buffer,
                                   BUFFER_LEN,
                                   (char *)out_comp_buf,
                                   OUT_COMP_BUF_SIZE);
        TEST_ASSERT_EQUAL(RESULT_SUCCESS, result);

        greentea_send_kv(MSG_TRNG_BUFFER, (const char *)out_comp_buf);
    }

    delete[] out_comp_buf;
    delete[] buffer;
    delete[] input_buf;
    delete[] temp_buf;
}

/*This method call first and second steps, it directs by the key received from the host*/
void trng_test()
{
    greentea_send_kv(MSG_TRNG_READY, MSG_VALUE_DUMMY);

    char key[MSG_KEY_LEN + 1] = { };
    char *value = new char[MSG_VALUE_LEN + 1];
    do {
        memset(key, 0, MSG_KEY_LEN + 1);
        memset(value, 0, MSG_VALUE_LEN + 1);

        greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);

        if (strcmp(key, MSG_TRNG_TEST_STEP1) == 0) {
            /*create trng data buffer and try to compress it, store it for later checks*/
            compress_and_compare(key, value);
        }

        if (strcmp(key, MSG_TRNG_TEST_STEP2) == 0) {
            /*create another trng data buffer and concatenate it to the stored trng data buffer
            try to compress them both*/
            compress_and_compare(key, value);
        }
    } while (strcmp(key, MSG_TRNG_EXIT) != 0);

    delete[] value;
}

Case cases[] = {
    Case("TRNG: trng_test", trng_test),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
    GREENTEA_SETUP(100, "trng_reset");
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
    bool ret = !Harness::run(specification);

    return ret;
}
<|endoftext|>


<commit_before>#include "ConnectionApi_p.hpp"

#include "AccountStorage.hpp"
#include "ClientBackend.hpp"
#include "ClientConnection.hpp"
#include "ClientRpcLayer.hpp"
#include "ClientSettings.hpp"
#include "CTelegramTransport.hpp"
#include "CClientTcpTransport.hpp"
#include "DataStorage.hpp"

#include "Operations/ClientAuthOperation_p.hpp"
#include "Operations/ClientPingOperation.hpp"
#include "Operations/ConnectionOperation.hpp"

#include <QLoggingCategory>

Q_LOGGING_CATEGORY(c_connectionApiLoggingCategory, "telegram.client.api.connection", QtWarningMsg)

namespace Telegram {

namespace Client {

ConnectionApiPrivate::ConnectionApiPrivate(ConnectionApi *parent) :
    ClientApiPrivate(parent)
{
}

ConnectionApiPrivate *ConnectionApiPrivate::get(ConnectionApi *parent)
{
    return reinterpret_cast<ConnectionApiPrivate*>(parent->d);
}

bool ConnectionApiPrivate::isSignedIn() const
{
    switch (m_status) {
    case ConnectionApi::StatusConnected:
    case ConnectionApi::StatusReady:
        return true;
    case ConnectionApi::StatusDisconnected:
    case ConnectionApi::StatusConnecting:
    case ConnectionApi::StatusWaitForAuthentication:
        return false;
    }
    Q_UNREACHABLE();
}

Connection *ConnectionApiPrivate::getDefaultConnection()
{
    if (mainConnection()) {
        return mainConnection();
    }

    if (m_initialConnectOperation) {
        return m_initialConnectOperation->connection();
    }
    return nullptr;
}

Connection *ConnectionApiPrivate::mainConnection()
{
    return m_mainConnection;
}

void ConnectionApiPrivate::setMainConnection(Connection *connection)
{
    m_mainConnection = connection;
    connect(m_mainConnection, &BaseConnection::statusChanged, this, &ConnectionApiPrivate::onMainConnectionStatusChanged);
    onMainConnectionStatusChanged(connection->status(), Connection::StatusReason::Local);
}

PendingOperation *ConnectionApiPrivate::connectToServer(const QVector<DcOption> &dcOptions)
{
    if (m_initialConnectOperation) {
        if (dcOptions.contains(m_initialConnectOperation->connection()->dcOption())) {
            switch (m_initialConnectOperation->connection()->status()) {
            case BaseConnection::Status::Connecting:
            case BaseConnection::Status::Connected:
            case BaseConnection::Status::HasDhKey:
            case BaseConnection::Status::Signed:
                return m_initialConnectOperation;
            default:
                m_initialConnectOperation->connection()->transport()->disconnectFromHost();
                break;
            }
        }
        m_initialConnectOperation->deleteLater();
        m_initialConnectOperation = nullptr;
    }

    if (mainConnection()) {
        if (mainConnection()->status() != Connection::Status::Disconnected) {
            return PendingOperation::failOperation<PendingOperation>
                    (QStringLiteral("Connection is already in progress"), this);
        } else {
            // TODO!
        }
    }

    if (!backend()->accountStorage()) {
        return PendingOperation::failOperation<PendingOperation>
                (QStringLiteral("Account storage is missing"), this);
    }
    if (!backend()->dataStorage()) {
        return PendingOperation::failOperation<PendingOperation>
                (QStringLiteral("Data storage is missing"), this);
    }

    Connection *connection = createConnection(dcOptions.first());
    connect(connection, &BaseConnection::statusChanged,
            this, &ConnectionApiPrivate::onInitialConnectionStatusChanged);

    m_initialConnectOperation = connection->connectToDc();
    connect(m_initialConnectOperation, &PendingOperation::finished, this, &ConnectionApiPrivate::onInitialConnectOperationFinished);
    return m_initialConnectOperation;
}

AuthOperation *ConnectionApiPrivate::startAuthentication()
{
    QVariantHash errorDetails = getBackendSetupErrorDetails();
    if (!errorDetails.isEmpty()) {
        return PendingOperation::failOperation<AuthOperation>(errorDetails, this);
    }

    if (isSignedIn()) {
        return PendingOperation::failOperation<AuthOperation>
                (QStringLiteral("Already signed in"), this);
    }
    if (m_authOperation && !m_authOperation->isFinished()) {
        return PendingOperation::failOperation<AuthOperation>
                (QStringLiteral("Auth operation is already in progress"), this);
    }

    m_authOperation = new AuthOperation(this);
    AuthOperationPrivate *priv = AuthOperationPrivate::get(m_authOperation);
    priv->setBackend(backend());
    priv->setRunMethod(&AuthOperation::requestAuthCode);
    connect(m_authOperation, &AuthOperation::finished, this, &ConnectionApiPrivate::onAuthFinished);
    connect(m_authOperation, &AuthOperation::authCodeRequired, this, &ConnectionApiPrivate::onAuthCodeRequired);
    PendingOperation *connectionOperation = connectToServer(backend()->settings()->serverConfiguration());
    m_authOperation->runAfter(connectionOperation);
    return m_authOperation;
}

AuthOperation *ConnectionApiPrivate::checkIn()
{
    QVariantHash errorDetails = getBackendSetupErrorDetails();
    if (!errorDetails.isEmpty()) {
        qCWarning(c_connectionApiLoggingCategory) << "Unable to initiate connection:" << errorDetails;
        return nullptr;
    }

    if (m_authOperation && !m_authOperation->isFinished()) {
        return PendingOperation::failOperation<AuthOperation>
                (QStringLiteral("Auth operation is already in progress"), this);
    }
    AccountStorage *accountStorage = backend()->accountStorage();
    if (!accountStorage || !accountStorage->hasMinimalDataSet()) {
        return PendingOperation::failOperation<AuthOperation>
                (QStringLiteral("No minimal account data set"), this);
    }
    m_authOperation = new AuthOperation(this);
    AuthOperationPrivate *priv = AuthOperationPrivate::get(m_authOperation);
    priv->setBackend(backend());
    priv->setRunMethod(&AuthOperation::checkAuthorization);
    connect(m_authOperation, &AuthOperation::finished, this, &ConnectionApiPrivate::onAuthFinished);
    PendingOperation *connectionOperation = connectToServer({accountStorage->dcInfo()});
    m_authOperation->runAfter(connectionOperation);
    m_initialConnectOperation->connection()->setAuthKey(accountStorage->authKey());
    m_initialConnectOperation->connection()->rpcLayer()->setSessionData(
                accountStorage->sessionId(),
                accountStorage->contentRelatedMessagesNumber());
    return m_authOperation;
}

QVariantHash ConnectionApiPrivate::getBackendSetupErrorDetails() const
{
    if (!backend()->accountStorage()) {
        return {{PendingOperation::c_text(), QStringLiteral("Account storage is missing")}};
    }
    if (!backend()->dataStorage()) {
        return {{PendingOperation::c_text(), QStringLiteral("Data storage is missing")}};
    }
    Settings *settings = backend()->settings();
    if (!settings) {
        return {{PendingOperation::c_text(), QStringLiteral("Settings object is missing")}};
    }
    if (!settings->isValid()) {
        return {{PendingOperation::c_text(), QStringLiteral("Invalid settings")}};
    }
    return {};
}

Connection *ConnectionApiPrivate::createConnection(const DcOption &dcOption)
{
    Connection *connection = new Connection(this);
    connection->setDcOption(dcOption);
    connection->rpcLayer()->setAppInformation(backend()->m_appInformation);
    connection->rpcLayer()->installUpdatesHandler(backend()->updatesApi());
    connection->setDeltaTime(backend()->accountStorage()->deltaTime());

    Settings *settings = backend()->m_settings;
    connection->setServerRsaKey(settings->serverRsaKey());
    TcpTransport *transport = new TcpTransport(connection);
    transport->setProxy(settings->proxy());

    switch (settings->preferedSessionType()) {
    case Settings::SessionType::None:
        qCWarning(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Session type is not set. Use fallback.";
        transport->setPreferedSessionType(TcpTransport::Obfuscated);
        break;
    case Settings::SessionType::Abridged:
        transport->setPreferedSessionType(TcpTransport::Abridged);
        break;
    case Settings::SessionType::Obfuscated:
        transport->setPreferedSessionType(TcpTransport::Obfuscated);
        break;
    }
    connection->setTransport(transport);
    return connection;
}

Connection *ConnectionApiPrivate::ensureConnection(const ConnectionSpec &connectionSpec)
{
    qCDebug(c_connectionApiLoggingCategory) << Q_FUNC_INFO << connectionSpec.dcId << connectionSpec.flags;
    ConnectionSpec spec = connectionSpec;
    spec.flags |= ConnectionSpec::RequestFlag::Ipv4Only; // Enable only ipv4 for now
    if (!m_connections.contains(connectionSpec)) {
        const DcOption opt = backend()->dataStorage()->serverConfiguration().getOption(spec);
        if (!opt.isValid()) {
            qCWarning(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Unable to find suitable DC";
            return nullptr;
        }
        m_connections.insert(connectionSpec, createConnection(opt));
    }
    return m_connections.value(connectionSpec);
}

void ConnectionApiPrivate::onInitialConnectOperationFinished(PendingOperation *operation)
{
    disconnect(m_initialConnectOperation->connection(), &BaseConnection::statusChanged,
               this, &ConnectionApiPrivate::onInitialConnectionStatusChanged);

    if (operation->isSucceeded()) {
        backend()->getDcConfig();
        return;
    }
    m_initialConnectOperation = nullptr;
    operation->deleteLater();
    setStatus(ConnectionApi::StatusDisconnected);
}

void ConnectionApiPrivate::onInitialConnectionStatusChanged(BaseConnection::Status status,
                                                             BaseConnection::StatusReason reason)
{
    qCDebug(c_connectionApiLoggingCategory) << Q_FUNC_INFO << status << reason;
    switch (status) {
    case BaseConnection::Status::Disconnected:
    case BaseConnection::Status::Disconnecting:
        setStatus(ConnectionApi::StatusDisconnected);
        break;
    case BaseConnection::Status::Connecting:
        setStatus(ConnectionApi::StatusConnecting);
        break;
    case BaseConnection::Status::Connected:
        // Nothing to do; wait for DH
        break;
    case BaseConnection::Status::HasDhKey:
        break;
    case BaseConnection::Status::Signed:
    case BaseConnection::Status::Failed:
        break;
    }
}

void ConnectionApiPrivate::onAuthFinished(PendingOperation *operation)
{
    if (operation != m_authOperation) {
        qCCritical(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Unexpected auth operation";
        return;
    }
    if (!operation->isSucceeded()) {
        setStatus(ConnectionApi::StatusWaitForAuthentication);
        qCDebug(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "TODO?";
        return;
    }
    AuthOperationPrivate *priv = AuthOperationPrivate::get(m_authOperation);
    Connection *conn = priv->m_authenticatedConnection;
    if (conn->status() != Connection::Status::Signed) {
        qCCritical(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Unexpected connection status" << conn->status();
        return;
    }
    setMainConnection(conn);
}

void ConnectionApiPrivate::onAuthCodeRequired()
{
    setStatus(ConnectionApi::StatusWaitForAuthentication, ConnectionApi::StatusReasonRemote);
}

void ConnectionApiPrivate::onMainConnectionStatusChanged(BaseConnection::Status status, BaseConnection::StatusReason reason)
{
    if (!m_mainConnection) {
        return;
    }

    const bool keepAliveIsWanted = (status == Connection::Status::Signed) || (status == Connection::Status::HasDhKey);
    if (keepAliveIsWanted) {
        if (!m_pingOperation) {
            m_pingOperation = new PingOperation(this);
            m_pingOperation->setSettings(backend()->m_settings);
            m_pingOperation->setRpcLayer(m_mainConnection->rpcLayer());
            connect(m_pingOperation, &PingOperation::pingFailed, this, &ConnectionApiPrivate::onPingFailed);
        }
        m_pingOperation->ensureActive();
    } else {
        if (m_pingOperation) {
            m_pingOperation->ensureInactive();
        }
    }

    switch (status) {
    case Connection::Status::Signed:
    {
        backend()->syncAccountToStorage();
        setStatus(ConnectionApi::StatusConnected);
        PendingOperation *syncOperation = backend()->sync();
        connect(syncOperation, &PendingOperation::finished, this, &ConnectionApiPrivate::onSyncFinished);
        syncOperation->startLater();
    }
        break;
    default:
        break;
    }
}

void ConnectionApiPrivate::onSyncFinished(PendingOperation *operation)
{
    if (operation->isSucceeded()) {
        setStatus(ConnectionApi::StatusReady, ConnectionApi::StatusReasonLocal);
    } else {
        qCCritical(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Unexpected sync operation status" << operation->errorDetails();
    }
}

void ConnectionApiPrivate::onPingFailed()
{
    qCWarning(c_connectionApiLoggingCategory) << Q_FUNC_INFO;
}

void ConnectionApiPrivate::setStatus(ConnectionApi::Status status, ConnectionApi::StatusReason reason)
{
    Q_Q(ConnectionApi);
    if (m_status == status) {
        return;
    }
    m_status = status;
    emit q->statusChanged(status, reason);
}

ConnectionApi::ConnectionApi(QObject *parent) :
    ClientApi(parent)
{
    d = new ConnectionApiPrivate(this);
}

bool ConnectionApi::isSignedIn() const
{
    Q_D(const ConnectionApi);
    return d->isSignedIn();
}

ConnectionApi::Status ConnectionApi::status() const
{
    Q_D(const ConnectionApi);
    return d->status();
}

Telegram::Client::AuthOperation *ConnectionApi::startAuthentication()
{
    Q_D(ConnectionApi);
    return d->startAuthentication();
}

AuthOperation *ConnectionApi::checkIn()
{
    Q_D(ConnectionApi);
    return d->checkIn();
}

} // Client namespace

} // Telegram namespace
<commit_msg>ConnectionApi: Fix checkIn (return failed op instead of nullptr)<commit_after>#include "ConnectionApi_p.hpp"

#include "AccountStorage.hpp"
#include "ClientBackend.hpp"
#include "ClientConnection.hpp"
#include "ClientRpcLayer.hpp"
#include "ClientSettings.hpp"
#include "CTelegramTransport.hpp"
#include "CClientTcpTransport.hpp"
#include "DataStorage.hpp"

#include "Operations/ClientAuthOperation_p.hpp"
#include "Operations/ClientPingOperation.hpp"
#include "Operations/ConnectionOperation.hpp"

#include <QLoggingCategory>

Q_LOGGING_CATEGORY(c_connectionApiLoggingCategory, "telegram.client.api.connection", QtWarningMsg)

namespace Telegram {

namespace Client {

ConnectionApiPrivate::ConnectionApiPrivate(ConnectionApi *parent) :
    ClientApiPrivate(parent)
{
}

ConnectionApiPrivate *ConnectionApiPrivate::get(ConnectionApi *parent)
{
    return reinterpret_cast<ConnectionApiPrivate*>(parent->d);
}

bool ConnectionApiPrivate::isSignedIn() const
{
    switch (m_status) {
    case ConnectionApi::StatusConnected:
    case ConnectionApi::StatusReady:
        return true;
    case ConnectionApi::StatusDisconnected:
    case ConnectionApi::StatusConnecting:
    case ConnectionApi::StatusWaitForAuthentication:
        return false;
    }
    Q_UNREACHABLE();
}

Connection *ConnectionApiPrivate::getDefaultConnection()
{
    if (mainConnection()) {
        return mainConnection();
    }

    if (m_initialConnectOperation) {
        return m_initialConnectOperation->connection();
    }
    return nullptr;
}

Connection *ConnectionApiPrivate::mainConnection()
{
    return m_mainConnection;
}

void ConnectionApiPrivate::setMainConnection(Connection *connection)
{
    m_mainConnection = connection;
    connect(m_mainConnection, &BaseConnection::statusChanged, this, &ConnectionApiPrivate::onMainConnectionStatusChanged);
    onMainConnectionStatusChanged(connection->status(), Connection::StatusReason::Local);
}

PendingOperation *ConnectionApiPrivate::connectToServer(const QVector<DcOption> &dcOptions)
{
    if (m_initialConnectOperation) {
        if (dcOptions.contains(m_initialConnectOperation->connection()->dcOption())) {
            switch (m_initialConnectOperation->connection()->status()) {
            case BaseConnection::Status::Connecting:
            case BaseConnection::Status::Connected:
            case BaseConnection::Status::HasDhKey:
            case BaseConnection::Status::Signed:
                return m_initialConnectOperation;
            default:
                m_initialConnectOperation->connection()->transport()->disconnectFromHost();
                break;
            }
        }
        m_initialConnectOperation->deleteLater();
        m_initialConnectOperation = nullptr;
    }

    if (mainConnection()) {
        if (mainConnection()->status() != Connection::Status::Disconnected) {
            return PendingOperation::failOperation<PendingOperation>
                    (QStringLiteral("Connection is already in progress"), this);
        } else {
            // TODO!
        }
    }

    if (!backend()->accountStorage()) {
        return PendingOperation::failOperation<PendingOperation>
                (QStringLiteral("Account storage is missing"), this);
    }
    if (!backend()->dataStorage()) {
        return PendingOperation::failOperation<PendingOperation>
                (QStringLiteral("Data storage is missing"), this);
    }

    Connection *connection = createConnection(dcOptions.first());
    connect(connection, &BaseConnection::statusChanged,
            this, &ConnectionApiPrivate::onInitialConnectionStatusChanged);

    m_initialConnectOperation = connection->connectToDc();
    connect(m_initialConnectOperation, &PendingOperation::finished, this, &ConnectionApiPrivate::onInitialConnectOperationFinished);
    return m_initialConnectOperation;
}

AuthOperation *ConnectionApiPrivate::startAuthentication()
{
    QVariantHash errorDetails = getBackendSetupErrorDetails();
    if (!errorDetails.isEmpty()) {
        return PendingOperation::failOperation<AuthOperation>(errorDetails, this);
    }

    if (isSignedIn()) {
        return PendingOperation::failOperation<AuthOperation>
                (QStringLiteral("Already signed in"), this);
    }
    if (m_authOperation && !m_authOperation->isFinished()) {
        return PendingOperation::failOperation<AuthOperation>
                (QStringLiteral("Auth operation is already in progress"), this);
    }

    m_authOperation = new AuthOperation(this);
    AuthOperationPrivate *priv = AuthOperationPrivate::get(m_authOperation);
    priv->setBackend(backend());
    priv->setRunMethod(&AuthOperation::requestAuthCode);
    connect(m_authOperation, &AuthOperation::finished, this, &ConnectionApiPrivate::onAuthFinished);
    connect(m_authOperation, &AuthOperation::authCodeRequired, this, &ConnectionApiPrivate::onAuthCodeRequired);
    PendingOperation *connectionOperation = connectToServer(backend()->settings()->serverConfiguration());
    m_authOperation->runAfter(connectionOperation);
    return m_authOperation;
}

AuthOperation *ConnectionApiPrivate::checkIn()
{
    QVariantHash errorDetails = getBackendSetupErrorDetails();
    if (!errorDetails.isEmpty()) {
        return PendingOperation::failOperation<AuthOperation>(errorDetails, this);
    }

    if (m_authOperation && !m_authOperation->isFinished()) {
        return PendingOperation::failOperation<AuthOperation>
                (QStringLiteral("Auth operation is already in progress"), this);
    }
    AccountStorage *accountStorage = backend()->accountStorage();
    if (!accountStorage || !accountStorage->hasMinimalDataSet()) {
        return PendingOperation::failOperation<AuthOperation>
                (QStringLiteral("No minimal account data set"), this);
    }
    m_authOperation = new AuthOperation(this);
    AuthOperationPrivate *priv = AuthOperationPrivate::get(m_authOperation);
    priv->setBackend(backend());
    priv->setRunMethod(&AuthOperation::checkAuthorization);
    connect(m_authOperation, &AuthOperation::finished, this, &ConnectionApiPrivate::onAuthFinished);
    PendingOperation *connectionOperation = connectToServer({accountStorage->dcInfo()});
    m_authOperation->runAfter(connectionOperation);
    m_initialConnectOperation->connection()->setAuthKey(accountStorage->authKey());
    m_initialConnectOperation->connection()->rpcLayer()->setSessionData(
                accountStorage->sessionId(),
                accountStorage->contentRelatedMessagesNumber());
    return m_authOperation;
}

QVariantHash ConnectionApiPrivate::getBackendSetupErrorDetails() const
{
    if (!backend()->accountStorage()) {
        return {{PendingOperation::c_text(), QStringLiteral("Account storage is missing")}};
    }
    if (!backend()->dataStorage()) {
        return {{PendingOperation::c_text(), QStringLiteral("Data storage is missing")}};
    }
    Settings *settings = backend()->settings();
    if (!settings) {
        return {{PendingOperation::c_text(), QStringLiteral("Settings object is missing")}};
    }
    if (!settings->isValid()) {
        return {{PendingOperation::c_text(), QStringLiteral("Invalid settings")}};
    }
    return {};
}

Connection *ConnectionApiPrivate::createConnection(const DcOption &dcOption)
{
    Connection *connection = new Connection(this);
    connection->setDcOption(dcOption);
    connection->rpcLayer()->setAppInformation(backend()->m_appInformation);
    connection->rpcLayer()->installUpdatesHandler(backend()->updatesApi());
    connection->setDeltaTime(backend()->accountStorage()->deltaTime());

    Settings *settings = backend()->m_settings;
    connection->setServerRsaKey(settings->serverRsaKey());
    TcpTransport *transport = new TcpTransport(connection);
    transport->setProxy(settings->proxy());

    switch (settings->preferedSessionType()) {
    case Settings::SessionType::None:
        qCWarning(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Session type is not set. Use fallback.";
        transport->setPreferedSessionType(TcpTransport::Obfuscated);
        break;
    case Settings::SessionType::Abridged:
        transport->setPreferedSessionType(TcpTransport::Abridged);
        break;
    case Settings::SessionType::Obfuscated:
        transport->setPreferedSessionType(TcpTransport::Obfuscated);
        break;
    }
    connection->setTransport(transport);
    return connection;
}

Connection *ConnectionApiPrivate::ensureConnection(const ConnectionSpec &connectionSpec)
{
    qCDebug(c_connectionApiLoggingCategory) << Q_FUNC_INFO << connectionSpec.dcId << connectionSpec.flags;
    ConnectionSpec spec = connectionSpec;
    spec.flags |= ConnectionSpec::RequestFlag::Ipv4Only; // Enable only ipv4 for now
    if (!m_connections.contains(connectionSpec)) {
        const DcOption opt = backend()->dataStorage()->serverConfiguration().getOption(spec);
        if (!opt.isValid()) {
            qCWarning(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Unable to find suitable DC";
            return nullptr;
        }
        m_connections.insert(connectionSpec, createConnection(opt));
    }
    return m_connections.value(connectionSpec);
}

void ConnectionApiPrivate::onInitialConnectOperationFinished(PendingOperation *operation)
{
    disconnect(m_initialConnectOperation->connection(), &BaseConnection::statusChanged,
               this, &ConnectionApiPrivate::onInitialConnectionStatusChanged);

    if (operation->isSucceeded()) {
        backend()->getDcConfig();
        return;
    }
    m_initialConnectOperation = nullptr;
    operation->deleteLater();
    setStatus(ConnectionApi::StatusDisconnected);
}

void ConnectionApiPrivate::onInitialConnectionStatusChanged(BaseConnection::Status status,
                                                             BaseConnection::StatusReason reason)
{
    qCDebug(c_connectionApiLoggingCategory) << Q_FUNC_INFO << status << reason;
    switch (status) {
    case BaseConnection::Status::Disconnected:
    case BaseConnection::Status::Disconnecting:
        setStatus(ConnectionApi::StatusDisconnected);
        break;
    case BaseConnection::Status::Connecting:
        setStatus(ConnectionApi::StatusConnecting);
        break;
    case BaseConnection::Status::Connected:
        // Nothing to do; wait for DH
        break;
    case BaseConnection::Status::HasDhKey:
        break;
    case BaseConnection::Status::Signed:
    case BaseConnection::Status::Failed:
        break;
    }
}

void ConnectionApiPrivate::onAuthFinished(PendingOperation *operation)
{
    if (operation != m_authOperation) {
        qCCritical(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Unexpected auth operation";
        return;
    }
    if (!operation->isSucceeded()) {
        setStatus(ConnectionApi::StatusWaitForAuthentication);
        qCDebug(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "TODO?";
        return;
    }
    AuthOperationPrivate *priv = AuthOperationPrivate::get(m_authOperation);
    Connection *conn = priv->m_authenticatedConnection;
    if (conn->status() != Connection::Status::Signed) {
        qCCritical(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Unexpected connection status" << conn->status();
        return;
    }
    setMainConnection(conn);
}

void ConnectionApiPrivate::onAuthCodeRequired()
{
    setStatus(ConnectionApi::StatusWaitForAuthentication, ConnectionApi::StatusReasonRemote);
}

void ConnectionApiPrivate::onMainConnectionStatusChanged(BaseConnection::Status status, BaseConnection::StatusReason reason)
{
    if (!m_mainConnection) {
        return;
    }

    const bool keepAliveIsWanted = (status == Connection::Status::Signed) || (status == Connection::Status::HasDhKey);
    if (keepAliveIsWanted) {
        if (!m_pingOperation) {
            m_pingOperation = new PingOperation(this);
            m_pingOperation->setSettings(backend()->m_settings);
            m_pingOperation->setRpcLayer(m_mainConnection->rpcLayer());
            connect(m_pingOperation, &PingOperation::pingFailed, this, &ConnectionApiPrivate::onPingFailed);
        }
        m_pingOperation->ensureActive();
    } else {
        if (m_pingOperation) {
            m_pingOperation->ensureInactive();
        }
    }

    switch (status) {
    case Connection::Status::Signed:
    {
        backend()->syncAccountToStorage();
        setStatus(ConnectionApi::StatusConnected);
        PendingOperation *syncOperation = backend()->sync();
        connect(syncOperation, &PendingOperation::finished, this, &ConnectionApiPrivate::onSyncFinished);
        syncOperation->startLater();
    }
        break;
    default:
        break;
    }
}

void ConnectionApiPrivate::onSyncFinished(PendingOperation *operation)
{
    if (operation->isSucceeded()) {
        setStatus(ConnectionApi::StatusReady, ConnectionApi::StatusReasonLocal);
    } else {
        qCCritical(c_connectionApiLoggingCategory) << Q_FUNC_INFO << "Unexpected sync operation status" << operation->errorDetails();
    }
}

void ConnectionApiPrivate::onPingFailed()
{
    qCWarning(c_connectionApiLoggingCategory) << Q_FUNC_INFO;
}

void ConnectionApiPrivate::setStatus(ConnectionApi::Status status, ConnectionApi::StatusReason reason)
{
    Q_Q(ConnectionApi);
    if (m_status == status) {
        return;
    }
    m_status = status;
    emit q->statusChanged(status, reason);
}

ConnectionApi::ConnectionApi(QObject *parent) :
    ClientApi(parent)
{
    d = new ConnectionApiPrivate(this);
}

bool ConnectionApi::isSignedIn() const
{
    Q_D(const ConnectionApi);
    return d->isSignedIn();
}

ConnectionApi::Status ConnectionApi::status() const
{
    Q_D(const ConnectionApi);
    return d->status();
}

Telegram::Client::AuthOperation *ConnectionApi::startAuthentication()
{
    Q_D(ConnectionApi);
    return d->startAuthentication();
}

AuthOperation *ConnectionApi::checkIn()
{
    Q_D(ConnectionApi);
    return d->checkIn();
}

} // Client namespace

} // Telegram namespace
<|endoftext|>


<commit_before>#include <cassert>
#include <climits>
#include <fstream>
#include <iostream>
#include <strstream>

#include <process.h>

#include <util/PlatformUtils.hpp>
#include <util/Mutexes.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/XalanFileOutputStream.hpp>
#include <PlatformSupport/XalanOutputStreamPrintWriter.hpp>

#include <XalanSourceTree/XalanSourceTreeDOMSupport.hpp>
#include <XalanSourceTree/XalanSourceTreeParserLiaison.hpp>

#include <XPath/XObjectFactoryDefault.hpp>
#include <XPath/XPathFactoryDefault.hpp>

#include <XSLT/StylesheetConstructionContextDefault.hpp>
#include <XSLT/StylesheetExecutionContextDefault.hpp>
#include <XSLT/StylesheetRoot.hpp>
#include <XSLT/XSLTEngineImpl.hpp>
#include <XSLT/XSLTInit.hpp>
#include <XSLT/XSLTInputSource.hpp>
#include <XSLT/XSLTProcessorEnvSupportDefault.hpp>
#include <XSLT/XSLTResultTarget.hpp>

//This is here for the threads.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winbase.h>

#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
	using std::cout;
	using std::endl;
	using std::ifstream;
	using std::ios_base;
	using std::ostrstream;
	using std::string;
#endif

// This is here for memory leak testing.
#if defined(_DEBUG)
#include <crtdbg.h>
#endif

// Used to hold compiled stylesheet
StylesheetRoot* glbStylesheetRoot;

extern "C" void theThreadRoutine(void* param);

class SynchronizedCounter
{
public:

	SynchronizedCounter();

	~SynchronizedCounter();

	void
	increment();

	void
	decrement();

	unsigned long
	getCounter() const;

private:

	mutable XMLMutex	m_mutex;

	unsigned long		m_counter;
};

SynchronizedCounter::SynchronizedCounter() :
	m_mutex(),
	m_counter(0)
{
}

SynchronizedCounter::~SynchronizedCounter()
{
}

void
SynchronizedCounter::increment()
{
	XMLMutexLock	theLock(&m_mutex);

	if (m_counter < ULONG_MAX)
	{
		++m_counter;
	}
}

void
SynchronizedCounter::decrement()
{
	XMLMutexLock	theLock(&m_mutex);

	if (m_counter > 0)
	{
		--m_counter;
	}
}

unsigned long
SynchronizedCounter::getCounter() const
{
	return m_counter;
}

struct
ThreadInfo
{
	ThreadInfo(
			unsigned int			theThreadNumber,
			SynchronizedCounter*	theCounter) :
		m_threadNumber(theThreadNumber),
		m_counter(theCounter)
	{
	}

	unsigned int			m_threadNumber;

	SynchronizedCounter*	m_counter;
};

void
theThreadRoutine(void*		param)
{
// This routine uses compiled stylesheet (glbStylesheetRoot), which is set using the
// theProcessor.setStylesheetRoot method. The transform is done using the theProcessor's
// process() method.

	const ThreadInfo*	theInfo = reinterpret_cast<const ThreadInfo*>(param);

	assert(theInfo != 0);

	theInfo->m_counter->increment();

	try
	{
		// Create the support objects that are necessary for running the processor...
		XalanSourceTreeDOMSupport		theDOMSupport;
		XalanSourceTreeParserLiaison	theParserLiaison(theDOMSupport);

		theDOMSupport.setParserLiaison(&theParserLiaison);
		// The default is that documents are not thread-safe.  Set this to
		// true so they are.
		//theParserLiaison.setThreadSafe(true);

		XSLTProcessorEnvSupportDefault	theXSLTProcessorEnvSupport;
		XObjectFactoryDefault			theXObjectFactory;
		XPathFactoryDefault				theXPathFactory;

		// Create a processor...and output start message.
		XSLTEngineImpl	theProcessor(
						theParserLiaison,
						theXSLTProcessorEnvSupport,
						theDOMSupport,
						theXObjectFactory,
						theXPathFactory);

		// Connect the processor to the support object...
		theXSLTProcessorEnvSupport.setProcessor(&theProcessor);

		// The execution context uses the same factory support objects as
		// the processor, since those objects have the same lifetime as
		// other objects created as a result of the execution.
		StylesheetExecutionContextDefault	ssExecutionContext(
							theProcessor,
							theXSLTProcessorEnvSupport,
							theDOMSupport,
							theXObjectFactory);

		// Our input files.  The assumption is that the executable will be run
		// from same directory as the input files.

		// Generate the input and output file names.
		const XalanDOMString	theXMLfile("birds.xml");

		const XalanDOMString	theOutputFile(
				XalanDOMString("birds") +
				UnsignedLongToDOMString(theInfo->m_threadNumber) +
				XalanDOMString(".out"));

		//Generate the XML input and output objects.
		XSLTInputSource		theInputSource(c_wstr(theXMLfile));
		XSLTResultTarget	theResultTarget(theOutputFile);

		// Set the stylesheet to be the compiled stylesheet. Then do the transform.
		// Report both the start of the transform and end of the thread.
		theProcessor.setStylesheetRoot(glbStylesheetRoot);
		theProcessor.process(theInputSource,theResultTarget,ssExecutionContext);
	}
	catch(...)
	{
	}

	// Decrement the counter because we're done...
	theInfo->m_counter->decrement();
}

void
doThreads(long	theThreadCount)
{
	cout << endl << "Starting " << theThreadCount << " threads." << endl;

	typedef std::vector<ThreadInfo>		ThreadInfoVectorType;

	ThreadInfoVectorType	theThreadInfo;

	theThreadInfo.reserve(theThreadCount);

	try
	{
		cout << endl << "Clock before starting threads: " << clock() << endl;

		SynchronizedCounter		theCounter;

		for (long i = 0; i < theThreadCount; i++)
		{
			theThreadInfo.push_back(ThreadInfoVectorType::value_type(i, &theCounter));

			const unsigned long		theThreadID =
					_beginthread(theThreadRoutine, 4096, reinterpret_cast<LPVOID>(&theThreadInfo.back()));

			if (theThreadID == unsigned(-1))
			{
				cerr << endl << "Unable to create thread number " << i + 1 << "." << endl;
			}
		}

		clock_t		theClock = 0;

		if (theThreadInfo.size() == 0)
		{
			cerr << endl << "No threads were created!" << endl;
		}
		else
		{
			unsigned int	theCheckCount = 0;

			do
			{
				Sleep(2000);

				// Check a couple of times, just in case, since
				// getCounter() is not synchronized...
				if (theCounter.getCounter() == 0)
				{
					if (theCheckCount == 0)
					{
						theClock = clock();
					}

					++theCheckCount;
				}
			}
			while(theCheckCount < 2);
		}

		cout << endl << "Clock after threads: " << theClock << endl;
	}
	catch(...)
	{
		cerr << "Exception caught!!!"
			 << endl
			<< endl;
	}
}

int
main(
			int				argc,
			const char*		argv[])
{
#if !defined(NDEBUG) && defined(_MSC_VER)
	_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

	_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
	_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
#endif

	if (argc > 2)
	{
		cerr << "Usage: ThreadTest"
			 << endl
			 << endl;
	}
	else
	{
		int	threadCount = 60;

		if (argc == 2)
		{
			threadCount = atoi(argv[1]);
		}

		try
		{
		  // Call the static initializers...
		  XMLPlatformUtils::Initialize();
          {
			XSLTInit	theInit;

			// Create the necessary stuff of compile the stylesheet.
			XercesDOMSupport				ssDOMSupport;
			XercesParserLiaison				ssParserLiaison(ssDOMSupport);
			XSLTProcessorEnvSupportDefault	ssXSLTProcessorEnvSupport;
			XObjectFactoryDefault			ssXObjectFactory;
			XPathFactoryDefault				ssXPathFactory;

			// Create a processor to compile the stylesheet...
			XSLTEngineImpl	ssProcessor(
					ssParserLiaison,
					ssXSLTProcessorEnvSupport,
					ssDOMSupport,
					ssXObjectFactory,
					ssXPathFactory);

			// Create separate factory support objects so the stylesheet's
			// factory-created XObject and XPath instances are independent
			// from processor's.
			XPathFactoryDefault		ssStylesheetXPathFactory;

			// Create a stylesheet construction context, using the
			// stylesheet's factory support objects.
			StylesheetConstructionContextDefault	ssConstructionContext(
													ssProcessor,
													ssXSLTProcessorEnvSupport,
													ssStylesheetXPathFactory);

			const XalanDOMString  theXSLFileName("birds.xsl");
			const XalanDOMString  theXMLFileName("birds.xml");

			// Our stylesheet input source...
			XSLTInputSource		ssStylesheetSourceXSL(c_wstr(theXSLFileName));
			XSLTInputSource		ssStylesheetSourceXML(c_wstr(theXMLFileName));

			// Ask the processor to create a StylesheetRoot for the specified
			// input XSL.  This is the compiled stylesheet.  We don't have to
			// delete it, since it is owned by the StylesheetConstructionContext
			// instance.

			glbStylesheetRoot = ssProcessor.processStylesheet(ssStylesheetSourceXSL,
													   ssConstructionContext);
			assert(glbStylesheetRoot != 0);

			doThreads(threadCount);
		  }

		XMLPlatformUtils::Terminate();

		}

		catch(...)
		{
			cerr << "Exception caught!!!"
				 << endl
				 << endl;
		}

	}

	return 0;
}
<commit_msg>Added support for pthreads.<commit_after>#include <cassert>
#include <iostream>

#include <util/PlatformUtils.hpp>
#include <util/Mutexes.hpp>

#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/XalanFileOutputStream.hpp>
#include <PlatformSupport/XalanOutputStreamPrintWriter.hpp>

#include <XalanSourceTree/XalanSourceTreeDOMSupport.hpp>
#include <XalanSourceTree/XalanSourceTreeParserLiaison.hpp>

#include <XPath/XObjectFactoryDefault.hpp>
#include <XPath/XPathFactoryDefault.hpp>

#include <XSLT/StylesheetConstructionContextDefault.hpp>
#include <XSLT/StylesheetExecutionContextDefault.hpp>
#include <XSLT/StylesheetRoot.hpp>
#include <XSLT/XSLTEngineImpl.hpp>
#include <XSLT/XSLTInit.hpp>
#include <XSLT/XSLTInputSource.hpp>
#include <XSLT/XSLTProcessorEnvSupportDefault.hpp>
#include <XSLT/XSLTResultTarget.hpp>

#if defined(WIN32)
//This is here for the threads.
#include <process.h>

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#elif defined(XALAN_POSIX2_AVAILABLE)
#include <pthread.h>
#include <unistd.h>
#else
#error Unsupported platform!
#endif

#if !defined(XALAN_NO_NAMESPACES)
	using std::cerr;
	using std::cout;
	using std::endl;
#endif

// This is here for memory leak testing.
#if defined(_DEBUG)
#include <crtdbg.h>
#endif

// Used to hold compiled stylesheet
StylesheetRoot* glbStylesheetRoot;

class SynchronizedCounter
{
public:

	SynchronizedCounter();

	~SynchronizedCounter();

	void
	increment();

	void
	decrement();

	unsigned long
	getCounter() const;

private:

	mutable XMLMutex	m_mutex;

	unsigned long		m_counter;
};

SynchronizedCounter::SynchronizedCounter() :
	m_mutex(),
	m_counter(0)
{
}

SynchronizedCounter::~SynchronizedCounter()
{
}

void
SynchronizedCounter::increment()
{
	XMLMutexLock	theLock(&m_mutex);

	if (m_counter < ULONG_MAX)
	{
		++m_counter;
	}
}

void
SynchronizedCounter::decrement()
{
	XMLMutexLock	theLock(&m_mutex);

	if (m_counter > 0)
	{
		--m_counter;
	}
}

unsigned long
SynchronizedCounter::getCounter() const
{
	return m_counter;
}

struct
ThreadInfo
{
	ThreadInfo(
			unsigned int			theThreadNumber,
			SynchronizedCounter*	theCounter) :
		m_threadNumber(theThreadNumber),
		m_counter(theCounter)
	{
	}

	unsigned int			m_threadNumber;

	SynchronizedCounter*	m_counter;
};

#if defined(WIN32)

extern "C" void theThreadRoutine(void* param);

void
#elif defined(XALAN_POSIX2_AVAILABLE)

extern "C" void* theThreadRoutine(void* param);

void*
#else
#error Unsupported platform!
#endif
theThreadRoutine(void*		param)
{
// This routine uses compiled stylesheet (glbStylesheetRoot), which is set using the
// theProcessor.setStylesheetRoot method. The transform is done using the theProcessor's
// process() method.

	const ThreadInfo*	theInfo = reinterpret_cast<const ThreadInfo*>(param);

	assert(theInfo != 0);

	theInfo->m_counter->increment();

	try
	{
		// Create the support objects that are necessary for running the processor...
		XalanSourceTreeDOMSupport		theDOMSupport;
		XalanSourceTreeParserLiaison	theParserLiaison(theDOMSupport);

		theDOMSupport.setParserLiaison(&theParserLiaison);
		// The default is that documents are not thread-safe.  Set this to
		// true so they are.
		//theParserLiaison.setThreadSafe(true);

		XSLTProcessorEnvSupportDefault	theXSLTProcessorEnvSupport;
		XObjectFactoryDefault			theXObjectFactory;
		XPathFactoryDefault				theXPathFactory;

		// Create a processor...and output start message.
		XSLTEngineImpl	theProcessor(
						theParserLiaison,
						theXSLTProcessorEnvSupport,
						theDOMSupport,
						theXObjectFactory,
						theXPathFactory);

		// Connect the processor to the support object...
		theXSLTProcessorEnvSupport.setProcessor(&theProcessor);

		// The execution context uses the same factory support objects as
		// the processor, since those objects have the same lifetime as
		// other objects created as a result of the execution.
		StylesheetExecutionContextDefault	ssExecutionContext(
							theProcessor,
							theXSLTProcessorEnvSupport,
							theDOMSupport,
							theXObjectFactory);

		// Our input files.  The assumption is that the executable will be run
		// from same directory as the input files.

		// Generate the input and output file names.
		const XalanDOMString	theXMLfile("birds.xml");

		const XalanDOMString	theOutputFile(
				XalanDOMString("birds") +
				UnsignedLongToDOMString(theInfo->m_threadNumber) +
				XalanDOMString(".out"));

		//Generate the XML input and output objects.
		XSLTInputSource		theInputSource(c_wstr(theXMLfile));
		XSLTResultTarget	theResultTarget(theOutputFile);

		// Set the stylesheet to be the compiled stylesheet. Then do the transform.
		// Report both the start of the transform and end of the thread.
		theProcessor.setStylesheetRoot(glbStylesheetRoot);
		theProcessor.process(theInputSource,theResultTarget,ssExecutionContext);
	}
	catch(...)
	{
	}

	// Decrement the counter because we're done...
	theInfo->m_counter->decrement();

#if defined(XALAN_POSIX2_AVAILABLE)
	return 0;
#endif
}

inline void
doSleep(unsigned int	theMilliseconds)
{
#if defined(WIN32)
	Sleep(theMilliseconds);
#elif defined(XALAN_POSIX2_AVAILABLE)
	usleep(theMilliseconds * 10);
#else
#error Unsupported platform!
#endif
}

void
doThreads(long	theThreadCount)
{
	cout << endl << "Starting " << theThreadCount << " threads." << endl;

	typedef std::vector<ThreadInfo>		ThreadInfoVectorType;

	ThreadInfoVectorType	theThreadInfo;

	theThreadInfo.reserve(theThreadCount);

	try
	{
		cout << endl << "Clock before starting threads: " << clock() << endl;

		SynchronizedCounter		theCounter;

		for (long i = 0; i < theThreadCount; i++)
		{
			theThreadInfo.push_back(ThreadInfoVectorType::value_type(i, &theCounter));

#if defined(WIN32)

			const unsigned long		theThreadID =
					_beginthread(theThreadRoutine, 4096, reinterpret_cast<LPVOID>(&theThreadInfo.back()));

			if (theThreadID == unsigned(-1))
			{
				cerr << endl << "Unable to create thread number " << i + 1 << "." << endl;
			}

#elif defined(XALAN_POSIX2_AVAILABLE)

			pthread_t	theThread;

			const int	theResult = pthread_create(&theThread, 0, theThreadRoutine, (void*)&theThreadInfo.back());

			if (theResult != 0)
			{
				cerr << endl << "Unable to create thread number " << i + 1 << "." << endl;
			}
			else
			{
				pthread_detach(theThread);
			}
#else
#error Unsupported platform!
#endif
		}

		clock_t		theClock = 0;

		if (theThreadInfo.size() == 0)
		{
			cerr << endl << "No threads were created!" << endl;
		}
		else
		{
			unsigned int	theCheckCount = 0;

			do
			{
				doSleep(2000);

				// Check a couple of times, just in case, since
				// getCounter() is not synchronized...
				if (theCounter.getCounter() == 0)
				{
					if (theCheckCount == 0)
					{
						theClock = clock();
					}

					++theCheckCount;
				}
			}
			while(theCheckCount < 2);
		}

		cout << endl << "Clock after threads: " << theClock << endl;
	}
	catch(...)
	{
		cerr << "Exception caught!!!"
			 << endl
			<< endl;
	}
}

int
main(
			int				argc,
			const char*		argv[])
{
#if !defined(NDEBUG) && defined(_MSC_VER)
	_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

	_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
	_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
#endif

	if (argc > 2)
	{
		cerr << "Usage: ThreadTest"
			 << endl
			 << endl;
	}
	else
	{
		int	threadCount = 60;

		if (argc == 2)
		{
			threadCount = atoi(argv[1]);
		}

		try
		{
		  // Call the static initializers...
		  XMLPlatformUtils::Initialize();
          {
			XSLTInit	theInit;

			// Create the necessary stuff of compile the stylesheet.
			XercesDOMSupport				ssDOMSupport;
			XercesParserLiaison				ssParserLiaison(ssDOMSupport);
			XSLTProcessorEnvSupportDefault	ssXSLTProcessorEnvSupport;
			XObjectFactoryDefault			ssXObjectFactory;
			XPathFactoryDefault				ssXPathFactory;

			// Create a processor to compile the stylesheet...
			XSLTEngineImpl	ssProcessor(
					ssParserLiaison,
					ssXSLTProcessorEnvSupport,
					ssDOMSupport,
					ssXObjectFactory,
					ssXPathFactory);

			// Create separate factory support objects so the stylesheet's
			// factory-created XObject and XPath instances are independent
			// from processor's.
			XPathFactoryDefault		ssStylesheetXPathFactory;

			// Create a stylesheet construction context, using the
			// stylesheet's factory support objects.
			StylesheetConstructionContextDefault	ssConstructionContext(
													ssProcessor,
													ssXSLTProcessorEnvSupport,
													ssStylesheetXPathFactory);

			const XalanDOMString  theXSLFileName("birds.xsl");
			const XalanDOMString  theXMLFileName("birds.xml");

			// Our stylesheet input source...
			XSLTInputSource		ssStylesheetSourceXSL(c_wstr(theXSLFileName));
			XSLTInputSource		ssStylesheetSourceXML(c_wstr(theXMLFileName));

			// Ask the processor to create a StylesheetRoot for the specified
			// input XSL.  This is the compiled stylesheet.  We don't have to
			// delete it, since it is owned by the StylesheetConstructionContext
			// instance.

			glbStylesheetRoot = ssProcessor.processStylesheet(ssStylesheetSourceXSL,
													   ssConstructionContext);
			assert(glbStylesheetRoot != 0);

			doThreads(threadCount);
		  }

		XMLPlatformUtils::Terminate();

		}

		catch(...)
		{
			cerr << "Exception caught!!!"
				 << endl
				 << endl;
		}

	}

	return 0;
}
<|endoftext|>


<commit_before>#include "bookmarkview.h"
#include "Library/customdialog.h"
#include <iostream>

/**
 * @brief BookmarkView::BookmarkView
 * Constructor.
 * @param parent Parent item of the BookmarkView.
 */
BookmarkView::BookmarkView(QListWidget* parent) {
    view = parent;
    view->addItem("Bookmarks:");
}

/**
 * @brief BookmarkView::get_num_bookmarks
 * @return Returns the number of bookmarks.
 */
int BookmarkView::get_num_bookmarks() {
    return view->count();
}

/**
 * @brief BookmarkView::add_bookmark
 * Adds a bookmark containing an image (thumbnail)
 * and a text description of the bookmark.
 * @param file_path Path to the image of the bookmark.
 */
void BookmarkView::add_bookmark(std::string file_path) {
    QImage img = QImage(QString::fromStdString(file_path), "TIFF");
    img = img.scaledToHeight(BOOKMARK_HEIGHT);

    QListWidgetItem *item = new QListWidgetItem(get_input_text(), view);
    item->setData(Qt::DecorationRole, QPixmap::fromImage(img));

    view->addItem(item);
}

/**
 * @brief BookmarkView::get_input_text
 * @return Returns a description for the bookmark,
 *         obtained from the user.
 */
QString BookmarkView::get_input_text() {
    std::string contrast_text = "";

    // Create the dialog
    CustomDialog dialog("Bookmark description", NULL);
    dialog.addLabel("Write a description of the bookmark:");
    dialog.addTextEdit(&contrast_text, false, false, TEXT_EDIT_HEIGHT,
                          "Write a description of the bookmark. This will be used when creating a report.");

    // Show the dialog (execution will stop here until the dialog is finished)
    dialog.exec();

    if (dialog.wasCancelled()) {
        return "";
    }

    return QString::fromStdString(contrast_text);
}
<commit_msg>Renamed variable.<commit_after>#include "bookmarkview.h"
#include "Library/customdialog.h"
#include <iostream>

/**
 * @brief BookmarkView::BookmarkView
 * Constructor.
 * @param parent Parent item of the BookmarkView.
 */
BookmarkView::BookmarkView(QListWidget* parent) {
    view = parent;
    view->addItem("Bookmarks:");
}

/**
 * @brief BookmarkView::get_num_bookmarks
 * @return Returns the number of bookmarks.
 */
int BookmarkView::get_num_bookmarks() {
    return view->count();
}

/**
 * @brief BookmarkView::add_bookmark
 * Adds a bookmark containing an image (thumbnail)
 * and a text description of the bookmark.
 * @param file_path Path to the image of the bookmark.
 */
void BookmarkView::add_bookmark(std::string file_path) {
    QImage img = QImage(QString::fromStdString(file_path), "TIFF");
    img = img.scaledToHeight(BOOKMARK_HEIGHT);

    QListWidgetItem *item = new QListWidgetItem(get_input_text(), view);
    item->setData(Qt::DecorationRole, QPixmap::fromImage(img));

    view->addItem(item);
}

/**
 * @brief BookmarkView::get_input_text
 * @return Returns a description for the bookmark,
 *         obtained from the user.
 */
QString BookmarkView::get_input_text() {
    std::string bookmark_text = "";

    // Create the dialog
    CustomDialog dialog("Bookmark description", NULL);
    dialog.addLabel("Write a description of the bookmark:");
    dialog.addTextEdit(&bookmark_text, false, false, TEXT_EDIT_HEIGHT,
                          "Write a description of the bookmark. This will be used when creating a report.");

    // Show the dialog (execution will stop here until the dialog is finished)
    dialog.exec();

    if (dialog.wasCancelled()) {
        return "";
    }

    return QString::fromStdString(bookmark_text);
}
<|endoftext|>


<commit_before>//#include <TCanvas.h>
//#include <TLegend.h>
//#include <TRandom3.h>
//#include "TH1.h"
//#include "TF1.h"
//#include "TMath.h"
#include <string>
#include <cstring>
#include <fstream>
#include <iostream>
#include <vector>

using namespace std;

class eeevent
{
	int num1;

	int num_trig;
	int num_acq;

	int secs;
	int nsecs;

	int clk1;
	int clk2;

	vector<int[2]> event1;
	vector<int[2]> event2;
	vector<int[2]> event3;

	double hv1;
	double hv2;
	double hv3;

	eeevent(int num1, int num_trig, int num_acq, int secs, int nsecs, int clk1, int clk2, int hv1, int hv2, int hv3):
		num1(num1), num_trig(num_trig), num_acq(num_acq), secs(secs), nsecs(nsecs),
		clk1(clk1), clk2(clk2), hv1(hv1), hv2(hv2), hv3(hv3) {}
};

int parse(string path)
{
	cout << "Path given: " << path << endl;

	ifstream file;
	file.open(path);
	const int linesize=65536;
	char* line = (char*)malloc(linesize*sizeof(char));  // get buffer for every line

	vector<eeevent> evector;

	while (!file.eof()) {
		file.getline(line, linesize);       // fill line

		char* piece = strtok (line," \t");  // get initial number
		if (piece==NULL) continue;          // the file is finished at this point, but better run the eof() check
		int num1 = atoi(piece);             // inital number
		if (num1 == 0) continue;            // line needs to start with a number, not characters (like the name line)

		piece = strtok (NULL, " \t");       // get descriptor
		string descriptor = piece;
		if (descriptor=="STATUS") {

		}
		else if (descriptor=="EVENT") {

		}
		else continue;

		while (piece != NULL) {
			piece = strtok (NULL, " \t");    // get more pieces
			//cout << piece << endl;
		}
	}

	return 0;
}

int main(int, char** argv)
{
	parse(argv[1]);
	return 0;
}
<commit_msg>Completed HV parsing part<commit_after>//#include <TCanvas.h>
//#include <TLegend.h>
//#include <TRandom3.h>
//#include "TH1.h"
//#include "TF1.h"
//#include "TMath.h"
#include <string>
#include <cstring>
#include <fstream>
#include <iostream>
#include <vector>

using namespace std;

class eeevent
{
	int num1;

	int num_trig;
	int num_acq;

	int secs;
	int nsecs;

	int clk1;
	int clk2;

	vector<int[2]> event1;
	vector<int[2]> event2;
	vector<int[2]> event3;

	double hv1;
	double hv2;
	double hv3;

	eeevent(int num1, int num_trig, int num_acq, int secs, int nsecs, int clk1, int clk2, int hv1, int hv2, int hv3):
		num1(num1), num_trig(num_trig), num_acq(num_acq), secs(secs), nsecs(nsecs),
		clk1(clk1), clk2(clk2), hv1(hv1), hv2(hv2), hv3(hv3) {}
};

int parse(string path)
{
	cout << "Path given: " << path << endl;

	ifstream file;
	file.open(path);
	const int linesize=65536;
	char* line = (char*)malloc(linesize*sizeof(char));  // get buffer for every line

	vector<eeevent> evector;               // vector of events
	double hv1, hv2, hv3;                  // variables for high voltage values

	while (!file.eof()) {
		file.getline(line, linesize);       // fill line

		char* piece = strtok (line," \t");  // get initial number
		if (piece==NULL) continue;          // the file is finished at this point, but better run the eof() check
		int num1 = atoi(piece);             // inital number
		if (num1 == 0) continue;            // line needs to start with a number, not characters (like the name line)

		piece = strtok (NULL, " \t");       // get descriptor
		string descriptor = piece;

		if (descriptor=="STATUS") {
			char* next=piece+7;              // hack to get after "STATUS"
			sscanf(next, "HV %lf %*f %lf %*f %lf %*f", &hv1, &hv2, &hv3);
			cout << "hv: " << hv1 << " - " << hv2 << " - " << hv3 << endl;
			continue;
		}
		else if (descriptor=="EVENT") {
			//cout << "e" << endl;
		}
		else continue;

		while (piece != NULL) {
			piece = strtok (NULL, " \t");    // get more pieces
			//cout << piece << endl;
		}
	}

	return 0;
}

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


<commit_before>/* Copyright 2017 QReal Research Group
 *
 * 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. */
#include "structuralControlFlowGenerator.h"

using namespace qReal;
using namespace generatorBase;
using namespace semantics;

StructuralControlFlowGenerator::StructuralControlFlowGenerator(const qrRepo::RepoApi &repo
		, ErrorReporterInterface &errorReporter
		, GeneratorCustomizer &customizer
		, PrimaryControlFlowValidator &validator
		, const Id &diagramId
		, QObject *parent
		, bool isThisDiagramMain)
	: ControlFlowGeneratorBase(repo, errorReporter, customizer, validator, diagramId, parent, isThisDiagramMain)
	, mNumberOfVerteces(0)
{
}

ControlFlowGeneratorBase *StructuralControlFlowGenerator::cloneFor(const Id &diagramId, bool cloneForNewDiagram)
{
	// to do
	return nullptr;
}

void StructuralControlFlowGenerator::beforeSearch()
{
	// to do
}

void StructuralControlFlowGenerator::visitFinal(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitFork(const Id &id, QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitJoin(const Id &id, QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitRegular(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitConditional(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitLoop(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitSwitch(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitUnknown(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::afterSearch()
{
	// to do
}

void StructuralControlFlowGenerator::performGeneration()
{
	ControlFlowGeneratorBase::performGeneration();
	// to check whether diagram was right

	findDominators();

	performAnalysis();
}

void StructuralControlFlowGenerator::buildGraph(const Id &id, const QList<LinkInfo> &links)
{
	int numberOfCurrentVertex = -1;
	if (mInitialVerteces.contains(id)) {
		numberOfCurrentVertex = mInitialVerteces[id];
	} else {
		numberOfCurrentVertex = mNumberOfVerteces;
		mNumberOfVerteces++;
		mInitialVerteces[id] = numberOfCurrentVertex;
		mVerteces.push_back(numberOfCurrentVertex);
	}

	for (const LinkInfo link : links) {
		int targetNumber = -1;
		if (mInitialVerteces.contains(link.target)) {
			targetNumber = mInitialVerteces[link.target];
		} else {
			targetNumber = mNumberOfVerteces;
			mNumberOfVerteces++;
			mInitialVerteces[link.target] = targetNumber;
			mVerteces.push_back(targetNumber);
		}
		mFollowers[numberOfCurrentVertex].push_back(targetNumber);
		mPredecessors[targetNumber].push_back(numberOfCurrentVertex);
	}
}

// to do
// to save invariant that mGraph only has valid nodes and edges,
// so it would be possible not to pass setOfNodes
void StructuralControlFlowGenerator::performAnalysis()
{
	for (VertexIterator it = mInitialVerteces.values().begin(); it != mInitialVerteces.values().end(); ++it) {
		mUsed[*it] = false;
		mPostOrder[*it] = -1;
	}
	int time = 0;
	const VertexLabel root = 0;
	dfs(root, time);

	int currentTime = 0;
	int maxTime = time;

	// it is supposed that mFollowers.size() == mPredecessors.size() == actual number of
	// verteces in current flowgraph

	while (mFollowers.keys().size() > 1 && currentTime < maxTime) {
		int currentNode = -1;

		// dummy cycle for finding node number that
		// has postOrder equal to currentTime

		for (VertexIterator it = mPostOrder.keys().begin(); it != mPostOrder.keys().end(); ++it) {
			VertexLabel number = *(it);
			if (mPostOrder[number] == currentTime) {
				currentNode = number;
				break;
			}
		}
	}
}

void StructuralControlFlowGenerator::findDominators()
{

	for (int i = 1; i < mVerteces.size(); i++) {
		mDominators[i] = mVerteces.toSet();
	}

	const VertexLabel root = 0;
	mDominators[root] = { root };

	bool somethingChanged = true;
	while (somethingChanged) {
		somethingChanged = false;

		// excluding root
		for (VertexIterator it = mVerteces.begin(); it != mVerteces.end(); it++) {
			VertexLabel vertex = *it;
			if (vertex) {
				QSet<VertexLabel> newDominators = mVerteces.toSet();
				for (int t = 0; t < mPredecessors[vertex].size(); t++) {
					VertexLabel predecessor = mPredecessors[vertex].at(t);
					newDominators.intersect(mDominators[predecessor]);
				}
				// adding the current number, because reflexivity of dominance relation
				newDominators.insert(vertex);
				if (newDominators != mDominators[vertex]) {
					somethingChanged = true;
					mDominators[vertex] = newDominators;
				}
			}
		}
	}
}

void StructuralControlFlowGenerator::dfs(VertexLabel u, int &postOrderLabel)
{
	mUsed[u] = true;
	for (int t = 0; t < mFollowers[u].size(); t++) {
		int v = mFollowers[u].at(t);
		if (!mUsed[v]) {
			dfs(v, postOrderLabel);
		}
	}
	mPostOrder[u] = postOrderLabel;
	postOrderLabel++;
}

StructuralControlFlowGenerator::RegionType StructuralControlFlowGenerator::acyclicRegionType(int &nodeNumber, QSet<int> &nodesThatComposeRegion)
{
	nodesThatComposeRegion.clear();

	int currentNodeNumber = nodeNumber;
	bool hasOnlyOneIncomingEdge = true;
	bool hasOnlyOneOutcomingEdge = mFollowers[currentNodeNumber].size() == 1;

	while (hasOnlyOneIncomingEdge && hasOnlyOneOutcomingEdge) {
		nodesThatComposeRegion.insert(currentNodeNumber);
		currentNodeNumber = mFollowers[currentNodeNumber].at(0);
		hasOnlyOneIncomingEdge = mPredecessors[currentNodeNumber].size() == 1;
		hasOnlyOneOutcomingEdge = mFollowers[currentNodeNumber].size() == 1;
	}

	if (hasOnlyOneIncomingEdge) {
		nodesThatComposeRegion.insert(currentNodeNumber);
	}

	currentNodeNumber = nodeNumber;
	hasOnlyOneIncomingEdge = mPredecessors[currentNodeNumber].size() == 1;
	hasOnlyOneOutcomingEdge = true;

	while (hasOnlyOneIncomingEdge && hasOnlyOneOutcomingEdge) {
		nodesThatComposeRegion.insert(currentNodeNumber);
		currentNodeNumber = mPredecessors[currentNodeNumber].at(0);
		hasOnlyOneIncomingEdge = mPredecessors[currentNodeNumber].size() == 1;
		hasOnlyOneOutcomingEdge = mFollowers[currentNodeNumber].size() == 1;
	}

	if (hasOnlyOneOutcomingEdge) {
		nodesThatComposeRegion.insert(currentNodeNumber);
	}

	nodeNumber = currentNodeNumber;

	if (nodesThatComposeRegion.size() == 2) {
		return Block;
	}

	// checking for IfThenElse
	if (mFollowers[nodeNumber].size() == 2) {
		int m = mFollowers[nodeNumber].at(0);
		int n = mFollowers[nodeNumber].at(1);

		if (mFollowers[m].size() == 1 && mFollowers[n].size() == 1
				&& mFollowers[m].at(0) == mFollowers[n].at(0)
				&& mPredecessors[m].size() == 1 && mPredecessors[n].size() == 1) {
			nodesThatComposeRegion.clear();
			nodesThatComposeRegion.insert(nodeNumber);
			nodesThatComposeRegion.insert(m);
			nodesThatComposeRegion.insert(n);
			return IfThenElse;
		}

	}

}

StructuralControlFlowGenerator::Node::Node(StructuralControlFlowGenerator::RegionType type, int number)
	: mRegionType(type)
	, mNumber(number)
	, mParent(nullptr)
{
}

void StructuralControlFlowGenerator::Node::appendChild(StructuralControlFlowGenerator::Node *child)
{
	mChildren.append(child);
}

void StructuralControlFlowGenerator::Node::appendChildren(const QVector<StructuralControlFlowGenerator::Node *> &children)
{
	for (StructuralControlFlowGenerator::Node *child : children) {
		mChildren.append(child);
	}
}

StructuralControlFlowGenerator::Node *StructuralControlFlowGenerator::Node::structOf() const
{
	return mParent;
}

void StructuralControlFlowGenerator::Node::setParent(StructuralControlFlowGenerator::Node *parent)
{
	mParent = parent;
}

StructuralControlFlowGenerator::RegionType StructuralControlFlowGenerator::Node::structType() const
{
	return mRegionType;
}

QVector<StructuralControlFlowGenerator::Node *> StructuralControlFlowGenerator::Node::structNodes() const
{
	return mChildren;
}

<commit_msg>Handling IfThen pattern<commit_after>/* Copyright 2017 QReal Research Group
 *
 * 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. */
#include "structuralControlFlowGenerator.h"

using namespace qReal;
using namespace generatorBase;
using namespace semantics;

StructuralControlFlowGenerator::StructuralControlFlowGenerator(const qrRepo::RepoApi &repo
		, ErrorReporterInterface &errorReporter
		, GeneratorCustomizer &customizer
		, PrimaryControlFlowValidator &validator
		, const Id &diagramId
		, QObject *parent
		, bool isThisDiagramMain)
	: ControlFlowGeneratorBase(repo, errorReporter, customizer, validator, diagramId, parent, isThisDiagramMain)
	, mNumberOfVerteces(0)
{
}

ControlFlowGeneratorBase *StructuralControlFlowGenerator::cloneFor(const Id &diagramId, bool cloneForNewDiagram)
{
	// to do
	return nullptr;
}

void StructuralControlFlowGenerator::beforeSearch()
{
	// to do
}

void StructuralControlFlowGenerator::visitFinal(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitFork(const Id &id, QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitJoin(const Id &id, QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitRegular(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitConditional(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitLoop(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitSwitch(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::visitUnknown(const Id &id, const QList<LinkInfo> &links)
{
	buildGraph(id, links);
}

void StructuralControlFlowGenerator::afterSearch()
{
	// to do
}

void StructuralControlFlowGenerator::performGeneration()
{
	ControlFlowGeneratorBase::performGeneration();
	// to check whether diagram was right

	findDominators();

	performAnalysis();
}

void StructuralControlFlowGenerator::buildGraph(const Id &id, const QList<LinkInfo> &links)
{
	int numberOfCurrentVertex = -1;
	if (mInitialVerteces.contains(id)) {
		numberOfCurrentVertex = mInitialVerteces[id];
	} else {
		numberOfCurrentVertex = mNumberOfVerteces;
		mNumberOfVerteces++;
		mInitialVerteces[id] = numberOfCurrentVertex;
		mVerteces.push_back(numberOfCurrentVertex);
	}

	for (const LinkInfo link : links) {
		int targetNumber = -1;
		if (mInitialVerteces.contains(link.target)) {
			targetNumber = mInitialVerteces[link.target];
		} else {
			targetNumber = mNumberOfVerteces;
			mNumberOfVerteces++;
			mInitialVerteces[link.target] = targetNumber;
			mVerteces.push_back(targetNumber);
		}
		mFollowers[numberOfCurrentVertex].push_back(targetNumber);
		mPredecessors[targetNumber].push_back(numberOfCurrentVertex);
	}
}

// to do
// to save invariant that mGraph only has valid nodes and edges,
// so it would be possible not to pass setOfNodes
void StructuralControlFlowGenerator::performAnalysis()
{
	for (VertexIterator it = mInitialVerteces.values().begin(); it != mInitialVerteces.values().end(); ++it) {
		mUsed[*it] = false;
		mPostOrder[*it] = -1;
	}
	int time = 0;
	const VertexLabel root = 0;
	dfs(root, time);

	int currentTime = 0;
	int maxTime = time;

	// it is supposed that mFollowers.size() == mPredecessors.size() == actual number of
	// verteces in current flowgraph

	while (mFollowers.keys().size() > 1 && currentTime < maxTime) {
		int currentNode = -1;

		// dummy cycle for finding node number that
		// has postOrder equal to currentTime

		for (VertexIterator it = mPostOrder.keys().begin(); it != mPostOrder.keys().end(); ++it) {
			VertexLabel number = *(it);
			if (mPostOrder[number] == currentTime) {
				currentNode = number;
				break;
			}
		}
	}
}

void StructuralControlFlowGenerator::findDominators()
{

	for (int i = 1; i < mVerteces.size(); i++) {
		mDominators[i] = mVerteces.toSet();
	}

	const VertexLabel root = 0;
	mDominators[root] = { root };

	bool somethingChanged = true;
	while (somethingChanged) {
		somethingChanged = false;

		// excluding root
		for (VertexIterator it = mVerteces.begin(); it != mVerteces.end(); it++) {
			VertexLabel vertex = *it;
			if (vertex) {
				QSet<VertexLabel> newDominators = mVerteces.toSet();
				for (int t = 0; t < mPredecessors[vertex].size(); t++) {
					VertexLabel predecessor = mPredecessors[vertex].at(t);
					newDominators.intersect(mDominators[predecessor]);
				}
				// adding the current number, because reflexivity of dominance relation
				newDominators.insert(vertex);
				if (newDominators != mDominators[vertex]) {
					somethingChanged = true;
					mDominators[vertex] = newDominators;
				}
			}
		}
	}
}

void StructuralControlFlowGenerator::dfs(VertexLabel u, int &postOrderLabel)
{
	mUsed[u] = true;
	for (int t = 0; t < mFollowers[u].size(); t++) {
		int v = mFollowers[u].at(t);
		if (!mUsed[v]) {
			dfs(v, postOrderLabel);
		}
	}
	mPostOrder[u] = postOrderLabel;
	postOrderLabel++;
}

StructuralControlFlowGenerator::RegionType StructuralControlFlowGenerator::acyclicRegionType(int &nodeNumber, QSet<int> &nodesThatComposeRegion)
{
	nodesThatComposeRegion.clear();

	int currentNodeNumber = nodeNumber;
	bool hasOnlyOneIncomingEdge = true;
	bool hasOnlyOneOutcomingEdge = mFollowers[currentNodeNumber].size() == 1;

	while (hasOnlyOneIncomingEdge && hasOnlyOneOutcomingEdge) {
		nodesThatComposeRegion.insert(currentNodeNumber);
		currentNodeNumber = mFollowers[currentNodeNumber].at(0);
		hasOnlyOneIncomingEdge = mPredecessors[currentNodeNumber].size() == 1;
		hasOnlyOneOutcomingEdge = mFollowers[currentNodeNumber].size() == 1;
	}

	if (hasOnlyOneIncomingEdge) {
		nodesThatComposeRegion.insert(currentNodeNumber);
	}

	currentNodeNumber = nodeNumber;
	hasOnlyOneIncomingEdge = mPredecessors[currentNodeNumber].size() == 1;
	hasOnlyOneOutcomingEdge = true;

	while (hasOnlyOneIncomingEdge && hasOnlyOneOutcomingEdge) {
		nodesThatComposeRegion.insert(currentNodeNumber);
		currentNodeNumber = mPredecessors[currentNodeNumber].at(0);
		hasOnlyOneIncomingEdge = mPredecessors[currentNodeNumber].size() == 1;
		hasOnlyOneOutcomingEdge = mFollowers[currentNodeNumber].size() == 1;
	}

	if (hasOnlyOneOutcomingEdge) {
		nodesThatComposeRegion.insert(currentNodeNumber);
	}

	nodeNumber = currentNodeNumber;

	if (nodesThatComposeRegion.size() == 2) {
		return Block;
	}

	nodesThatComposeRegion.clear();

	// checking for IfThenElse
	if (mFollowers[nodeNumber].size() == 2) {
		int m = mFollowers[nodeNumber].at(0);
		int n = mFollowers[nodeNumber].at(1);

		if (mFollowers[m].size() == 1 && mFollowers[n].size() == 1
				&& mFollowers[m].at(0) == mFollowers[n].at(0)
				&& mPredecessors[m].size() == 1 && mPredecessors[n].size() == 1) {

			nodesThatComposeRegion.insert(nodeNumber);
			nodesThatComposeRegion.insert(m);
			nodesThatComposeRegion.insert(n);
			return IfThenElse;
		}

	}

	// checking IfThen
	if (mFollowers[nodeNumber].size() == 2) {
		int m = mFollowers[nodeNumber].at(0);
		int n = mFollowers[nodeNumber].at(1);

		int thenNodeNumber = -1;
		if (mFollowers[m].size() == 1 && mFollowers[m].at(0) == n && mPredecessors[m].size() == 1) {
			thenNodeNumber = m;
		} else if (mFollowers[n].size() == 1 && mFollowers[n].at(0) == m && mPredecessors[n].size() == 1) {
			thenNodeNumber = n;
		}

		if (thenNodeNumber != -1) {
			nodesThatComposeRegion.insert(nodeNumber);
			nodesThatComposeRegion.insert(m);
			nodesThatComposeRegion.insert(n);
			return IfThen;
		}
	}

}

StructuralControlFlowGenerator::Node::Node(StructuralControlFlowGenerator::RegionType type, int number)
	: mRegionType(type)
	, mNumber(number)
	, mParent(nullptr)
{
}

void StructuralControlFlowGenerator::Node::appendChild(StructuralControlFlowGenerator::Node *child)
{
	mChildren.append(child);
}

void StructuralControlFlowGenerator::Node::appendChildren(const QVector<StructuralControlFlowGenerator::Node *> &children)
{
	for (StructuralControlFlowGenerator::Node *child : children) {
		mChildren.append(child);
	}
}

StructuralControlFlowGenerator::Node *StructuralControlFlowGenerator::Node::structOf() const
{
	return mParent;
}

void StructuralControlFlowGenerator::Node::setParent(StructuralControlFlowGenerator::Node *parent)
{
	mParent = parent;
}

StructuralControlFlowGenerator::RegionType StructuralControlFlowGenerator::Node::structType() const
{
	return mRegionType;
}

QVector<StructuralControlFlowGenerator::Node *> StructuralControlFlowGenerator::Node::structNodes() const
{
	return mChildren;
}

<|endoftext|>


<commit_before>#include <QtGui/QGuiApplication>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlComponent>
#include <QtQuick/QQuickWindow>
#include <QtCore/QUrl>
#include <QUrlQuery>
#include <QDateTime>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QDebug>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include <QMutex>
#include <QNetworkAccessManager>
#include <QTimer>

#include "chat/ChatApplication.hpp"
#include "chat/net/NetworkRequest.hpp"

using chat::ChatApplication;
using chat::net::NetworkRequest;

ChatApplication::ChatApplication(QObject *parent): QObject(parent) {
    QQmlEngine *engine = new QQmlEngine;
    QQmlComponent *component = new QQmlComponent(engine);
    component->loadUrl(QUrl("qrc:/assets/ChatWindow.qml"));

    QObject *root;
    if (component->isReady())
        root = component->create();
    else {
        qWarning() << component->errorString();
        return;
    }

    QObject *button = root->findChild<QObject*>("sendButton");
    if (button) {
        connect(button, SIGNAL(clicked()), this, SLOT(onClicked()));
    }
    _chatText = root->findChild<QObject*>("chatText");
    _input = root->findChild<QObject*>("input");

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(onTimeOut()));
    timer->start(1000);
}

void ChatApplication::onTimeOut() {
    QUrl url("http://localhost:8080/chatServer/getMessages");
    QUrlQuery query;
    query.addQueryItem("after", "1");
    url.setQuery(query);

    NetworkRequest *request = new NetworkRequest(url);
    request->get();

    connect(request, SIGNAL(finished(QNetworkReply*)), this, SLOT(onMessages(QNetworkReply*)));
    connect(request, SIGNAL(finished(QNetworkReply*)), request, SLOT(deleteLater()));
}

void ChatApplication::onMessages(QNetworkReply *reply) {

    QByteArray contents = reply->readAll();
    QJsonDocument jsonDoc = QJsonDocument::fromJson(contents);
    QVariantList messages = jsonDoc.object()["msg"].toObject()["messages"].toArray().toVariantList();

    QString string;
    foreach (QVariant i, messages) {
        QVariantMap map = i.toMap();
        string += map["sender"].toString() + ": " + map["message"].toString() + "\n";
    }

    _chatText->setProperty("text", string);

    qDebug() << messages;
}

void ChatApplication::onClicked() {

    QUrl url("http://localhost:8080/chatServer/postMessage");
    QUrlQuery query;
    query.addQueryItem("sender", "konrad@EKCHAT.com");
    query.addQueryItem("timeSent", QString::number(QDateTime::currentDateTime().toTime_t()));
    query.addQueryItem("conversation", "1");
    url.setQuery(query);

    NetworkRequest *request = new NetworkRequest(url);
    request->post(_input->property("text").toByteArray());

    connect(request, SIGNAL(finished(QNetworkReply*)), this, SLOT(onPostFinished(QNetworkReply*)));
    connect(request, SIGNAL(finished(QNetworkReply*)), request, SLOT(deleteLater()));
}

void ChatApplication::onPostFinished(QNetworkReply *reply) {
    qDebug() << reply->readAll();
    qDebug() << reply->errorString();
}
<commit_msg>hooked ENTER key to send<commit_after>#include <QtGui/QGuiApplication>
#include <QtQml/QQmlEngine>
#include <QtQml/QQmlComponent>
#include <QtQuick/QQuickWindow>
#include <QtCore/QUrl>
#include <QUrlQuery>
#include <QDateTime>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QDebug>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>
#include <QMutex>
#include <QNetworkAccessManager>
#include <QTimer>

#include "chat/ChatApplication.hpp"
#include "chat/net/NetworkRequest.hpp"

using chat::ChatApplication;
using chat::net::NetworkRequest;

ChatApplication::ChatApplication(QObject *parent): QObject(parent) {
    QQmlEngine *engine = new QQmlEngine;
    QQmlComponent *component = new QQmlComponent(engine);
    component->loadUrl(QUrl("qrc:/assets/ChatWindow.qml"));

    QObject *root;
    if (component->isReady())
        root = component->create();
    else {
        qWarning() << component->errorString();
        return;
    }

    QObject *button = root->findChild<QObject*>("sendButton");
    if (button) {
        connect(button, SIGNAL(clicked()), this, SLOT(onClicked()));
    }
    _chatText = root->findChild<QObject*>("chatText");
    _input = root->findChild<QObject*>("input");

    connect(_input, SIGNAL(accepted()), this, SLOT(onClicked()));

    QTimer *timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(onTimeOut()));
    timer->start(1000);
}

void ChatApplication::onTimeOut() {
    QUrl url("http://localhost:8080/chatServer/getMessages");
    QUrlQuery query;
    query.addQueryItem("after", "1");
    url.setQuery(query);

    NetworkRequest *request = new NetworkRequest(url);
    request->get();

    connect(request, SIGNAL(finished(QNetworkReply*)), this, SLOT(onMessages(QNetworkReply*)));
    connect(request, SIGNAL(finished(QNetworkReply*)), request, SLOT(deleteLater()));
}

void ChatApplication::onMessages(QNetworkReply *reply) {

    QByteArray contents = reply->readAll();
    QJsonDocument jsonDoc = QJsonDocument::fromJson(contents);
    QVariantList messages = jsonDoc.object()["msg"].toObject()["messages"].toArray().toVariantList();

    QString string;
    foreach (QVariant i, messages) {
        QVariantMap map = i.toMap();
        string += map["sender"].toString() + ": " + map["message"].toString() + "\n";
    }

    _chatText->setProperty("text", string);

    qDebug() << messages;
}

void ChatApplication::onClicked() {

    QUrl url("http://localhost:8080/chatServer/postMessage");
    QUrlQuery query;
    query.addQueryItem("sender", "konrad@EKCHAT.com");
    query.addQueryItem("timeSent", QString::number(QDateTime::currentDateTime().toTime_t()));
    query.addQueryItem("conversation", "1");
    url.setQuery(query);

    NetworkRequest *request = new NetworkRequest(url);
    request->post(_input->property("text").toByteArray());

    _input->setProperty("text", "");

    connect(request, SIGNAL(finished(QNetworkReply*)), this, SLOT(onPostFinished(QNetworkReply*)));
    connect(request, SIGNAL(finished(QNetworkReply*)), request, SLOT(deleteLater()));
}

void ChatApplication::onPostFinished(QNetworkReply *reply) {
    qDebug() << reply->readAll();
    qDebug() << reply->errorString();
}
<|endoftext|>