<commit_before>/*
    Copyright (C) 2013 Timo Linna. All Rights Reserved.
*/
#include "cnuodb.h"
#include "NuoDB.h"
#include <cstring>
#include <string>

using namespace NuoDB;

struct nuodb {
    Connection *conn;
    std::string error;
};

static int setError(struct nuodb *db, SQLException &e) {
    db->error.assign(e.getText());
    return e.getSqlcode();
}

static int closeDb(struct nuodb *db) {
    if (db->conn) {
        try {
            db->conn->close();
            db->conn = 0;
        } catch (SQLException &e) {
            return setError(db, e);
        }
    }
    return 0;
}

void nuodb_init(struct nuodb **db) {
    *db = new struct nuodb;
    (*db)->conn = 0;
}

const char *nuodb_error(const struct nuodb *db) {
    return db ? db->error.c_str() : "null db";
}

int nuodb_open(struct nuodb *db, const char *database, const char *username,
               const char *password, const char *schema, const char *timezone) {
    closeDb(db);
    Connection *conn = 0;
    try {
        conn = Connection::create();
        Properties *props = conn->allocProperties(); // TODO: freed on conn->close()?
        props->putValue("user", username);
        props->putValue("password", password);
        if (schema && std::strlen(schema) > 0) {
            props->putValue("schema", schema);
        }
        if (timezone && std::strlen(timezone) > 0) {
            props->putValue("timezone", timezone);
        }
        conn->openDatabase(database, props);
        conn->setAutoCommit(true); // enforce autocommit by default
        db->conn = conn;
        return 0;
    } catch (SQLException &e) {
        if (conn) {
            conn->close();
        }
        return setError(db, e);
    }
}

int nuodb_close(struct nuodb **db) {
    int rc = 0;
    if (db && *db) {
        rc = closeDb(*db);
        delete (*db);
        *db = 0;
    }
    return rc;
}

int nuodb_autocommit(struct nuodb *db, int *state) {
    try {
        *state = db->conn->getAutoCommit();
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_autocommit_set(struct nuodb *db, int state) {
    try {
        db->conn->setAutoCommit(!!state);
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_commit(struct nuodb *db) {
    try {
        db->conn->commit();
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_rollback(struct nuodb *db) {
    try {
        db->conn->rollback();
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_statement_prepare(struct nuodb *db, const char *sql,
                            struct nuodb_statement **st, int *parameter_count) {
    PreparedStatement *stmt = 0;
    try {
        stmt = db->conn->prepareStatement(sql, RETURN_GENERATED_KEYS);
        *parameter_count = stmt->getParameterMetaData()->getParameterCount();
        *st = reinterpret_cast<struct nuodb_statement *>(stmt);
        return 0;
    } catch (SQLException &e) {
        if (stmt) {
            stmt->close();
        }
        return setError(db, e);
    }
}

int nuodb_statement_bind(struct nuodb *db, struct nuodb_statement *st,
                         struct nuodb_value parameters[]) {
    PreparedStatement *stmt = reinterpret_cast<PreparedStatement *>(st);
    try {
        int parameterCount = stmt->getParameterMetaData()->getParameterCount();
        for (int i=0; i < parameterCount; ++i) {
            int parameterIndex = i+1;
            switch (parameters[i].vt) {
                case NUODB_TYPE_NULL:
                    stmt->setNull(parameterIndex, NUOSQL_NULL);
                    break;
                case NUODB_TYPE_INT64:
                    stmt->setLong(parameterIndex, parameters[i].i64);
                    break;
                case NUODB_TYPE_FLOAT64: {
                    union {
                        int64_t i64;
                        double float64;
                    } value = { parameters[i].i64 };
                    stmt->setDouble(parameterIndex, value.float64);
                    break;
                }
                case NUODB_TYPE_BOOL:
                    stmt->setBoolean(parameterIndex, !!parameters[i].i64);
                    break;
                case NUODB_TYPE_STRING: {
                    union {
                        int64_t i64;
                        const char *bytes;
                    } value = { parameters[i].i64 };
                    // Extra conversion due to missing length param from the setString API
                    std::string str(value.bytes, parameters[i].i32);
                    stmt->setString(parameterIndex, str.c_str());
                    break;
                }
                case NUODB_TYPE_BYTES: {
                    union {
                        int64_t i64;
                        const unsigned char *bytes;
                    } value = { parameters[i].i64 };
                    stmt->setBytes(parameterIndex, parameters[i].i32, value.bytes);
                    break;
                }
                case NUODB_TYPE_TIME: {
                    int64_t seconds = parameters[i].i64;
                    int32_t nanos = parameters[i].i32;
                    SqlTimestamp ts(seconds, nanos);
                    stmt->setTimestamp(parameterIndex, &ts);
                    break;
                }
            }
        }
        return 0;
    } catch  (SQLException &e) {
        if (stmt) {
            stmt->close();
        }
        return setError(db, e);
    }
}

int nuodb_statement_execute(struct nuodb *db, struct nuodb_statement *st,
                            struct nuodb_resultset **rs, int *column_count, int64_t *affected_rows) {
    ResultSet *resultSet = 0;
    PreparedStatement *stmt = reinterpret_cast<PreparedStatement *>(st);
    try {
        int updateCount;
        bool hasResults = stmt->execute();
        if (hasResults) {
            resultSet = stmt->getResultSet();
            updateCount = 0;
        } else {
            resultSet = stmt->getGeneratedKeys();
            updateCount = stmt->getUpdateCount();
        }
        *column_count = resultSet->getMetaData()->getColumnCount();
        *affected_rows = updateCount;
        *rs = reinterpret_cast<struct nuodb_resultset *>(resultSet);
        return 0;
    } catch (SQLException &e) {
        if (resultSet) {
            resultSet->close();
        }
        return setError(db, e);
    }
}

int nuodb_statement_close(struct nuodb *db, struct nuodb_statement **st) {
    try {
        if (st && *st) {
            PreparedStatement *stmt = reinterpret_cast<PreparedStatement *>(*st);
            stmt->close();
            *st = 0;
        }
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_last_insert_id(struct nuodb *db, struct nuodb_resultset *rs,
                                   int64_t *last_insert_id) {
    ResultSet *resultSet = reinterpret_cast<ResultSet *>(rs);
    try {
        int64_t lastInsertId = 0;
        if (resultSet->getMetaData()->getColumnCount() == 1) {
            while (resultSet->next()) {
                // TODO find out how to read the last id first
            }
            lastInsertId = resultSet->getLong(1);
        }
        *last_insert_id = lastInsertId;
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_column_names(struct nuodb *db, struct nuodb_resultset *rs,
                                 struct nuodb_value names[]) {
    ResultSet *resultSet = reinterpret_cast<ResultSet *>(rs);
    try {
        ResultSetMetaData *resultSetMetaData = resultSet->getMetaData();
        int columnCount = resultSetMetaData->getColumnCount();
        for (int i=0; i < columnCount; ++i) {
            int columnIndex = i+1;
            union {
                const char *string;
                int64_t i64;
            } value = { resultSetMetaData->getColumnLabel(columnIndex) };
            names[i].i64 = value.i64;
        }
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_next(struct nuodb *db, struct nuodb_resultset *rs,
                         int *has_values, int *bytes_count, struct nuodb_value values[]) {
    ResultSet *resultSet = reinterpret_cast<ResultSet *>(rs);
    try {
        int bytesCount = 0;
        *has_values = resultSet->next();
        if (*has_values) {
            ResultSetMetaData *resultSetMetaData = resultSet->getMetaData();
            int columnCount = resultSetMetaData->getColumnCount();
            for (int i=0; i < columnCount; ++i) {
                int64_t i64 = 0;
                int32_t i32 = 0;
                enum nuodb_value_type vt = NUODB_TYPE_NULL;
                int columnIndex = i+1;
                switch (resultSetMetaData->getColumnType(columnIndex)) {
                    case NUOSQL_NULL:
                        vt = NUODB_TYPE_NULL;
                        break;
                    case NUOSQL_TINYINT:
                    case NUOSQL_SMALLINT:
                    case NUOSQL_INTEGER:
                    case NUOSQL_BIGINT:
                        if (resultSetMetaData->getScale(columnIndex) == 0) {
                            i64 = resultSet->getLong(columnIndex);
                            if (!resultSet->wasNull()) {
                                vt = NUODB_TYPE_INT64;
                            }
                            break;
                        }
                        // fallthrough; must be fetched as a string
                    case NUOSQL_NUMERIC:
                    case NUOSQL_DECIMAL: {
                        const char *str = resultSet->getString(columnIndex);
                        if (str && !resultSet->wasNull()) {
                            vt = NUODB_TYPE_BYTES; // strings are returned as bytes
                            i32 = std::strlen(str);
                            bytesCount += i32;
                        }
                        break;
                    }
                    case NUOSQL_FLOAT:
                    case NUOSQL_DOUBLE: {
                        union {
                            double float64;
                            int64_t i64;
                        } value = { resultSet->getDouble(columnIndex) };
                        if (!resultSet->wasNull()) {
                            vt = NUODB_TYPE_FLOAT64;
                            i64 = value.i64;
                        }
                        break;
                    }
                    case NUOSQL_BIT:
                    case NUOSQL_BOOLEAN:
                        i64 = resultSet->getBoolean(columnIndex);
                        if (!resultSet->wasNull()) {
                            vt = NUODB_TYPE_BOOL;
                        }
                        break;
                    case NUOSQL_DATE:
                    case NUOSQL_TIME:
                    case NUOSQL_TIMESTAMP: {
                        Timestamp *ts = resultSet->getTimestamp(columnIndex);
                        if (ts && !resultSet->wasNull()) {
                            vt = NUODB_TYPE_TIME;
                            i64 = ts->getSeconds();
                            i32 = ts->getNanos();
                        }
                        break;
                    }
                    default: {
                        const Bytes b = resultSet->getBytes(columnIndex);
                        if (!resultSet->wasNull()) {
                            vt = NUODB_TYPE_BYTES;
                            i32 = b.length;
                            bytesCount += i32;
                        }
                        break;
                    }
                }
                values[i].i64 = i64;
                values[i].i32 = i32;
                values[i].vt = vt;
            }
        }
        *bytes_count = bytesCount;
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_bytes(struct nuodb *db, struct nuodb_resultset *rs, unsigned char *bytes) {
    ResultSet *resultSet = reinterpret_cast<ResultSet *>(rs);
    try {
        ResultSetMetaData *resultSetMetaData = resultSet->getMetaData();
        int columnCount = resultSetMetaData->getColumnCount();
        for (int i=0; i < columnCount; ++i) {
            int columnIndex = i+1;
            switch (resultSetMetaData->getColumnType(columnIndex)) {
                case NUOSQL_NULL:
                case NUOSQL_FLOAT:
                case NUOSQL_DOUBLE:
                case NUOSQL_BIT:
                case NUOSQL_BOOLEAN:
                case NUOSQL_DATE:
                case NUOSQL_TIME:
                case NUOSQL_TIMESTAMP:
                    break; // skip
                case NUOSQL_TINYINT:
                case NUOSQL_SMALLINT:
                case NUOSQL_INTEGER:
                case NUOSQL_BIGINT:
                    if (resultSetMetaData->getScale(columnIndex) == 0) {
                        break; // skip
                    }
                    // fallthrough; must be fetched as a string
                case NUOSQL_NUMERIC:
                case NUOSQL_DECIMAL: {
                    const char *str = resultSet->getString(columnIndex);
                    if (str && !resultSet->wasNull()) {
                        size_t length = std::strlen(str);
                        std::memcpy(bytes, str, length);
                        bytes += length;
                    }
                    break;
                }
                default: {
                    const Bytes b = resultSet->getBytes(columnIndex);
                    if (!resultSet->wasNull()) {
                        std::memcpy(bytes, b.data, b.length);
                        bytes += b.length;
                    }
                    break;
                }
            }
        }
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_close(struct nuodb *db, struct nuodb_resultset **rs) {
    try {
        if (rs && *rs) {
            ResultSet *resultSet = reinterpret_cast<ResultSet *>(*rs);
            resultSet->close();
            *rs = 0;
        }
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}
<commit_msg>Enforce affected_rows to be >= 0 in execute<commit_after>/*
    Copyright (C) 2013 Timo Linna. All Rights Reserved.
*/
#include "cnuodb.h"
#include "NuoDB.h"
#include <algorithm>
#include <cstring>
#include <string>

using namespace NuoDB;

struct nuodb {
    Connection *conn;
    std::string error;
};

static int setError(struct nuodb *db, SQLException &e) {
    db->error.assign(e.getText());
    return e.getSqlcode();
}

static int closeDb(struct nuodb *db) {
    if (db->conn) {
        try {
            db->conn->close();
            db->conn = 0;
        } catch (SQLException &e) {
            return setError(db, e);
        }
    }
    return 0;
}

void nuodb_init(struct nuodb **db) {
    *db = new struct nuodb;
    (*db)->conn = 0;
}

const char *nuodb_error(const struct nuodb *db) {
    return db ? db->error.c_str() : "null db";
}

int nuodb_open(struct nuodb *db, const char *database, const char *username,
               const char *password, const char *schema, const char *timezone) {
    closeDb(db);
    Connection *conn = 0;
    try {
        conn = Connection::create();
        Properties *props = conn->allocProperties(); // TODO: freed on conn->close()?
        props->putValue("user", username);
        props->putValue("password", password);
        if (schema && std::strlen(schema) > 0) {
            props->putValue("schema", schema);
        }
        if (timezone && std::strlen(timezone) > 0) {
            props->putValue("timezone", timezone);
        }
        conn->openDatabase(database, props);
        conn->setAutoCommit(true); // enforce autocommit by default
        db->conn = conn;
        return 0;
    } catch (SQLException &e) {
        if (conn) {
            conn->close();
        }
        return setError(db, e);
    }
}

int nuodb_close(struct nuodb **db) {
    int rc = 0;
    if (db && *db) {
        rc = closeDb(*db);
        delete (*db);
        *db = 0;
    }
    return rc;
}

int nuodb_autocommit(struct nuodb *db, int *state) {
    try {
        *state = db->conn->getAutoCommit();
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_autocommit_set(struct nuodb *db, int state) {
    try {
        db->conn->setAutoCommit(!!state);
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_commit(struct nuodb *db) {
    try {
        db->conn->commit();
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_rollback(struct nuodb *db) {
    try {
        db->conn->rollback();
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_statement_prepare(struct nuodb *db, const char *sql,
                            struct nuodb_statement **st, int *parameter_count) {
    PreparedStatement *stmt = 0;
    try {
        stmt = db->conn->prepareStatement(sql, RETURN_GENERATED_KEYS);
        *parameter_count = stmt->getParameterMetaData()->getParameterCount();
        *st = reinterpret_cast<struct nuodb_statement *>(stmt);
        return 0;
    } catch (SQLException &e) {
        if (stmt) {
            stmt->close();
        }
        return setError(db, e);
    }
}

int nuodb_statement_bind(struct nuodb *db, struct nuodb_statement *st,
                         struct nuodb_value parameters[]) {
    PreparedStatement *stmt = reinterpret_cast<PreparedStatement *>(st);
    try {
        int parameterCount = stmt->getParameterMetaData()->getParameterCount();
        for (int i=0; i < parameterCount; ++i) {
            int parameterIndex = i+1;
            switch (parameters[i].vt) {
                case NUODB_TYPE_NULL:
                    stmt->setNull(parameterIndex, NUOSQL_NULL);
                    break;
                case NUODB_TYPE_INT64:
                    stmt->setLong(parameterIndex, parameters[i].i64);
                    break;
                case NUODB_TYPE_FLOAT64: {
                    union {
                        int64_t i64;
                        double float64;
                    } value = { parameters[i].i64 };
                    stmt->setDouble(parameterIndex, value.float64);
                    break;
                }
                case NUODB_TYPE_BOOL:
                    stmt->setBoolean(parameterIndex, !!parameters[i].i64);
                    break;
                case NUODB_TYPE_STRING: {
                    union {
                        int64_t i64;
                        const char *bytes;
                    } value = { parameters[i].i64 };
                    // Extra conversion due to missing length param from the setString API
                    std::string str(value.bytes, parameters[i].i32);
                    stmt->setString(parameterIndex, str.c_str());
                    break;
                }
                case NUODB_TYPE_BYTES: {
                    union {
                        int64_t i64;
                        const unsigned char *bytes;
                    } value = { parameters[i].i64 };
                    stmt->setBytes(parameterIndex, parameters[i].i32, value.bytes);
                    break;
                }
                case NUODB_TYPE_TIME: {
                    int64_t seconds = parameters[i].i64;
                    int32_t nanos = parameters[i].i32;
                    SqlTimestamp ts(seconds, nanos);
                    stmt->setTimestamp(parameterIndex, &ts);
                    break;
                }
            }
        }
        return 0;
    } catch  (SQLException &e) {
        if (stmt) {
            stmt->close();
        }
        return setError(db, e);
    }
}

int nuodb_statement_execute(struct nuodb *db, struct nuodb_statement *st,
                            struct nuodb_resultset **rs, int *column_count, int64_t *affected_rows) {
    ResultSet *resultSet = 0;
    PreparedStatement *stmt = reinterpret_cast<PreparedStatement *>(st);
    try {
        int updateCount;
        bool hasResults = stmt->execute();
        if (hasResults) {
            resultSet = stmt->getResultSet();
            updateCount = 0;
        } else {
            resultSet = stmt->getGeneratedKeys();
            // NuoDB uses -1 as a flag for zero-rows-affected
            updateCount = std::max(0, stmt->getUpdateCount());
        }
        *column_count = resultSet->getMetaData()->getColumnCount();
        *affected_rows = updateCount;
        *rs = reinterpret_cast<struct nuodb_resultset *>(resultSet);
        return 0;
    } catch (SQLException &e) {
        if (resultSet) {
            resultSet->close();
        }
        return setError(db, e);
    }
}

int nuodb_statement_close(struct nuodb *db, struct nuodb_statement **st) {
    try {
        if (st && *st) {
            PreparedStatement *stmt = reinterpret_cast<PreparedStatement *>(*st);
            stmt->close();
            *st = 0;
        }
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_last_insert_id(struct nuodb *db, struct nuodb_resultset *rs,
                                   int64_t *last_insert_id) {
    ResultSet *resultSet = reinterpret_cast<ResultSet *>(rs);
    try {
        int64_t lastInsertId = 0;
        if (resultSet->getMetaData()->getColumnCount() == 1) {
            while (resultSet->next()) {
                // TODO find out how to read the last id first
            }
            lastInsertId = resultSet->getLong(1);
        }
        *last_insert_id = lastInsertId;
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_column_names(struct nuodb *db, struct nuodb_resultset *rs,
                                 struct nuodb_value names[]) {
    ResultSet *resultSet = reinterpret_cast<ResultSet *>(rs);
    try {
        ResultSetMetaData *resultSetMetaData = resultSet->getMetaData();
        int columnCount = resultSetMetaData->getColumnCount();
        for (int i=0; i < columnCount; ++i) {
            int columnIndex = i+1;
            union {
                const char *string;
                int64_t i64;
            } value = { resultSetMetaData->getColumnLabel(columnIndex) };
            names[i].i64 = value.i64;
        }
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_next(struct nuodb *db, struct nuodb_resultset *rs,
                         int *has_values, int *bytes_count, struct nuodb_value values[]) {
    ResultSet *resultSet = reinterpret_cast<ResultSet *>(rs);
    try {
        int bytesCount = 0;
        *has_values = resultSet->next();
        if (*has_values) {
            ResultSetMetaData *resultSetMetaData = resultSet->getMetaData();
            int columnCount = resultSetMetaData->getColumnCount();
            for (int i=0; i < columnCount; ++i) {
                int64_t i64 = 0;
                int32_t i32 = 0;
                enum nuodb_value_type vt = NUODB_TYPE_NULL;
                int columnIndex = i+1;
                switch (resultSetMetaData->getColumnType(columnIndex)) {
                    case NUOSQL_NULL:
                        vt = NUODB_TYPE_NULL;
                        break;
                    case NUOSQL_TINYINT:
                    case NUOSQL_SMALLINT:
                    case NUOSQL_INTEGER:
                    case NUOSQL_BIGINT:
                        if (resultSetMetaData->getScale(columnIndex) == 0) {
                            i64 = resultSet->getLong(columnIndex);
                            if (!resultSet->wasNull()) {
                                vt = NUODB_TYPE_INT64;
                            }
                            break;
                        }
                        // fallthrough; must be fetched as a string
                    case NUOSQL_NUMERIC:
                    case NUOSQL_DECIMAL: {
                        const char *str = resultSet->getString(columnIndex);
                        if (str && !resultSet->wasNull()) {
                            vt = NUODB_TYPE_BYTES; // strings are returned as bytes
                            i32 = std::strlen(str);
                            bytesCount += i32;
                        }
                        break;
                    }
                    case NUOSQL_FLOAT:
                    case NUOSQL_DOUBLE: {
                        union {
                            double float64;
                            int64_t i64;
                        } value = { resultSet->getDouble(columnIndex) };
                        if (!resultSet->wasNull()) {
                            vt = NUODB_TYPE_FLOAT64;
                            i64 = value.i64;
                        }
                        break;
                    }
                    case NUOSQL_BIT:
                    case NUOSQL_BOOLEAN:
                        i64 = resultSet->getBoolean(columnIndex);
                        if (!resultSet->wasNull()) {
                            vt = NUODB_TYPE_BOOL;
                        }
                        break;
                    case NUOSQL_DATE:
                    case NUOSQL_TIME:
                    case NUOSQL_TIMESTAMP: {
                        Timestamp *ts = resultSet->getTimestamp(columnIndex);
                        if (ts && !resultSet->wasNull()) {
                            vt = NUODB_TYPE_TIME;
                            i64 = ts->getSeconds();
                            i32 = ts->getNanos();
                        }
                        break;
                    }
                    default: {
                        const Bytes b = resultSet->getBytes(columnIndex);
                        if (!resultSet->wasNull()) {
                            vt = NUODB_TYPE_BYTES;
                            i32 = b.length;
                            bytesCount += i32;
                        }
                        break;
                    }
                }
                values[i].i64 = i64;
                values[i].i32 = i32;
                values[i].vt = vt;
            }
        }
        *bytes_count = bytesCount;
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_bytes(struct nuodb *db, struct nuodb_resultset *rs, unsigned char *bytes) {
    ResultSet *resultSet = reinterpret_cast<ResultSet *>(rs);
    try {
        ResultSetMetaData *resultSetMetaData = resultSet->getMetaData();
        int columnCount = resultSetMetaData->getColumnCount();
        for (int i=0; i < columnCount; ++i) {
            int columnIndex = i+1;
            switch (resultSetMetaData->getColumnType(columnIndex)) {
                case NUOSQL_NULL:
                case NUOSQL_FLOAT:
                case NUOSQL_DOUBLE:
                case NUOSQL_BIT:
                case NUOSQL_BOOLEAN:
                case NUOSQL_DATE:
                case NUOSQL_TIME:
                case NUOSQL_TIMESTAMP:
                    break; // skip
                case NUOSQL_TINYINT:
                case NUOSQL_SMALLINT:
                case NUOSQL_INTEGER:
                case NUOSQL_BIGINT:
                    if (resultSetMetaData->getScale(columnIndex) == 0) {
                        break; // skip
                    }
                    // fallthrough; must be fetched as a string
                case NUOSQL_NUMERIC:
                case NUOSQL_DECIMAL: {
                    const char *str = resultSet->getString(columnIndex);
                    if (str && !resultSet->wasNull()) {
                        size_t length = std::strlen(str);
                        std::memcpy(bytes, str, length);
                        bytes += length;
                    }
                    break;
                }
                default: {
                    const Bytes b = resultSet->getBytes(columnIndex);
                    if (!resultSet->wasNull()) {
                        std::memcpy(bytes, b.data, b.length);
                        bytes += b.length;
                    }
                    break;
                }
            }
        }
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}

int nuodb_resultset_close(struct nuodb *db, struct nuodb_resultset **rs) {
    try {
        if (rs && *rs) {
            ResultSet *resultSet = reinterpret_cast<ResultSet *>(*rs);
            resultSet->close();
            *rs = 0;
        }
        return 0;
    } catch (SQLException &e) {
        return setError(db, e);
    }
}
<|endoftext|>


<commit_before>//
// Created by dar on 2/11/16.
//

#include "TextManager.h"

TextManager::TextManager() { }

void TextManager::init() {
    if (this->charRender == nullptr) {
        this->charRender = new CharRender();
    }
}

void TextManager::render(const std::string &string, glm::mat4 projectionMatrix, glm::mat4 viewMatrix, int x, int y, float scale, int color, char flags) {
    for (int i = 0; i < string.length(); i++) {
        int j = this->charRender->getGlyphPos(string.at(i));
        if (j == -1) {
            x += this->charRender->TEXT_SPACESIZE * scale;
            continue;
        }
        this->charRender->render(string.at(i), projectionMatrix, viewMatrix, x, y, scale, color, flags);
        x += this->charRender->getGlyphSize(j) * scale + SPACING_PX;
    }
}

TextManager::~TextManager() {
    delete this->charRender;
}
<commit_msg>Cleanup<commit_after>//
// Created by dar on 2/11/16.
//

#include "TextManager.h"

TextManager::TextManager() { }

void TextManager::init() {
    this->charRender = new CharRender();
}

void TextManager::render(const std::string &string, glm::mat4 projectionMatrix, glm::mat4 viewMatrix, int x, int y, float scale, int color, char flags) {
    for (int i = 0; i < string.length(); i++) {
        int j = this->charRender->getGlyphPos(string.at(i));
        if (j == -1) {
            x += this->charRender->TEXT_SPACESIZE * scale;
            continue;
        }
        this->charRender->render(string.at(i), projectionMatrix, viewMatrix, x, y, scale, color, flags);
        x += this->charRender->getGlyphSize(j) * scale + SPACING_PX;
    }
}

TextManager::~TextManager() {
    delete this->charRender;
}
<|endoftext|>


<commit_before>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2011 Steven Lovegrove
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <pangolin/video/drivers/uvc.h>

namespace pangolin
{

UvcVideo::UvcVideo(int vendor_id, int product_id, const char* sn, int width, int height, int fps)
    : ctx_(NULL),
      dev_(NULL),
      devh_(NULL),
      frame_(NULL)
{
    uvc_init(&ctx_, NULL);
    if(!ctx_) {
        throw VideoException("Unable to open UVC Context");
    }

    InitDevice(vendor_id, product_id, sn, width, height, fps);
    Start();
}

UvcVideo::~UvcVideo()
{
    DeinitDevice();

//    if (ctx_) {
//        // Work out how to kill this properly
//        uvc_exit(ctx_);
//        ctx_ = 0;
//    }
}

void UvcVideo::InitDevice(int vid, int pid, const char* sn, int width, int height, int fps)
{
    uvc_error_t find_err = uvc_find_device(ctx_, &dev_, vid, pid, sn );
    if (find_err != UVC_SUCCESS) {
        uvc_perror(find_err, "uvc_find_device");
        throw VideoException("Unable to open UVC Device");
    }
    if(!dev_) {
        throw VideoException("Unable to open UVC Device - no pointer returned.");
    }

    uvc_error_t open_err = uvc_open(dev_, &devh_);
    if (open_err != UVC_SUCCESS) {
        uvc_perror(open_err, "uvc_open");
        uvc_unref_device(dev_);
        throw VideoException("Unable to open device");
    }

    uvc_error_t mode_err = uvc_get_stream_ctrl_format_size(
                devh_, &ctrl_,
                UVC_COLOR_FORMAT_GRAY8,
                width, height,
                fps);

    if (mode_err != UVC_SUCCESS) {
        uvc_perror(mode_err, "uvc_get_stream_ctrl_format_size");
        uvc_close(devh_);
        uvc_unref_device(dev_);
        throw VideoException("Unable to set device mode.");
    }

    uvc_error_t strm_err = uvc_stream_open_ctrl(devh_, &strm_, &ctrl_);
    if(strm_err != UVC_SUCCESS) {
        uvc_perror(strm_err, "uvc_stream_open_ctrl");
        uvc_close(devh_);
        uvc_unref_device(dev_);
        throw VideoException("Unable to open device stream.");
    }

    const VideoPixelFormat pfmt = VideoFormatFromString("GRAY8");
    const StreamInfo stream_info(pfmt, width, height, (width*pfmt.bpp)/8, 0);
    streams.push_back(stream_info);
}

void UvcVideo::DeinitDevice()
{
    Stop();

    if (frame_) {
        uvc_free_frame(frame_);
        frame_ = 0;
    }
}

void UvcVideo::Start()
{
    uvc_error_t stream_err = uvc_start_iso_streaming(devh_, &ctrl_, NULL, this);

    if (stream_err != UVC_SUCCESS) {
        uvc_perror(stream_err, "uvc_start_iso_streaming");
        uvc_close(devh_);
        uvc_unref_device(dev_);
        throw VideoException("Unable to start iso streaming.");
    }

    if (frame_) {
        uvc_free_frame(frame_);
    }

    size_bytes = ctrl_.dwMaxVideoFrameSize;
    frame_ = uvc_allocate_frame(size_bytes);
    if(!frame_) {
        throw VideoException("Unable to allocate frame.");
    }
}

void UvcVideo::Stop()
{
    if(devh_) {
        uvc_stop_streaming(devh_);
    }
}

size_t UvcVideo::SizeBytes() const
{
    return size_bytes;
}

const std::vector<StreamInfo>& UvcVideo::Streams() const
{
    return streams;
}

bool UvcVideo::GrabNext( unsigned char* image, bool wait )
{
    uvc_frame_t* frame = NULL;
    uvc_error_t err = uvc_stream_get_frame(strm_, &frame, 0);

    if(err!= UVC_SUCCESS) {
        uvc_perror(err, "uvc_get_frame");
        return false;
    }else{
        if(frame) {
            memcpy(image, frame->data, frame->data_bytes );
            return true;
        }else{
            std::cerr << "No data..." << std::endl;
            return false;
        }
    }
}

bool UvcVideo::GrabNewest( unsigned char* image, bool wait )
{
    return GrabNext(image, wait);
}

}
<commit_msg>fixes for uvc driver<commit_after>/* This file is part of the Pangolin Project.
 * http://github.com/stevenlovegrove/Pangolin
 *
 * Copyright (c) 2011 Steven Lovegrove
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <pangolin/video/drivers/uvc.h>

namespace pangolin
{

UvcVideo::UvcVideo(int vendor_id, int product_id, const char* sn, int width, int height, int fps)
    : ctx_(NULL),
      dev_(NULL),
      devh_(NULL),
      frame_(NULL)
{
    uvc_init(&ctx_, NULL);
    if(!ctx_) {
        throw VideoException("Unable to open UVC Context");
    }

    InitDevice(vendor_id, product_id, sn, width, height, fps);
    Start();
}

UvcVideo::~UvcVideo()
{
    DeinitDevice();

//    if (ctx_) {
//        // Work out how to kill this properly
//        uvc_exit(ctx_);
//        ctx_ = 0;
//    }
}

void UvcVideo::InitDevice(int vid, int pid, const char* sn, int width, int height, int fps)
{
    uvc_error_t find_err = uvc_find_device(ctx_, &dev_, vid, pid, sn );
    if (find_err != UVC_SUCCESS) {
        uvc_perror(find_err, "uvc_find_device");
        throw VideoException("Unable to open UVC Device");
    }
    if(!dev_) {
        throw VideoException("Unable to open UVC Device - no pointer returned.");
    }

    uvc_error_t open_err = uvc_open(dev_, &devh_);
    if (open_err != UVC_SUCCESS) {
        uvc_perror(open_err, "uvc_open");
        uvc_unref_device(dev_);
        throw VideoException("Unable to open device");
    }

    //uvc_print_diag(devh_, stderr);

    uvc_error_t mode_err = uvc_get_stream_ctrl_format_size(
                devh_, &ctrl_,
                UVC_FRAME_FORMAT_YUYV,
                width, height,
                fps);

    //uvc_print_stream_ctrl(&ctrl_, stderr);

    if (mode_err != UVC_SUCCESS) {
        uvc_perror(mode_err, "uvc_get_stream_ctrl_format_size");
        uvc_close(devh_);
        uvc_unref_device(dev_);
        throw VideoException("Unable to set device mode.");
    }

    uvc_error_t strm_err = uvc_stream_open_ctrl(devh_, &strm_, &ctrl_);
    if(strm_err != UVC_SUCCESS) {
        uvc_perror(strm_err, "uvc_stream_open_ctrl");
        uvc_close(devh_);
        uvc_unref_device(dev_);
        throw VideoException("Unable to open device stream.");
    }

    const VideoPixelFormat pfmt = VideoFormatFromString("GRAY8");
    const StreamInfo stream_info(pfmt, width, height, (width*pfmt.bpp)/8, 0);
    streams.push_back(stream_info);
}

void UvcVideo::DeinitDevice()
{
    Stop();

    if (frame_) {
        uvc_free_frame(frame_);
        frame_ = 0;
    }
}

void UvcVideo::Start()
{
    uvc_error_t stream_err = uvc_stream_start(strm_, NULL, this, 0);

    if (stream_err != UVC_SUCCESS) {
        uvc_perror(stream_err, "uvc_stream_start");
        uvc_close(devh_);
        uvc_unref_device(dev_);
        throw VideoException("Unable to start streaming.");
    }

    if (frame_) {
        uvc_free_frame(frame_);
    }

    size_bytes = ctrl_.dwMaxVideoFrameSize;
    frame_ = uvc_allocate_frame(size_bytes);
    if(!frame_) {
        throw VideoException("Unable to allocate frame.");
    }
}

void UvcVideo::Stop()
{
    if(devh_) {
        uvc_stop_streaming(devh_);
    }
}

size_t UvcVideo::SizeBytes() const
{
    return size_bytes;
}

const std::vector<StreamInfo>& UvcVideo::Streams() const
{
    return streams;
}

bool UvcVideo::GrabNext( unsigned char* image, bool wait )
{
    uvc_frame_t* frame = NULL;
    uvc_error_t err = uvc_stream_get_frame(strm_, &frame, 0);

    if(err!= UVC_SUCCESS) {
        uvc_perror(err, "uvc_get_frame");
        return false;
    }else{
        if(frame) {
            memcpy(image, frame->data, frame->data_bytes );
            return true;
        }else{
            std::cerr << "No data..." << std::endl;
            return false;
        }
    }
}

bool UvcVideo::GrabNewest( unsigned char* image, bool wait )
{
    return GrabNext(image, wait);
}

}
<|endoftext|>


<commit_before>//===- llvm/Support/DiagnosticInfo.cpp - Diagnostic Definitions -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the a diagnostic printer relying on raw_ostream.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/Twine.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(char C) {
  Stream << C;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(unsigned char C) {
  Stream << C;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(signed char C) {
  Stream << C;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(StringRef Str) {
  Stream << Str;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const char *Str) {
  Stream << Str;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(
    const std::string &Str) {
  Stream << Str;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(unsigned long N) {
  Stream << N;
  return *this;
}
DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(long N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(
    unsigned long long N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(long long N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const void *P) {
  Stream << P;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(unsigned int N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(int N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(double N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const Twine &Str) {
  Stream << Str.getSingleStringRef();
  return *this;
}

// IR related types.
DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const Value &V) {
  Stream << V.getName();
  return *this;
}
<commit_msg>[DiagnosticPrinter] Use the appropriate method to print a Twine object in a raw_ostream.<commit_after>//===- llvm/Support/DiagnosticInfo.cpp - Diagnostic Definitions -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the a diagnostic printer relying on raw_ostream.
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/Twine.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(char C) {
  Stream << C;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(unsigned char C) {
  Stream << C;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(signed char C) {
  Stream << C;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(StringRef Str) {
  Stream << Str;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const char *Str) {
  Stream << Str;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(
    const std::string &Str) {
  Stream << Str;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(unsigned long N) {
  Stream << N;
  return *this;
}
DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(long N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(
    unsigned long long N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(long long N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const void *P) {
  Stream << P;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(unsigned int N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(int N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(double N) {
  Stream << N;
  return *this;
}

DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const Twine &Str) {
  Str.print(Stream);
  return *this;
}

// IR related types.
DiagnosticPrinter &DiagnosticPrinterRawOStream::operator<<(const Value &V) {
  Stream << V.getName();
  return *this;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: jpeg.hxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 09:51:45 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _JPEG_HXX
#define _JPEG_HXX

#ifndef _GRAPH_HXX
#include <vcl/graph.hxx>
#endif
#ifndef _FLTCALL_HXX
#include "fltcall.hxx"
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_H_
#include <com/sun/star/uno/Sequence.h>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif

#ifdef _JPEGPRIVATE

// --------
// - Enum -
// --------

enum ReadState
{
    JPEGREAD_OK,
    JPEGREAD_ERROR,
    JPEGREAD_NEED_MORE
};

// --------------
// - JPEGReader -
// --------------

class JPEGReader : public GraphicReader
{
    SvStream&           rIStm;
    Bitmap              aBmp;
    Bitmap              aBmp1;
    BitmapWriteAccess*  pAcc;
    BitmapWriteAccess*  pAcc1;
    void*               pBuffer;
    long                nLastPos;
    long                nFormerPos;
    long                nLastLines;
    sal_Bool            bSetLogSize;

    Graphic             CreateIntermediateGraphic( const Bitmap& rBitmap, long nLines );
    void                FillBitmap();

public:

    void*               CreateBitmap( void* JPEGCreateBitmapParam );

public:

                        JPEGReader( SvStream& rStm, void* pCallData, sal_Bool bSetLogSize );
    virtual             ~JPEGReader();

    ReadState           Read( Graphic& rGraphic );
};

// --------------
// - JPEGWriter -
// --------------

class JPEGWriter
{
    SvStream&           rOStm;
    Bitmap              aBmp;
    BitmapReadAccess*   pAcc;
    BYTE*               pBuffer;
    PFilterCallback     pCallback;
    void*               pCallerData;
    BOOL                bNative;

public:

    void*               GetScanline( long nY );

public:

                        JPEGWriter( SvStream& rOStm, PFilterCallback pCallback, void* pCallData );
                        ~JPEGWriter() {};

    BOOL                Write( const Graphic& rGraphic, const
                        ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData );
};

#endif // _JPEGPRIVATE

// ---------------------
// - Import/ExportJPEG -
// ---------------------

BOOL ImportJPEG( SvStream& rStream, Graphic& rGraphic, void* pCallerData, sal_Int32 nImportFlags );

BOOL ExportJPEG( SvStream& rStream, const Graphic& rGraphic,
                 PFilterCallback pCallback, void* pCallerData,
                 const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData );

#endif // _JPEG_HXX
<commit_msg>INTEGRATION: CWS aw024 (1.6.1052); FILE MERGED 2005/09/19 17:47:07 aw 1.6.1052.2: RESYNC: (1.6-1.7); FILE MERGED 2005/08/04 15:37:38 sj 1.6.1052.1: #48467# using GraphicExporter component for exports, graphic filter progress now works now via xStatusIndicater instead of callback mechanism<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: jpeg.hxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: ihi $ $Date: 2006-11-14 15:38:19 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _JPEG_HXX
#define _JPEG_HXX

#ifndef _GRAPH_HXX
#include <vcl/graph.hxx>
#endif
#ifndef _FLTCALL_HXX
#include "fltcall.hxx"
#endif
#ifndef _COM_SUN_STAR_UNO_SEQUENCE_H_
#include <com/sun/star/uno/Sequence.h>
#endif
#ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUE_HPP_
#include <com/sun/star/beans/PropertyValue.hpp>
#endif
#ifndef _COM_SUN_STAR_TASK_XSTATUSINDICATOR_HPP_
#include <com/sun/star/task/XStatusIndicator.hpp>
#endif

#ifdef _JPEGPRIVATE

// --------
// - Enum -
// --------

enum ReadState
{
    JPEGREAD_OK,
    JPEGREAD_ERROR,
    JPEGREAD_NEED_MORE
};

// --------------
// - JPEGReader -
// --------------

class JPEGReader : public GraphicReader
{
    SvStream&           rIStm;
    Bitmap              aBmp;
    Bitmap              aBmp1;
    BitmapWriteAccess*  pAcc;
    BitmapWriteAccess*  pAcc1;
    void*               pBuffer;
    long                nLastPos;
    long                nFormerPos;
    long                nLastLines;
    sal_Bool            bSetLogSize;

    Graphic             CreateIntermediateGraphic( const Bitmap& rBitmap, long nLines );
    void                FillBitmap();

public:

    void*               CreateBitmap( void* JPEGCreateBitmapParam );

public:

                        JPEGReader( SvStream& rStm, void* pCallData, sal_Bool bSetLogSize );
    virtual             ~JPEGReader();

    ReadState           Read( Graphic& rGraphic );
};

// --------------
// - JPEGWriter -
// --------------

class JPEGWriter
{
    SvStream&           rOStm;
    Bitmap              aBmp;
    BitmapReadAccess*   pAcc;
    BYTE*               pBuffer;
    BOOL                bNative;

    sal_Bool            bGreys;
    sal_Int32           nQuality;

    com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator;

public:

    void*               GetScanline( long nY );

                        JPEGWriter( SvStream& rOStm, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData );
                        ~JPEGWriter() {};

    BOOL                Write( const Graphic& rGraphic );
};

#endif // _JPEGPRIVATE

// ---------------------
// - Import/ExportJPEG -
// ---------------------

BOOL ImportJPEG( SvStream& rStream, Graphic& rGraphic, void* pCallerData, sal_Int32 nImportFlags );

BOOL ExportJPEG( SvStream& rStream, const Graphic& rGraphic, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData );

#endif // _JPEG_HXX
<|endoftext|>


<commit_before>int scanf(const char *format, ...);
int globalVal;
char * globalVala;
int * globalValp;
char globalVala2;
int functionWork1(int retIndex) {
  int i;
  char a[10];
  int b;
  int *p = &b;
  if (scanf("%i", &i) != 1) // GOOD
    return -1;
  if (scanf("%s", a) != 1) // GOOD
    return -1;
  if (scanf("%i", p) != 1) // GOOD
    return -1;
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}

int functionWork1_(int retIndex) {
  int i;
  char a[10];
  int b;
  int *p = &b;
  int r;
  r = scanf("%i", &i);
  if (r != 1) // GOOD
    return -1;
  r = scanf("%s", a);
  if (r == 1) // GOOD
    return -1;
  r = scanf("%i", p);
  if (r != 1) // GOOD
    return -1;
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}

int functionWork1b(int retIndex) {
  int i;
  char a[10];
  int b;
  int *p = &b;
  scanf("%i", &i); // BAD
  scanf("%s", a); // BAD
  scanf("%i", p); // BAD
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}
int functionWork1_() {
  int i;
  scanf("%i",&i); // BAD [NOT DETECTED]
  if(i<10)
    return -1;
  return i;
}
int functionWork2(int retIndex) {
  int i = 0;
  char a[10] = "";
  int b = 1;
  int *p = &b;
  scanf("%i", &i); // GOOD:Argument initialized even when scanf fails.
  scanf("%s", a); // GOOD:Argument initialized even when scanf fails.
  scanf("%i", p); // GOOD:Argument initialized even when scanf fails.
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}

int functionWork2_(int retIndex) {
  int i;
  i = 0;
  char a[10];
  a[0] = '\0';
  int b;
  b=1;
  int *p = &b;
  scanf("%i", &i); // GOOD:Argument initialized even when scanf fails.
  scanf("%s", a); // GOOD:Argument initialized even when scanf fails.
  scanf("%i", p); // GOOD:Argument initialized even when scanf fails.
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}
int functionWork2b() {
  int i;
  char a[10];
  int b;
  int *p = &b;
  scanf("%i", &i); // BAD
  scanf("%s", a); // BAD
  scanf("%i", p); // BAD
  globalVal = i;
  globalVala = a;
  globalValp = p;
  return 0;
}
int functionWork2b_() {
  char a[10];
  scanf("%s", a); // BAD
  globalVala2 = a[0];
  return 0;
}
int functionWork3b(int i) {
  scanf("%i", &i); // BAD
  return 0;
}
int functionWork3() {
  char number[] = "42";
  int d;
  sscanf(number, "%d", &d); // GOOD: sscanf always succeeds
  if (d < 16)
    return -1;
}
<commit_msg>Update test.cpp<commit_after>int scanf(const char *format, ...);
int globalVal;
char * globalVala;
int * globalValp;
char globalVala2;
int functionWork1(int retIndex) {
  int i;
  char a[10];
  int b;
  int *p = &b;
  if (scanf("%i", &i) != 1) // GOOD
    return -1;
  if (scanf("%s", a) != 1) // GOOD
    return -1;
  if (scanf("%i", p) != 1) // GOOD
    return -1;
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}

int functionWork1_(int retIndex) {
  int i;
  char a[10];
  int b;
  int *p = &b;
  int r;
  r = scanf("%i", &i);
  if (r != 1) // GOOD
    return -1;
  r = scanf("%s", a);
  if (r == 1) // GOOD
    return -1;
  r = scanf("%i", p);
  if (r != 1) // GOOD
    return -1;
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}

int functionWork1b(int retIndex) {
  int i;
  char a[10];
  int b;
  int *p = &b;
  scanf("%i", &i); // BAD
  scanf("%s", a); // BAD
  scanf("%i", p); // BAD
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}
int functionWork1_() {
  int i;
  scanf("%i",&i); // BAD [NOT DETECTED]
  if(i<10)
    return -1;
  return i;
}
int functionWork2(int retIndex) {
  int i = 0;
  char a[10] = "";
  int b = 1;
  int *p = &b;
  scanf("%i", &i); // GOOD:Argument initialized even when scanf fails.
  scanf("%s", a); // GOOD:Argument initialized even when scanf fails.
  scanf("%i", p); // GOOD:Argument initialized even when scanf fails.
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}

int functionWork2_(int retIndex) {
  int i;
  i = 0;
  char a[10];
  a[0] = '\0';
  int b;
  b=1;
  int *p = &b;
  scanf("%i", &i); // GOOD:Argument initialized even when scanf fails.
  scanf("%s", a); // GOOD:Argument initialized even when scanf fails.
  scanf("%i", p); // GOOD:Argument initialized even when scanf fails.
  if(retIndex == 0)
    return (int)*a;
  if(retIndex == 1)
    return *p;
  return i;
}
int functionWork2b() {
  int i;
  char a[10];
  int b;
  int *p = &b;
  scanf("%i", &i); // BAD
  scanf("%s", a); // BAD
  scanf("%i", p); // BAD
  globalVal = i;
  globalVala = a;
  globalValp = p;
  return 0;
}
int functionWork2b_() {
  char a[10];
  scanf("%s", a); // BAD
  globalVala2 = a[0];
  return 0;
}
int functionWork3b(int * i) {
  scanf("%i", i); // BAD
  return 0;
}
int functionWork3() {
  char number[] = "42";
  int d;
  sscanf(number, "%d", &d); // GOOD: sscanf always succeeds
  if (d < 16)
    return -1;
}
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2008, Distributed Systems Architecture Group, Universidad   */
/* Complutense de Madrid (dsa-research.org)                                   */
/*                                                                            */
/* 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 "VirtualNetwork.h"
#include "Nebula.h"
#include "RangedLeases.h"
#include "FixedLeases.h"

/* ************************************************************************** */
/* Virtual Network :: Constructor/Destructor                                  */
/* ************************************************************************** */

VirtualNetwork::VirtualNetwork(unsigned int  mp, int ds):
                PoolObjectSQL(-1),
                name(""),
                uid(-1),
                bridge(""),
                type(UNINITIALIZED),
                leases(0),
                mac_prefix(mp),
                default_size(ds)
{
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

VirtualNetwork::~VirtualNetwork()
{
    if (leases != 0)
    {
        delete leases;
    }
}

/* ************************************************************************** */
/* Virtual Network :: Database Access Functions                               */
/* ************************************************************************** */

const char * VirtualNetwork::table               = "network_pool";

const char * VirtualNetwork::db_names            = "(oid,uid,name,type,bridge)";

const char * VirtualNetwork::db_bootstrap        = "CREATE TABLE network_pool ("
     "oid INTEGER,uid INTEGER, name TEXT PRIMARY KEY,type INTEGER, bridge TEXT)";

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int VirtualNetwork::unmarshall(int num, char **names, char ** values)
{
    if     ((values[OID]    == 0)  ||
            (values[UID]    == 0)  ||
            (values[NAME]   == 0)  ||
            (values[TYPE]   == 0)  ||
            (values[BRIDGE] == 0)  ||
            (num            != LIMIT ))
    {
        return -1;
    }

    oid    = atoi(values[OID]);
    uid    = atoi(values[UID]);

    name   = values[NAME];

    type   = (NetworkType)atoi(values[TYPE]);

    bridge = values[BRIDGE];

    // Virtual Network template ID is the Network ID
    vn_template.id = oid;

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

extern "C" int vn_select_cb (
        void *                  _vn,
        int                     num,
        char **                 values,
        char **                 names)
{
    VirtualNetwork *    vn;

    vn = static_cast<VirtualNetwork *>(_vn);

    if (vn == 0)
    {
        return -1;
    }

    return vn->unmarshall(num,names,values);
};

/* -------------------------------------------------------------------------- */

int VirtualNetwork::select(SqliteDB * db)
{
    ostringstream   oss;
    ostringstream   ose;

    int             rc;
    int             boid;

    string          network_address;

    oss << "SELECT * FROM " << table << " WHERE oid = " << oid;

    boid = oid;
    oid  = -1;

    rc = db->exec(oss,vn_select_cb,(void *) this);

    if ((rc != 0) || (oid != boid ))
    {
        goto error_id;
    }

    //Get the template
    rc = vn_template.select(db);

    if (rc != 0)
    {
        goto error_template;
    }

    //Get the leases
    if (type == RANGED)
    {
    	string 	nclass = "";
    	int		size = 0;

        // retrieve specific information from template
        get_template_attribute("NETWORK_ADDRESS",network_address);

        if (network_address.empty())
        {
        	goto error_addr;
        }

        get_template_attribute("NETWORK_SIZE",nclass);

        if ( nclass == "B" )
        {
        	size = 65534;
        }
        else if ( nclass == "C" )
        {
        	size = 254;
        }
        else if (!nclass.empty()) //Assume its a number
        {
        	istringstream iss(nclass);
        	iss >> size;
        }

        if (size == 0)
        {
        	size = default_size;
        }

        leases = new RangedLeases::RangedLeases(db,
                                                oid,
                                                size,
                                                mac_prefix,
                                                network_address);
    }
    else if(type == FIXED)
    {
    	leases = new  FixedLeases(db,
                                  oid,
                                  mac_prefix);
    }
    else
    {
    	goto error_type;
    }

    if (leases == 0)
    {
        goto error_leases;
    }

    return leases->select(db);

error_id:
    ose << "Error getting Virtual Network nid: " << oid;
	goto error_common;

error_template:
    ose << "Can not get template for Virtual Network nid: " << oid;
	goto error_common;

error_leases:
    ose << "Error getting Virtual Network leases nid: " << oid;
	goto error_common;

error_type:
	ose << "Wrong type of Virtual Network: " << type;
    goto error_common;

error_addr:
	ose << "Network address is not defined nid: " << oid;

error_common:
	Nebula::log("VNM", Log::ERROR, ose);
	return -1;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int VirtualNetwork::insert(SqliteDB * db)
{
    ostringstream   ose;
    int             rc;

    if ( vn_template.id == -1 )
    {
        vn_template.id = oid;
    }

    // Insert the template first
    rc = vn_template.insert(db);

    if ( rc != 0 )
    {
    	goto error_template;
    }

    // Insert the Virtual Network
    rc = update(db);

    if ( rc != 0 )
    {
    	goto error_update;
    }

     //Get the leases
     if (type == VirtualNetwork::RANGED)
     {
    	 string nclass = "";
    	 string naddr  = "";
    	 int    size   = 0;

         // retrieve specific information from template
         get_template_attribute("NETWORK_ADDRESS",naddr);

         if (naddr.empty())
         {
         	goto error_addr;
         }

         get_template_attribute("NETWORK_SIZE",nclass);

         if ( nclass == "B" )
         {
        	 size = 65534;
         }
         else if ( nclass == "C" )
         {
             size = 254;
         }
         else if (!nclass.empty())//Assume its a number
         {
        	 istringstream iss(nclass);

        	 iss >> size;
         }

         if (size == 0)
         {
        	 size = default_size;
         }

         leases = new RangedLeases::RangedLeases(db,
                                                 oid,
                                                 size,
                                                 mac_prefix,
                                                 naddr);
     }
     else if(type == VirtualNetwork::FIXED)
     {
    	 vector<const Attribute *>   vector_leases;

    	 get_template_attribute("LEASES",vector_leases);

         leases = new FixedLeases::FixedLeases(db,
                                               oid,
                                               mac_prefix,
                                               vector_leases);
     }
     else
     {
    	 goto error_type;
     }

     if (leases == 0)
     {
    	 goto error_null_leases;
     }

     return 0;

error_template:
	ose << "Can not insert in DB template for Virtual Network id " << oid;
    goto error_common;

error_update:
	ose << "Can not update Virtual Network id " << oid;
	vn_template.drop(db);
	goto error_common;

error_type:
	ose << "Wrong type of Virtual Network: " << type;
    goto error_leases;

error_addr:
	ose << "Network address is not defined nid: " << oid;
    goto error_leases;

error_null_leases:
    ose << "Error getting Virtual Network leases nid: " << oid;

error_leases:
 	vn_template.drop(db);
    vn_drop(db);

error_common:
	Nebula::log("VNM", Log::ERROR, ose);
    return -1;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int VirtualNetwork::update(SqliteDB * db)
{
    ostringstream   oss;
    int             rc;

    oss << "INSERT OR REPLACE INTO " << table << " "<< db_names <<" VALUES ("<<
        oid << "," <<
        uid << "," <<
        "'" << name << "',"  <<
        type << "," <<
        "'" << bridge << "')";

    rc = db->exec(oss);

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int VirtualNetwork::vn_drop(SqliteDB * db)
{
    ostringstream   oss;
    int             rc;

    oss << "DELETE FROM " << table << " WHERE OID=" << oid;

    rc = db->exec(oss);

    return rc;
}

/* ************************************************************************** */
/* Virtual Network :: Misc                                                    */
/* ************************************************************************** */

ostream& operator<<(ostream& os, VirtualNetwork& vn)
{
    os << "NID               : " << vn.oid << endl;
    os << "UID               : " << vn.uid << endl;
    os << "Network Name      : " << vn.name << endl;
    os << "Type              : ";
    if ( vn.type==VirtualNetwork::RANGED )
    {
        os << "Ranged" << endl;
    }
    else
    {
       os << "Fixed" << endl;
    }
    os << "Size              : " << vn.get_size() << endl;
    os << "Bridge            : " << vn.bridge << endl << endl;

    os << "....: Template :...."  << vn.vn_template << endl << endl;

    os << "....: Leases :...."   << endl << *(vn.leases) << endl;

    return os;
};
<commit_msg>solved a bug when removing a network and then adding a new one<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2008, Distributed Systems Architecture Group, Universidad   */
/* Complutense de Madrid (dsa-research.org)                                   */
/*                                                                            */
/* 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 "VirtualNetwork.h"
#include "Nebula.h"
#include "RangedLeases.h"
#include "FixedLeases.h"

/* ************************************************************************** */
/* Virtual Network :: Constructor/Destructor                                  */
/* ************************************************************************** */

VirtualNetwork::VirtualNetwork(unsigned int  mp, int ds):
                PoolObjectSQL(-1),
                name(""),
                uid(-1),
                bridge(""),
                type(UNINITIALIZED),
                leases(0),
                mac_prefix(mp),
                default_size(ds)
{
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

VirtualNetwork::~VirtualNetwork()
{
    if (leases != 0)
    {
        delete leases;
    }
}

/* ************************************************************************** */
/* Virtual Network :: Database Access Functions                               */
/* ************************************************************************** */

const char * VirtualNetwork::table               = "network_pool";

const char * VirtualNetwork::db_names            = "(oid,uid,name,type,bridge)";

const char * VirtualNetwork::db_bootstrap        = "CREATE TABLE network_pool ("
     "oid INTEGER,uid INTEGER, name TEXT PRIMARY KEY,type INTEGER, bridge TEXT)";

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int VirtualNetwork::unmarshall(int num, char **names, char ** values)
{
    if     ((values[OID]    == 0)  ||
            (values[UID]    == 0)  ||
            (values[NAME]   == 0)  ||
            (values[TYPE]   == 0)  ||
            (values[BRIDGE] == 0)  ||
            (num            != LIMIT ))
    {
        return -1;
    }

    oid    = atoi(values[OID]);
    uid    = atoi(values[UID]);

    name   = values[NAME];

    type   = (NetworkType)atoi(values[TYPE]);

    bridge = values[BRIDGE];

    // Virtual Network template ID is the Network ID
    vn_template.id = oid;

    return 0;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

extern "C" int vn_select_cb (
        void *                  _vn,
        int                     num,
        char **                 values,
        char **                 names)
{
    VirtualNetwork *    vn;

    vn = static_cast<VirtualNetwork *>(_vn);

    if (vn == 0)
    {
        return -1;
    }

    return vn->unmarshall(num,names,values);
};

/* -------------------------------------------------------------------------- */

int VirtualNetwork::select(SqliteDB * db)
{
    ostringstream   oss;
    ostringstream   ose;

    int             rc;
    int             boid;

    string          network_address;

    oss << "SELECT * FROM " << table << " WHERE oid = " << oid;

    boid = oid;
    oid  = -1;

    rc = db->exec(oss,vn_select_cb,(void *) this);

    if ((rc != 0) || (oid != boid ))
    {
        goto error_id;
    }

    //Get the template
    rc = vn_template.select(db);

    if (rc != 0)
    {
        goto error_template;
    }

    //Get the leases
    if (type == RANGED)
    {
    	string 	nclass = "";
    	int		size = 0;

        // retrieve specific information from template
        get_template_attribute("NETWORK_ADDRESS",network_address);

        if (network_address.empty())
        {
        	goto error_addr;
        }

        get_template_attribute("NETWORK_SIZE",nclass);

        if ( nclass == "B" )
        {
        	size = 65534;
        }
        else if ( nclass == "C" )
        {
        	size = 254;
        }
        else if (!nclass.empty()) //Assume its a number
        {
        	istringstream iss(nclass);
        	iss >> size;
        }

        if (size == 0)
        {
        	size = default_size;
        }

        leases = new RangedLeases::RangedLeases(db,
                                                oid,
                                                size,
                                                mac_prefix,
                                                network_address);
    }
    else if(type == FIXED)
    {
    	leases = new  FixedLeases(db,
                                  oid,
                                  mac_prefix);
    }
    else
    {
    	goto error_type;
    }

    if (leases == 0)
    {
        goto error_leases;
    }

    return leases->select(db);

error_id:
    ose << "Error getting Virtual Network nid: " << oid;
	goto error_common;

error_template:
    ose << "Can not get template for Virtual Network nid: " << oid;
	goto error_common;

error_leases:
    ose << "Error getting Virtual Network leases nid: " << oid;
	goto error_common;

error_type:
	ose << "Wrong type of Virtual Network: " << type;
    goto error_common;

error_addr:
	ose << "Network address is not defined nid: " << oid;

error_common:
	Nebula::log("VNM", Log::ERROR, ose);
	return -1;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int VirtualNetwork::insert(SqliteDB * db)
{
    ostringstream   ose;
    int             rc;

    if ( vn_template.id == -1 )
    {
        vn_template.id = oid;
    }

    // Insert the template first
    rc = vn_template.update(db);

    if ( rc != 0 )
    {
    	goto error_template;
    }

    // Insert the Virtual Network
    rc = update(db);

    if ( rc != 0 )
    {
    	goto error_update;
    }

     //Get the leases
     if (type == VirtualNetwork::RANGED)
     {
    	 string nclass = "";
    	 string naddr  = "";
    	 int    size   = 0;

         // retrieve specific information from template
         get_template_attribute("NETWORK_ADDRESS",naddr);

         if (naddr.empty())
         {
         	goto error_addr;
         }

         get_template_attribute("NETWORK_SIZE",nclass);

         if ( nclass == "B" )
         {
        	 size = 65534;
         }
         else if ( nclass == "C" )
         {
             size = 254;
         }
         else if (!nclass.empty())//Assume its a number
         {
        	 istringstream iss(nclass);

        	 iss >> size;
         }

         if (size == 0)
         {
        	 size = default_size;
         }

         leases = new RangedLeases::RangedLeases(db,
                                                 oid,
                                                 size,
                                                 mac_prefix,
                                                 naddr);
     }
     else if(type == VirtualNetwork::FIXED)
     {
    	 vector<const Attribute *>   vector_leases;

    	 get_template_attribute("LEASES",vector_leases);

         leases = new FixedLeases::FixedLeases(db,
                                               oid,
                                               mac_prefix,
                                               vector_leases);
     }
     else
     {
    	 goto error_type;
     }

     if (leases == 0)
     {
    	 goto error_null_leases;
     }

     return 0;

error_template:
	ose << "Can not insert in DB template for Virtual Network id " << oid;
    goto error_common;

error_update:
	ose << "Can not update Virtual Network id " << oid;
	vn_template.drop(db);
	goto error_common;

error_type:
	ose << "Wrong type of Virtual Network: " << type;
    goto error_leases;

error_addr:
	ose << "Network address is not defined nid: " << oid;
    goto error_leases;

error_null_leases:
    ose << "Error getting Virtual Network leases nid: " << oid;

error_leases:
 	vn_template.drop(db);
    vn_drop(db);

error_common:
	Nebula::log("VNM", Log::ERROR, ose);
    return -1;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int VirtualNetwork::update(SqliteDB * db)
{
    ostringstream   oss;
    int             rc;

    oss << "INSERT OR REPLACE INTO " << table << " "<< db_names <<" VALUES ("<<
        oid << "," <<
        uid << "," <<
        "'" << name << "',"  <<
        type << "," <<
        "'" << bridge << "')";

    rc = db->exec(oss);

    return rc;
}

/* -------------------------------------------------------------------------- */
/* -------------------------------------------------------------------------- */

int VirtualNetwork::vn_drop(SqliteDB * db)
{
    ostringstream   oss;
    int             rc;

    oss << "DELETE FROM " << table << " WHERE OID=" << oid;

    rc = db->exec(oss);

    return rc;
}

/* ************************************************************************** */
/* Virtual Network :: Misc                                                    */
/* ************************************************************************** */

ostream& operator<<(ostream& os, VirtualNetwork& vn)
{
    os << "NID               : " << vn.oid << endl;
    os << "UID               : " << vn.uid << endl;
    os << "Network Name      : " << vn.name << endl;
    os << "Type              : ";
    if ( vn.type==VirtualNetwork::RANGED )
    {
        os << "Ranged" << endl;
    }
    else
    {
       os << "Fixed" << endl;
    }
    os << "Size              : " << vn.get_size() << endl;
    os << "Bridge            : " << vn.bridge << endl << endl;

    os << "....: Template :...."  << vn.vn_template << endl << endl;

    os << "....: Leases :...."   << endl << *(vn.leases) << endl;

    return os;
};
<|endoftext|>


<commit_before>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include "fnord/util/binarymessagewriter.h"
#include "tsdb/TSDBServlet.h"
#include "tsdb/RecordEnvelope.pb.h"
#include "fnord/json/json.h"
#include <fnord/wallclock.h>
#include <fnord/thread/wakeup.h>
#include "fnord/protobuf/MessageEncoder.h"
#include "fnord/protobuf/MessagePrinter.h"
#include "fnord/protobuf/msg.h"
#include <fnord/util/Base64.h>
#include <fnord/fnv.h>
#include <sstable/sstablereader.h>
#include <chartsql/runtime/ASCIITableFormat.h>

using namespace fnord;

namespace tsdb {

TSDBServlet::TSDBServlet(TSDBNode* node) : node_(node) {}

void TSDBServlet::handleHTTPRequest(
    RefPtr<http::HTTPRequestStream> req_stream,
    RefPtr<http::HTTPResponseStream> res_stream) {
  req_stream->readBody();
  const auto& req = req_stream->request();
  URI uri(req.uri());

  http::HTTPResponse res;
  res.populateFromRequest(req);
  res.addHeader("Access-Control-Allow-Origin", "*");
  res.addHeader("Access-Control-Allow-Methods", "GET, POST");
  res.addHeader("Access-Control-Allow-Headers", "X-TSDB-Namespace");

  if (req.method() == http::HTTPMessage::M_OPTIONS) {
    res.setStatus(http::kStatusOK);
    res_stream->writeResponse(res);
    return;
  }

  try {
    if (uri.path() == "/tsdb/insert") {
      insertRecords(&req, &res, &uri);
      res_stream->writeResponse(res);
      return;
    }

    if (uri.path() == "/tsdb/stream") {
      streamPartition(&req, &res, res_stream, &uri);
      return;
    }

    if (uri.path() == "/tsdb/partition_info") {
      fetchPartitionInfo(&req, &res, &uri);
      res_stream->writeResponse(res);
      return;
    }

    if (uri.path() == "/tsdb/sql") {
      executeSQL(&req, &res, res_stream, &uri);
      return;
    }

    res.setStatus(fnord::http::kStatusNotFound);
    res.addBody("not found");
    res_stream->writeResponse(res);
  } catch (const Exception& e) {
    fnord::logError("tsdb", e, "error while processing HTTP request");

    res.setStatus(http::kStatusInternalServerError);
    res.addBody(StringUtil::format("error: $0: $1", e.getTypeName(), e.getMessage()));
    res_stream->writeResponse(res);
  }

  res_stream->finishResponse();
}

void TSDBServlet::insertRecords(
    const http::HTTPRequest* req,
    http::HTTPResponse* res,
    URI* uri) {
  auto record_list = msg::decode<RecordEnvelopeList>(req->body());

  Vector<RefPtr<Partition>> partition_refs;
  HashMap<Partition*, Vector<RecordRef>> grouped;
  for (const auto& record : record_list.records()) {
    auto partition = node_->findOrCreatePartition(
        record.tsdb_namespace(),
        record.stream_key(),
        SHA1Hash::fromHexString(record.partition_key()));

    auto record_data = record.record_data().data();
    auto record_size = record.record_data().size();

    if (grouped.count(partition.get()) == 0) {
      partition_refs.emplace_back(partition);
    }

    grouped[partition.get()].emplace_back(
        SHA1Hash::fromHexString(record.record_id()),
        Buffer(record_data, record_size));
  }

  for (const auto& group : grouped) {
    group.first->insertRecords(group.second);
  }

  res->setStatus(http::kStatusCreated);
}

void TSDBServlet::streamPartition(
    const http::HTTPRequest* req,
    http::HTTPResponse* res,
    RefPtr<http::HTTPResponseStream> res_stream,
    URI* uri) {
  const auto& params = uri->queryParams();

  String tsdb_namespace;
  if (!URI::getParam(params, "namespace", &tsdb_namespace)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?namespace=... parameter");
    return;
  }

  String stream_key;
  if (!URI::getParam(params, "stream", &stream_key)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?stream=... parameter");
    return;
  }

  String partition_key;
  if (!URI::getParam(params, "partition", &partition_key)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?partition=... parameter");
    return;
  }

  size_t sample_mod = 0;
  size_t sample_idx = 0;
  String sample_str;
  if (URI::getParam(params, "sample", &sample_str)) {
    auto parts = StringUtil::split(sample_str, ":");

    if (parts.size() != 2) {
      res->setStatus(fnord::http::kStatusBadRequest);
      res->addBody("invalid ?sample=... parameter, format is <mod>:<idx>");
      res_stream->writeResponse(*res);
    }

    sample_mod = std::stoull(parts[0]);
    sample_idx = std::stoull(parts[1]);
  }

  res->setStatus(http::kStatusOK);
  res->addHeader("Content-Type", "application/octet-stream");
  res->addHeader("Connection", "close");
  res_stream->startResponse(*res);

  auto partition = node_->findPartition(
      tsdb_namespace,
      stream_key,
      SHA1Hash::fromHexString(partition_key));

  if (!partition.isEmpty()) {
    FNV<uint64_t> fnv;
    auto files = partition.get()->listFiles();

    for (const auto& f : files) {
      auto fpath = FileUtil::joinPaths(node_->dbPath(), f);
      sstable::SSTableReader reader(fpath);
      auto cursor = reader.getCursor();

      while (cursor->valid()) {
        uint64_t* key;
        size_t key_size;
        cursor->getKey((void**) &key, &key_size);
        if (key_size != SHA1Hash::kSize) {
          RAISE(kRuntimeError, "invalid row");
        }

        if (sample_mod == 0 ||
            (fnv.hash(key, key_size) % sample_mod == sample_idx)) {
          void* data;
          size_t data_size;
          cursor->getData(&data, &data_size);

          util::BinaryMessageWriter buf;
          if (data_size > 0) {
            buf.appendUInt64(data_size);
            buf.append(data, data_size);
            res_stream->writeBodyChunk(Buffer(buf.data(), buf.size()));
          }
          res_stream->waitForReader();
        }

        if (!cursor->next()) {
          break;
        }
      }
    }
  }

  util::BinaryMessageWriter buf;
  buf.appendUInt64(0);
  res_stream->writeBodyChunk(Buffer(buf.data(), buf.size()));

  res_stream->finishResponse();
}

void TSDBServlet::fetchPartitionInfo(
    const http::HTTPRequest* req,
    http::HTTPResponse* res,
    URI* uri) {
  const auto& params = uri->queryParams();

  String tsdb_namespace;
  if (!URI::getParam(params, "namespace", &tsdb_namespace)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?namespace=... parameter");
    return;
  }

  String stream_key;
  if (!URI::getParam(params, "stream", &stream_key)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?stream=... parameter");
    return;
  }

  String partition_key;
  if (!URI::getParam(params, "partition", &partition_key)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?partition=... parameter");
    return;
  }

  auto partition = node_->findPartition(
      tsdb_namespace,
      stream_key,
      SHA1Hash::fromHexString(partition_key));

  PartitionInfo pinfo;
  pinfo.set_partition_key(partition_key);
  if (!partition.isEmpty()) {
    pinfo = partition.get()->partitionInfo();
  }

  res->setStatus(http::kStatusOK);
  res->addHeader("Content-Type", "application/x-protobuf");
  res->addBody(*msg::encode(pinfo));
}

void TSDBServlet::executeSQL(
    const http::HTTPRequest* req,
    http::HTTPResponse* res,
    RefPtr<http::HTTPResponseStream> res_stream,
    URI* uri) {
  if (!req->hasHeader("X-TSDB-Namespace")) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing X-TSDB-Namespace header");
    res_stream->writeResponse(*res);
    return;
  }

  auto tsdb_ns = req->getHeader("X-TSDB-Namespace");
  bool with_status = req->hasHeader("X-TSDB-With-Status");

  auto query = req->body().toString();
  auto qplan = node_->sqlEngine()->parseAndBuildQueryPlan(
      tsdb_ns,
      query);

  csql::ExecutionContext context;

  http::HTTPSSEStream sse_stream(res, res_stream);
  if (with_status) {
    sse_stream.start();

  //auto send_status_update = [&sse_stream, &task_future] {
  //  auto status = task_future->status();
  //  auto progress = status.progress();

  //  Buffer buf;
  //  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));
  //  json.beginObject();
  //  json.addObjectEntry("status");
  //  json.addString("running");
  //  json.addComma();
  //  json.addObjectEntry("progress");
  //  json.addFloat(progress);
  //  json.addComma();
  //  json.addObjectEntry("message");
  //  if (progress == 0.0f) {
  //    json.addString("Waiting...");
  //  } else if (progress == 1.0f) {
  //    json.addString("Downloading...");
  //  } else {
  //    json.addString("Running...");
  //  }
  //  json.endObject();

  //  sse_stream.sendEvent(buf, Some(String("status")));
  //};
  }

  Buffer result;
  csql::ASCIITableFormat format;
  format.formatResults(qplan, BufferOutputStream::fromBuffer(&result));

  if (with_status) {
    sse_stream.sendEvent(result, Some(String("result")));
    sse_stream.finish();
  } else {
    res->setStatus(http::kStatusOK);
    res->addHeader("Content-Type", "text/plain");
    res->addHeader("Connection", "close");
    res_stream->startResponse(*res);
    res_stream->writeBodyChunk(result);
    res_stream->finishResponse();
  }
}

}

<commit_msg>CORS headers<commit_after>/**
 * This file is part of the "libfnord" project
 *   Copyright (c) 2015 Paul Asmuth
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include "fnord/util/binarymessagewriter.h"
#include "tsdb/TSDBServlet.h"
#include "tsdb/RecordEnvelope.pb.h"
#include "fnord/json/json.h"
#include <fnord/wallclock.h>
#include <fnord/thread/wakeup.h>
#include "fnord/protobuf/MessageEncoder.h"
#include "fnord/protobuf/MessagePrinter.h"
#include "fnord/protobuf/msg.h"
#include <fnord/util/Base64.h>
#include <fnord/fnv.h>
#include <sstable/sstablereader.h>
#include <chartsql/runtime/ASCIITableFormat.h>

using namespace fnord;

namespace tsdb {

TSDBServlet::TSDBServlet(TSDBNode* node) : node_(node) {}

void TSDBServlet::handleHTTPRequest(
    RefPtr<http::HTTPRequestStream> req_stream,
    RefPtr<http::HTTPResponseStream> res_stream) {
  req_stream->readBody();
  const auto& req = req_stream->request();
  URI uri(req.uri());

  http::HTTPResponse res;
  res.populateFromRequest(req);
  res.addHeader("Access-Control-Allow-Origin", "*");
  res.addHeader("Access-Control-Allow-Methods", "GET, POST");
  res.addHeader("Access-Control-Allow-Headers", "X-TSDB-Namespace, X-TSDB-With-Status");

  if (req.method() == http::HTTPMessage::M_OPTIONS) {
    res.setStatus(http::kStatusOK);
    res_stream->writeResponse(res);
    return;
  }

  try {
    if (uri.path() == "/tsdb/insert") {
      insertRecords(&req, &res, &uri);
      res_stream->writeResponse(res);
      return;
    }

    if (uri.path() == "/tsdb/stream") {
      streamPartition(&req, &res, res_stream, &uri);
      return;
    }

    if (uri.path() == "/tsdb/partition_info") {
      fetchPartitionInfo(&req, &res, &uri);
      res_stream->writeResponse(res);
      return;
    }

    if (uri.path() == "/tsdb/sql") {
      executeSQL(&req, &res, res_stream, &uri);
      return;
    }

    res.setStatus(fnord::http::kStatusNotFound);
    res.addBody("not found");
    res_stream->writeResponse(res);
  } catch (const Exception& e) {
    fnord::logError("tsdb", e, "error while processing HTTP request");

    res.setStatus(http::kStatusInternalServerError);
    res.addBody(StringUtil::format("error: $0: $1", e.getTypeName(), e.getMessage()));
    res_stream->writeResponse(res);
  }

  res_stream->finishResponse();
}

void TSDBServlet::insertRecords(
    const http::HTTPRequest* req,
    http::HTTPResponse* res,
    URI* uri) {
  auto record_list = msg::decode<RecordEnvelopeList>(req->body());

  Vector<RefPtr<Partition>> partition_refs;
  HashMap<Partition*, Vector<RecordRef>> grouped;
  for (const auto& record : record_list.records()) {
    auto partition = node_->findOrCreatePartition(
        record.tsdb_namespace(),
        record.stream_key(),
        SHA1Hash::fromHexString(record.partition_key()));

    auto record_data = record.record_data().data();
    auto record_size = record.record_data().size();

    if (grouped.count(partition.get()) == 0) {
      partition_refs.emplace_back(partition);
    }

    grouped[partition.get()].emplace_back(
        SHA1Hash::fromHexString(record.record_id()),
        Buffer(record_data, record_size));
  }

  for (const auto& group : grouped) {
    group.first->insertRecords(group.second);
  }

  res->setStatus(http::kStatusCreated);
}

void TSDBServlet::streamPartition(
    const http::HTTPRequest* req,
    http::HTTPResponse* res,
    RefPtr<http::HTTPResponseStream> res_stream,
    URI* uri) {
  const auto& params = uri->queryParams();

  String tsdb_namespace;
  if (!URI::getParam(params, "namespace", &tsdb_namespace)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?namespace=... parameter");
    return;
  }

  String stream_key;
  if (!URI::getParam(params, "stream", &stream_key)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?stream=... parameter");
    return;
  }

  String partition_key;
  if (!URI::getParam(params, "partition", &partition_key)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?partition=... parameter");
    return;
  }

  size_t sample_mod = 0;
  size_t sample_idx = 0;
  String sample_str;
  if (URI::getParam(params, "sample", &sample_str)) {
    auto parts = StringUtil::split(sample_str, ":");

    if (parts.size() != 2) {
      res->setStatus(fnord::http::kStatusBadRequest);
      res->addBody("invalid ?sample=... parameter, format is <mod>:<idx>");
      res_stream->writeResponse(*res);
    }

    sample_mod = std::stoull(parts[0]);
    sample_idx = std::stoull(parts[1]);
  }

  res->setStatus(http::kStatusOK);
  res->addHeader("Content-Type", "application/octet-stream");
  res->addHeader("Connection", "close");
  res_stream->startResponse(*res);

  auto partition = node_->findPartition(
      tsdb_namespace,
      stream_key,
      SHA1Hash::fromHexString(partition_key));

  if (!partition.isEmpty()) {
    FNV<uint64_t> fnv;
    auto files = partition.get()->listFiles();

    for (const auto& f : files) {
      auto fpath = FileUtil::joinPaths(node_->dbPath(), f);
      sstable::SSTableReader reader(fpath);
      auto cursor = reader.getCursor();

      while (cursor->valid()) {
        uint64_t* key;
        size_t key_size;
        cursor->getKey((void**) &key, &key_size);
        if (key_size != SHA1Hash::kSize) {
          RAISE(kRuntimeError, "invalid row");
        }

        if (sample_mod == 0 ||
            (fnv.hash(key, key_size) % sample_mod == sample_idx)) {
          void* data;
          size_t data_size;
          cursor->getData(&data, &data_size);

          util::BinaryMessageWriter buf;
          if (data_size > 0) {
            buf.appendUInt64(data_size);
            buf.append(data, data_size);
            res_stream->writeBodyChunk(Buffer(buf.data(), buf.size()));
          }
          res_stream->waitForReader();
        }

        if (!cursor->next()) {
          break;
        }
      }
    }
  }

  util::BinaryMessageWriter buf;
  buf.appendUInt64(0);
  res_stream->writeBodyChunk(Buffer(buf.data(), buf.size()));

  res_stream->finishResponse();
}

void TSDBServlet::fetchPartitionInfo(
    const http::HTTPRequest* req,
    http::HTTPResponse* res,
    URI* uri) {
  const auto& params = uri->queryParams();

  String tsdb_namespace;
  if (!URI::getParam(params, "namespace", &tsdb_namespace)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?namespace=... parameter");
    return;
  }

  String stream_key;
  if (!URI::getParam(params, "stream", &stream_key)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?stream=... parameter");
    return;
  }

  String partition_key;
  if (!URI::getParam(params, "partition", &partition_key)) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing ?partition=... parameter");
    return;
  }

  auto partition = node_->findPartition(
      tsdb_namespace,
      stream_key,
      SHA1Hash::fromHexString(partition_key));

  PartitionInfo pinfo;
  pinfo.set_partition_key(partition_key);
  if (!partition.isEmpty()) {
    pinfo = partition.get()->partitionInfo();
  }

  res->setStatus(http::kStatusOK);
  res->addHeader("Content-Type", "application/x-protobuf");
  res->addBody(*msg::encode(pinfo));
}

void TSDBServlet::executeSQL(
    const http::HTTPRequest* req,
    http::HTTPResponse* res,
    RefPtr<http::HTTPResponseStream> res_stream,
    URI* uri) {
  if (!req->hasHeader("X-TSDB-Namespace")) {
    res->setStatus(fnord::http::kStatusBadRequest);
    res->addBody("missing X-TSDB-Namespace header");
    res_stream->writeResponse(*res);
    return;
  }

  auto tsdb_ns = req->getHeader("X-TSDB-Namespace");
  bool with_status = req->hasHeader("X-TSDB-With-Status");

  auto query = req->body().toString();
  auto qplan = node_->sqlEngine()->parseAndBuildQueryPlan(
      tsdb_ns,
      query);

  csql::ExecutionContext context;

  http::HTTPSSEStream sse_stream(res, res_stream);
  if (with_status) {
    sse_stream.start();

  //auto send_status_update = [&sse_stream, &task_future] {
  //  auto status = task_future->status();
  //  auto progress = status.progress();

  //  Buffer buf;
  //  json::JSONOutputStream json(BufferOutputStream::fromBuffer(&buf));
  //  json.beginObject();
  //  json.addObjectEntry("status");
  //  json.addString("running");
  //  json.addComma();
  //  json.addObjectEntry("progress");
  //  json.addFloat(progress);
  //  json.addComma();
  //  json.addObjectEntry("message");
  //  if (progress == 0.0f) {
  //    json.addString("Waiting...");
  //  } else if (progress == 1.0f) {
  //    json.addString("Downloading...");
  //  } else {
  //    json.addString("Running...");
  //  }
  //  json.endObject();

  //  sse_stream.sendEvent(buf, Some(String("status")));
  //};
  }

  Buffer result;
  csql::ASCIITableFormat format;
  format.formatResults(qplan, BufferOutputStream::fromBuffer(&result));

  if (with_status) {
    sse_stream.sendEvent(result, Some(String("result")));
    sse_stream.finish();
  } else {
    res->setStatus(http::kStatusOK);
    res->addHeader("Content-Type", "text/plain");
    res->addHeader("Connection", "close");
    res_stream->startResponse(*res);
    res_stream->writeBodyChunk(result);
    res_stream->finishResponse();
  }
}

}

<|endoftext|>